@riverbankcms/sdk 0.70.2 → 0.70.4

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 (89) hide show
  1. package/README.md +29 -0
  2. package/dist/_dts/api/src/contentTypes.d.ts +2 -1
  3. package/dist/_dts/block-form/src/client/index.d.ts +1 -1
  4. package/dist/_dts/block-form/src/fields/types.d.ts +14 -2
  5. package/dist/_dts/block-form/src/registry/schemas.d.ts +2 -0
  6. package/dist/_dts/block-form/src/widgets/MediaField/mediaFieldDefaults.d.ts +2 -2
  7. package/dist/_dts/block-form/src/widgets/MediaField/mediaFieldSchema.d.ts +2 -2
  8. package/dist/_dts/blocks/src/lib/media.d.ts +1 -1
  9. package/dist/_dts/blocks/src/system/blocks/appointment-booking.d.ts +1829 -149
  10. package/dist/_dts/blocks/src/system/blocks/blog-listing.d.ts +1829 -149
  11. package/dist/_dts/blocks/src/system/blocks/cart.d.ts +1829 -149
  12. package/dist/_dts/blocks/src/system/blocks/checkout.d.ts +1829 -149
  13. package/dist/_dts/blocks/src/system/blocks/collection.d.ts +1829 -149
  14. package/dist/_dts/blocks/src/system/blocks/cta-full.d.ts +1 -30727
  15. package/dist/_dts/blocks/src/system/blocks/events/event-spotlight.d.ts +11 -30827
  16. package/dist/_dts/blocks/src/system/blocks/faq.d.ts +1829 -149
  17. package/dist/_dts/blocks/src/system/blocks/file-download.d.ts +3 -3
  18. package/dist/_dts/blocks/src/system/blocks/gifting.d.ts +1829 -149
  19. package/dist/_dts/blocks/src/system/blocks/media-text.d.ts +106 -1
  20. package/dist/_dts/blocks/src/system/blocks/product-detail.d.ts +1829 -149
  21. package/dist/_dts/blocks/src/system/blocks/product-list.d.ts +1829 -149
  22. package/dist/_dts/blocks/src/system/blocks/shop.d.ts +1829 -149
  23. package/dist/_dts/blocks/src/system/defineBlock.d.ts +3 -3
  24. package/dist/_dts/blocks/src/system/fragments/library/card.d.ts +2 -30793
  25. package/dist/_dts/blocks/src/system/fragments/library/ctaRow.d.ts +2 -30727
  26. package/dist/_dts/blocks/src/system/fragments/library/feedbackCallout.d.ts +2 -30779
  27. package/dist/_dts/blocks/src/system/fragments/library/heroCtaRow.d.ts +33 -30743
  28. package/dist/_dts/blocks/src/system/fragments/library/sectionState.d.ts +2 -30770
  29. package/dist/_dts/blocks/src/system/fragments/types.d.ts +8 -7
  30. package/dist/_dts/blocks/src/system/manifest/derivedContent.d.ts +7 -5
  31. package/dist/_dts/blocks/src/system/manifest/fieldValidation/index.d.ts +1 -1
  32. package/dist/_dts/blocks/src/system/manifest/schema.d.ts +192 -3
  33. package/dist/_dts/blocks/src/system/runtime/nodes/file-download.d.ts +1 -1
  34. package/dist/_dts/content-model/src/content-types/schema.d.ts +7 -0
  35. package/dist/_dts/content-model/src/contentManifest.d.ts +4 -1
  36. package/dist/_dts/content-model/src/templates/bindingTypeCompatibility.d.ts +1 -1
  37. package/dist/_dts/core/src/index.d.ts +1 -1
  38. package/dist/_dts/core/src/planner.d.ts +4 -0
  39. package/dist/_dts/db/src/generated/supabase/database.types.d.ts +53 -20
  40. package/dist/_dts/editor-blocks/src/index.d.ts +1 -1
  41. package/dist/_dts/editor-blocks/src/media/MediaField.d.ts +6 -5
  42. package/dist/_dts/media-core/src/videoSlotPolicy.d.ts +0 -1
  43. package/dist/_dts/media-editor/src/context.d.ts +4 -1
  44. package/dist/_dts/media-react/src/hooks/useApiMediaUploader.d.ts +8 -1
  45. package/dist/_dts/media-react/src/index.d.ts +1 -5
  46. package/dist/_dts/preview-next/src/client/widgets/PreviewMediaField.d.ts +2 -1
  47. package/dist/_dts/preview-next/src/client/widgets/widgetOverrides.d.ts +1 -0
  48. package/dist/_dts/sdk/src/cli/commands/delete.d.ts +3 -0
  49. package/dist/_dts/sdk/src/cli/commands/style.d.ts +18 -0
  50. package/dist/_dts/sdk/src/cli/helpers.d.ts +8 -33
  51. package/dist/_dts/sdk/src/cli/site-commands/oneOffCommands.d.ts +81 -0
  52. package/dist/_dts/sdk/src/components.d.ts +2 -1
  53. package/dist/_dts/sdk/src/config/field-definitions.d.ts +6 -2
  54. package/dist/_dts/sdk/src/config/typed-entries.d.ts +4 -2
  55. package/dist/_dts/sdk/src/contracts/system-block-content.d.ts +2 -1
  56. package/dist/_dts/sdk/src/manifest/prompt/examples/cta.d.ts +5 -5
  57. package/dist/_dts/sdk/src/manifest/prompt/examples/features-grid.d.ts +2 -2
  58. package/dist/_dts/sdk/src/manifest/prompt/examples/hero.d.ts +2 -2
  59. package/dist/_dts/sdk/src/manifest/prompt/examples/pricing.d.ts +10 -10
  60. package/dist/_dts/sdk/src/manifest/prompt/examples/testimonials.d.ts +4 -4
  61. package/dist/_dts/sdk/src/manifest/validation/output-schema.d.ts +11 -1
  62. package/dist/_dts/sdk/src/next/types.d.ts +4 -2
  63. package/dist/_dts/sdk/src/public-api/contracts.d.ts +2 -1
  64. package/dist/_dts/sdk/src/rendering/index.d.ts +2 -1
  65. package/dist/_dts/sdk/src/rendering/overrideResolution.d.ts +10 -0
  66. package/dist/_dts/sdk/src/rendering/overrides.d.ts +12 -0
  67. package/dist/_dts/sdk/src/version.d.ts +1 -1
  68. package/dist/cli/index.mjs +1072 -289
  69. package/dist/cli/init-docs/content/workflow-preview-mode.md +167 -0
  70. package/dist/client/client.mjs +443 -403
  71. package/dist/client/hooks.mjs +172 -121
  72. package/dist/client/rendering/client.mjs +148 -112
  73. package/dist/client/rendering/islands.mjs +80 -31
  74. package/dist/client/rendering.mjs +25531 -25481
  75. package/dist/preview-next/client/runtime.mjs +394 -1136
  76. package/dist/server/components.mjs +229 -171
  77. package/dist/server/config-template-validation.mjs +31 -1
  78. package/dist/server/config-validation.mjs +172 -121
  79. package/dist/server/config.mjs +172 -121
  80. package/dist/server/data.mjs +172 -121
  81. package/dist/server/index.mjs +1 -1
  82. package/dist/server/next.mjs +301 -174
  83. package/dist/server/page-converter.mjs +379 -185
  84. package/dist/server/prebuild.mjs +1 -1
  85. package/dist/server/rendering/server.mjs +219 -171
  86. package/dist/server/rendering.mjs +229 -171
  87. package/dist/server/routing.mjs +175 -124
  88. package/dist/server/server.mjs +173 -122
  89. package/package.json +5 -3
@@ -916,6 +916,9 @@ var init_repeaterGrid = __esm({
916
916
  DEFAULT_REPEATER_GRID_COLUMN_FIELD_ID = "gridColumn";
917
917
  }
918
918
  });
919
+ function isDisplayMediaKind(kind) {
920
+ return DISPLAY_MEDIA_KINDS.includes(kind);
921
+ }
919
922
  function assertNeverSelectSource(value) {
920
923
  throw new Error(`Unhandled select source: ${JSON.stringify(value)}`);
921
924
  }
@@ -927,6 +930,7 @@ function getFieldSchemaInternal() {
927
930
  textFieldSchema,
928
931
  richTextFieldSchema,
929
932
  mediaFieldSchema,
933
+ fileFieldSchema,
930
934
  booleanFieldSchema,
931
935
  numberFieldSchema,
932
936
  dateFieldSchema,
@@ -993,13 +997,32 @@ function createSdkSelectField(input) {
993
997
  })
994
998
  );
995
999
  }
996
- var visibilityLevels, siteOptionSources, mediaDeliverySchema, selectOptionSchema, selectSourceSchema, uiSchema, baseFieldSchema, textFieldSchema, richTextFieldSchema, mediaFieldSchema, booleanFieldSchema, dateFieldSchema, timeFieldSchema, dateTimeFieldSchema, slugFieldSchema, urlFieldSchema, linkFieldSchema, selectFieldSchema, referenceFieldSchema, itemTypeSchema, repeaterFieldSchema, groupFieldSchema, modalFieldSchema, numberFieldSchema, tabDefinitionSchema, tabGroupFieldSchema, presetOptionSchema, presetOrCustomFieldSchema, contentTypeSelectFieldSchema, entryPickerFieldSchema, _fieldSchemaInternal, fieldSchema, slotSchema, typographyTokens, colorTokens, spacingTokens, radiusTokens, styleTokenSchema, behaviourSchema, blockCategoryEnum;
1000
+ var visibilityLevels, MEDIA_KINDS, DISPLAY_MEDIA_KINDS, PUBLIC_FILE_FIELD_KINDS, siteOptionSources, mediaDeliverySchema, selectOptionSchema, selectSourceSchema, uiSchema, baseFieldSchema, textFieldSchema, richTextFieldSchema, mediaFieldSchema, fileFieldSchema, booleanFieldSchema, dateFieldSchema, timeFieldSchema, dateTimeFieldSchema, slugFieldSchema, urlFieldSchema, linkFieldSchema, selectFieldSchema, referenceFieldSchema, itemTypeSchema, repeaterFieldSchema, groupFieldSchema, modalFieldSchema, numberFieldSchema, tabDefinitionSchema, tabGroupFieldSchema, presetOptionSchema, presetOrCustomFieldSchema, contentTypeSelectFieldSchema, entryPickerFieldSchema, _fieldSchemaInternal, fieldSchema, slotSchema, typographyTokens, colorTokens, spacingTokens, radiusTokens, styleTokenSchema, behaviourSchema, blockCategoryEnum;
997
1001
  var init_schema2 = __esm({
998
1002
  "../blocks/src/system/manifest/schema.ts"() {
999
1003
  init_src2();
1000
1004
  init_node();
1001
1005
  init_repeaterGrid();
1002
1006
  visibilityLevels = ["admin", "designer", "author"];
1007
+ MEDIA_KINDS = [
1008
+ "image",
1009
+ "video",
1010
+ "audio",
1011
+ "document",
1012
+ "spreadsheet",
1013
+ "archive"
1014
+ ];
1015
+ DISPLAY_MEDIA_KINDS = [
1016
+ "image",
1017
+ "video",
1018
+ "audio"
1019
+ ];
1020
+ PUBLIC_FILE_FIELD_KINDS = [
1021
+ "document",
1022
+ "spreadsheet",
1023
+ "archive",
1024
+ "audio"
1025
+ ];
1003
1026
  siteOptionSources = [
1004
1027
  "eventCategories",
1005
1028
  "venues",
@@ -1160,11 +1183,19 @@ var init_schema2 = __esm({
1160
1183
  });
1161
1184
  mediaFieldSchema = baseFieldSchema.extend({
1162
1185
  type: z.literal("media"),
1163
- mediaKinds: z.array(
1164
- z.enum(["image", "video", "audio", "document", "spreadsheet", "archive"])
1165
- ).default(["image"]),
1186
+ // Keep full MEDIA_KINDS parse compatibility for pre-file-field manifests.
1187
+ // New authoring surfaces should use `file.fileKinds` for document/archive
1188
+ // style assets, but old saved schemas must not fail to open.
1189
+ mediaKinds: z.array(z.enum(MEDIA_KINDS)).default(["image"]).transform((kinds) => {
1190
+ const displayKinds = kinds.filter(isDisplayMediaKind);
1191
+ return displayKinds.length > 0 ? displayKinds : ["image"];
1192
+ }),
1166
1193
  aspectRatio: z.string().optional()
1167
1194
  });
1195
+ fileFieldSchema = baseFieldSchema.extend({
1196
+ type: z.literal("file"),
1197
+ fileKinds: z.array(z.enum(PUBLIC_FILE_FIELD_KINDS)).default([...PUBLIC_FILE_FIELD_KINDS])
1198
+ });
1168
1199
  booleanFieldSchema = baseFieldSchema.extend({
1169
1200
  type: z.literal("boolean")
1170
1201
  });
@@ -3402,7 +3433,10 @@ var init_soft_pill = __esm({
3402
3433
  });
3403
3434
 
3404
3435
  // ../theme-core/src/buttons/personalities/index.ts
3405
- var buttonPersonalities;
3436
+ function findButtonPersonality(id) {
3437
+ return personalitiesById.get(id);
3438
+ }
3439
+ var buttonPersonalities, personalitiesById;
3406
3440
  var init_personalities = __esm({
3407
3441
  "../theme-core/src/buttons/personalities/index.ts"() {
3408
3442
  init_brushed_wash();
@@ -3422,7 +3456,7 @@ var init_personalities = __esm({
3422
3456
  brushedWash,
3423
3457
  showtimePill
3424
3458
  ];
3425
- new Map(
3459
+ personalitiesById = new Map(
3426
3460
  buttonPersonalities.map((p) => [p.id, p])
3427
3461
  );
3428
3462
  }
@@ -5115,7 +5149,10 @@ var init_warm_neutral = __esm({
5115
5149
  });
5116
5150
 
5117
5151
  // ../theme-core/src/palette/variants/index.ts
5118
- var paletteVariants;
5152
+ function findPaletteVariant(id) {
5153
+ return paletteVariantsById.get(id);
5154
+ }
5155
+ var paletteVariants, paletteVariantsById;
5119
5156
  var init_variants = __esm({
5120
5157
  "../theme-core/src/palette/variants/index.ts"() {
5121
5158
  init_brand_led();
@@ -5142,7 +5179,7 @@ var init_variants = __esm({
5142
5179
  softNaturalStone,
5143
5180
  softNaturalWatercolor
5144
5181
  ];
5145
- new Map(
5182
+ paletteVariantsById = new Map(
5146
5183
  paletteVariants.map((v) => [v.id, v])
5147
5184
  );
5148
5185
  }
@@ -5407,7 +5444,10 @@ function floatingGlassHeader(theme) {
5407
5444
  }
5408
5445
  };
5409
5446
  }
5410
- var headerLookCatalog;
5447
+ function findHeaderLook(id) {
5448
+ return headerLooksById.get(id);
5449
+ }
5450
+ var headerLookCatalog, headerLooksById;
5411
5451
  var init_headerLooks = __esm({
5412
5452
  "../theme-core/src/site-styles/headerLooks.ts"() {
5413
5453
  init_headerCtaVariants();
@@ -5487,7 +5527,7 @@ var init_headerLooks = __esm({
5487
5527
  compile: floatingGlassHeader
5488
5528
  }
5489
5529
  ];
5490
- new Map(
5530
+ headerLooksById = new Map(
5491
5531
  headerLookCatalog.map((look) => [look.id, look])
5492
5532
  );
5493
5533
  }
@@ -5556,7 +5596,10 @@ function brandTwoBandFooter(theme) {
5556
5596
  }
5557
5597
  };
5558
5598
  }
5559
- var footerLookCatalog;
5599
+ function findFooterLook(id) {
5600
+ return footerLooksById.get(id);
5601
+ }
5602
+ var footerLookCatalog, footerLooksById;
5560
5603
  var init_footerLooks = __esm({
5561
5604
  "../theme-core/src/site-styles/footerLooks.ts"() {
5562
5605
  init_customizableSurfaces();
@@ -5575,7 +5618,7 @@ var init_footerLooks = __esm({
5575
5618
  compile: brandTwoBandFooter
5576
5619
  }
5577
5620
  ];
5578
- new Map(
5621
+ footerLooksById = new Map(
5579
5622
  footerLookCatalog.map((look) => [look.id, look])
5580
5623
  );
5581
5624
  }
@@ -9257,13 +9300,19 @@ function defineFragment(config2) {
9257
9300
  function scopeFragmentFields(fragment, scope) {
9258
9301
  const normalizedScope = scope.trim();
9259
9302
  if (!normalizedScope) {
9260
- return fragment.fields.map((field) => cloneFieldDefinition2(field));
9303
+ return fragment.fields.map(
9304
+ (field) => cloneFieldDefinition2(field)
9305
+ );
9261
9306
  }
9262
- return fragment.fields.map((field) => prefixFieldId(field, normalizedScope));
9307
+ return fragment.fields.map(
9308
+ (field) => prefixFieldId(field, normalizedScope)
9309
+ );
9263
9310
  }
9264
9311
  function scopeFragmentLayout(fragment, scope) {
9265
9312
  const normalizedScope = scope.trim();
9266
- return fragment.layout.map((node) => cloneAndScopeNode(node, normalizedScope));
9313
+ return fragment.layout.map(
9314
+ (node) => cloneAndScopeNode(node, normalizedScope)
9315
+ );
9267
9316
  }
9268
9317
  function validateFieldDefinitions(fields3, fragmentId) {
9269
9318
  const seen = /* @__PURE__ */ new Set();
@@ -9345,7 +9394,9 @@ function cloneAndScopeNode(node, scope) {
9345
9394
  ...node
9346
9395
  };
9347
9396
  if (node.children) {
9348
- cloned.children = node.children.map((child) => cloneAndScopeNode(child, scope));
9397
+ cloned.children = node.children.map(
9398
+ (child) => cloneAndScopeNode(child, scope)
9399
+ );
9349
9400
  }
9350
9401
  if (node.props) {
9351
9402
  cloned.props = scopePropBindings(node.props, scope);
@@ -9371,7 +9422,9 @@ function scopeBinding(binding, scope) {
9371
9422
  const cloned = {
9372
9423
  ...binding,
9373
9424
  transforms: binding.transforms?.map(
9374
- (step) => ({ ...step })
9425
+ (step) => ({
9426
+ ...step
9427
+ })
9375
9428
  ) ?? []
9376
9429
  };
9377
9430
  cloned.from = scopeContentPath(binding.from, scope);
@@ -9415,7 +9468,9 @@ function scopePropValue(value, scope) {
9415
9468
  };
9416
9469
  }
9417
9470
  const result = {};
9418
- for (const [key, entry] of Object.entries(value)) {
9471
+ for (const [key, entry] of Object.entries(
9472
+ value
9473
+ )) {
9419
9474
  result[key] = scopePropValue(entry, scope);
9420
9475
  }
9421
9476
  return result;
@@ -9461,13 +9516,18 @@ var init_types13 = __esm({
9461
9516
  loader: dataLoaderSchema.optional()
9462
9517
  });
9463
9518
  fragmentConfigSchema = z.object({
9464
- id: z.string().min(1, "Fragment id is required").regex(FRAGMENT_ID_PATTERN, "Fragment id must be alphanumeric with optional . _ - separators"),
9519
+ id: z.string().min(1, "Fragment id is required").regex(
9520
+ FRAGMENT_ID_PATTERN,
9521
+ "Fragment id must be alphanumeric with optional . _ - separators"
9522
+ ),
9465
9523
  title: z.string().optional(),
9466
9524
  description: z.string().optional(),
9467
9525
  category: z.enum(["content", "media", "interactive", "layout"]).optional(),
9468
9526
  icon: z.string().optional(),
9469
9527
  fields: fieldSchema.array().default([]),
9470
- layout: z.union([NodeSchema, NodeSchema.array()]).transform((value) => Array.isArray(value) ? value : [value]),
9528
+ layout: z.union([NodeSchema, NodeSchema.array()]).transform(
9529
+ (value) => Array.isArray(value) ? value : [value]
9530
+ ),
9471
9531
  data: fragmentDataSchema.optional()
9472
9532
  });
9473
9533
  FragmentConfigError = class extends Error {
@@ -9937,34 +9997,35 @@ var init_ctaRow2 = __esm({
9937
9997
  });
9938
9998
 
9939
9999
  // ../blocks/src/system/fragments/library/heroCtaRow.ts
9940
- var heroCtaRowFragment;
10000
+ var heroCtaFields, heroCtaRowFragment;
9941
10001
  var init_heroCtaRow = __esm({
9942
10002
  "../blocks/src/system/fragments/library/heroCtaRow.ts"() {
9943
10003
  init_types13();
9944
10004
  init_fragments();
9945
10005
  init_ctas();
10006
+ heroCtaFields = [
10007
+ createCtasRepeater({
10008
+ label: "Calls to action",
10009
+ itemLabel: "CTA",
10010
+ maxItems: 3,
10011
+ button: {
10012
+ variants: [
10013
+ { value: "default", label: "Default" },
10014
+ { value: "primary", label: "Primary" },
10015
+ { value: "secondary", label: "Secondary" },
10016
+ { value: "outline", label: "Outline" }
10017
+ ],
10018
+ defaultVariant: "default",
10019
+ includeSize: true,
10020
+ defaultSize: "lg"
10021
+ }
10022
+ })
10023
+ ];
9946
10024
  heroCtaRowFragment = defineFragment({
9947
10025
  id: "heroCtaRow",
9948
10026
  title: "Hero CTAs",
9949
10027
  description: "Repeatable hero calls to action rendered inline.",
9950
- fields: [
9951
- createCtasRepeater({
9952
- label: "Calls to action",
9953
- itemLabel: "CTA",
9954
- maxItems: 3,
9955
- button: {
9956
- variants: [
9957
- { value: "default", label: "Default" },
9958
- { value: "primary", label: "Primary" },
9959
- { value: "secondary", label: "Secondary" },
9960
- { value: "outline", label: "Outline" }
9961
- ],
9962
- defaultVariant: "default",
9963
- includeSize: true,
9964
- defaultSize: "lg"
9965
- }
9966
- })
9967
- ],
10028
+ fields: heroCtaFields,
9968
10029
  layout: [
9969
10030
  ctaRow({
9970
10031
  collectionPath: "content.ctas",
@@ -12557,8 +12618,7 @@ var init_media2 = __esm({
12557
12618
  "document",
12558
12619
  "spreadsheet",
12559
12620
  "archive",
12560
- "audio",
12561
- "video"
12621
+ "audio"
12562
12622
  ];
12563
12623
  hotspotSchema2 = z41.object({
12564
12624
  x: z41.number().min(0).max(1),
@@ -24611,6 +24671,7 @@ function deriveFieldValidationPlan(field, path24 = [field.id]) {
24611
24671
  case "richText":
24612
24672
  return makePlan("richText", "object", field, path24, required, commonConstraints(required, { kind: "richTextDoc" }));
24613
24673
  case "media":
24674
+ case "file":
24614
24675
  return makePlan("media", "object", field, path24, required, commonConstraints(required, { kind: "mediaObject" }));
24615
24676
  case "link":
24616
24677
  return makePlan("link", "object", field, path24, required, commonConstraints(required, { kind: "linkObject" }));
@@ -29307,104 +29368,107 @@ init_fragments();
29307
29368
  init_boxStyles();
29308
29369
  init_defineBlock();
29309
29370
  init_shared3();
29310
- var eventSpotlightManifest = createBlockManifest({
29371
+ var eventSpotlightFields = [
29372
+ ...sectionHeaderFields("Upcoming Events"),
29373
+ {
29374
+ id: "maxEvents",
29375
+ type: "select",
29376
+ label: "Events to display",
29377
+ description: "Number of events to show",
29378
+ required: false,
29379
+ multiple: false,
29380
+ defaultValue: "3",
29381
+ options: [
29382
+ { value: "1", label: "1 event" },
29383
+ { value: "2", label: "2 events" },
29384
+ { value: "3", label: "3 events" },
29385
+ { value: "4", label: "4 events" },
29386
+ { value: "5", label: "5 events" },
29387
+ { value: "6", label: "6 events" }
29388
+ ],
29389
+ ui: { intent: "display" }
29390
+ },
29391
+ {
29392
+ id: "ctaLabel",
29393
+ type: "text",
29394
+ label: "Section button text",
29395
+ description: "Optional button shown below the spotlight cards",
29396
+ required: false,
29397
+ multiline: false,
29398
+ maxLength: 40,
29399
+ ui: { intent: "content" }
29400
+ },
29401
+ {
29402
+ id: "ctaUrl",
29403
+ type: "link",
29404
+ label: "Section button destination",
29405
+ required: false,
29406
+ ui: { intent: "display" }
29407
+ },
29408
+ layoutField,
29409
+ columnsField(["2", "3"]),
29410
+ ...cardStylingFields,
29411
+ ...eventDisplayFields,
29412
+ emptyStateField,
29413
+ sectionStylesField({
29414
+ id: "_sectionStyles",
29415
+ label: "Section styles"
29416
+ })
29417
+ ];
29418
+ var eventSpotlightLayout = [
29419
+ styledSection({
29420
+ children: sectionContainer([
29421
+ // Optional heading
29422
+ text(
29423
+ { as: "h2" },
29424
+ bind("content.heading"),
29425
+ when("content.heading")
29426
+ ),
29427
+ // Optional description
29428
+ richText(
29429
+ { className: "rb-prose rb-max-w-none" },
29430
+ bind("content.description"),
29431
+ when("content.description")
29432
+ ),
29433
+ // Event spotlight component
29434
+ el("event-spotlight", {
29435
+ events: { $bind: { from: "data.events" } },
29436
+ layout: { $bind: { from: "content.layout", fallback: "grid" } },
29437
+ columns: { $bind: { from: "content.columns", fallback: "3" } },
29438
+ cardVariant: { $bind: { from: "content.cardVariant", fallback: "default" } },
29439
+ buttonVariant: { $bind: { from: "content.buttonVariant", fallback: "primary" } },
29440
+ buttonText: { $bind: { from: "content.buttonText", fallback: "View event" } },
29441
+ ctaLabel: { $bind: { from: "content.ctaLabel" } },
29442
+ ctaUrl: { $bind: { from: "content.ctaUrl", transforms: [{ id: "links.resolve" }] } },
29443
+ showVenue: { $bind: { from: "content.showVenue" } },
29444
+ showMap: { $bind: { from: "content.showMap" } },
29445
+ showCapacity: { $bind: { from: "content.showCapacity" } },
29446
+ emptyMessage: { $bind: { from: "content.emptyMessage" } }
29447
+ })
29448
+ ], {
29449
+ gap: "lg"
29450
+ }),
29451
+ // sectionContainer (rb-container) already provides horizontal padding
29452
+ baseClass: "",
29453
+ spacing: "comfortable"
29454
+ })
29455
+ ];
29456
+ var eventSpotlightConfig = {
29311
29457
  id: "block.event-spotlight",
29312
29458
  version: "1.1.0",
29313
29459
  title: "Event Spotlight",
29314
29460
  titleSource: "heading",
29315
29461
  description: "Feature a few upcoming events on your homepage",
29316
29462
  skipSectionStyles: true,
29317
- additionalFields: [
29318
- ...sectionHeaderFields("Upcoming Events"),
29319
- {
29320
- id: "maxEvents",
29321
- type: "select",
29322
- label: "Events to display",
29323
- description: "Number of events to show",
29324
- required: false,
29325
- multiple: false,
29326
- defaultValue: "3",
29327
- options: [
29328
- { value: "1", label: "1 event" },
29329
- { value: "2", label: "2 events" },
29330
- { value: "3", label: "3 events" },
29331
- { value: "4", label: "4 events" },
29332
- { value: "5", label: "5 events" },
29333
- { value: "6", label: "6 events" }
29334
- ],
29335
- ui: { intent: "display" }
29336
- },
29337
- {
29338
- id: "ctaLabel",
29339
- type: "text",
29340
- label: "Section button text",
29341
- description: "Optional button shown below the spotlight cards",
29342
- required: false,
29343
- multiline: false,
29344
- maxLength: 40,
29345
- ui: { intent: "content" }
29346
- },
29347
- {
29348
- id: "ctaUrl",
29349
- type: "link",
29350
- label: "Section button destination",
29351
- required: false,
29352
- ui: { intent: "display" }
29353
- },
29354
- layoutField,
29355
- columnsField(["2", "3"]),
29356
- ...cardStylingFields,
29357
- ...eventDisplayFields,
29358
- emptyStateField,
29359
- sectionStylesField({
29360
- id: "_sectionStyles",
29361
- label: "Section styles"
29362
- })
29363
- ],
29463
+ additionalFields: eventSpotlightFields,
29364
29464
  styleTokens: { background: "surface", typography: "body", spacing: "md" },
29365
29465
  behaviours: { supportsThemeSwitching: true, inlineEditing: false, animation: false, paletteHidden: false },
29366
29466
  category: "content",
29367
29467
  tags: ["events", "featured", "homepage", "spotlight", "upcoming"],
29368
29468
  icon: "Star",
29369
- layout: [
29370
- styledSection({
29371
- children: sectionContainer([
29372
- // Optional heading
29373
- text(
29374
- { as: "h2" },
29375
- bind("content.heading"),
29376
- when("content.heading")
29377
- ),
29378
- // Optional description
29379
- richText(
29380
- { className: "rb-prose rb-max-w-none" },
29381
- bind("content.description"),
29382
- when("content.description")
29383
- ),
29384
- // Event spotlight component
29385
- el("event-spotlight", {
29386
- events: { $bind: { from: "data.events" } },
29387
- layout: { $bind: { from: "content.layout", fallback: "grid" } },
29388
- columns: { $bind: { from: "content.columns", fallback: "3" } },
29389
- cardVariant: { $bind: { from: "content.cardVariant", fallback: "default" } },
29390
- buttonVariant: { $bind: { from: "content.buttonVariant", fallback: "primary" } },
29391
- buttonText: { $bind: { from: "content.buttonText", fallback: "View event" } },
29392
- ctaLabel: { $bind: { from: "content.ctaLabel" } },
29393
- ctaUrl: { $bind: { from: "content.ctaUrl", transforms: [{ id: "links.resolve" }] } },
29394
- showVenue: { $bind: { from: "content.showVenue" } },
29395
- showMap: { $bind: { from: "content.showMap" } },
29396
- showCapacity: { $bind: { from: "content.showCapacity" } },
29397
- emptyMessage: { $bind: { from: "content.emptyMessage" } }
29398
- })
29399
- ], {
29400
- gap: "lg"
29401
- }),
29402
- // sectionContainer (rb-container) already provides horizontal padding
29403
- baseClass: "",
29404
- spacing: "comfortable"
29405
- })
29406
- ]
29407
- });
29469
+ layout: eventSpotlightLayout
29470
+ };
29471
+ var eventSpotlightManifest = createBlockManifest(eventSpotlightConfig);
29408
29472
  var eventSpotlightBlockDefinition = {
29409
29473
  manifest: eventSpotlightManifest,
29410
29474
  dataSchemas: {
@@ -30818,18 +30882,18 @@ var fileDownloadManifest = createBlockManifest({
30818
30882
  title: "File Download",
30819
30883
  titleSource: ["title", "file.filename"],
30820
30884
  category: "media",
30821
- description: "Add a simple public download link for a document, ZIP, audio, or video file.",
30885
+ description: "Add a simple public download link for a document, ZIP, or audio file.",
30822
30886
  tags: ["file", "download", "document", "zip", "media"],
30823
30887
  icon: "Download",
30824
30888
  includeContainerStyles: true,
30825
30889
  additionalFields: [
30826
30890
  {
30827
30891
  id: "file",
30828
- type: "media",
30892
+ type: "file",
30829
30893
  label: "Download file",
30830
30894
  description: "Choose the file visitors can download.",
30831
30895
  required: false,
30832
- mediaKinds: [...PUBLIC_DOWNLOAD_MEDIA_TYPES],
30896
+ fileKinds: [...PUBLIC_DOWNLOAD_MEDIA_TYPES],
30833
30897
  ui: { intent: "content" }
30834
30898
  },
30835
30899
  {
@@ -37529,14 +37593,14 @@ function createCommandContext(command) {
37529
37593
  "This command does not support --env=both. Use --env=local or --env=remote."
37530
37594
  );
37531
37595
  }
37532
- const primaryTarget = envTargets[0];
37533
- const env = loadEnvironment(primaryTarget === "remote");
37596
+ const targetEnv = envTargets[0] ?? "local";
37597
+ const env = loadEnvironment(targetEnv === "remote");
37534
37598
  const client = createManagementClient({
37535
37599
  dashboardUrl: env.dashboardUrl,
37536
37600
  managementApiKey: env.managementApiKey,
37537
37601
  siteId: env.siteId
37538
37602
  });
37539
- return { output, client, isRemote, isJsonOutput, envTargets };
37603
+ return { output, client, isRemote, isJsonOutput, targetEnv, siteId: env.siteId, envTargets };
37540
37604
  }
37541
37605
  function getOutputContext(command) {
37542
37606
  const globalOpts = command.optsWithGlobals();
@@ -37582,6 +37646,14 @@ function withErrorHandling(action) {
37582
37646
  }
37583
37647
  };
37584
37648
  }
37649
+ function withCommandContext(action) {
37650
+ return withErrorHandling(async (...allArgs) => {
37651
+ const command = allArgs[allArgs.length - 1];
37652
+ const actionArgs = allArgs.slice(0, -1);
37653
+ const ctx = createCommandContext(command);
37654
+ await action(ctx, ...actionArgs);
37655
+ });
37656
+ }
37585
37657
  function withConfirmation(getMessage, action) {
37586
37658
  return async (...allArgs) => {
37587
37659
  const command = allArgs[allArgs.length - 1];
@@ -37616,40 +37688,6 @@ function withConfirmation(getMessage, action) {
37616
37688
  function capitalize(str) {
37617
37689
  return str.charAt(0).toUpperCase() + str.slice(1);
37618
37690
  }
37619
- function createPublishCommand(config2) {
37620
- const cmd = new Command("publish").description(`Publish a ${config2.resourceName}`);
37621
- for (const arg of config2.args) {
37622
- cmd.argument(`<${arg}>`, `${capitalize(arg.replace("-", " "))}`);
37623
- }
37624
- return cmd.action(
37625
- withErrorHandling(async (...actionArgs) => {
37626
- const args = actionArgs.slice(0, config2.args.length);
37627
- const command = actionArgs[actionArgs.length - 1];
37628
- const { output, client } = createCommandContext(command);
37629
- const label = args.join("/");
37630
- output.info(`Publishing ${config2.resourceName}: ${label}`);
37631
- await config2.action(client, ...args);
37632
- output.success(`${capitalize(config2.resourceName)} published: ${label}`);
37633
- })
37634
- );
37635
- }
37636
- function createUnpublishCommand(config2) {
37637
- const cmd = new Command("unpublish").description(`Unpublish a ${config2.resourceName}`);
37638
- for (const arg of config2.args) {
37639
- cmd.argument(`<${arg}>`, `${capitalize(arg.replace("-", " "))}`);
37640
- }
37641
- return cmd.action(
37642
- withErrorHandling(async (...actionArgs) => {
37643
- const args = actionArgs.slice(0, config2.args.length);
37644
- const command = actionArgs[actionArgs.length - 1];
37645
- const { output, client } = createCommandContext(command);
37646
- const label = args.join("/");
37647
- output.info(`Unpublishing ${config2.resourceName}: ${label}`);
37648
- await config2.action(client, ...args);
37649
- output.success(`${capitalize(config2.resourceName)} unpublished: ${label}`);
37650
- })
37651
- );
37652
- }
37653
37691
  function createGetCommand(config2) {
37654
37692
  const cmd = new Command("get").description(`Get a single ${config2.resourceName}`);
37655
37693
  for (const arg of config2.args) {
@@ -37715,6 +37753,7 @@ function createListCommand(config2) {
37715
37753
  }
37716
37754
 
37717
37755
  // src/cli/push-config.ts
37756
+ var DEFAULT_CONFIG_PATH = "./riverbank.config.ts";
37718
37757
  function isRecord5(value) {
37719
37758
  return typeof value === "object" && value !== null;
37720
37759
  }
@@ -37850,6 +37889,13 @@ async function pushConfigAction(output, options) {
37850
37889
  let siteIdForErrorContext;
37851
37890
  try {
37852
37891
  process.env.RIVERBANK_ENV = options.isRemote ? "remote" : "local";
37892
+ if (!isJsonOutput) {
37893
+ output.info("push-config target", {
37894
+ env: process.env.RIVERBANK_ENV,
37895
+ dashboardUrl: options.dashboard,
37896
+ configPath: options.config ?? DEFAULT_CONFIG_PATH
37897
+ });
37898
+ }
37853
37899
  const rawConfig = await loadConfigFile(options.config);
37854
37900
  if (!isJsonOutput) output.info("Validating config...");
37855
37901
  const parseResult = riverbankSiteConfigSchema.safeParse(rawConfig);
@@ -37962,7 +38008,7 @@ function resolveManagementApiKey(output, cliOption, isRemote) {
37962
38008
  }
37963
38009
  return apiKey;
37964
38010
  }
37965
- var pushConfigCommand = new Command("push-config").description("Push SDK config to dashboard").option("--api-key <key>", "Management API key (or set RIVERBANK_*_MGMT_API_KEY)").option("--dashboard <url>", "Dashboard URL (or set RIVERBANK_*_DASHBOARD_URL env var)").option("--config <path>", "Path to config file (default: ./riverbank.config.ts)").option(
38011
+ var pushConfigCommand = new Command("push-config").description("Push SDK config to dashboard").option("--api-key <key>", "Management API key (or set RIVERBANK_*_MGMT_API_KEY)").option("--dashboard <url>", "Dashboard URL (or set RIVERBANK_*_DASHBOARD_URL env var)").option("--config <path>", `Path to config file (default: ${DEFAULT_CONFIG_PATH})`).option(
37966
38012
  "--force-content-types",
37967
38013
  "Force overwrite content type schema even if modified in dashboard after last SDK sync"
37968
38014
  ).addHelpText("after", `
@@ -37980,6 +38026,7 @@ Description:
37980
38026
 
37981
38027
  Examples:
37982
38028
  $ npx riverbankcms push-config
38029
+ $ npx riverbankcms push-config --env=remote
37983
38030
  $ npx riverbankcms push-config --api-key bld_mgmt_sk_... --dashboard https://www.riverbankcms.com
37984
38031
  $ npx riverbankcms push-config --config ./src/riverbank.config.ts
37985
38032
  `).action(async (options, command) => {
@@ -52226,6 +52273,403 @@ function reportMediaValidationWarningsAndCollectBlocking(output, validation) {
52226
52273
  return validation.diagnostics.filter((diagnostic) => diagnostic.severity === "error").map((diagnostic) => formatMediaGuardDiagnostic(diagnostic));
52227
52274
  }
52228
52275
 
52276
+ // src/cli/site-commands/oneOffCommands.ts
52277
+ init_src();
52278
+ function compileOneOffEntryCommand(input) {
52279
+ const commandBinding2 = oneOffEntryCommandBinding(input.mutation);
52280
+ return planCliCommandBatchForBindings({
52281
+ source: input.source,
52282
+ siteId: input.siteId,
52283
+ targetEnv: input.targetEnv,
52284
+ commandTypes: entrySiteCommandTypes,
52285
+ commandBindings: [commandBinding2]
52286
+ });
52287
+ }
52288
+ function compileOneOffPageCommand(input) {
52289
+ const commandBinding2 = oneOffPageCommandBinding(input.mutation);
52290
+ return planCliCommandBatchForBindings({
52291
+ source: input.source,
52292
+ siteId: input.siteId,
52293
+ targetEnv: input.targetEnv,
52294
+ commandTypes: pageSiteCommandTypes,
52295
+ commandBindings: [commandBinding2]
52296
+ });
52297
+ }
52298
+ function compileOneOffBlockCommand(input) {
52299
+ const commandBinding2 = oneOffBlockCommandBinding(input.mutation);
52300
+ return planCliCommandBatchForBindings({
52301
+ source: input.source,
52302
+ siteId: input.siteId,
52303
+ targetEnv: input.targetEnv,
52304
+ commandTypes: pageSiteCommandTypes,
52305
+ commandBindings: [commandBinding2]
52306
+ });
52307
+ }
52308
+ function compileOneOffNavigationCommand(input) {
52309
+ const commandBinding2 = oneOffNavigationCommandBinding(input.mutation);
52310
+ return planCliCommandBatchForBindings({
52311
+ source: input.source,
52312
+ siteId: input.siteId,
52313
+ targetEnv: input.targetEnv,
52314
+ commandTypes: navigationSiteCommandTypes,
52315
+ commandBindings: [commandBinding2]
52316
+ });
52317
+ }
52318
+ async function executeOneOffEntryCommand(input) {
52319
+ const plannedCommand = singlePlannedCommand(input.compiledPlan.plan.commands);
52320
+ return input.apply(plannedCommand.command, input.client);
52321
+ }
52322
+ async function executeOneOffPageCommand(input) {
52323
+ const plannedCommand = singlePlannedCommand(input.compiledPlan.plan.commands);
52324
+ return input.apply(plannedCommand.command, input.client);
52325
+ }
52326
+ async function executeOneOffNavigationCommand(input) {
52327
+ const plannedCommand = singlePlannedCommand(input.compiledPlan.plan.commands);
52328
+ return input.apply(plannedCommand.command, input.client);
52329
+ }
52330
+ async function applyOneOffEntryCommand(command, client) {
52331
+ switch (command.type) {
52332
+ case "upsertContentEntry":
52333
+ return client.entries.upsert({
52334
+ identifier: entryIdentifierForCommand(command),
52335
+ contentType: command.input.contentTypeKey,
52336
+ data: command.input.data ?? {},
52337
+ slug: command.input.slug
52338
+ });
52339
+ case "publishContentEntry":
52340
+ await client.entries.publish(
52341
+ command.input.contentTypeKey,
52342
+ entryIdentifierForCommand(command)
52343
+ );
52344
+ return;
52345
+ case "unpublishContentEntry":
52346
+ await client.entries.unpublish(
52347
+ command.input.contentTypeKey,
52348
+ entryIdentifierForCommand(command)
52349
+ );
52350
+ return;
52351
+ case "deleteContentEntry":
52352
+ await client.entries.delete(
52353
+ command.input.contentTypeKey,
52354
+ entryIdentifierForCommand(command)
52355
+ );
52356
+ return;
52357
+ default:
52358
+ assertNever(command);
52359
+ }
52360
+ }
52361
+ async function applyOneOffEntryCommandReturningEntry(command, client) {
52362
+ const result = await applyOneOffEntryCommand(command, client);
52363
+ if (!result) {
52364
+ throw new Error("Entry upsert completed without returning an entry.");
52365
+ }
52366
+ return result;
52367
+ }
52368
+ async function applyOneOffPageCommand(command, client) {
52369
+ switch (command.type) {
52370
+ case "upsertPage":
52371
+ return client.pages.upsert({
52372
+ identifier: pageIdentifierForCommand(command),
52373
+ title: command.input.title,
52374
+ path: pagePathForCommand(command),
52375
+ seoTitle: command.input.seoTitle,
52376
+ seoDescription: command.input.seoDescription
52377
+ });
52378
+ case "publishPage":
52379
+ await client.pages.publish(pageIdentifierForCommand(command));
52380
+ return;
52381
+ case "unpublishPage":
52382
+ await client.pages.unpublish(pageIdentifierForCommand(command));
52383
+ return;
52384
+ case "upsertPageBlock":
52385
+ return client.blocks.upsert(pageIdentifierForBlockCommand(command), {
52386
+ identifier: blockIdentifierForCommand(command),
52387
+ kind: command.input.type,
52388
+ data: command.input.props ?? {}
52389
+ });
52390
+ case "reorderPageBlocks":
52391
+ await client.blocks.reorder(
52392
+ pageIdentifierForBlockCommand(command),
52393
+ [...blockOrderIdentifiersForCommand(command)]
52394
+ );
52395
+ return;
52396
+ case "deletePageBlock":
52397
+ await client.blocks.delete(
52398
+ pageIdentifierForBlockCommand(command),
52399
+ blockIdentifierForCommand(command)
52400
+ );
52401
+ return;
52402
+ default:
52403
+ assertNever(command);
52404
+ }
52405
+ }
52406
+ async function applyOneOffPageCommandReturningPage(command, client) {
52407
+ const result = await applyOneOffPageCommand(command, client);
52408
+ if (!result || !isManagementPage(result)) {
52409
+ throw new Error("Page upsert completed without returning a page.");
52410
+ }
52411
+ return result;
52412
+ }
52413
+ async function applyOneOffPageCommandReturningBlock(command, client) {
52414
+ const result = await applyOneOffPageCommand(command, client);
52415
+ if (!result || !isManagementBlock(result)) {
52416
+ throw new Error("Block upsert completed without returning a block.");
52417
+ }
52418
+ return result;
52419
+ }
52420
+ async function applyOneOffNavigationCommand(command, client) {
52421
+ const role = navigationCommandRole2(command);
52422
+ return client.navigation.upsert({
52423
+ name: navigationCommandMenuName2(command),
52424
+ items: command.input.items.map(navigationItemInput2),
52425
+ ...role === "primary" ? { isPrimary: true } : {},
52426
+ ...role === "footer" ? { isFooter: true } : {}
52427
+ });
52428
+ }
52429
+ function oneOffEntryCommandBinding(mutation) {
52430
+ const contentType = asCliContentTypeKey(mutation.contentType);
52431
+ const identifier = asCliEntryIdentifier(mutation.identifier);
52432
+ switch (mutation.kind) {
52433
+ case "upsert": {
52434
+ const title = titleFromEntryData(mutation.data);
52435
+ const command = {
52436
+ type: "upsertContentEntry",
52437
+ ref: createContentEntryRef([contentType, identifier]),
52438
+ input: {
52439
+ identifier,
52440
+ contentTypeKey: contentType,
52441
+ ...mutation.slug ? { slug: mutation.slug } : {},
52442
+ ...title ? { title } : {},
52443
+ data: mutation.data
52444
+ }
52445
+ };
52446
+ return {
52447
+ command,
52448
+ reportSubject: { contentType, identifier, counter: "updated" }
52449
+ };
52450
+ }
52451
+ case "publish": {
52452
+ const command = {
52453
+ type: "publishContentEntry",
52454
+ ref: createCommandRef("publish", [contentType, identifier]),
52455
+ input: { contentTypeKey: contentType, identifier }
52456
+ };
52457
+ return {
52458
+ command,
52459
+ reportSubject: { contentType, identifier, counter: "published" }
52460
+ };
52461
+ }
52462
+ case "unpublish": {
52463
+ const command = {
52464
+ type: "unpublishContentEntry",
52465
+ ref: createCommandRef("unpublish", [contentType, identifier]),
52466
+ input: { contentTypeKey: contentType, identifier }
52467
+ };
52468
+ return {
52469
+ command,
52470
+ reportSubject: { contentType, identifier, counter: "unpublished" }
52471
+ };
52472
+ }
52473
+ default:
52474
+ assertNever(mutation);
52475
+ }
52476
+ }
52477
+ function oneOffPageCommandBinding(mutation) {
52478
+ const identifier = asCliPageIdentifier(mutation.identifier);
52479
+ switch (mutation.kind) {
52480
+ case "upsert": {
52481
+ const command = {
52482
+ type: "upsertPage",
52483
+ ref: createPageRef([identifier]),
52484
+ input: {
52485
+ identifier,
52486
+ slug: identifier,
52487
+ title: mutation.title,
52488
+ path: mutation.path,
52489
+ ...mutation.seoTitle ? { seoTitle: mutation.seoTitle } : {},
52490
+ ...mutation.seoDescription ? { seoDescription: mutation.seoDescription } : {}
52491
+ }
52492
+ };
52493
+ return {
52494
+ command,
52495
+ reportSubject: { resource: "page", identifier, counter: "updated" }
52496
+ };
52497
+ }
52498
+ case "publish": {
52499
+ const command = {
52500
+ type: "publishPage",
52501
+ ref: createCommandRef("publish-page", [identifier]),
52502
+ input: { identifier }
52503
+ };
52504
+ return {
52505
+ command,
52506
+ reportSubject: { resource: "page", identifier, counter: "published" }
52507
+ };
52508
+ }
52509
+ case "unpublish": {
52510
+ const command = {
52511
+ type: "unpublishPage",
52512
+ ref: createCommandRef("unpublish-page", [identifier]),
52513
+ input: { identifier }
52514
+ };
52515
+ return {
52516
+ command,
52517
+ reportSubject: { resource: "page", identifier, counter: "unpublished" }
52518
+ };
52519
+ }
52520
+ default:
52521
+ assertNever(mutation);
52522
+ }
52523
+ }
52524
+ function oneOffBlockCommandBinding(mutation) {
52525
+ const pageIdentifier = asCliPageIdentifier(mutation.pageIdentifier);
52526
+ switch (mutation.kind) {
52527
+ case "upsert": {
52528
+ const identifier = asCliBlockIdentifier(mutation.blockIdentifier);
52529
+ const command = {
52530
+ type: "upsertPageBlock",
52531
+ ref: createBlockRef([pageIdentifier, identifier]),
52532
+ input: {
52533
+ pageIdentifier,
52534
+ identifier,
52535
+ type: mutation.blockKind,
52536
+ props: mutation.data
52537
+ }
52538
+ };
52539
+ return {
52540
+ command,
52541
+ reportSubject: {
52542
+ resource: "block",
52543
+ pageIdentifier,
52544
+ identifier,
52545
+ counter: "updated"
52546
+ }
52547
+ };
52548
+ }
52549
+ case "reorder": {
52550
+ const identifiers = mutation.blockIdentifiers.map(asCliBlockIdentifier);
52551
+ const command = {
52552
+ type: "reorderPageBlocks",
52553
+ ref: createBlocksRef([pageIdentifier]),
52554
+ input: {
52555
+ pageIdentifier,
52556
+ blocks: identifiers.map((identifier) => ({
52557
+ blockRef: createBlockRef([pageIdentifier, identifier]),
52558
+ identifier
52559
+ }))
52560
+ }
52561
+ };
52562
+ return {
52563
+ command,
52564
+ reportSubject: {
52565
+ resource: "block",
52566
+ pageIdentifier,
52567
+ identifier: pageIdentifier,
52568
+ counter: "reordered"
52569
+ }
52570
+ };
52571
+ }
52572
+ default:
52573
+ assertNever(mutation);
52574
+ }
52575
+ }
52576
+ function oneOffNavigationCommandBinding(mutation) {
52577
+ const name = asCliNavigationMenuName(mutation.menuName);
52578
+ const command = {
52579
+ type: "upsertNavigationMenu",
52580
+ ref: createNavigationRef([name]),
52581
+ input: {
52582
+ name,
52583
+ items: mutation.items.map(navigationItemForCommand2)
52584
+ }
52585
+ };
52586
+ return {
52587
+ command,
52588
+ reportSubject: { name, counter: "updated" }
52589
+ };
52590
+ }
52591
+ function navigationItemForCommand2(item) {
52592
+ return {
52593
+ label: item.label,
52594
+ ...item.isCta ? { isCta: true } : {},
52595
+ ...item.link ? { link: navigationLinkForCommand(item.link) } : {},
52596
+ ...item.children ? { children: item.children.map(navigationItemForCommand2) } : {}
52597
+ };
52598
+ }
52599
+ function navigationLinkForCommand(link2) {
52600
+ switch (link2.kind) {
52601
+ case "page":
52602
+ return { kind: "page", identifier: link2.identifier };
52603
+ case "entry":
52604
+ return {
52605
+ kind: "entry",
52606
+ contentType: link2.contentType,
52607
+ identifier: link2.identifier
52608
+ };
52609
+ case "external":
52610
+ return { kind: "external", href: link2.href };
52611
+ case "url":
52612
+ return { kind: "url", href: link2.href };
52613
+ case "portal":
52614
+ return {
52615
+ kind: "portal",
52616
+ ...link2.path ? { path: link2.path } : {},
52617
+ ...link2.labels ? { labels: link2.labels } : {}
52618
+ };
52619
+ case "cart":
52620
+ return {
52621
+ kind: "cart",
52622
+ badge: link2.badge,
52623
+ label: link2.label
52624
+ };
52625
+ default:
52626
+ assertNever(link2);
52627
+ }
52628
+ }
52629
+ function navigationItemInput2(item) {
52630
+ return {
52631
+ label: item.label,
52632
+ ...item.isCta ? { isCta: true } : {},
52633
+ ...item.link ? { link: item.link } : {},
52634
+ ...item.children ? { children: item.children.map(navigationItemInput2) } : {}
52635
+ };
52636
+ }
52637
+ function navigationCommandMenuName2(command) {
52638
+ const name = command.input.name ?? command.input.location;
52639
+ if (name) return name;
52640
+ throw new Error(`Invalid navigation command ${command.ref}: missing input.name or input.location.`);
52641
+ }
52642
+ function navigationCommandRole2(command) {
52643
+ if (command.input.role) return command.input.role;
52644
+ switch (command.input.location) {
52645
+ case "main":
52646
+ case "header":
52647
+ return "primary";
52648
+ case "footer":
52649
+ return "footer";
52650
+ case void 0:
52651
+ return void 0;
52652
+ default:
52653
+ return assertNever(command.input.location);
52654
+ }
52655
+ }
52656
+ function isManagementPage(value) {
52657
+ return "path" in value;
52658
+ }
52659
+ function isManagementBlock(value) {
52660
+ return "kind" in value;
52661
+ }
52662
+ function singlePlannedCommand(commands) {
52663
+ if (commands.length !== 1) {
52664
+ throw new Error(`Expected exactly one one-off site command, got ${commands.length}.`);
52665
+ }
52666
+ const plannedCommand = commands[0];
52667
+ if (!plannedCommand) {
52668
+ throw new Error("Expected one one-off site command, got none.");
52669
+ }
52670
+ return plannedCommand;
52671
+ }
52672
+
52229
52673
  // src/cli/commands/entry.ts
52230
52674
  var ENTRY_LIST_COLUMNS = [
52231
52675
  "id",
@@ -52389,8 +52833,8 @@ async function validateEntryUpsertMedia(options) {
52389
52833
  };
52390
52834
  }
52391
52835
  var upsertCommand = new Command("upsert").description("Create or update an entry").argument("<type>", "Content type").argument("<identifier>", "Entry identifier").option("--data <json>", "Entry data as JSON string").option("--file <path>", "Path to JSON file with entry data").option("--slug <slug>", "Entry slug (defaults to identifier)").action(
52392
- withErrorHandling(async (type, identifier, options, command) => {
52393
- const { output, client } = createCommandContext(command);
52836
+ withCommandContext(async (ctx, type, identifier, options) => {
52837
+ const { output, client, siteId, targetEnv } = ctx;
52394
52838
  const data = await parseJsonData(options);
52395
52839
  output.info(`Upserting entry: ${type}/${identifier}`);
52396
52840
  const mediaValidation = await validateEntryUpsertMedia({
@@ -52406,11 +52850,25 @@ var upsertCommand = new Command("upsert").description("Create or update an entry
52406
52850
  suggestion: "Resolve media identifiers on the CMS first, or remove invalid media references."
52407
52851
  });
52408
52852
  }
52409
- const entry = await client.entries.upsert({
52410
- contentType: type,
52411
- identifier,
52412
- data,
52413
- slug: options.slug
52853
+ const compiled = compileOneOffEntryCommand({
52854
+ source: "one_off_entry",
52855
+ siteId,
52856
+ targetEnv,
52857
+ mutation: {
52858
+ kind: "upsert",
52859
+ contentType: type,
52860
+ identifier,
52861
+ data,
52862
+ ...options.slug ? { slug: options.slug } : {}
52863
+ }
52864
+ });
52865
+ if (!compiled.ok) {
52866
+ return output.error(compiled.error.message);
52867
+ }
52868
+ const entry = await executeOneOffEntryCommand({
52869
+ compiledPlan: compiled.value,
52870
+ client,
52871
+ apply: applyOneOffEntryCommandReturningEntry
52414
52872
  });
52415
52873
  output.success(`Entry upserted: ${entry.identifier}`, {
52416
52874
  id: entry.id,
@@ -52420,16 +52878,50 @@ var upsertCommand = new Command("upsert").description("Create or update an entry
52420
52878
  });
52421
52879
  })
52422
52880
  );
52423
- var publishCommand = createPublishCommand({
52424
- resourceName: "entry",
52425
- args: ["type", "identifier"],
52426
- action: (client, type, identifier) => client.entries.publish(type, identifier)
52427
- });
52428
- var unpublishCommand = createUnpublishCommand({
52429
- resourceName: "entry",
52430
- args: ["type", "identifier"],
52431
- action: (client, type, identifier) => client.entries.unpublish(type, identifier)
52432
- });
52881
+ var publishCommand = new Command("publish").description("Publish a entry").argument("<type>", "Type").argument("<identifier>", "Identifier").action(
52882
+ withCommandContext(async (ctx, type, identifier) => {
52883
+ const { output, client, siteId, targetEnv } = ctx;
52884
+ const label = `${type}/${identifier}`;
52885
+ output.info(`Publishing entry: ${label}`);
52886
+ const compiled = compileOneOffEntryCommand({
52887
+ source: "one_off_entry",
52888
+ siteId,
52889
+ targetEnv,
52890
+ mutation: { kind: "publish", contentType: type, identifier }
52891
+ });
52892
+ if (!compiled.ok) {
52893
+ return output.error(compiled.error.message);
52894
+ }
52895
+ await executeOneOffEntryCommand({
52896
+ compiledPlan: compiled.value,
52897
+ client,
52898
+ apply: applyOneOffEntryCommand
52899
+ });
52900
+ output.success(`Entry published: ${label}`);
52901
+ })
52902
+ );
52903
+ var unpublishCommand = new Command("unpublish").description("Unpublish a entry").argument("<type>", "Type").argument("<identifier>", "Identifier").action(
52904
+ withCommandContext(async (ctx, type, identifier) => {
52905
+ const { output, client, siteId, targetEnv } = ctx;
52906
+ const label = `${type}/${identifier}`;
52907
+ output.info(`Unpublishing entry: ${label}`);
52908
+ const compiled = compileOneOffEntryCommand({
52909
+ source: "one_off_entry",
52910
+ siteId,
52911
+ targetEnv,
52912
+ mutation: { kind: "unpublish", contentType: type, identifier }
52913
+ });
52914
+ if (!compiled.ok) {
52915
+ return output.error(compiled.error.message);
52916
+ }
52917
+ await executeOneOffEntryCommand({
52918
+ compiledPlan: compiled.value,
52919
+ client,
52920
+ apply: applyOneOffEntryCommand
52921
+ });
52922
+ output.success(`Entry unpublished: ${label}`);
52923
+ })
52924
+ );
52433
52925
  async function findEntryById(client, contentType, entryId, options = {}) {
52434
52926
  const limit = options.limit ?? 20;
52435
52927
  if (!Number.isFinite(limit) || limit <= 0) {
@@ -52564,15 +53056,29 @@ var formatPageRow = (page) => [
52564
53056
  formatDateShort(page.updatedAt)
52565
53057
  ];
52566
53058
  var upsertCommand2 = new Command("upsert").description("Create or update a page").argument("<identifier>", "Page identifier").requiredOption("--title <title>", "Page title").requiredOption("--path <path>", "Page path (e.g., /about)").option("--seo-title <title>", "SEO title").option("--seo-description <description>", "SEO description").action(
52567
- withErrorHandling(async (identifier, options, command) => {
52568
- const { output, client } = createCommandContext(command);
53059
+ withCommandContext(async (ctx, identifier, options) => {
53060
+ const { output, client, siteId, targetEnv } = ctx;
52569
53061
  output.info(`Upserting page: ${identifier}`);
52570
- const page = await client.pages.upsert({
52571
- identifier,
52572
- title: options.title,
52573
- path: options.path,
52574
- seoTitle: options.seoTitle,
52575
- seoDescription: options.seoDescription
53062
+ const compiled = compileOneOffPageCommand({
53063
+ source: "one_off_page",
53064
+ siteId,
53065
+ targetEnv,
53066
+ mutation: {
53067
+ kind: "upsert",
53068
+ identifier,
53069
+ title: options.title,
53070
+ path: options.path,
53071
+ ...options.seoTitle ? { seoTitle: options.seoTitle } : {},
53072
+ ...options.seoDescription ? { seoDescription: options.seoDescription } : {}
53073
+ }
53074
+ });
53075
+ if (!compiled.ok) {
53076
+ return output.error(compiled.error.message);
53077
+ }
53078
+ const page = await executeOneOffPageCommand({
53079
+ compiledPlan: compiled.value,
53080
+ client,
53081
+ apply: applyOneOffPageCommandReturningPage
52576
53082
  });
52577
53083
  output.success(`Page upserted: ${page.identifier}`, {
52578
53084
  id: page.id,
@@ -52582,16 +53088,48 @@ var upsertCommand2 = new Command("upsert").description("Create or update a page"
52582
53088
  });
52583
53089
  })
52584
53090
  );
52585
- var publishCommand2 = createPublishCommand({
52586
- resourceName: "page",
52587
- args: ["identifier"],
52588
- action: (client, identifier) => client.pages.publish(identifier)
52589
- });
52590
- var unpublishCommand2 = createUnpublishCommand({
52591
- resourceName: "page",
52592
- args: ["identifier"],
52593
- action: (client, identifier) => client.pages.unpublish(identifier)
52594
- });
53091
+ var publishCommand2 = new Command("publish").description("Publish a page").argument("<identifier>", "Identifier").action(
53092
+ withCommandContext(async (ctx, identifier) => {
53093
+ const { output, client, siteId, targetEnv } = ctx;
53094
+ output.info(`Publishing page: ${identifier}`);
53095
+ const compiled = compileOneOffPageCommand({
53096
+ source: "one_off_page",
53097
+ siteId,
53098
+ targetEnv,
53099
+ mutation: { kind: "publish", identifier }
53100
+ });
53101
+ if (!compiled.ok) {
53102
+ return output.error(compiled.error.message);
53103
+ }
53104
+ await executeOneOffPageCommand({
53105
+ compiledPlan: compiled.value,
53106
+ client,
53107
+ apply: applyOneOffPageCommand
53108
+ });
53109
+ output.success(`Page published: ${identifier}`);
53110
+ })
53111
+ );
53112
+ var unpublishCommand2 = new Command("unpublish").description("Unpublish a page").argument("<identifier>", "Identifier").action(
53113
+ withCommandContext(async (ctx, identifier) => {
53114
+ const { output, client, siteId, targetEnv } = ctx;
53115
+ output.info(`Unpublishing page: ${identifier}`);
53116
+ const compiled = compileOneOffPageCommand({
53117
+ source: "one_off_page",
53118
+ siteId,
53119
+ targetEnv,
53120
+ mutation: { kind: "unpublish", identifier }
53121
+ });
53122
+ if (!compiled.ok) {
53123
+ return output.error(compiled.error.message);
53124
+ }
53125
+ await executeOneOffPageCommand({
53126
+ compiledPlan: compiled.value,
53127
+ client,
53128
+ apply: applyOneOffPageCommand
53129
+ });
53130
+ output.success(`Page unpublished: ${identifier}`);
53131
+ })
53132
+ );
52595
53133
  var getCommand2 = createGetCommand({
52596
53134
  resourceName: "page",
52597
53135
  args: ["identifier"],
@@ -52653,9 +53191,9 @@ async function validateBlockUpsertMedia(options) {
52653
53191
  };
52654
53192
  }
52655
53193
  var upsertCommand3 = new Command("upsert").description("Create or update a block on a page").argument("<page-identifier>", "Page identifier").argument("<block-identifier>", "Block identifier").requiredOption("--kind <kind>", "Block kind (e.g., block.hero, block.body-text)").option("--data <json>", "Block data as JSON string").option("--file <path>", "Path to JSON file with block data").option("--position <n>", "Block position (0-indexed)").action(
52656
- withErrorHandling(
52657
- async (pageIdentifier, blockIdentifier, options, command) => {
52658
- const { output, client } = createCommandContext(command);
53194
+ withCommandContext(
53195
+ async (ctx, pageIdentifier, blockIdentifier, options) => {
53196
+ const { output, client, siteId, targetEnv } = ctx;
52659
53197
  const data = await parseJsonData(options);
52660
53198
  output.info(`Upserting block: ${pageIdentifier}/${blockIdentifier}`);
52661
53199
  const mediaValidation = await validateBlockUpsertMedia({
@@ -52672,12 +53210,37 @@ var upsertCommand3 = new Command("upsert").description("Create or update a block
52672
53210
  suggestion: "Resolve media identifiers on the CMS first, or remove invalid media references."
52673
53211
  });
52674
53212
  }
52675
- const block = await client.blocks.upsert(pageIdentifier, {
52676
- identifier: blockIdentifier,
52677
- kind: options.kind,
52678
- data,
52679
- position: options.position ? parseInt(options.position, 10) : void 0
52680
- });
53213
+ const position = options.position ? parseInt(options.position, 10) : void 0;
53214
+ let block;
53215
+ if (position !== void 0) {
53216
+ block = await client.blocks.upsert(pageIdentifier, {
53217
+ identifier: blockIdentifier,
53218
+ kind: options.kind,
53219
+ data,
53220
+ position
53221
+ });
53222
+ } else {
53223
+ const compiled = compileOneOffBlockCommand({
53224
+ source: "one_off_block",
53225
+ siteId,
53226
+ targetEnv,
53227
+ mutation: {
53228
+ kind: "upsert",
53229
+ pageIdentifier,
53230
+ blockIdentifier,
53231
+ blockKind: options.kind,
53232
+ data
53233
+ }
53234
+ });
53235
+ if (!compiled.ok) {
53236
+ return output.error(compiled.error.message);
53237
+ }
53238
+ block = await executeOneOffPageCommand({
53239
+ compiledPlan: compiled.value,
53240
+ client,
53241
+ apply: applyOneOffPageCommandReturningBlock
53242
+ });
53243
+ }
52681
53244
  output.success(`Block upserted: ${block.identifier}`, {
52682
53245
  id: block.id,
52683
53246
  identifier: block.identifier,
@@ -52688,14 +53251,27 @@ var upsertCommand3 = new Command("upsert").description("Create or update a block
52688
53251
  )
52689
53252
  );
52690
53253
  var reorderCommand = new Command("reorder").description("Reorder blocks on a page").argument("<page-identifier>", "Page identifier").argument("<identifiers...>", "Block identifiers in desired order").action(
52691
- withErrorHandling(
52692
- async (pageIdentifier, identifiers, _options, command) => {
52693
- const { output, client } = createCommandContext(command);
53254
+ withCommandContext(
53255
+ async (ctx, pageIdentifier, identifiers) => {
53256
+ const { output, client, siteId, targetEnv } = ctx;
52694
53257
  if (identifiers.length < 2) {
52695
53258
  return output.error("At least 2 block identifiers are required for reordering");
52696
53259
  }
52697
53260
  output.info(`Reordering blocks on page: ${pageIdentifier}`);
52698
- await client.blocks.reorder(pageIdentifier, identifiers);
53261
+ const compiled = compileOneOffBlockCommand({
53262
+ source: "one_off_block",
53263
+ siteId,
53264
+ targetEnv,
53265
+ mutation: { kind: "reorder", pageIdentifier, blockIdentifiers: identifiers }
53266
+ });
53267
+ if (!compiled.ok) {
53268
+ return output.error(compiled.error.message);
53269
+ }
53270
+ await executeOneOffPageCommand({
53271
+ compiledPlan: compiled.value,
53272
+ client,
53273
+ apply: applyOneOffPageCommand
53274
+ });
52699
53275
  output.success(`Blocks reordered`, {
52700
53276
  page: pageIdentifier,
52701
53277
  order: identifiers
@@ -52763,13 +53339,23 @@ function countItems(items) {
52763
53339
  return count;
52764
53340
  }
52765
53341
  var upsertCommand4 = new Command("upsert").description("Create or update a navigation menu").argument("<menu-name>", "Navigation menu name").option("--file <path>", "Path to JSON file with menu items").option("--data <json>", "Menu items as JSON string").action(
52766
- withErrorHandling(async (menuName, options, command) => {
52767
- const { output, client } = createCommandContext(command);
53342
+ withCommandContext(async (ctx, menuName, options) => {
53343
+ const { output, client, siteId, targetEnv } = ctx;
52768
53344
  const items = await parseJsonArray(options);
52769
53345
  output.info(`Upserting navigation menu: ${menuName}`);
52770
- const menu = await client.navigation.upsert({
52771
- name: menuName,
52772
- items
53346
+ const compiled = compileOneOffNavigationCommand({
53347
+ source: "one_off_navigation",
53348
+ siteId,
53349
+ targetEnv,
53350
+ mutation: { kind: "upsert", menuName, items }
53351
+ });
53352
+ if (!compiled.ok) {
53353
+ return output.error(compiled.error.message);
53354
+ }
53355
+ const menu = await executeOneOffNavigationCommand({
53356
+ compiledPlan: compiled.value,
53357
+ client,
53358
+ apply: applyOneOffNavigationCommand
52773
53359
  });
52774
53360
  output.success(`Navigation menu upserted: ${menu.name}`, {
52775
53361
  id: menu.id,
@@ -53919,7 +54505,8 @@ async function initDocs(options) {
53919
54505
  { filename: "content-types.md", template: "workflow-content-types" },
53920
54506
  { filename: "templates.md", template: "workflow-templates" },
53921
54507
  { filename: "cmsify-page.md", template: "workflow-cmsify-page" },
53922
- { filename: "editor-workflows.md", template: "workflow-editor-workflows" }
54508
+ { filename: "editor-workflows.md", template: "workflow-editor-workflows" },
54509
+ { filename: "preview-mode.md", template: "workflow-preview-mode" }
53923
54510
  ];
53924
54511
  await Promise.all(
53925
54512
  coreWorkflows.map(
@@ -54249,7 +54836,7 @@ var SimpleCache = class {
54249
54836
  };
54250
54837
 
54251
54838
  // src/version.ts
54252
- var SDK_VERSION = "0.70.2";
54839
+ var SDK_VERSION = "0.70.4";
54253
54840
 
54254
54841
  // src/client/error.ts
54255
54842
  var RiverbankApiError = class _RiverbankApiError extends Error {
@@ -57302,7 +57889,14 @@ function collectLayoutClassNames(node, out = /* @__PURE__ */ new Set()) {
57302
57889
  }
57303
57890
 
57304
57891
  // src/manifest/validation/output-schema.ts
57305
- var blockCategoryEnum2 = z.enum(["marketing", "content", "blog", "media", "layout", "interactive"]);
57892
+ var blockCategoryEnum2 = z.enum([
57893
+ "marketing",
57894
+ "content",
57895
+ "blog",
57896
+ "media",
57897
+ "layout",
57898
+ "interactive"
57899
+ ]);
57306
57900
  var llmColorValue = z.object({
57307
57901
  name: z.string(),
57308
57902
  hex: z.string()
@@ -57320,8 +57914,16 @@ var llmThemePatchValue = z.union([
57320
57914
  z.array(llmThemePrimitive)
57321
57915
  ]);
57322
57916
  var llmThemePatchOpSchema = z.discriminatedUnion("op", [
57323
- z.object({ op: z.literal("add"), path: z.string().min(1), value: llmThemePatchValue }),
57324
- z.object({ op: z.literal("replace"), path: z.string().min(1), value: llmThemePatchValue }),
57917
+ z.object({
57918
+ op: z.literal("add"),
57919
+ path: z.string().min(1),
57920
+ value: llmThemePatchValue
57921
+ }),
57922
+ z.object({
57923
+ op: z.literal("replace"),
57924
+ path: z.string().min(1),
57925
+ value: llmThemePatchValue
57926
+ }),
57325
57927
  z.object({ op: z.literal("remove"), path: z.string().min(1) })
57326
57928
  ]);
57327
57929
  var llmCssDeclaration = z.object({
@@ -57398,7 +58000,11 @@ var llmRichTextFieldSchema = llmBaseFieldSchema.extend({
57398
58000
  });
57399
58001
  var llmMediaFieldSchema = llmBaseFieldSchema.extend({
57400
58002
  type: z.literal("media"),
57401
- mediaKinds: z.array(z.enum(["image", "video", "audio", "document", "spreadsheet", "archive"])).nullable()
58003
+ mediaKinds: z.array(z.enum(["image", "video", "audio"])).nullable()
58004
+ });
58005
+ var llmFileFieldSchema = llmBaseFieldSchema.extend({
58006
+ type: z.literal("file"),
58007
+ fileKinds: z.array(z.enum(["document", "spreadsheet", "archive", "audio"])).nullable()
57402
58008
  });
57403
58009
  var llmBooleanFieldSchema = llmBaseFieldSchema.extend({
57404
58010
  type: z.literal("boolean")
@@ -57408,10 +58014,12 @@ var llmLinkFieldSchema = llmBaseFieldSchema.extend({
57408
58014
  });
57409
58015
  var llmSelectFieldSchema = llmBaseFieldSchema.extend({
57410
58016
  type: z.literal("select"),
57411
- options: z.array(z.object({
57412
- value: z.string(),
57413
- label: z.string()
57414
- })),
58017
+ options: z.array(
58018
+ z.object({
58019
+ value: z.string(),
58020
+ label: z.string()
58021
+ })
58022
+ ),
57415
58023
  multiple: z.boolean().nullable()
57416
58024
  });
57417
58025
  var llmNumberFieldSchema = llmBaseFieldSchema.extend({
@@ -57447,6 +58055,7 @@ var llmFieldSchema = z.union([
57447
58055
  llmTextFieldSchema,
57448
58056
  llmRichTextFieldSchema,
57449
58057
  llmMediaFieldSchema,
58058
+ llmFileFieldSchema,
57450
58059
  llmBooleanFieldSchema,
57451
58060
  llmLinkFieldSchema,
57452
58061
  llmSelectFieldSchema,
@@ -57457,9 +58066,11 @@ var llmFieldSchema = z.union([
57457
58066
  var llmBindingSchema = z.object({
57458
58067
  from: z.string(),
57459
58068
  fallback: z.string().nullable(),
57460
- transforms: z.array(z.object({
57461
- id: z.string()
57462
- })).nullable()
58069
+ transforms: z.array(
58070
+ z.object({
58071
+ id: z.string()
58072
+ })
58073
+ ).nullable()
57463
58074
  });
57464
58075
  var llmRepeatSchema = z.object({
57465
58076
  collection: z.object({ from: z.string() }),
@@ -57518,11 +58129,17 @@ function collectValidationErrors(output) {
57518
58129
  const blockIds = output.blocks.map((b) => b.id);
57519
58130
  const singleBlockId = blockIds.length === 1 ? blockIds[0] ?? null : null;
57520
58131
  for (const block of output.blocks) {
57521
- const layoutErrors = validateLayoutDeep(block.layout, block.id, block.fields);
58132
+ const layoutErrors = validateLayoutDeep(
58133
+ block.layout,
58134
+ block.id,
58135
+ block.fields
58136
+ );
57522
58137
  errors.push(...layoutErrors);
57523
58138
  const fieldInfo = collectFieldInfo(block.fields);
57524
58139
  const used = collectUsedFieldRefs(block.layout);
57525
- const unusedTopLevelFields = Array.from(fieldInfo.topLevelFieldIds).filter((id) => !used.topLevel.has(id));
58140
+ const unusedTopLevelFields = Array.from(fieldInfo.topLevelFieldIds).filter(
58141
+ (id) => !used.topLevel.has(id)
58142
+ );
57526
58143
  if (unusedTopLevelFields.length > 0) {
57527
58144
  errors.push({
57528
58145
  path: `blocks["${block.id}"].fields`,
@@ -57530,10 +58147,15 @@ function collectValidationErrors(output) {
57530
58147
  suggestion: `Every field should be bound to a layout node. Add $bind: { from: "content.${unusedTopLevelFields[0]}" } to an appropriate node, or remove unused fields.`
57531
58148
  });
57532
58149
  }
57533
- for (const [repeaterFieldId, nestedFieldIds] of fieldInfo.repeaterNestedFieldIds.entries()) {
58150
+ for (const [
58151
+ repeaterFieldId,
58152
+ nestedFieldIds
58153
+ ] of fieldInfo.repeaterNestedFieldIds.entries()) {
57534
58154
  if (!used.topLevel.has(repeaterFieldId)) continue;
57535
58155
  const usedNested = used.nestedByRepeater.get(repeaterFieldId) ?? /* @__PURE__ */ new Set();
57536
- const missingNested = Array.from(nestedFieldIds).filter((id) => !usedNested.has(id));
58156
+ const missingNested = Array.from(nestedFieldIds).filter(
58157
+ (id) => !usedNested.has(id)
58158
+ );
57537
58159
  if (missingNested.length === 0) continue;
57538
58160
  const itemName = used.itemNameByRepeater.get(repeaterFieldId) ?? "item";
57539
58161
  errors.push({
@@ -57546,10 +58168,18 @@ function collectValidationErrors(output) {
57546
58168
  errors.push(...missingBindings);
57547
58169
  errors.push(...validateLinkFieldDefaultValues(block));
57548
58170
  errors.push(...findMissingLinkHrefs(block.layout, block.id, block.fields));
57549
- errors.push(...detectRedundantLinkLabels(block.layout, block.id, block.fields));
58171
+ errors.push(
58172
+ ...detectRedundantLinkLabels(block.layout, block.id, block.fields)
58173
+ );
57550
58174
  }
57551
58175
  if (output.customCssRules && output.customCssRules.length > 0) {
57552
- errors.push(...validateCustomCssRules(output.customCssRules, singleBlockId, output.blocks));
58176
+ errors.push(
58177
+ ...validateCustomCssRules(
58178
+ output.customCssRules,
58179
+ singleBlockId,
58180
+ output.blocks
58181
+ )
58182
+ );
57553
58183
  }
57554
58184
  return errors;
57555
58185
  }
@@ -57625,7 +58255,9 @@ function resolveFieldTypeForFrom(allFields, from, repeatStack) {
57625
58255
  const segments = from.slice(prefix.length).split(".").filter(Boolean);
57626
58256
  const [nestedId, ...rest] = segments;
57627
58257
  if (!nestedId) return null;
57628
- let current = ctx.fields.find((f) => f.id === nestedId);
58258
+ let current = ctx.fields.find(
58259
+ (f) => f.id === nestedId
58260
+ );
57629
58261
  if (!current) return null;
57630
58262
  for (const seg of rest) {
57631
58263
  const nested = getNestedFields(current);
@@ -57641,7 +58273,9 @@ function bindingHasTransform(bind2, id) {
57641
58273
  if (!bind2) return false;
57642
58274
  const transforms = bind2.transforms;
57643
58275
  if (!Array.isArray(transforms)) return false;
57644
- return transforms.some((t) => t && typeof t === "object" && t.id === id);
58276
+ return transforms.some(
58277
+ (t) => t && typeof t === "object" && t.id === id
58278
+ );
57645
58279
  }
57646
58280
  function extractNestedHrefBindFromProps(props2) {
57647
58281
  if (!props2 || typeof props2 !== "object") return null;
@@ -57702,7 +58336,15 @@ function findMissingLinkHrefs(node, blockId, fields3, path24 = "layout", repeatS
57702
58336
  }
57703
58337
  if ("children" in n && Array.isArray(n.children)) {
57704
58338
  for (let i = 0; i < n.children.length; i++) {
57705
- errors.push(...findMissingLinkHrefs(n.children[i], blockId, fields3, `${path24}.children[${i}]`, nextRepeatStack));
58339
+ errors.push(
58340
+ ...findMissingLinkHrefs(
58341
+ n.children[i],
58342
+ blockId,
58343
+ fields3,
58344
+ `${path24}.children[${i}]`,
58345
+ nextRepeatStack
58346
+ )
58347
+ );
57706
58348
  }
57707
58349
  }
57708
58350
  return errors;
@@ -57726,22 +58368,30 @@ function detectRedundantLinkLabels(node, blockId, fields3, path24 = "layout", re
57726
58368
  }
57727
58369
  if (Array.isArray(n.children) && n.children.length > 1) {
57728
58370
  const children = n.children;
57729
- const redundancies = findRedundantLinkTextSiblings(children, nextRepeatStack, path24);
57730
- errors.push(...redundancies.map((r) => ({
57731
- path: r.path,
57732
- message: `Block "${blockId}": ${r.message}`,
57733
- suggestion: r.suggestion
57734
- })));
58371
+ const redundancies = findRedundantLinkTextSiblings(
58372
+ children,
58373
+ nextRepeatStack,
58374
+ path24
58375
+ );
58376
+ errors.push(
58377
+ ...redundancies.map((r) => ({
58378
+ path: r.path,
58379
+ message: `Block "${blockId}": ${r.message}`,
58380
+ suggestion: r.suggestion
58381
+ }))
58382
+ );
57735
58383
  }
57736
58384
  if (Array.isArray(n.children)) {
57737
58385
  for (let i = 0; i < n.children.length; i++) {
57738
- errors.push(...detectRedundantLinkLabels(
57739
- n.children[i],
57740
- blockId,
57741
- fields3,
57742
- `${path24}.children[${i}]`,
57743
- nextRepeatStack
57744
- ));
58386
+ errors.push(
58387
+ ...detectRedundantLinkLabels(
58388
+ n.children[i],
58389
+ blockId,
58390
+ fields3,
58391
+ `${path24}.children[${i}]`,
58392
+ nextRepeatStack
58393
+ )
58394
+ );
57745
58395
  }
57746
58396
  }
57747
58397
  return errors;
@@ -57795,7 +58445,8 @@ function checkRedundantLabelBinding(linkBindFrom, textBindFrom, repeatStack) {
57795
58445
  const ctx = repeatStack[i];
57796
58446
  if (!ctx) continue;
57797
58447
  const prefix = `${ctx.itemName}.`;
57798
- if (!linkBindFrom.startsWith(prefix) || !textBindFrom.startsWith(prefix)) continue;
58448
+ if (!linkBindFrom.startsWith(prefix) || !textBindFrom.startsWith(prefix))
58449
+ continue;
57799
58450
  const linkFieldId = linkBindFrom.slice(prefix.length).split(".")[0] ?? "";
57800
58451
  const textFieldId = textBindFrom.slice(prefix.length).split(".")[0] ?? "";
57801
58452
  const linkField = ctx.fields.find((f) => f.id === linkFieldId);
@@ -57820,7 +58471,10 @@ function validateCustomCssRules(rules, singleBlockId, blocks) {
57820
58471
  const layoutClassNamesByBlockId = /* @__PURE__ */ new Map();
57821
58472
  const layoutNodeInfosByBlockId = /* @__PURE__ */ new Map();
57822
58473
  for (const block of blocks) {
57823
- layoutClassNamesByBlockId.set(block.id, collectLayoutClassNames(block.layout));
58474
+ layoutClassNamesByBlockId.set(
58475
+ block.id,
58476
+ collectLayoutClassNames(block.layout)
58477
+ );
57824
58478
  layoutNodeInfosByBlockId.set(block.id, collectLayoutNodeInfos(block.layout));
57825
58479
  }
57826
58480
  const missingLayoutHooksByBlockId = /* @__PURE__ */ new Map();
@@ -57889,11 +58543,18 @@ function validateCustomCssRules(rules, singleBlockId, blocks) {
57889
58543
  }
57890
58544
  }
57891
58545
  }
57892
- for (const [blockId, missingClassNames] of missingLayoutHooksByBlockId.entries()) {
58546
+ for (const [
58547
+ blockId,
58548
+ missingClassNames
58549
+ ] of missingLayoutHooksByBlockId.entries()) {
57893
58550
  const missing = Array.from(missingClassNames).sort();
57894
58551
  if (missing.length === 0) continue;
57895
58552
  const layoutNodeInfos = layoutNodeInfosByBlockId.get(blockId) ?? [];
57896
- const attachSuggestions = buildClassHookAttachSuggestions(blockId, missing, layoutNodeInfos);
58553
+ const attachSuggestions = buildClassHookAttachSuggestions(
58554
+ blockId,
58555
+ missing,
58556
+ layoutNodeInfos
58557
+ );
57897
58558
  const attachSuggestionsLine = attachSuggestions ? `
57898
58559
 
57899
58560
  Suggested attachments:
@@ -57927,7 +58588,9 @@ function buildClassHookAttachSuggestions(blockId, missingClassNames, nodes) {
57927
58588
  continue;
57928
58589
  }
57929
58590
  if ((lower.includes("headline") || lower.includes("title")) && (headlineNode ?? firstStack)) {
57930
- lines.push(`- ${className} \u2192 add to ${headlineNode ?? firstStack}.props.className`);
58591
+ lines.push(
58592
+ `- ${className} \u2192 add to ${headlineNode ?? firstStack}.props.className`
58593
+ );
57931
58594
  continue;
57932
58595
  }
57933
58596
  if (lower.includes("highlight") && highlightNode) {
@@ -57935,7 +58598,9 @@ function buildClassHookAttachSuggestions(blockId, missingClassNames, nodes) {
57935
58598
  continue;
57936
58599
  }
57937
58600
  if ((lower.includes("body") || lower.includes("copy") || lower.includes("paragraph")) && (paragraphNode ?? firstStack)) {
57938
- lines.push(`- ${className} \u2192 add to ${paragraphNode ?? firstStack}.props.className`);
58601
+ lines.push(
58602
+ `- ${className} \u2192 add to ${paragraphNode ?? firstStack}.props.className`
58603
+ );
57939
58604
  continue;
57940
58605
  }
57941
58606
  lines.push(`- ${className} \u2192 add to ${rootPath}.props.className (fallback)`);
@@ -57943,7 +58608,10 @@ function buildClassHookAttachSuggestions(blockId, missingClassNames, nodes) {
57943
58608
  return lines.slice(0, 8).join("\n");
57944
58609
  }
57945
58610
  function extractSelectorClasses(selector) {
57946
- const withoutDataBlockAttrs = selector.replace(/\[data-block=(["']).*?\1\]/g, "");
58611
+ const withoutDataBlockAttrs = selector.replace(
58612
+ /\[data-block=(["']).*?\1\]/g,
58613
+ ""
58614
+ );
57947
58615
  const classes = /* @__PURE__ */ new Set();
57948
58616
  const re = /\.([_a-zA-Z][-_a-zA-Z0-9]*)/g;
57949
58617
  let match;
@@ -57960,7 +58628,9 @@ function extractBlockIdFromSelector(selector) {
57960
58628
  return match?.[2] ?? null;
57961
58629
  }
57962
58630
  function validateNodeType(nodeType, path24, ctx) {
57963
- if (!ALLOWED_NODE_TYPES.includes(nodeType)) {
58631
+ if (!ALLOWED_NODE_TYPES.includes(
58632
+ nodeType
58633
+ )) {
57964
58634
  return {
57965
58635
  path: `${path24}.type`,
57966
58636
  message: `Block "${ctx.blockId}": Unknown node type "${nodeType}" at ${path24}`,
@@ -57974,7 +58644,9 @@ function validateTransforms(transforms, path24, ctx) {
57974
58644
  for (let i = 0; i < transforms.length; i++) {
57975
58645
  const transform = transforms[i];
57976
58646
  if (transform.id && typeof transform.id === "string") {
57977
- if (!ALLOWED_TRANSFORM_IDS.includes(transform.id)) {
58647
+ if (!ALLOWED_TRANSFORM_IDS.includes(
58648
+ transform.id
58649
+ )) {
57978
58650
  errors.push({
57979
58651
  path: `${path24}.transforms[${i}].id`,
57980
58652
  message: `Block "${ctx.blockId}": Unknown transform "${transform.id}"`,
@@ -58023,16 +58695,28 @@ function validateLayoutNode(node, path24, ctx) {
58023
58695
  if (typeError) errors.push(typeError);
58024
58696
  }
58025
58697
  if ("$bind" in n && n.$bind && typeof n.$bind === "object") {
58026
- const bindErrors = validateBinding(n.$bind, `${path24}.$bind`, ctx);
58698
+ const bindErrors = validateBinding(
58699
+ n.$bind,
58700
+ `${path24}.$bind`,
58701
+ ctx
58702
+ );
58027
58703
  errors.push(...bindErrors);
58028
58704
  }
58029
58705
  if ("props" in n && n.props && typeof n.props === "object") {
58030
- const propsErrors = validatePropsBindings(n.props, `${path24}.props`, ctx);
58706
+ const propsErrors = validatePropsBindings(
58707
+ n.props,
58708
+ `${path24}.props`,
58709
+ ctx
58710
+ );
58031
58711
  errors.push(...propsErrors);
58032
58712
  }
58033
58713
  if ("children" in n && Array.isArray(n.children)) {
58034
58714
  for (let i = 0; i < n.children.length; i++) {
58035
- const childErrors = validateLayoutNode(n.children[i], `${path24}.children[${i}]`, ctx);
58715
+ const childErrors = validateLayoutNode(
58716
+ n.children[i],
58717
+ `${path24}.children[${i}]`,
58718
+ ctx
58719
+ );
58036
58720
  errors.push(...childErrors);
58037
58721
  }
58038
58722
  }
@@ -58046,7 +58730,11 @@ function validatePropsBindings(props2, path24, ctx) {
58046
58730
  const bindErrors = validateBinding(bind2, `${path24}.${key}.$bind`, ctx);
58047
58731
  errors.push(...bindErrors);
58048
58732
  } else if (value && typeof value === "object" && !Array.isArray(value)) {
58049
- const nestedErrors = validatePropsBindings(value, `${path24}.${key}`, ctx);
58733
+ const nestedErrors = validatePropsBindings(
58734
+ value,
58735
+ `${path24}.${key}`,
58736
+ ctx
58737
+ );
58050
58738
  errors.push(...nestedErrors);
58051
58739
  }
58052
58740
  }
@@ -58087,7 +58775,10 @@ function collectFieldInfo(fields3) {
58087
58775
  topLevelFieldIds.add(field.id);
58088
58776
  if (field.type === "repeater" && field.schema && typeof field.schema === "object" && "fields" in field.schema) {
58089
58777
  const nestedFields = field.schema.fields ?? [];
58090
- repeaterNestedFieldIds.set(field.id, new Set(nestedFields.map((f) => f.id)));
58778
+ repeaterNestedFieldIds.set(
58779
+ field.id,
58780
+ new Set(nestedFields.map((f) => f.id))
58781
+ );
58091
58782
  }
58092
58783
  }
58093
58784
  return { topLevelFieldIds, repeaterNestedFieldIds };
@@ -58207,7 +58898,11 @@ function findMissingBindings(node, blockId, path24 = "layout") {
58207
58898
  }
58208
58899
  if ("children" in n && Array.isArray(n.children)) {
58209
58900
  for (let i = 0; i < n.children.length; i++) {
58210
- const childErrors = findMissingBindings(n.children[i], blockId, `${path24}.children[${i}]`);
58901
+ const childErrors = findMissingBindings(
58902
+ n.children[i],
58903
+ blockId,
58904
+ `${path24}.children[${i}]`
58905
+ );
58211
58906
  errors.push(...childErrors);
58212
58907
  }
58213
58908
  }
@@ -58218,7 +58913,9 @@ function getMaxDepth(node, currentDepth = 0) {
58218
58913
  const n = node;
58219
58914
  if (!n.children || !Array.isArray(n.children)) return currentDepth;
58220
58915
  if (n.children.length === 0) return currentDepth;
58221
- return Math.max(...n.children.map((child) => getMaxDepth(child, currentDepth + 1)));
58916
+ return Math.max(
58917
+ ...n.children.map((child) => getMaxDepth(child, currentDepth + 1))
58918
+ );
58222
58919
  }
58223
58920
  var CONTAINER_NODE_TYPES = ["section", "stack", "grid", "div", "inline"];
58224
58921
  function detectPotentialTruncation(node, maxAllowedDepth, currentDepth = 0, path24 = "layout") {
@@ -58233,7 +58930,12 @@ function detectPotentialTruncation(node, maxAllowedDepth, currentDepth = 0, path
58233
58930
  if (n.children && Array.isArray(n.children)) {
58234
58931
  n.children.forEach((child, i) => {
58235
58932
  truncatedPaths.push(
58236
- ...detectPotentialTruncation(child, maxAllowedDepth, currentDepth + 1, `${path24}.children[${i}]`)
58933
+ ...detectPotentialTruncation(
58934
+ child,
58935
+ maxAllowedDepth,
58936
+ currentDepth + 1,
58937
+ `${path24}.children[${i}]`
58938
+ )
58237
58939
  );
58238
58940
  });
58239
58941
  }
@@ -58248,14 +58950,20 @@ function formatValidationFeedback(errors, output) {
58248
58950
  if (truncatedPaths.length > 0) {
58249
58951
  lines.push("### DEPTH LIMIT WARNING");
58250
58952
  lines.push("");
58251
- lines.push(`The layout reached the maximum depth of ${MAX_LAYOUT_DEPTH} levels.`);
58953
+ lines.push(
58954
+ `The layout reached the maximum depth of ${MAX_LAYOUT_DEPTH} levels.`
58955
+ );
58252
58956
  lines.push("These container nodes at the depth limit have no children:");
58253
58957
  for (const path24 of truncatedPaths) {
58254
58958
  lines.push(` \u26A0\uFE0F ${path24}`);
58255
58959
  }
58256
58960
  lines.push("");
58257
- lines.push("**FIX**: Flatten your layout structure or use $repeat for lists.");
58258
- lines.push("- Combine wrapper nodes where possible (e.g., section > stack > div \u2192 section > stack)");
58961
+ lines.push(
58962
+ "**FIX**: Flatten your layout structure or use $repeat for lists."
58963
+ );
58964
+ lines.push(
58965
+ "- Combine wrapper nodes where possible (e.g., section > stack > div \u2192 section > stack)"
58966
+ );
58259
58967
  lines.push("- Use $repeat instead of manual nesting for repeated items");
58260
58968
  lines.push(`- Current max depth: ${maxDepth}, limit: ${MAX_LAYOUT_DEPTH}`);
58261
58969
  lines.push("");
@@ -58264,13 +58972,19 @@ function formatValidationFeedback(errors, output) {
58264
58972
  if (errors.length === 0) {
58265
58973
  return lines.length > 0 ? lines.join("\n") : "";
58266
58974
  }
58267
- lines.push("## CRITICAL: Your output failed validation. You MUST fix these errors.");
58975
+ lines.push(
58976
+ "## CRITICAL: Your output failed validation. You MUST fix these errors."
58977
+ );
58268
58978
  lines.push("");
58269
58979
  lines.push("Your previous output had the following problems:");
58270
58980
  lines.push("");
58271
58981
  const missingBindErrors = errors.filter((e) => e.message.includes("no $bind"));
58272
- const unusedFieldErrors = errors.filter((e) => e.message.includes("never used"));
58273
- const otherErrors = errors.filter((e) => !e.message.includes("no $bind") && !e.message.includes("never used"));
58982
+ const unusedFieldErrors = errors.filter(
58983
+ (e) => e.message.includes("never used")
58984
+ );
58985
+ const otherErrors = errors.filter(
58986
+ (e) => !e.message.includes("no $bind") && !e.message.includes("never used")
58987
+ );
58274
58988
  if (missingBindErrors.length > 0) {
58275
58989
  lines.push("### MISSING $bind ERRORS (nodes that display nothing)");
58276
58990
  lines.push("");
@@ -58278,16 +58992,22 @@ function formatValidationFeedback(errors, output) {
58278
58992
  lines.push(`\u274C ${error.message}`);
58279
58993
  }
58280
58994
  lines.push("");
58281
- lines.push("**FIX**: Every text, richText, media, button, and link node MUST have $bind.");
58995
+ lines.push(
58996
+ "**FIX**: Every text, richText, media, button, and link node MUST have $bind."
58997
+ );
58282
58998
  lines.push("");
58283
58999
  lines.push("WRONG (displays nothing):");
58284
59000
  lines.push("```json");
58285
- lines.push('{ "type": "text", "props": { "as": "h1" }, "children": null, "$bind": null }');
59001
+ lines.push(
59002
+ '{ "type": "text", "props": { "as": "h1" }, "children": null, "$bind": null }'
59003
+ );
58286
59004
  lines.push("```");
58287
59005
  lines.push("");
58288
59006
  lines.push("CORRECT (bound to field):");
58289
59007
  lines.push("```json");
58290
- lines.push('{ "type": "text", "props": { "as": "h1" }, "children": null, "$bind": { "from": "content.headline", "fallback": null, "transforms": null } }');
59008
+ lines.push(
59009
+ '{ "type": "text", "props": { "as": "h1" }, "children": null, "$bind": { "from": "content.headline", "fallback": null, "transforms": null } }'
59010
+ );
58291
59011
  lines.push("```");
58292
59012
  lines.push("");
58293
59013
  }
@@ -58306,11 +59026,15 @@ function formatValidationFeedback(errors, output) {
58306
59026
  if (fieldNames.length > 0) {
58307
59027
  lines.push("**CHECKLIST - Add a binding for EACH of these fields:**");
58308
59028
  for (const field of fieldNames) {
58309
- lines.push(`- [ ] ${field} \u2192 text node with $bind: { from: "content.${field}" }`);
59029
+ lines.push(
59030
+ `- [ ] ${field} \u2192 text node with $bind: { from: "content.${field}" }`
59031
+ );
58310
59032
  }
58311
59033
  lines.push("");
58312
59034
  }
58313
- lines.push("**COMMON MISTAKE**: Creating container nodes with `children: null` instead of actual bindings.");
59035
+ lines.push(
59036
+ "**COMMON MISTAKE**: Creating container nodes with `children: null` instead of actual bindings."
59037
+ );
58314
59038
  lines.push("");
58315
59039
  lines.push("This is WRONG (container with no content inside):");
58316
59040
  lines.push("```json");
@@ -58320,12 +59044,18 @@ function formatValidationFeedback(errors, output) {
58320
59044
  lines.push("This is CORRECT (container with bound text node):");
58321
59045
  lines.push("```json");
58322
59046
  lines.push('{ "type": "inline", "children": [');
58323
- lines.push(' { "type": "text", "$bind": { "from": "content.fieldName", "fallback": null, "transforms": null }, "props": null, "$repeat": null, "$when": null, "children": null }');
59047
+ lines.push(
59048
+ ' { "type": "text", "$bind": { "from": "content.fieldName", "fallback": null, "transforms": null }, "props": null, "$repeat": null, "$when": null, "children": null }'
59049
+ );
58324
59050
  lines.push("] }");
58325
59051
  lines.push("```");
58326
59052
  lines.push("");
58327
- lines.push("**FIX**: Every field you define MUST be used in a $bind somewhere in the layout.");
58328
- lines.push('If you have a field "highlight", you MUST have a node with $bind: { from: "content.highlight" }');
59053
+ lines.push(
59054
+ "**FIX**: Every field you define MUST be used in a $bind somewhere in the layout."
59055
+ );
59056
+ lines.push(
59057
+ 'If you have a field "highlight", you MUST have a node with $bind: { from: "content.highlight" }'
59058
+ );
58329
59059
  lines.push("");
58330
59060
  }
58331
59061
  if (otherErrors.length > 0) {
@@ -60883,6 +61613,10 @@ Examples:
60883
61613
  }
60884
61614
  })
60885
61615
  );
61616
+
61617
+ // src/cli/commands/style.ts
61618
+ init_buttons();
61619
+ init_site_styles();
60886
61620
  function buildStyleSelectionApplyInputFromOptions(options) {
60887
61621
  const baseSelectionVersion = Number(options.baseSelectionVersion);
60888
61622
  if (!Number.isInteger(baseSelectionVersion) || baseSelectionVersion < 0) {
@@ -60915,6 +61649,55 @@ function isStringRecord(value) {
60915
61649
  }
60916
61650
  return Object.values(value).every((entry) => typeof entry === "string");
60917
61651
  }
61652
+ function buildStyleCatalogListRows(styles = curatedSiteStyles, options = {}) {
61653
+ const filteredStyles = options.siteStyleId ? styles.filter((style) => String(style.id) === options.siteStyleId) : styles;
61654
+ return filteredStyles.map((style) => ({
61655
+ siteStyleId: style.id,
61656
+ name: style.name,
61657
+ palettes: style.paletteVariantChoices.map((choice) => ({
61658
+ id: choice.id,
61659
+ label: findPaletteVariant(choice.id)?.name ?? choice.id
61660
+ })),
61661
+ buttonPersonalities: style.buttonPersonalityChoices.map((choice) => ({
61662
+ id: choice.id,
61663
+ label: findButtonPersonality(choice.id)?.name ?? choice.id
61664
+ })),
61665
+ headerLooks: style.recommendedHeaderLookIds.map((lookId) => ({
61666
+ id: lookId,
61667
+ label: findHeaderLook(lookId)?.label ?? lookId
61668
+ })),
61669
+ footerLooks: style.recommendedFooterLookIds.map((lookId) => ({
61670
+ id: lookId,
61671
+ label: findFooterLook(lookId)?.label ?? lookId
61672
+ }))
61673
+ }));
61674
+ }
61675
+ function formatStyleCatalogListRow(row) {
61676
+ return [
61677
+ row.siteStyleId,
61678
+ row.name,
61679
+ formatChoiceList(row.palettes),
61680
+ formatChoiceList(row.buttonPersonalities),
61681
+ formatChoiceList(row.headerLooks),
61682
+ formatChoiceList(row.footerLooks)
61683
+ ];
61684
+ }
61685
+ function formatChoiceList(choices) {
61686
+ return choices.map((choice) => `${choice.id} (${choice.label})`).join(", ");
61687
+ }
61688
+ var listCommand8 = new Command("list").description("List curated site styles and compatible selection IDs").option("--site-style-id <id>", "Show one curated site style").action(
61689
+ withErrorHandling(async (options, command) => {
61690
+ const { output } = getOutputContext(command);
61691
+ const rows = buildStyleCatalogListRows(curatedSiteStyles, options);
61692
+ if (options.siteStyleId && rows.length === 0) {
61693
+ output.error(`Unknown site style: ${options.siteStyleId}`);
61694
+ }
61695
+ output.table(
61696
+ ["Site Style ID", "Name", "Palettes", "Buttons", "Header Looks", "Footer Looks"],
61697
+ rows.map(formatStyleCatalogListRow)
61698
+ );
61699
+ })
61700
+ );
60918
61701
  var applyCommand = new Command("apply").description("Apply a curated site-style selection").requiredOption("--site-style-id <id>", "Site style ID, e.g. site-style:calm-studio").requiredOption("--base-selection-version <version>", "Current style selection version").option("--selection-id <id>", "Current style selection row ID").option("--button-personality-id <id>", "Button personality ID").option("--palette-variant-id <id>", "Palette variant ID").option("--palette-overrides <json>", "JSON object of palette token overrides").option("--header-look-id <id>", "Header look ID").option("--footer-look-id <id>", "Footer look ID").action(
60919
61702
  withErrorHandling(async (options, command) => {
60920
61703
  const { output, client } = createCommandContext(command);
@@ -60935,7 +61718,7 @@ var styleCommand = new Command("style").description("Manage curated site styles"
60935
61718
  Examples:
60936
61719
  $ riverbankcms style apply --site-style-id site-style:calm-studio --base-selection-version 3
60937
61720
  $ riverbankcms style apply --site-style-id site-style:calm-studio --base-selection-version 3 --palette-variant-id soft-natural-sage
60938
- `).addCommand(applyCommand);
61721
+ `).addCommand(listCommand8).addCommand(applyCommand);
60939
61722
 
60940
61723
  // src/cli/index.ts
60941
61724
  config({ path: ".env.local" });