@riverbankcms/sdk 0.67.0 → 0.68.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 (88) hide show
  1. package/README.md +21 -11
  2. package/dist/_dts/api/src/aiPlayground.d.ts +62 -14
  3. package/dist/_dts/api/src/billing.d.ts +7 -40
  4. package/dist/_dts/api/src/bookingManagementEndpoints.d.ts +4 -1
  5. package/dist/_dts/api/src/bookingOperations.d.ts +32 -1
  6. package/dist/_dts/api/src/endpoints.d.ts +7 -0
  7. package/dist/_dts/api/src/public/types.d.ts +1 -1
  8. package/dist/_dts/billing/src/components/index.d.ts +426 -0
  9. package/dist/_dts/blocks/src/PageRenderer.d.ts +4 -0
  10. package/dist/_dts/blocks/src/client.d.ts +6 -0
  11. package/dist/_dts/blocks/src/system/runtime/hooks/useAvailableDates.d.ts +1 -0
  12. package/dist/_dts/blocks/src/system/runtime/hooks/useAvailableSlots.d.ts +3 -1
  13. package/dist/_dts/blocks/src/system/runtime/hooks/useHeadlessBookingFlow.d.ts +140 -0
  14. package/dist/_dts/blocks/src/system/runtime/hooks/useHeadlessBookingFlow.state.d.ts +2 -0
  15. package/dist/_dts/blocks/src/system/runtime/hooks/useVisibleTabPolling.d.ts +10 -0
  16. package/dist/_dts/blocks/src/system/runtime/nodes/booking-form.default-ui.d.ts +8 -0
  17. package/dist/_dts/blocks/src/system/runtime/nodes/booking-form.headless.state.d.ts +484 -0
  18. package/dist/_dts/blocks/src/system/runtime/nodes/booking-form.state.d.ts +5 -2
  19. package/dist/_dts/sdk/src/bookings/index.d.ts +5 -2
  20. package/dist/_dts/sdk/src/bookings/types.d.ts +2 -0
  21. package/dist/_dts/sdk/src/cli/commands/push/scopes/commandBackedDatedOfferingScope.d.ts +32 -0
  22. package/dist/_dts/sdk/src/cli/commands/push/scopes/types.d.ts +5 -1
  23. package/dist/_dts/sdk/src/cli/site-commands/commandRuntime.d.ts +41 -11
  24. package/dist/_dts/sdk/src/cli/site-commands/commandRuntimeCompat.d.ts +21 -0
  25. package/dist/_dts/sdk/src/cli/site-commands/commandSurfaceDispatch.d.ts +27 -0
  26. package/dist/_dts/sdk/src/cli/site-commands/datedOfferingCommands.d.ts +56 -0
  27. package/dist/_dts/sdk/src/cli/site-commands/entryCommands.d.ts +3 -1
  28. package/dist/_dts/sdk/src/cli/site-commands/footerCommands.d.ts +7 -1
  29. package/dist/_dts/sdk/src/cli/site-commands/formCommands.d.ts +4 -8
  30. package/dist/_dts/sdk/src/cli/site-commands/index.d.ts +1 -0
  31. package/dist/_dts/sdk/src/cli/site-commands/navigationCommands.d.ts +4 -8
  32. package/dist/_dts/sdk/src/cli/site-commands/pageCommands.d.ts +4 -8
  33. package/dist/_dts/sdk/src/cli/site-commands/pushExecution.d.ts +14 -68
  34. package/dist/_dts/sdk/src/cli/site-commands/pushExecutionPlan.d.ts +8 -0
  35. package/dist/_dts/sdk/src/cli/site-commands/pushExecutionTypes.d.ts +97 -0
  36. package/dist/_dts/sdk/src/cli/site-commands/residualSettingsTrimming.d.ts +15 -0
  37. package/dist/_dts/sdk/src/cli/sync/index.d.ts +1 -0
  38. package/dist/_dts/sdk/src/cli/sync/syncResultAggregation.d.ts +4 -0
  39. package/dist/_dts/sdk/src/rendering/overrides.d.ts +2 -0
  40. package/dist/_dts/sdk/src/theme-bridge/ThemeBridgeProvider.d.ts +4 -4
  41. package/dist/_dts/sdk/src/theme-bridge/generateCssVars.d.ts +4 -12
  42. package/dist/_dts/sdk/src/theme-bridge/index.d.ts +1 -1
  43. package/dist/_dts/sdk/src/theme-bridge/types.d.ts +17 -9
  44. package/dist/_dts/sdk/src/version.d.ts +1 -1
  45. package/dist/_dts/site-commands/src/commands.d.ts +228 -1
  46. package/dist/_dts/site-commands/src/domain.d.ts +1 -1
  47. package/dist/_dts/site-commands/src/index.d.ts +1 -0
  48. package/dist/_dts/site-commands/src/metadata.d.ts +66 -1
  49. package/dist/_dts/site-commands/src/refContributions.d.ts +1 -0
  50. package/dist/_dts/site-commands/src/refs.d.ts +7 -1
  51. package/dist/_dts/{sdk/src/cli/merge-remote → site-commands/src}/stableJson.d.ts +2 -0
  52. package/dist/_dts/theme-core/src/generated/containerResponsiveThemeCss.d.ts +1 -1
  53. package/dist/_dts/theme-core/src/index.d.ts +1 -1
  54. package/dist/_dts/theme-core/src/runtime/buildThemeRuntimeFromBridge.d.ts +30 -23
  55. package/dist/cli/index.mjs +1699 -766
  56. package/dist/client/bookings.mjs +5107 -3348
  57. package/dist/client/client.mjs +4004 -3522
  58. package/dist/client/hooks.mjs +14 -0
  59. package/dist/client/rendering/client.mjs +4185 -3721
  60. package/dist/client/rendering/islands.mjs +4317 -3853
  61. package/dist/client/rendering.mjs +4076 -3592
  62. package/dist/preview-next/before-render.mjs +14 -0
  63. package/dist/preview-next/client/runtime.mjs +2770 -2268
  64. package/dist/preview-next/middleware.mjs +14 -0
  65. package/dist/server/components.mjs +172 -58
  66. package/dist/server/config-validation.mjs +14 -0
  67. package/dist/server/config.mjs +14 -0
  68. package/dist/server/data.mjs +14 -0
  69. package/dist/server/index.mjs +15 -1
  70. package/dist/server/next.mjs +166 -52
  71. package/dist/server/prebuild.mjs +1 -1
  72. package/dist/server/rendering/server.mjs +174 -58
  73. package/dist/server/rendering.mjs +174 -58
  74. package/dist/server/routing.mjs +14 -0
  75. package/dist/server/server.mjs +15 -1
  76. package/dist/server/theme-bridge.mjs +1247 -4825
  77. package/dist/styles/index.css +38 -38
  78. package/package.json +1 -1
  79. package/dist/_dts/blocks/src/system/runtime/components/booking/DateTimeSelectionStep.d.ts +0 -18
  80. package/dist/_dts/blocks/src/system/runtime/components/booking/PaymentOptionSelectionStep.d.ts +0 -9
  81. package/dist/_dts/blocks/src/system/runtime/components/booking/ServiceResourceSelector.d.ts +0 -44
  82. package/dist/_dts/blocks/src/system/runtime/components/booking/ServiceResourceSelector.state.d.ts +0 -23
  83. package/dist/_dts/blocks/src/system/runtime/components/booking/ServiceSelectionStep.d.ts +0 -18
  84. package/dist/_dts/blocks/src/system/runtime/components/booking/slotDisplay.d.ts +0 -2
  85. package/dist/_dts/blocks/src/system/runtime/components/multi-step/MultiStepForm.d.ts +0 -21
  86. package/dist/_dts/blocks/src/system/runtime/components/multi-step/useMultiStep.d.ts +0 -15
  87. package/dist/_dts/blocks/src/system/runtime/components/multi-step/useMultiStep.state.d.ts +0 -51
  88. package/dist/_dts/blocks/src/system/runtime/hooks/useBookingSteps.d.ts +0 -22
@@ -18991,6 +18991,20 @@ var ENDPOINT_DEFINITIONS = {
18991
18991
  responseKind: "json",
18992
18992
  errors: ["validation:invalid_input", "billing:plan_limit_exceeded", "server:internal_error"]
18993
18993
  },
18994
+ createAppointmentResourceWithAccountAccess: {
18995
+ path: "/sites/{siteId}/bookings/resources/account-access",
18996
+ method: "POST",
18997
+ auth: "user",
18998
+ responseKind: "json",
18999
+ errors: [
19000
+ "validation:invalid_input",
19001
+ "auth:forbidden",
19002
+ "billing:plan_limit_exceeded",
19003
+ "resource:conflict",
19004
+ "resource:not_found",
19005
+ "server:internal_error"
19006
+ ]
19007
+ },
18994
19008
  getAppointmentResource: {
18995
19009
  path: "/sites/{siteId}/bookings/resources/{resourceId}",
18996
19010
  method: "GET",
@@ -34907,6 +34921,11 @@ init_buildThemeRuntime();
34907
34921
  // ../theme-core/src/runtime/buildThemeRuntimeFromBridge.ts
34908
34922
  init_colorConversion();
34909
34923
  init_shadow2();
34924
+ init_core();
34925
+ init_core2();
34926
+ init_status();
34927
+ init_progress();
34928
+ init_blocks();
34910
34929
 
34911
34930
  // ../theme-core/src/siteChrome.tsx
34912
34931
  init_types2();
@@ -41576,6 +41595,43 @@ function formatSyncResult(result, dryRun) {
41576
41595
  return lines.join("\n");
41577
41596
  }
41578
41597
 
41598
+ // src/cli/sync/syncResultAggregation.ts
41599
+ var syncCounterKeysBySection = {
41600
+ entries: ["created", "updated", "deleted", "failed", "published", "unpublished"],
41601
+ pages: ["created", "updated", "failed", "published", "unpublished"],
41602
+ blocks: ["created", "updated", "deleted", "failed"],
41603
+ navigation: ["created", "updated", "failed"],
41604
+ settings: ["updated", "failed"],
41605
+ forms: ["created", "updated", "failed"],
41606
+ footer: ["updated", "failed"]
41607
+ };
41608
+ function mergeManySyncResults(results) {
41609
+ return results.reduce(
41610
+ (merged, result) => mergeSyncResults(merged, result),
41611
+ createEmptySyncResult()
41612
+ );
41613
+ }
41614
+ function mergeSyncResults(first, second) {
41615
+ return {
41616
+ entries: addCounters(first.entries, second.entries, syncCounterKeysBySection.entries),
41617
+ pages: addCounters(first.pages, second.pages, syncCounterKeysBySection.pages),
41618
+ blocks: addCounters(first.blocks, second.blocks, syncCounterKeysBySection.blocks),
41619
+ navigation: addCounters(first.navigation, second.navigation, syncCounterKeysBySection.navigation),
41620
+ settings: addCounters(first.settings, second.settings, syncCounterKeysBySection.settings),
41621
+ forms: addCounters(first.forms, second.forms, syncCounterKeysBySection.forms),
41622
+ footer: addCounters(first.footer, second.footer, syncCounterKeysBySection.footer),
41623
+ errors: [...first.errors, ...second.errors],
41624
+ warnings: [...first.warnings, ...second.warnings]
41625
+ };
41626
+ }
41627
+ function addCounters(first, second, keys) {
41628
+ const result = {};
41629
+ for (const key of keys) {
41630
+ result[key] = (first[key] ?? 0) + (second[key] ?? 0);
41631
+ }
41632
+ return result;
41633
+ }
41634
+
41579
41635
  // src/cli/commands/pull-scope-diff.ts
41580
41636
  function zeroEntriesSummary() {
41581
41637
  return { create: 0, update: 0, delete: 0, unchanged: 0, publish: 0, unpublish: 0 };
@@ -43909,6 +43965,7 @@ var resourceKinds = [
43909
43965
  "content",
43910
43966
  "staff",
43911
43967
  "venue",
43968
+ "event-category",
43912
43969
  "event",
43913
43970
  "course",
43914
43971
  "ticket",
@@ -43955,6 +44012,18 @@ function createFormRef(parts) {
43955
44012
  function createFooterRef(parts) {
43956
44013
  return `footer:${joinRefSlugParts(parts)}`;
43957
44014
  }
44015
+ function createVenueRef(parts) {
44016
+ return `venue:${joinRefSlugParts(parts)}`;
44017
+ }
44018
+ function createEventCategoryRef(parts) {
44019
+ return `event-category:${joinRefSlugParts(parts)}`;
44020
+ }
44021
+ function createEventSeriesRef(parts) {
44022
+ return `event:${joinRefSlugParts(parts)}`;
44023
+ }
44024
+ function createCourseRef(parts) {
44025
+ return `course:${joinRefSlugParts(parts)}`;
44026
+ }
43958
44027
  function createSiteCommandSiteRef(parts) {
43959
44028
  return `site:${joinRefSlugParts(parts)}`;
43960
44029
  }
@@ -44002,6 +44071,7 @@ var footerRefSchema = resourceRefSchema("footer");
44002
44071
  var contentEntryRefSchema = resourceRefSchema("content");
44003
44072
  var staffRefSchema = resourceRefSchema("staff");
44004
44073
  var venueRefSchema = resourceRefSchema("venue");
44074
+ var eventCategoryRefSchema = resourceRefSchema("event-category");
44005
44075
  var eventSeriesRefSchema = resourceRefSchema("event");
44006
44076
  var courseRefSchema = resourceRefSchema("course");
44007
44077
  var ticketTypeRefSchema = resourceRefSchema("ticket");
@@ -44115,6 +44185,7 @@ var geoPointSchema = z.object({
44115
44185
  var contentSummarySchema = z.object({
44116
44186
  summary: z.string().min(1).optional(),
44117
44187
  body: z.unknown().optional(),
44188
+ image: z.unknown().optional(),
44118
44189
  imageRef: mediaRefSchema.optional(),
44119
44190
  mediaRefs: z.array(mediaRefSchema).readonly().optional(),
44120
44191
  contentEntryRef: contentEntryRefSchema.optional()
@@ -44440,6 +44511,33 @@ var upsertVenueCommandSchema = z.object({
44440
44511
  mapEmbedUrl: z.string().url().optional()
44441
44512
  }).strict()
44442
44513
  }).strict();
44514
+ var deleteVenueCommandSchema = z.object({
44515
+ type: z.literal("deleteVenue"),
44516
+ ref: commandRefSchema,
44517
+ input: z.object({
44518
+ slug: z.string().min(1),
44519
+ venueRef: venueRefSchema.optional()
44520
+ }).strict()
44521
+ }).strict();
44522
+ var upsertEventCategoryCommandSchema = z.object({
44523
+ type: z.literal("upsertEventCategory"),
44524
+ ref: eventCategoryRefSchema,
44525
+ input: z.object({
44526
+ identifier: z.string().min(1).optional(),
44527
+ name: z.string().min(1),
44528
+ description: z.string().min(1).nullable().optional(),
44529
+ color: z.string().min(1).nullable().optional(),
44530
+ sortOrder: z.number().int().optional()
44531
+ }).strict()
44532
+ }).strict();
44533
+ var deleteEventCategoryCommandSchema = z.object({
44534
+ type: z.literal("deleteEventCategory"),
44535
+ ref: commandRefSchema,
44536
+ input: z.object({
44537
+ identifier: z.string().min(1),
44538
+ eventCategoryRef: eventCategoryRefSchema.optional()
44539
+ }).strict()
44540
+ }).strict();
44443
44541
  var upsertEventSeriesCommandSchema = z.object({
44444
44542
  type: z.literal("upsertEventSeries"),
44445
44543
  ref: eventSeriesRefSchema,
@@ -44447,18 +44545,38 @@ var upsertEventSeriesCommandSchema = z.object({
44447
44545
  slug: z.string().min(1),
44448
44546
  title: z.string().min(1),
44449
44547
  archetype: z.enum(offeringArchetypes),
44548
+ status: z.enum(["draft", "active", "archived", "cancelled"]).optional(),
44450
44549
  visibility: z.enum(offeringVisibilities),
44451
44550
  timezone: ianaTimezoneSchema,
44452
44551
  venueRef: venueRefSchema.optional(),
44552
+ venueIdentifier: z.string().min(1).optional(),
44553
+ categoryRef: eventCategoryRefSchema.optional(),
44554
+ categoryIdentifier: z.string().min(1).optional(),
44555
+ formRef: formRefSchema.optional(),
44556
+ formIdentifier: z.string().min(1).optional(),
44453
44557
  capacity: offeringCapacitySchema.optional(),
44454
44558
  waitlist: waitlistIntentSchema.optional(),
44455
44559
  pricing: eventPricingIntentSchema,
44560
+ priceDisplay: z.string().min(1).nullable().optional(),
44561
+ acceptsPasses: z.boolean().optional(),
44562
+ acceptsMemberships: z.boolean().optional(),
44456
44563
  deliveryMode: z.enum(["in_person", "online", "hybrid"]).optional(),
44457
44564
  occurrences: z.array(eventOccurrenceSchema).min(1).readonly(),
44458
44565
  content: contentSummarySchema.optional(),
44566
+ settings: unknownRecordSchema.optional(),
44567
+ presentation: unknownRecordSchema.nullable().optional(),
44568
+ tags: z.array(z.string()).readonly().optional(),
44459
44569
  staffRefs: z.array(staffRefSchema).readonly().optional()
44460
44570
  }).strict()
44461
44571
  }).strict();
44572
+ var deleteEventSeriesCommandSchema = z.object({
44573
+ type: z.literal("deleteEventSeries"),
44574
+ ref: commandRefSchema,
44575
+ input: z.object({
44576
+ identifier: z.string().min(1),
44577
+ eventRef: eventSeriesRefSchema.optional()
44578
+ }).strict()
44579
+ }).strict();
44462
44580
  var upsertEventTicketTypeCommandSchema = z.object({
44463
44581
  type: z.literal("upsertEventTicketType"),
44464
44582
  ref: ticketTypeRefSchema,
@@ -44479,17 +44597,38 @@ var upsertCourseCommandSchema = z.object({
44479
44597
  input: z.object({
44480
44598
  slug: z.string().min(1),
44481
44599
  title: z.string().min(1),
44600
+ status: z.enum(["draft", "active", "cancelled"]).optional(),
44482
44601
  visibility: z.enum(offeringVisibilities),
44483
44602
  timezone: ianaTimezoneSchema,
44484
44603
  venueRef: venueRefSchema.optional(),
44604
+ venueIdentifier: z.string().min(1).optional(),
44605
+ categoryRef: eventCategoryRefSchema.optional(),
44606
+ categoryIdentifier: z.string().min(1).optional(),
44607
+ formRef: formRefSchema.optional(),
44608
+ formIdentifier: z.string().min(1).optional(),
44485
44609
  capacity: offeringCapacitySchema.optional(),
44610
+ enrollmentCapacity: positiveIntegerSchema.nullable().optional(),
44486
44611
  waitlist: waitlistIntentSchema.optional(),
44487
44612
  pricing: coursePricingIntentSchema,
44613
+ acceptsMemberships: z.boolean().optional(),
44488
44614
  sessions: z.array(courseSessionSchema2).min(1).readonly(),
44489
44615
  content: contentSummarySchema.optional(),
44616
+ programRef: z.string().min(1).nullable().optional(),
44617
+ program: z.object({
44618
+ identifier: z.string().min(1).nullable().optional(),
44619
+ data: unknownRecordSchema
44620
+ }).strict().nullable().optional(),
44490
44621
  staffRefs: z.array(staffRefSchema).readonly().optional()
44491
44622
  }).strict()
44492
44623
  }).strict();
44624
+ var deleteCourseCommandSchema = z.object({
44625
+ type: z.literal("deleteCourse"),
44626
+ ref: commandRefSchema,
44627
+ input: z.object({
44628
+ identifier: z.string().min(1),
44629
+ courseRef: courseRefSchema.optional()
44630
+ }).strict()
44631
+ }).strict();
44493
44632
  var ensureTeamMemberProfileCommandSchema = z.object({
44494
44633
  type: z.literal("ensureTeamMemberProfile"),
44495
44634
  ref: contentEntryRefSchema,
@@ -44848,9 +44987,14 @@ var siteCommandSchema = z.discriminatedUnion("type", [
44848
44987
  upsertStaffMemberCommandSchema,
44849
44988
  ensureTeamMemberProfileCommandSchema,
44850
44989
  upsertVenueCommandSchema,
44990
+ deleteVenueCommandSchema,
44991
+ upsertEventCategoryCommandSchema,
44992
+ deleteEventCategoryCommandSchema,
44851
44993
  upsertEventSeriesCommandSchema,
44994
+ deleteEventSeriesCommandSchema,
44852
44995
  upsertEventTicketTypeCommandSchema,
44853
44996
  upsertCourseCommandSchema,
44997
+ deleteCourseCommandSchema,
44854
44998
  upsertBookingPassProductCommandSchema,
44855
44999
  upsertBookingMembershipProductCommandSchema,
44856
45000
  seedBookingCustomerCommandSchema,
@@ -44971,7 +45115,7 @@ var siteCommandMetadata = {
44971
45115
  conflictPolicy: "update_existing",
44972
45116
  previewability: "static_preview",
44973
45117
  allowedRuntimes: ["development", "staging", "demo", "production"],
44974
- intendedExposure: ["recipe", "sdk_cli", "onboarding_planner", "ai_proposal", "internal_apply"],
45118
+ intendedExposure: ["recipe", "sdk_cli", "onboarding_planner", "internal_apply"],
44975
45119
  capability: "theme.write",
44976
45120
  support: "supported"
44977
45121
  },
@@ -45209,6 +45353,45 @@ var siteCommandMetadata = {
45209
45353
  capability: "bookings.venues.write",
45210
45354
  support: "supported"
45211
45355
  },
45356
+ deleteVenue: {
45357
+ scope: "venue",
45358
+ risk: "medium",
45359
+ writeSemantics: "delete",
45360
+ lifecycleIntent: "mutation",
45361
+ idempotencyStrategy: "existing_id",
45362
+ conflictPolicy: "update_existing",
45363
+ previewability: "effect_required",
45364
+ allowedRuntimes: ["development", "staging", "demo", "production"],
45365
+ intendedExposure: ["sdk_cli", "internal_apply"],
45366
+ capability: "bookings.venues.delete",
45367
+ support: "supported"
45368
+ },
45369
+ upsertEventCategory: {
45370
+ scope: "event_category",
45371
+ risk: "medium",
45372
+ writeSemantics: "upsert",
45373
+ lifecycleIntent: "mutation",
45374
+ idempotencyStrategy: "recipe_ref",
45375
+ conflictPolicy: "update_existing",
45376
+ previewability: "dry_run_only",
45377
+ allowedRuntimes: ["development", "staging", "demo", "production"],
45378
+ intendedExposure: ["sdk_cli", "internal_apply"],
45379
+ capability: "bookings.event_categories.write",
45380
+ support: "supported"
45381
+ },
45382
+ deleteEventCategory: {
45383
+ scope: "event_category",
45384
+ risk: "medium",
45385
+ writeSemantics: "delete",
45386
+ lifecycleIntent: "mutation",
45387
+ idempotencyStrategy: "existing_id",
45388
+ conflictPolicy: "update_existing",
45389
+ previewability: "effect_required",
45390
+ allowedRuntimes: ["development", "staging", "demo", "production"],
45391
+ intendedExposure: ["sdk_cli", "internal_apply"],
45392
+ capability: "bookings.event_categories.delete",
45393
+ support: "supported"
45394
+ },
45212
45395
  upsertEventSeries: {
45213
45396
  scope: "event",
45214
45397
  risk: "medium",
@@ -45222,6 +45405,19 @@ var siteCommandMetadata = {
45222
45405
  capability: "bookings.events.write",
45223
45406
  support: "supported"
45224
45407
  },
45408
+ deleteEventSeries: {
45409
+ scope: "event",
45410
+ risk: "medium",
45411
+ writeSemantics: "delete",
45412
+ lifecycleIntent: "mutation",
45413
+ idempotencyStrategy: "existing_id",
45414
+ conflictPolicy: "update_existing",
45415
+ previewability: "effect_required",
45416
+ allowedRuntimes: ["development", "staging", "demo", "production"],
45417
+ intendedExposure: ["sdk_cli", "internal_apply"],
45418
+ capability: "bookings.events.delete",
45419
+ support: "supported"
45420
+ },
45225
45421
  upsertEventTicketType: {
45226
45422
  scope: "ticket",
45227
45423
  risk: "medium",
@@ -45248,6 +45444,19 @@ var siteCommandMetadata = {
45248
45444
  capability: "bookings.courses.write",
45249
45445
  support: "supported"
45250
45446
  },
45447
+ deleteCourse: {
45448
+ scope: "course",
45449
+ risk: "medium",
45450
+ writeSemantics: "delete",
45451
+ lifecycleIntent: "mutation",
45452
+ idempotencyStrategy: "existing_id",
45453
+ conflictPolicy: "update_existing",
45454
+ previewability: "effect_required",
45455
+ allowedRuntimes: ["development", "staging", "demo", "production"],
45456
+ intendedExposure: ["sdk_cli", "internal_apply"],
45457
+ capability: "bookings.courses.delete",
45458
+ support: "supported"
45459
+ },
45251
45460
  upsertBookingPassProduct: {
45252
45461
  scope: "pass",
45253
45462
  risk: "medium",
@@ -45466,6 +45675,7 @@ function commandRefContributions(command) {
45466
45675
  case "upsertFooterContent":
45467
45676
  case "upsertStaffMember":
45468
45677
  case "upsertVenue":
45678
+ case "upsertEventCategory":
45469
45679
  case "upsertBookingMembershipProduct":
45470
45680
  case "seedBookingCustomer":
45471
45681
  case "upsertAppointmentService":
@@ -45541,6 +45751,21 @@ function commandRefContributions(command) {
45541
45751
  provides: [{ ref: command.ref, field: "ref" }],
45542
45752
  requires: collectOfferingRequires(command.input, command.input.occurrences, "input.occurrences")
45543
45753
  };
45754
+ case "deleteVenue":
45755
+ return {
45756
+ provides: [],
45757
+ requires: optionalRef(command.input.venueRef, "input.venueRef")
45758
+ };
45759
+ case "deleteEventCategory":
45760
+ return {
45761
+ provides: [],
45762
+ requires: optionalRef(command.input.eventCategoryRef, "input.eventCategoryRef")
45763
+ };
45764
+ case "deleteEventSeries":
45765
+ return {
45766
+ provides: [],
45767
+ requires: optionalRef(command.input.eventRef, "input.eventRef")
45768
+ };
45544
45769
  case "upsertEventTicketType":
45545
45770
  return {
45546
45771
  provides: [{ ref: command.ref, field: "ref" }],
@@ -45551,6 +45776,11 @@ function commandRefContributions(command) {
45551
45776
  provides: [{ ref: command.ref, field: "ref" }],
45552
45777
  requires: collectOfferingRequires(command.input, command.input.sessions, "input.sessions")
45553
45778
  };
45779
+ case "deleteCourse":
45780
+ return {
45781
+ provides: [],
45782
+ requires: optionalRef(command.input.courseRef, "input.courseRef")
45783
+ };
45554
45784
  case "ensureTeamMemberProfile":
45555
45785
  return {
45556
45786
  provides: [{ ref: command.ref, field: "ref" }],
@@ -45596,7 +45826,11 @@ function commandRefContributions(command) {
45596
45826
  case "reorderPageBlocks":
45597
45827
  return {
45598
45828
  provides: [{ ref: command.ref, field: "ref" }],
45599
- requires: command.input.pageRef ? [{ ref: command.input.pageRef, field: "input.pageRef" }] : []
45829
+ requires: command.input.pageRef ? [{ ref: command.input.pageRef, field: "input.pageRef" }] : [],
45830
+ requiresIfProvided: command.input.blocks.map((block, index) => ({
45831
+ ref: block.blockRef,
45832
+ field: `input.blocks[${index}].blockRef`
45833
+ }))
45600
45834
  };
45601
45835
  case "upsertContentEntry":
45602
45836
  return {
@@ -45659,6 +45893,8 @@ function portalOrderSubjectRefContribution(subject) {
45659
45893
  function collectOfferingRequires(input, intervals, intervalPath) {
45660
45894
  return [
45661
45895
  ...optionalRef(input.venueRef, "input.venueRef"),
45896
+ ...optionalRef(input.categoryRef, "input.categoryRef"),
45897
+ ...optionalRef(input.formRef, "input.formRef"),
45662
45898
  ...(input.content?.mediaRefs ?? []).map((ref, index) => ({
45663
45899
  ref,
45664
45900
  field: `input.content.mediaRefs[${index}]`
@@ -45888,12 +46124,22 @@ function matchSiteCommand(command, match) {
45888
46124
  return match(command);
45889
46125
  case "upsertVenue":
45890
46126
  return match(command);
46127
+ case "deleteVenue":
46128
+ return match(command);
46129
+ case "upsertEventCategory":
46130
+ return match(command);
46131
+ case "deleteEventCategory":
46132
+ return match(command);
45891
46133
  case "upsertEventSeries":
45892
46134
  return match(command);
46135
+ case "deleteEventSeries":
46136
+ return match(command);
45893
46137
  case "upsertEventTicketType":
45894
46138
  return match(command);
45895
46139
  case "upsertCourse":
45896
46140
  return match(command);
46141
+ case "deleteCourse":
46142
+ return match(command);
45897
46143
  case "upsertBookingPassProduct":
45898
46144
  return match(command);
45899
46145
  case "upsertBookingMembershipProduct":
@@ -45938,11 +46184,11 @@ function parseAndPlanCommandBatchForTypes(input, allowedTypes) {
45938
46184
  }
45939
46185
  function narrowSiteCommandPlan(plan, allowedTypes) {
45940
46186
  const allowedTypeSet = new Set(allowedTypes);
45941
- const unsupported = plan.commands.filter(
46187
+ const unsupported2 = plan.commands.filter(
45942
46188
  (plannedCommand) => !allowedTypeSet.has(plannedCommand.command.type)
45943
46189
  );
45944
- if (unsupported.length > 0) {
45945
- return err(unsupported.map(({ command }) => ({
46190
+ if (unsupported2.length > 0) {
46191
+ return err(unsupported2.map(({ command }) => ({
45946
46192
  code: "unsupported_command_type_for_plan",
45947
46193
  commandRef: command.ref,
45948
46194
  commandType: command.type,
@@ -46029,7 +46275,12 @@ function validateBatchRefs(batch) {
46029
46275
  contributions: contributions.requires,
46030
46276
  errors
46031
46277
  });
46032
- contributionsByCommand.set(command.ref, { provides, requires });
46278
+ const requiresIfProvided = parseContributions({
46279
+ commandRef: command.ref,
46280
+ contributions: contributions.requiresIfProvided ?? [],
46281
+ errors
46282
+ });
46283
+ contributionsByCommand.set(command.ref, { provides, requires, requiresIfProvided });
46033
46284
  requiresByCommand.set(command.ref, [...dedupeContributions(requires)]);
46034
46285
  for (const { ref } of provides) {
46035
46286
  const existing = providerByRef.get(ref);
@@ -46044,6 +46295,12 @@ function validateBatchRefs(batch) {
46044
46295
  }
46045
46296
  }
46046
46297
  }
46298
+ addInBatchProvidedRefRequirements({
46299
+ batch,
46300
+ providerByRef,
46301
+ contributionsByCommand,
46302
+ requiresByCommand
46303
+ });
46047
46304
  for (const [commandRef, requires] of requiresByCommand) {
46048
46305
  for (const { ref, field } of requires) {
46049
46306
  if (!providerByRef.has(ref)) {
@@ -46064,6 +46321,33 @@ function validateBatchRefs(batch) {
46064
46321
  requiresByCommand
46065
46322
  };
46066
46323
  }
46324
+ function addInBatchProvidedRefRequirements(input) {
46325
+ for (const command of input.batch.commands) {
46326
+ const contribution = input.contributionsByCommand.get(command.ref);
46327
+ for (const softRequirement of contribution?.requiresIfProvided ?? []) {
46328
+ addInBatchProvidedRefRequirement({
46329
+ commandRef: command.ref,
46330
+ requirement: softRequirement,
46331
+ providerByRef: input.providerByRef,
46332
+ contributionsByCommand: input.contributionsByCommand,
46333
+ requiresByCommand: input.requiresByCommand
46334
+ });
46335
+ }
46336
+ }
46337
+ }
46338
+ function addInBatchProvidedRefRequirement(input) {
46339
+ if (!input.providerByRef.has(input.requirement.ref)) return;
46340
+ const currentRequires = input.requiresByCommand.get(input.commandRef) ?? [];
46341
+ const nextRequires = [...dedupeContributions([...currentRequires, input.requirement])];
46342
+ input.requiresByCommand.set(input.commandRef, nextRequires);
46343
+ const contribution = input.contributionsByCommand.get(input.commandRef);
46344
+ if (contribution) {
46345
+ input.contributionsByCommand.set(input.commandRef, {
46346
+ ...contribution,
46347
+ requires: nextRequires
46348
+ });
46349
+ }
46350
+ }
46067
46351
  function parseContributions(input) {
46068
46352
  return input.contributions.flatMap((contribution) => {
46069
46353
  const parsed = parseResourceRef(contribution.ref);
@@ -46162,14 +46446,14 @@ function checkTicketPricedEventsHaveTickets(indexes) {
46162
46446
  }
46163
46447
  function checkTicketQuantitiesWithinCapacity(indexes) {
46164
46448
  return indexes.events.flatMap((event) => {
46165
- const capacity = limitedCapacityQuantity(event.input.capacity);
46166
- if (capacity === void 0) return [];
46449
+ const capacity2 = limitedCapacityQuantity(event.input.capacity);
46450
+ if (capacity2 === void 0) return [];
46167
46451
  const ticketQuantityTotal = (indexes.ticketsByEventRef.get(event.ref) ?? []).reduce((total, ticket) => total + (ticket.input.quantity ?? 0), 0);
46168
- if (ticketQuantityTotal <= capacity) return [];
46452
+ if (ticketQuantityTotal <= capacity2) return [];
46169
46453
  return [commandInvariantViolation(
46170
46454
  event.ref,
46171
46455
  "input.capacity",
46172
- `Event ticket quantities (${ticketQuantityTotal}) cannot exceed event capacity (${capacity}).`
46456
+ `Event ticket quantities (${ticketQuantityTotal}) cannot exceed event capacity (${capacity2}).`
46173
46457
  )];
46174
46458
  });
46175
46459
  }
@@ -46198,8 +46482,8 @@ function checkTicketCurrencyMatchesEvent(indexes) {
46198
46482
  )];
46199
46483
  }));
46200
46484
  }
46201
- function limitedCapacityQuantity(capacity) {
46202
- return capacity?.kind === "limited" ? capacity.quantity : void 0;
46485
+ function limitedCapacityQuantity(capacity2) {
46486
+ return capacity2?.kind === "limited" ? capacity2.quantity : void 0;
46203
46487
  }
46204
46488
  function commandInvariantViolation(commandRef, field, message) {
46205
46489
  return {
@@ -46336,6 +46620,35 @@ function countRisks(risks) {
46336
46620
  };
46337
46621
  }
46338
46622
 
46623
+ // ../site-commands/src/stableJson.ts
46624
+ init_src();
46625
+ function stableStringify(value) {
46626
+ const sorted = sortValue(value);
46627
+ switch (typeof sorted) {
46628
+ case "bigint":
46629
+ case "function":
46630
+ case "symbol":
46631
+ case "undefined":
46632
+ return String(sorted);
46633
+ case "boolean":
46634
+ case "number":
46635
+ case "object":
46636
+ case "string":
46637
+ return JSON.stringify(sorted);
46638
+ }
46639
+ return assertNever(sorted);
46640
+ }
46641
+ function sortValue(value) {
46642
+ if (Array.isArray(value)) return value.map(sortValue);
46643
+ if (value && typeof value === "object") return sortRecord(value);
46644
+ return value;
46645
+ }
46646
+ function sortRecord(record) {
46647
+ return Object.fromEntries(
46648
+ Object.entries(record).sort(([left], [right]) => left.localeCompare(right)).map(([key, value]) => [key, sortValue(value)])
46649
+ );
46650
+ }
46651
+
46339
46652
  // src/cli/site-commands/commandRuntime.ts
46340
46653
  function createCliCommandBatchRef(input) {
46341
46654
  return [
@@ -46418,13 +46731,18 @@ async function executeCliCommandPlan(input) {
46418
46731
  return { status: "applied", applied };
46419
46732
  }
46420
46733
  function commandExecutionToReport(input) {
46421
- const appliedSubjects = [];
46734
+ const outcomes = [];
46422
46735
  const warnings = [];
46423
46736
  const appliedRefs = new Set(input.execution.applied.map((command) => command.commandRef));
46424
46737
  for (const reportedCommand of input.reportedCommands) {
46425
46738
  const command = reportedCommand.plannedCommand.command;
46426
46739
  if (!appliedRefs.has(command.ref)) continue;
46427
- appliedSubjects.push(reportedCommand.reportSubject);
46740
+ outcomes.push({
46741
+ status: "applied",
46742
+ commandRef: command.ref,
46743
+ commandType: command.type,
46744
+ subject: reportedCommand.reportSubject
46745
+ });
46428
46746
  }
46429
46747
  if (input.execution.status === "failed") {
46430
46748
  const { failed } = input.execution;
@@ -46438,46 +46756,91 @@ function commandExecutionToReport(input) {
46438
46756
  `Stopped before applying ${skippedCount} remaining ${input.resourceLabel} command${skippedCount === 1 ? "" : "s"}.`
46439
46757
  );
46440
46758
  }
46441
- return {
46442
- appliedSubjects,
46443
- failure: {
46444
- identifier: failedCommand ? input.commandDisplayIdentifier(failedCommand) : String(failed.commandRef),
46445
- message: failed.message,
46446
- ...input.includeFailureSubject && failedIndex >= 0 ? { subject: input.reportedCommands[failedIndex]?.reportSubject } : {}
46447
- },
46448
- warnings
46449
- };
46759
+ const failedSubject = failedIndex >= 0 ? input.reportedCommands[failedIndex]?.reportSubject : void 0;
46760
+ outcomes.push({
46761
+ status: "failed",
46762
+ commandRef: failed.commandRef,
46763
+ commandType: failed.commandType,
46764
+ identifier: failedCommand ? input.commandDisplayIdentifier(failedCommand) : String(failed.commandRef),
46765
+ message: failed.message,
46766
+ ...input.includeFailureSubject && failedSubject ? { subject: failedSubject } : {}
46767
+ });
46768
+ for (const skippedCommand of failedIndex >= 0 ? input.reportedCommands.slice(failedIndex + 1) : []) {
46769
+ outcomes.push({
46770
+ status: "skipped_by_stop_policy",
46771
+ commandRef: skippedCommand.plannedCommand.command.ref,
46772
+ commandType: skippedCommand.plannedCommand.command.type,
46773
+ identifier: input.commandDisplayIdentifier(skippedCommand.plannedCommand.command),
46774
+ subject: skippedCommand.reportSubject
46775
+ });
46776
+ }
46450
46777
  }
46451
- return {
46452
- appliedSubjects,
46453
- failure: null,
46454
- warnings
46455
- };
46778
+ return reportFromOutcomes({ outcomes, warnings });
46456
46779
  }
46457
- function commandReportToSyncResult(input) {
46458
- const result = createEmptySyncResult();
46459
- for (const subject of input.report.appliedSubjects) {
46460
- input.incrementSuccess(result, subject);
46461
- }
46462
- if (input.report.failure) {
46463
- input.recordFailure(
46464
- result,
46465
- input.report.failure.identifier,
46466
- input.report.failure.message,
46467
- input.report.failure.subject
46468
- );
46469
- }
46470
- result.warnings.push(...input.report.warnings);
46471
- return result;
46780
+ function commandCompileFailureToReport(input) {
46781
+ return reportFromOutcomes({
46782
+ outcomes: [{
46783
+ status: "compile_failed",
46784
+ identifier: input.identifier,
46785
+ message: input.message,
46786
+ ...input.subject ? { subject: input.subject } : {}
46787
+ }],
46788
+ warnings: input.warnings ?? []
46789
+ });
46472
46790
  }
46473
- async function executeCompiledCliCommandPlanAsSyncResult(input) {
46791
+ async function executeCompiledCliCommandPlanAsReport(input) {
46474
46792
  input.onBeforeExecute?.(input.compiledPlan.plan.commands.length);
46475
46793
  const execution = await input.executePlan(input.compiledPlan.plan);
46476
- return input.executionToSyncResult({
46794
+ return input.executionToReport({
46477
46795
  execution,
46478
46796
  compiledPlan: input.compiledPlan
46479
46797
  });
46480
46798
  }
46799
+ function reportFromOutcomes(input) {
46800
+ const appliedSubjects = input.outcomes.flatMap(appliedSubjectFromOutcome);
46801
+ const failureOutcome = input.outcomes.map(failureFromOutcome).find((failure) => failure !== null) ?? null;
46802
+ return {
46803
+ outcomes: input.outcomes,
46804
+ appliedSubjects,
46805
+ failure: failureOutcome ? {
46806
+ identifier: failureOutcome.identifier,
46807
+ message: failureOutcome.message,
46808
+ ...failureOutcome.subject ? { subject: failureOutcome.subject } : {}
46809
+ } : null,
46810
+ warnings: input.warnings ?? []
46811
+ };
46812
+ }
46813
+ function commandReportHasFailures(report) {
46814
+ return report.outcomes.some((outcome) => failureFromOutcome(outcome) !== null);
46815
+ }
46816
+ function appliedSubjectFromOutcome(outcome) {
46817
+ switch (outcome.status) {
46818
+ case "applied":
46819
+ return [outcome.subject];
46820
+ case "failed":
46821
+ case "skipped_by_stop_policy":
46822
+ case "compile_failed":
46823
+ return [];
46824
+ default:
46825
+ assertNever(outcome);
46826
+ }
46827
+ }
46828
+ function failureFromOutcome(outcome) {
46829
+ switch (outcome.status) {
46830
+ case "failed":
46831
+ case "compile_failed":
46832
+ return {
46833
+ identifier: outcome.identifier,
46834
+ message: outcome.message,
46835
+ ...outcome.subject ? { subject: outcome.subject } : {}
46836
+ };
46837
+ case "applied":
46838
+ case "skipped_by_stop_policy":
46839
+ return null;
46840
+ default:
46841
+ assertNever(outcome);
46842
+ }
46843
+ }
46481
46844
  function appliedCommand(command) {
46482
46845
  return {
46483
46846
  commandRef: command.ref,
@@ -46491,6 +46854,553 @@ function reportSubjectForCommandRef(subjectsByCommandRef, commandRef) {
46491
46854
  throw new Error(`Internal command planning error: missing report subject for ${commandRef}.`);
46492
46855
  }
46493
46856
 
46857
+ // src/cli/site-commands/datedOfferingCommands.ts
46858
+ init_src();
46859
+ var datedOfferingSiteCommandTypes = [
46860
+ "upsertVenue",
46861
+ "deleteVenue",
46862
+ "upsertEventCategory",
46863
+ "deleteEventCategory",
46864
+ "upsertEventSeries",
46865
+ "deleteEventSeries",
46866
+ "upsertCourse",
46867
+ "deleteCourse"
46868
+ ];
46869
+ function compileDatedOfferingPushCommands(input) {
46870
+ const commandBindings = [];
46871
+ for (const venue of input.venues?.items ?? []) {
46872
+ const command = venueCommand(venue.item);
46873
+ if (!command.ok) return command;
46874
+ commandBindings.push(commandBinding(command.value, {
46875
+ scopeCommand: "venues",
46876
+ scopeName: "venues",
46877
+ itemLabelSingular: "venue",
46878
+ identifier: venue.item.slug,
46879
+ counter: venue.exists ? "updated" : "created"
46880
+ }));
46881
+ }
46882
+ for (const category of input.eventCategories?.items ?? []) {
46883
+ commandBindings.push(commandBinding(eventCategoryCommand(category.item), {
46884
+ scopeCommand: "event-categories",
46885
+ scopeName: "event categories",
46886
+ itemLabelSingular: "event category",
46887
+ identifier: category.item.identifier,
46888
+ counter: category.exists ? "updated" : "created"
46889
+ }));
46890
+ }
46891
+ for (const event of input.events?.items ?? []) {
46892
+ const command = eventSeriesCommand(event.item);
46893
+ if (!command.ok) return command;
46894
+ commandBindings.push(commandBinding(command.value, {
46895
+ scopeCommand: "events",
46896
+ scopeName: "events",
46897
+ itemLabelSingular: "event",
46898
+ identifier: event.item.identifier,
46899
+ counter: event.exists ? "updated" : "created"
46900
+ }));
46901
+ }
46902
+ for (const course of input.courses?.items ?? []) {
46903
+ const command = courseCommand(course.item);
46904
+ if (!command.ok) return command;
46905
+ commandBindings.push(commandBinding(command.value, {
46906
+ scopeCommand: "courses",
46907
+ scopeName: "courses",
46908
+ itemLabelSingular: "course",
46909
+ identifier: course.item.identifier,
46910
+ counter: course.exists ? "updated" : "created"
46911
+ }));
46912
+ }
46913
+ for (const identifier of input.delete?.events ?? []) {
46914
+ commandBindings.push(commandBinding({
46915
+ type: "deleteEventSeries",
46916
+ ref: createCommandRef("delete-event", [identifier]),
46917
+ input: { identifier }
46918
+ }, deleteSubject("events", "events", "event", identifier)));
46919
+ }
46920
+ for (const identifier of input.delete?.courses ?? []) {
46921
+ commandBindings.push(commandBinding({
46922
+ type: "deleteCourse",
46923
+ ref: createCommandRef("delete-course", [identifier]),
46924
+ input: { identifier }
46925
+ }, deleteSubject("courses", "courses", "course", identifier)));
46926
+ }
46927
+ for (const slug of input.delete?.venues ?? []) {
46928
+ commandBindings.push(commandBinding({
46929
+ type: "deleteVenue",
46930
+ ref: createCommandRef("delete-venue", [slug]),
46931
+ input: { slug }
46932
+ }, deleteSubject("venues", "venues", "venue", slug)));
46933
+ }
46934
+ for (const identifier of input.delete?.eventCategories ?? []) {
46935
+ commandBindings.push(commandBinding({
46936
+ type: "deleteEventCategory",
46937
+ ref: createCommandRef("delete-event-category", [identifier]),
46938
+ input: { identifier }
46939
+ }, deleteSubject("event-categories", "event categories", "event category", identifier)));
46940
+ }
46941
+ const planned = planCliCommandBatchForBindings({
46942
+ ...input,
46943
+ commandTypes: datedOfferingSiteCommandTypes,
46944
+ commandBindings
46945
+ });
46946
+ return planned.ok ? ok(planned.value) : err(planned.error);
46947
+ }
46948
+ async function executeDatedOfferingCommandPlanAsPushScopeResult(input) {
46949
+ const result = {
46950
+ status: "pushed",
46951
+ scopeCommand: input.scopeCommand,
46952
+ scopeName: input.scopeName,
46953
+ created: 0,
46954
+ updated: 0,
46955
+ deleted: 0,
46956
+ failed: 0,
46957
+ errors: []
46958
+ };
46959
+ for (const reportedCommand of input.compiledPlan.reportedCommands) {
46960
+ const command = reportedCommand.plannedCommand.command;
46961
+ try {
46962
+ await applyDatedOfferingCommand(input.client, command);
46963
+ increment(result, reportedCommand.reportSubject.counter);
46964
+ } catch (error) {
46965
+ result.failed++;
46966
+ result.errors.push({
46967
+ identifier: reportedCommand.reportSubject.identifier,
46968
+ error: formatManagementError(error)
46969
+ });
46970
+ }
46971
+ }
46972
+ if (result.failed > 0 && result.created === 0 && result.updated === 0 && result.deleted === 0) {
46973
+ result.status = "failed";
46974
+ }
46975
+ return result;
46976
+ }
46977
+ function syncResultForDatedOfferingCommandCompileError(error, scopeCommand, scopeName) {
46978
+ const identifier = error.code === "command_validation_failed" ? "command-validation" : error.identifier;
46979
+ return {
46980
+ status: "failed",
46981
+ scopeCommand,
46982
+ scopeName,
46983
+ created: 0,
46984
+ updated: 0,
46985
+ deleted: 0,
46986
+ failed: 1,
46987
+ errors: [{ identifier, error: error.message }]
46988
+ };
46989
+ }
46990
+ function commandBinding(command, reportSubject2) {
46991
+ return { command, reportSubject: reportSubject2 };
46992
+ }
46993
+ function deleteSubject(scopeCommand, scopeName, itemLabelSingular, identifier) {
46994
+ return {
46995
+ scopeCommand,
46996
+ scopeName,
46997
+ itemLabelSingular,
46998
+ identifier,
46999
+ counter: "deleted"
47000
+ };
47001
+ }
47002
+ function venueCommand(venue) {
47003
+ if (!venue.timezone) {
47004
+ return unsupported(venue.slug, `Venue ${venue.slug} is missing timezone; command-backed venue pushes require an IANA timezone.`);
47005
+ }
47006
+ if (venue.location && (typeof venue.location.lat !== "number" || typeof venue.location.lng !== "number")) {
47007
+ return unsupported(venue.slug, `Venue ${venue.slug} has an incomplete location; command-backed venue pushes require both lat and lng.`);
47008
+ }
47009
+ const location2 = venue.location && typeof venue.location.lat === "number" && typeof venue.location.lng === "number" ? {
47010
+ latitude: venue.location.lat,
47011
+ longitude: venue.location.lng
47012
+ } : void 0;
47013
+ return ok({
47014
+ type: "upsertVenue",
47015
+ ref: createVenueRef([venue.slug]),
47016
+ input: {
47017
+ slug: venue.slug,
47018
+ title: venue.title,
47019
+ description: venue.description ?? void 0,
47020
+ timezone: venue.timezone,
47021
+ capacity: venue.capacity ?? void 0,
47022
+ address: venue.address ? {
47023
+ line1: venue.address.line1 ?? void 0,
47024
+ line2: venue.address.line2 ?? void 0,
47025
+ city: venue.address.city ?? void 0,
47026
+ region: venue.address.region ?? void 0,
47027
+ postalCode: venue.address.postcode ?? void 0,
47028
+ country: venue.address.country ?? void 0
47029
+ } : void 0,
47030
+ location: location2,
47031
+ mapEmbedUrl: venue.mapEmbed ?? void 0
47032
+ }
47033
+ });
47034
+ }
47035
+ function eventCategoryCommand(category) {
47036
+ return {
47037
+ type: "upsertEventCategory",
47038
+ ref: createEventCategoryRef([category.identifier]),
47039
+ input: {
47040
+ identifier: category.identifier,
47041
+ name: category.name,
47042
+ description: category.description ?? null,
47043
+ color: category.color ?? null,
47044
+ sortOrder: category.sortOrder
47045
+ }
47046
+ };
47047
+ }
47048
+ function eventSeriesCommand(event) {
47049
+ if (event.identifier !== event.slug) {
47050
+ return unsupported(event.identifier, `Event identifier "${event.identifier}" must match slug "${event.slug}".`);
47051
+ }
47052
+ if (event.schedule?.recurrenceRule) {
47053
+ return unsupported(event.identifier, `Event ${event.identifier} uses recurrenceRule; command-backed SDK pushes currently support one-off events only.`);
47054
+ }
47055
+ const occurrence = eventOccurrence(event);
47056
+ if (!occurrence.ok) return occurrence;
47057
+ const pricing = eventPricing(event);
47058
+ if (!pricing.ok) return pricing;
47059
+ return ok({
47060
+ type: "upsertEventSeries",
47061
+ ref: createEventSeriesRef([event.identifier]),
47062
+ input: {
47063
+ slug: event.slug,
47064
+ title: event.title,
47065
+ archetype: "custom",
47066
+ status: event.status === "completed" ? void 0 : event.status,
47067
+ visibility: offeringVisibility(event.visibility, event.status),
47068
+ // SDK event files currently store date/time without an IANA timezone.
47069
+ // Keep the legacy UTC interpretation until the file format can carry timezone explicitly.
47070
+ timezone: "UTC",
47071
+ venueIdentifier: event.venueRef ?? void 0,
47072
+ categoryIdentifier: event.categoryRef ?? void 0,
47073
+ formIdentifier: event.formRef ?? void 0,
47074
+ capacity: capacity(event.capacity),
47075
+ pricing: pricing.value,
47076
+ priceDisplay: event.pricing?.priceDisplay ?? void 0,
47077
+ acceptsPasses: event.pricing?.acceptsPasses,
47078
+ acceptsMemberships: event.pricing?.acceptsMemberships,
47079
+ occurrences: [occurrence.value],
47080
+ content: event.content ? {
47081
+ summary: event.content.summary ?? void 0,
47082
+ body: event.content.body ?? void 0,
47083
+ image: event.content.image ?? void 0
47084
+ } : void 0,
47085
+ settings: event.settings,
47086
+ presentation: event.presentation,
47087
+ tags: event.tags
47088
+ }
47089
+ });
47090
+ }
47091
+ function courseCommand(course) {
47092
+ if (course.identifier !== course.slug) {
47093
+ return unsupported(course.identifier, `Course identifier "${course.identifier}" must match slug "${course.slug}".`);
47094
+ }
47095
+ const pricing = coursePricing(course);
47096
+ if (!pricing.ok) return pricing;
47097
+ return ok({
47098
+ type: "upsertCourse",
47099
+ ref: createCourseRef([course.identifier]),
47100
+ input: {
47101
+ slug: course.slug,
47102
+ title: course.title,
47103
+ status: course.status === "completed" ? void 0 : course.status,
47104
+ visibility: offeringVisibility(course.visibility, course.status),
47105
+ // SDK course files currently store session timestamps only; keep UTC as
47106
+ // the command-level timezone placeholder until local files carry timezone.
47107
+ timezone: "UTC",
47108
+ venueIdentifier: course.venueRef ?? void 0,
47109
+ categoryIdentifier: course.categoryRef ?? void 0,
47110
+ formIdentifier: course.formRef ?? void 0,
47111
+ capacity: capacity(course.capacity),
47112
+ enrollmentCapacity: course.enrollmentCapacity ?? void 0,
47113
+ pricing: pricing.value,
47114
+ acceptsMemberships: course.acceptsMemberships,
47115
+ sessions: course.sessions.map((session) => ({
47116
+ startAt: session.startsAt,
47117
+ endAt: session.endsAt
47118
+ })),
47119
+ programRef: course.programRef ?? void 0,
47120
+ program: course.program ?? void 0
47121
+ }
47122
+ });
47123
+ }
47124
+ function eventOccurrence(event) {
47125
+ const startDate = event.schedule?.startDate;
47126
+ if (!startDate) {
47127
+ return unsupported(event.identifier, `Event ${event.identifier} is missing schedule.startDate; command-backed event pushes require a concrete occurrence.`);
47128
+ }
47129
+ const startTime = event.schedule?.defaultStartTime ?? "09:00:00";
47130
+ const durationMinutes = event.schedule?.durationMinutes ?? 60;
47131
+ const startAt = toUtcIso(startDate, startTime);
47132
+ const endAt = new Date(Date.parse(startAt) + durationMinutes * 6e4).toISOString();
47133
+ return ok({
47134
+ startAt,
47135
+ endAt
47136
+ });
47137
+ }
47138
+ function eventPricing(event) {
47139
+ const pricing = event.pricing;
47140
+ if (!pricing?.requiresPayment) return ok({ kind: "free" });
47141
+ const amount = pricing.priceAmount;
47142
+ if (typeof amount !== "number" || amount < 0) {
47143
+ return unsupported(event.identifier, `Event ${event.identifier} requires payment but has no valid priceAmount.`);
47144
+ }
47145
+ return ok({
47146
+ kind: "fixed_price",
47147
+ price: {
47148
+ amountCents: amount,
47149
+ currency: pricing.priceCurrency
47150
+ }
47151
+ });
47152
+ }
47153
+ function coursePricing(course) {
47154
+ const amount = course.priceCents;
47155
+ if (amount === void 0 || amount === null || amount === 0) return ok({ kind: "free" });
47156
+ if (amount < 0) {
47157
+ return unsupported(course.identifier, `Course ${course.identifier} has invalid priceCents.`);
47158
+ }
47159
+ return ok({
47160
+ kind: "fixed_price",
47161
+ price: {
47162
+ amountCents: amount,
47163
+ currency: course.currency
47164
+ }
47165
+ });
47166
+ }
47167
+ function venueUpsertInput(command) {
47168
+ return {
47169
+ slug: command.input.slug,
47170
+ title: command.input.title,
47171
+ description: command.input.description ?? null,
47172
+ timezone: command.input.timezone,
47173
+ capacity: command.input.capacity ?? null,
47174
+ address: command.input.address ? {
47175
+ line1: command.input.address.line1,
47176
+ line2: command.input.address.line2,
47177
+ city: command.input.address.city,
47178
+ region: command.input.address.region,
47179
+ postcode: command.input.address.postalCode,
47180
+ country: command.input.address.country
47181
+ } : void 0,
47182
+ location: command.input.location ? {
47183
+ lat: command.input.location.latitude,
47184
+ lng: command.input.location.longitude
47185
+ } : null,
47186
+ mapEmbed: command.input.mapEmbedUrl ?? null
47187
+ };
47188
+ }
47189
+ function eventSeriesUpsertInput(command) {
47190
+ const occurrence = command.input.occurrences[0];
47191
+ if (!occurrence) throw new Error(`Event command ${command.ref} has no occurrence.`);
47192
+ return {
47193
+ identifier: command.input.slug,
47194
+ title: command.input.title,
47195
+ slug: command.input.slug,
47196
+ status: command.input.status,
47197
+ visibility: managementVisibility(command.input.visibility),
47198
+ schedule: scheduleFromOccurrence(occurrence),
47199
+ capacity: capacityLimit(command.input.capacity),
47200
+ pricing: eventPricingInput(command.input),
47201
+ venueRef: command.input.venueIdentifier ?? (command.input.venueRef ? refSlug(command.input.venueRef) : null),
47202
+ categoryRef: command.input.categoryIdentifier ?? (command.input.categoryRef ? refSlug(command.input.categoryRef) : null),
47203
+ content: eventContentInput(command.input.content),
47204
+ formRef: command.input.formIdentifier ?? (command.input.formRef ? refSlug(command.input.formRef) : null),
47205
+ settings: command.input.settings,
47206
+ presentation: command.input.presentation,
47207
+ tags: command.input.tags ? [...command.input.tags] : void 0
47208
+ };
47209
+ }
47210
+ function eventContentInput(content) {
47211
+ if (!content) return void 0;
47212
+ return {
47213
+ ...content.summary ? { summary: content.summary } : {},
47214
+ ...typeof content.body === "string" || isRecord11(content.body) ? { body: content.body } : {},
47215
+ ...typeof content.image === "string" || isRecord11(content.image) ? { image: content.image } : {}
47216
+ };
47217
+ }
47218
+ function courseUpsertInput(command) {
47219
+ return {
47220
+ identifier: command.input.slug,
47221
+ title: command.input.title,
47222
+ slug: command.input.slug,
47223
+ status: command.input.status,
47224
+ visibility: managementVisibility(command.input.visibility),
47225
+ venueRef: command.input.venueIdentifier ?? (command.input.venueRef ? refSlug(command.input.venueRef) : null),
47226
+ categoryRef: command.input.categoryIdentifier ?? (command.input.categoryRef ? refSlug(command.input.categoryRef) : null),
47227
+ formRef: command.input.formIdentifier ?? (command.input.formRef ? refSlug(command.input.formRef) : null),
47228
+ capacity: capacityLimit(command.input.capacity),
47229
+ enrollmentCapacity: command.input.enrollmentCapacity ?? null,
47230
+ acceptsMemberships: command.input.acceptsMemberships ?? false,
47231
+ ...coursePricingInput(command.input.pricing),
47232
+ sessions: command.input.sessions.map((session) => ({
47233
+ startsAt: session.startAt,
47234
+ endsAt: session.endAt
47235
+ })),
47236
+ programRef: command.input.programRef ?? null,
47237
+ program: command.input.program ? {
47238
+ identifier: command.input.program.identifier ?? null,
47239
+ data: command.input.program.data
47240
+ } : null
47241
+ };
47242
+ }
47243
+ function eventPricingInput(input) {
47244
+ switch (input.pricing.kind) {
47245
+ case "free":
47246
+ return {
47247
+ requiresPayment: false,
47248
+ priceAmount: null,
47249
+ priceCurrency: null,
47250
+ priceDisplay: input.priceDisplay ?? null,
47251
+ acceptsPasses: input.acceptsPasses ?? false,
47252
+ acceptsMemberships: input.acceptsMemberships ?? false
47253
+ };
47254
+ case "fixed_price":
47255
+ return {
47256
+ requiresPayment: input.pricing.price.amountCents > 0,
47257
+ priceAmount: input.pricing.price.amountCents,
47258
+ priceCurrency: input.pricing.price.currency ?? null,
47259
+ priceDisplay: input.priceDisplay ?? null,
47260
+ acceptsPasses: input.acceptsPasses ?? false,
47261
+ acceptsMemberships: input.acceptsMemberships ?? false
47262
+ };
47263
+ case "ticket_types":
47264
+ return {
47265
+ requiresPayment: false,
47266
+ priceAmount: null,
47267
+ priceCurrency: input.pricing.currency ?? null,
47268
+ priceDisplay: input.priceDisplay ?? null,
47269
+ acceptsPasses: input.acceptsPasses ?? false,
47270
+ acceptsMemberships: input.acceptsMemberships ?? false
47271
+ };
47272
+ case "manual_payment":
47273
+ case "external":
47274
+ throw new Error(`Unsupported event pricing mode reached SDK mapper: ${input.pricing.kind}`);
47275
+ default:
47276
+ return assertNever(input.pricing);
47277
+ }
47278
+ }
47279
+ function coursePricingInput(pricing) {
47280
+ switch (pricing.kind) {
47281
+ case "free":
47282
+ return { priceCents: null };
47283
+ case "fixed_price":
47284
+ return {
47285
+ priceCents: pricing.price.amountCents,
47286
+ ...pricing.price.currency ? { currency: pricing.price.currency } : {}
47287
+ };
47288
+ case "manual_payment":
47289
+ case "external":
47290
+ throw new Error(`Unsupported course pricing mode reached SDK mapper: ${pricing.kind}`);
47291
+ default:
47292
+ return assertNever(pricing);
47293
+ }
47294
+ }
47295
+ function increment(result, counter) {
47296
+ switch (counter) {
47297
+ case "created":
47298
+ result.created++;
47299
+ return;
47300
+ case "updated":
47301
+ result.updated++;
47302
+ return;
47303
+ case "deleted":
47304
+ result.deleted++;
47305
+ return;
47306
+ default:
47307
+ assertNever(counter);
47308
+ }
47309
+ }
47310
+ async function applyDatedOfferingCommand(client, command) {
47311
+ switch (command.type) {
47312
+ case "upsertVenue":
47313
+ await client.venues.upsert(venueUpsertInput(command));
47314
+ return;
47315
+ case "deleteVenue":
47316
+ await client.venues.delete(command.input.slug);
47317
+ return;
47318
+ case "upsertEventCategory":
47319
+ await client.eventCategories.upsert({
47320
+ identifier: command.input.identifier ?? refSlug(command.ref),
47321
+ name: command.input.name,
47322
+ description: command.input.description ?? null,
47323
+ color: command.input.color ?? null,
47324
+ sortOrder: command.input.sortOrder
47325
+ });
47326
+ return;
47327
+ case "deleteEventCategory":
47328
+ await client.eventCategories.delete(command.input.identifier);
47329
+ return;
47330
+ case "upsertEventSeries":
47331
+ await client.events.upsert(eventSeriesUpsertInput(command));
47332
+ return;
47333
+ case "deleteEventSeries":
47334
+ await client.events.delete(command.input.identifier);
47335
+ return;
47336
+ case "upsertCourse":
47337
+ try {
47338
+ await client.courses.upsert(courseUpsertInput(command));
47339
+ } catch (error) {
47340
+ throw new Error(courseSessionConflictMessage(error));
47341
+ }
47342
+ return;
47343
+ case "deleteCourse":
47344
+ await client.courses.delete(command.input.identifier);
47345
+ return;
47346
+ default:
47347
+ assertNever(command);
47348
+ }
47349
+ }
47350
+ function capacity(value) {
47351
+ return typeof value === "number" ? { kind: "limited", quantity: value } : { kind: "unlimited" };
47352
+ }
47353
+ function capacityLimit(value) {
47354
+ return !value || value.kind === "unlimited" ? null : value.quantity;
47355
+ }
47356
+ function offeringVisibility(visibility, status) {
47357
+ if (status === "draft") return "draft";
47358
+ if (visibility === "unlisted") return "unlisted";
47359
+ if (visibility === "private") return "draft";
47360
+ return "listed";
47361
+ }
47362
+ function managementVisibility(visibility) {
47363
+ switch (visibility) {
47364
+ case "draft":
47365
+ return "private";
47366
+ case "unlisted":
47367
+ return "unlisted";
47368
+ case "listed":
47369
+ case "published":
47370
+ return "public";
47371
+ default:
47372
+ return assertNever(visibility);
47373
+ }
47374
+ }
47375
+ function scheduleFromOccurrence(occurrence) {
47376
+ return {
47377
+ recurrenceRule: null,
47378
+ startDate: occurrence.startAt.slice(0, 10),
47379
+ defaultStartTime: occurrence.startAt.slice(11, 19),
47380
+ durationMinutes: Math.round((Date.parse(occurrence.endAt) - Date.parse(occurrence.startAt)) / 6e4)
47381
+ };
47382
+ }
47383
+ function toUtcIso(date, time) {
47384
+ const normalizedTime = time.length === 5 ? `${time}:00` : time;
47385
+ return (/* @__PURE__ */ new Date(`${date}T${normalizedTime}Z`)).toISOString();
47386
+ }
47387
+ function isRecord11(value) {
47388
+ return Boolean(value && typeof value === "object" && !Array.isArray(value));
47389
+ }
47390
+ function unsupported(identifier, message) {
47391
+ return err({
47392
+ code: "unsupported_local_shape",
47393
+ identifier,
47394
+ message
47395
+ });
47396
+ }
47397
+ function courseSessionConflictMessage(error) {
47398
+ if (!(error instanceof CourseSessionConflictError)) {
47399
+ return error instanceof Error ? error.message : String(error);
47400
+ }
47401
+ return error.conflicts.map((conflict) => conflict.message).join("; ") || error.message;
47402
+ }
47403
+
46494
47404
  // src/cli/site-commands/entryCommands.ts
46495
47405
  init_src();
46496
47406
 
@@ -46502,6 +47412,43 @@ var asCliBlockIdentifier = (value) => value;
46502
47412
  var asCliFormSlug = (value) => value;
46503
47413
  var asCliNavigationMenuName = (value) => value;
46504
47414
 
47415
+ // src/cli/site-commands/commandRuntimeCompat.ts
47416
+ init_src();
47417
+ function commandReportToSyncResult(input) {
47418
+ const result = createEmptySyncResult();
47419
+ for (const outcome of input.report.outcomes) {
47420
+ switch (outcome.status) {
47421
+ case "applied":
47422
+ input.incrementSuccess(result, outcome.subject);
47423
+ break;
47424
+ case "failed":
47425
+ case "compile_failed":
47426
+ input.recordFailure(
47427
+ result,
47428
+ outcome.identifier,
47429
+ outcome.message,
47430
+ outcome.subject
47431
+ );
47432
+ break;
47433
+ case "skipped_by_stop_policy":
47434
+ break;
47435
+ default:
47436
+ assertNever(outcome);
47437
+ }
47438
+ }
47439
+ result.warnings.push(...input.report.warnings);
47440
+ return result;
47441
+ }
47442
+ async function executeCompiledCliCommandPlanAsSyncResult(input) {
47443
+ const report = await executeCompiledCliCommandPlanAsReport({
47444
+ compiledPlan: input.compiledPlan,
47445
+ onBeforeExecute: input.onBeforeExecute,
47446
+ executePlan: input.executePlan,
47447
+ executionToReport: input.executionToReport
47448
+ });
47449
+ return input.reportToSyncResult(report);
47450
+ }
47451
+
46505
47452
  // src/cli/site-commands/entryCommands.ts
46506
47453
  var entrySiteCommandTypes = [
46507
47454
  "upsertContentEntry",
@@ -46587,20 +47534,29 @@ async function executeEntryCommandPlanAsSyncResult(input) {
46587
47534
  client: input.client,
46588
47535
  plan
46589
47536
  }),
46590
- executionToSyncResult: entryCommandExecutionToSyncResult
47537
+ executionToReport: entryCommandExecutionToReport,
47538
+ reportToSyncResult: entryCommandReportToSyncResult
47539
+ });
47540
+ }
47541
+ function executeEntryCommandPlanAsReport(input) {
47542
+ return executeCompiledCliCommandPlanAsReport({
47543
+ compiledPlan: input.compiledPlan,
47544
+ onBeforeExecute: input.onBeforeExecute,
47545
+ executePlan: (plan) => executeEntryCommandPlan({
47546
+ client: input.client,
47547
+ plan
47548
+ }),
47549
+ executionToReport: entryCommandExecutionToReport
46591
47550
  });
46592
47551
  }
46593
47552
  function syncResultForEntryCommandCompileError(error) {
46594
- const result = createEmptySyncResult();
46595
- recordEntryFailure(
46596
- result,
46597
- error.code === "missing_local_entry" ? `${error.contentType}/${error.identifier}` : "command-validation",
46598
- error.message
46599
- );
46600
- return result;
47553
+ return entryCommandReportToSyncResult(entryCommandCompileErrorToReport(error));
46601
47554
  }
46602
- function entryCommandExecutionToSyncResult(input) {
46603
- return entryCommandReportToSyncResult(entryCommandExecutionToReport(input));
47555
+ function entryCommandCompileErrorToReport(error) {
47556
+ return commandCompileFailureToReport({
47557
+ identifier: error.code === "missing_local_entry" ? `${error.contentType}/${error.identifier}` : "command-validation",
47558
+ message: error.message
47559
+ });
46604
47560
  }
46605
47561
  function entryCommandExecutionToReport(input) {
46606
47562
  return commandExecutionToReport({
@@ -46814,28 +47770,22 @@ async function executeFormCommandPlan(input) {
46814
47770
  }
46815
47771
  });
46816
47772
  }
46817
- async function executeFormCommandPlanAsSyncResult(input) {
46818
- return executeCompiledCliCommandPlanAsSyncResult({
47773
+ function executeFormCommandPlanAsReport(input) {
47774
+ return executeCompiledCliCommandPlanAsReport({
46819
47775
  compiledPlan: input.compiledPlan,
46820
47776
  onBeforeExecute: input.onBeforeExecute,
46821
47777
  executePlan: (plan) => executeFormCommandPlan({
46822
47778
  client: input.client,
46823
47779
  plan
46824
47780
  }),
46825
- executionToSyncResult: formCommandExecutionToSyncResult
47781
+ executionToReport: formCommandExecutionToReport
46826
47782
  });
46827
47783
  }
46828
- function syncResultForFormCommandCompileError(error) {
46829
- const result = createEmptySyncResult();
46830
- recordFormFailure(
46831
- result,
46832
- error.code === "missing_local_form" ? error.slug : "command-validation",
46833
- error.message
46834
- );
46835
- return result;
46836
- }
46837
- function formCommandExecutionToSyncResult(input) {
46838
- return formCommandReportToSyncResult(formCommandExecutionToReport(input));
47784
+ function formCommandCompileErrorToReport(error) {
47785
+ return commandCompileFailureToReport({
47786
+ identifier: error.code === "missing_local_form" ? error.slug : "command-validation",
47787
+ message: error.message
47788
+ });
46839
47789
  }
46840
47790
  function formCommandExecutionToReport(input) {
46841
47791
  return commandExecutionToReport({
@@ -46959,16 +47909,18 @@ async function executeFooterCommandPlanAsSyncResult(input) {
46959
47909
  client: input.client,
46960
47910
  plan
46961
47911
  }),
46962
- executionToSyncResult: footerCommandExecutionToSyncResult
47912
+ executionToReport: footerCommandExecutionToReport,
47913
+ reportToSyncResult: footerCommandReportToSyncResult
46963
47914
  });
46964
47915
  }
46965
47916
  function syncResultForFooterCommandCompileError(error) {
46966
- const result = createEmptySyncResult();
46967
- recordFooterFailure(result, "footer", error.message);
46968
- return result;
47917
+ return footerCommandReportToSyncResult(footerCommandCompileErrorToReport(error));
46969
47918
  }
46970
- function footerCommandExecutionToSyncResult(input) {
46971
- return footerCommandReportToSyncResult(footerCommandExecutionToReport(input));
47919
+ function footerCommandCompileErrorToReport(error) {
47920
+ return commandCompileFailureToReport({
47921
+ identifier: "footer",
47922
+ message: error.message
47923
+ });
46972
47924
  }
46973
47925
  function footerCommandExecutionToReport(input) {
46974
47926
  return commandExecutionToReport({
@@ -47071,28 +48023,22 @@ async function executeNavigationCommandPlan(input) {
47071
48023
  }
47072
48024
  });
47073
48025
  }
47074
- async function executeNavigationCommandPlanAsSyncResult(input) {
47075
- return executeCompiledCliCommandPlanAsSyncResult({
48026
+ function executeNavigationCommandPlanAsReport(input) {
48027
+ return executeCompiledCliCommandPlanAsReport({
47076
48028
  compiledPlan: input.compiledPlan,
47077
48029
  onBeforeExecute: input.onBeforeExecute,
47078
48030
  executePlan: (plan) => executeNavigationCommandPlan({
47079
48031
  client: input.client,
47080
48032
  plan
47081
48033
  }),
47082
- executionToSyncResult: navigationCommandExecutionToSyncResult
48034
+ executionToReport: navigationCommandExecutionToReport
47083
48035
  });
47084
48036
  }
47085
- function syncResultForNavigationCommandCompileError(error) {
47086
- const result = createEmptySyncResult();
47087
- recordNavigationFailure(
47088
- result,
47089
- error.code === "missing_local_navigation_menu" ? error.name : "command-validation",
47090
- error.message
47091
- );
47092
- return result;
47093
- }
47094
- function navigationCommandExecutionToSyncResult(input) {
47095
- return navigationCommandReportToSyncResult(navigationCommandExecutionToReport(input));
48037
+ function navigationCommandCompileErrorToReport(error) {
48038
+ return commandCompileFailureToReport({
48039
+ identifier: error.code === "missing_local_navigation_menu" ? error.name : "command-validation",
48040
+ message: error.message
48041
+ });
47096
48042
  }
47097
48043
  function navigationCommandExecutionToReport(input) {
47098
48044
  return commandExecutionToReport({
@@ -47394,39 +48340,34 @@ async function executePageCommandPlan(input) {
47394
48340
  }
47395
48341
  });
47396
48342
  }
47397
- async function executePageCommandPlanAsSyncResult(input) {
47398
- const result = await executeCompiledCliCommandPlanAsSyncResult({
48343
+ async function executePageCommandPlanAsReport(input) {
48344
+ const report = await executeCompiledCliCommandPlanAsReport({
47399
48345
  compiledPlan: input.compiledPlan,
47400
48346
  onBeforeExecute: input.onBeforeExecute,
47401
48347
  executePlan: (plan) => executePageCommandPlan({
47402
48348
  client: input.client,
47403
48349
  plan
47404
48350
  }),
47405
- executionToSyncResult: pageCommandExecutionToSyncResult
48351
+ executionToReport: pageCommandExecutionToReport
47406
48352
  });
47407
- result.warnings.push(...input.compiledPlan.warnings);
47408
- return result;
48353
+ return pageCommandReportWithWarnings(report, [
48354
+ ...report.warnings,
48355
+ ...input.compiledPlan.warnings
48356
+ ]);
47409
48357
  }
47410
- function syncResultForPageCommandCompileError(error) {
47411
- const result = createEmptySyncResult();
48358
+ function pageCommandCompileErrorToReport(error) {
47412
48359
  const identifier = error.code === "command_validation_failed" ? "command-validation" : error.identifier;
47413
- if (error.code === "missing_local_block" || error.code === "invalid_page_block") {
47414
- result.blocks.failed++;
47415
- result.errors.push({
48360
+ return commandCompileFailureToReport({
48361
+ identifier,
48362
+ message: error.message,
48363
+ subject: error.code === "missing_local_block" || error.code === "invalid_page_block" ? {
47416
48364
  resource: "block",
47417
- identifier,
47418
- error: error.message
47419
- });
47420
- if (error.code === "invalid_page_block") {
47421
- result.warnings.push(...error.warnings);
47422
- }
47423
- return result;
47424
- }
47425
- recordPageFailure(result, identifier, error.message);
47426
- return result;
47427
- }
47428
- function pageCommandExecutionToSyncResult(input) {
47429
- return pageCommandReportToSyncResult(pageCommandExecutionToReport(input));
48365
+ pageIdentifier: pageIdentifierFromPageBlockIdentifier(identifier),
48366
+ identifier: blockIdentifierFromPageBlockIdentifier(identifier),
48367
+ counter: "updated"
48368
+ } : void 0,
48369
+ warnings: error.code === "invalid_page_block" ? error.warnings : []
48370
+ });
47430
48371
  }
47431
48372
  function pageCommandExecutionToReport(input) {
47432
48373
  return commandExecutionToReport({
@@ -47444,6 +48385,12 @@ function pageCommandReportToSyncResult(report) {
47444
48385
  recordFailure: recordPageFailure
47445
48386
  });
47446
48387
  }
48388
+ function pageCommandReportWithWarnings(report, warnings) {
48389
+ return reportFromOutcomes({
48390
+ outcomes: report.outcomes,
48391
+ warnings
48392
+ });
48393
+ }
47447
48394
  function pageCommandsForDiff(input) {
47448
48395
  if (input.pageDiff.type === "unchanged" && !input.pageDiff.statusChange) {
47449
48396
  return ok(emptyPageCommandCompileFragment());
@@ -47747,49 +48694,107 @@ function blockReportSubject(input) {
47747
48694
  function pageBlockIdentifier(pageIdentifier, blockIdentifier) {
47748
48695
  return `${pageIdentifier}/${blockIdentifier}`;
47749
48696
  }
48697
+ function pageIdentifierFromPageBlockIdentifier(identifier) {
48698
+ return asCliPageIdentifier(identifier.split("/")[0] ?? identifier);
48699
+ }
48700
+ function blockIdentifierFromPageBlockIdentifier(identifier) {
48701
+ return asCliBlockIdentifier(identifier.split("/")[1] ?? identifier);
48702
+ }
47750
48703
 
47751
48704
  // src/cli/site-commands/pushExecution.ts
47752
48705
  init_src();
47753
- var baselineResidualOmittedCommandSurfaces = ["navigation"];
47754
- var baselineResidualOmittedCommandSurfaceSet = new Set(
47755
- baselineResidualOmittedCommandSurfaces
47756
- );
47757
- async function executeContentPushPlan(input) {
47758
- const executionPlan = planContentPushExecution({
47759
- pushScope: input.pushScope,
47760
- siteId: input.siteId,
47761
- target: input.target,
47762
- diff: input.diff,
47763
- local: input.local,
47764
- blockFieldExtensions: input.blockFieldExtensions
48706
+
48707
+ // src/cli/site-commands/commandSurfaceDispatch.ts
48708
+ init_src();
48709
+ function compileContentPushExecutionPlan(plan, input, dependencies = {}) {
48710
+ const steps = [];
48711
+ for (const step of plan.steps) {
48712
+ switch (step.kind) {
48713
+ case "residual-settings-sync":
48714
+ steps.push(step);
48715
+ break;
48716
+ case "command-surface": {
48717
+ const compiled = commandSurfaceCompileSuccess(
48718
+ (dependencies.compileCommandSurface ?? compileCommandSurface)(step.surface, input)
48719
+ );
48720
+ if (!compiled.ok) return err(compiled.error);
48721
+ steps.push({
48722
+ ...step,
48723
+ surface: compiled.value
48724
+ });
48725
+ break;
48726
+ }
48727
+ default:
48728
+ assertNever(step);
48729
+ }
48730
+ }
48731
+ return ok({
48732
+ kind: "compiled-sync-steps",
48733
+ steps
47765
48734
  });
47766
- if (!executionPlan.ok) return executionPlan.error;
47767
- return executePushExecutionSteps(executionPlan.value.steps, input);
47768
48735
  }
47769
- function planContentPushExecution(input) {
47770
- const directCommand = directCommandStepForPushScope(input);
47771
- if (directCommand) {
47772
- return directCommand.ok ? ok(syncPlanWithSteps([directCommand.value])) : err(directCommand.error);
47773
- }
47774
- switch (input.pushScope) {
47775
- case "pages": {
47776
- return ok(syncPlanWithResidualOnly(input));
47777
- }
47778
- case "all":
47779
- return pushAllExecutionPlan(input);
48736
+ async function executeCommandSurfaceAsReport(surface, input) {
48737
+ switch (surface.surface) {
48738
+ case "entry":
48739
+ return {
48740
+ surface: "entry",
48741
+ report: await executeEntryCommandPlanAsReport({
48742
+ client: input.client,
48743
+ compiledPlan: surface.compileValue,
48744
+ onBeforeExecute: input.onEntryCommandCount
48745
+ })
48746
+ };
48747
+ case "page":
48748
+ return {
48749
+ surface: "page",
48750
+ report: await executePageCommandPlanAsReport({
48751
+ client: input.client,
48752
+ compiledPlan: surface.compileValue,
48753
+ onBeforeExecute: input.onPageCommandCount
48754
+ })
48755
+ };
48756
+ case "form":
48757
+ return {
48758
+ surface: "form",
48759
+ report: await executeFormCommandPlanAsReport({
48760
+ client: input.client,
48761
+ compiledPlan: surface.compileValue,
48762
+ onBeforeExecute: input.onFormCommandCount
48763
+ })
48764
+ };
48765
+ case "navigation":
48766
+ return {
48767
+ surface: "navigation",
48768
+ report: await executeNavigationCommandPlanAsReport({
48769
+ client: input.client,
48770
+ compiledPlan: surface.compileValue,
48771
+ onBeforeExecute: input.onNavigationCommandCount
48772
+ })
48773
+ };
47780
48774
  default:
47781
- return ok(syncPlanWithResidualOnly(input));
48775
+ assertNever(surface);
47782
48776
  }
47783
48777
  }
47784
- function directCommandStepForPushScope(input) {
47785
- const commandSurface = directCommandSurfaceForPushScope(input);
47786
- if (!commandSurface) return null;
47787
- const compiled = commandSurfaceCompileSuccess(commandSurface);
47788
- return compiled.ok ? ok(commandSurfaceStep(compiled.value, "continue")) : err(compiled.error);
48778
+ function skippedRemainingCommandReports(steps) {
48779
+ return steps.flatMap((step) => step.kind === "command-surface" ? [skippedCommandSurfaceReport(step.surface)] : []);
47789
48780
  }
47790
- function directCommandSurfaceForPushScope(input) {
47791
- switch (input.pushScope) {
47792
- case "entries":
48781
+ function commandSurfaceReportToSyncResult(report) {
48782
+ switch (report.surface) {
48783
+ case "entry":
48784
+ return entryCommandReportToSyncResult(report.report);
48785
+ case "page":
48786
+ return pageCommandReportToSyncResult(report.report);
48787
+ case "form":
48788
+ return formCommandReportToSyncResult(report.report);
48789
+ case "navigation":
48790
+ return navigationCommandReportToSyncResult(report.report);
48791
+ default:
48792
+ assertNever(report);
48793
+ }
48794
+ }
48795
+ function compileCommandSurface(surface, input) {
48796
+ switch (surface) {
48797
+ case "entry":
47793
48798
  return {
47794
48799
  surface: "entry",
47795
48800
  compileResult: compileEntryPushCommands({
@@ -47800,7 +48805,19 @@ function directCommandSurfaceForPushScope(input) {
47800
48805
  local: input.local
47801
48806
  })
47802
48807
  };
47803
- case "forms":
48808
+ case "page":
48809
+ return {
48810
+ surface: "page",
48811
+ compileResult: compilePagePushCommands({
48812
+ source: "push_pages",
48813
+ siteId: input.siteId,
48814
+ targetEnv: input.target,
48815
+ diff: input.diff,
48816
+ local: input.local,
48817
+ blockFieldExtensions: input.blockFieldExtensions
48818
+ })
48819
+ };
48820
+ case "form":
47804
48821
  return {
47805
48822
  surface: "form",
47806
48823
  compileResult: compileFormPushCommands({
@@ -47822,249 +48839,152 @@ function directCommandSurfaceForPushScope(input) {
47822
48839
  local: input.local
47823
48840
  })
47824
48841
  };
47825
- case "pages":
47826
- return pageCommandRouting(input.diff).kind === "command_backed" ? {
47827
- surface: "page",
47828
- compileResult: compilePagePushCommands({
47829
- source: "push_pages",
47830
- siteId: input.siteId,
47831
- targetEnv: input.target,
47832
- diff: input.diff,
47833
- local: input.local,
47834
- blockFieldExtensions: input.blockFieldExtensions
47835
- })
47836
- } : null;
47837
48842
  default:
47838
- return null;
47839
- }
47840
- }
47841
- function pushAllExecutionPlan(input) {
47842
- const pageRouting = pageCommandRouting(input.diff);
47843
- const successfulSurfaces = [];
47844
- for (const surface of commandSurfacesForPushAll({ ...input, pageRouting })) {
47845
- const compiled = commandSurfaceCompileSuccess(surface);
47846
- if (!compiled.ok) return compiled;
47847
- successfulSurfaces.push(compiled.value);
47848
- }
47849
- const orderedSurfaces = orderCommandSurfacesForPushAll(successfulSurfaces);
47850
- const beforeResidualSteps = orderedSurfaces.beforeResidualSync.map(
47851
- (surface) => commandSurfaceStep(surface, "stop")
47852
- );
47853
- const residualPlan = residualSettingsPlan(input, successfulSurfaces);
47854
- const residualStep = residualPlan ? { kind: "residual-settings-sync", residual: residualPlan, onFailure: "continue" } : null;
47855
- const afterResidualSteps = orderedSurfaces.afterResidualSync.map(
47856
- (surface) => commandSurfaceStep(surface, "continue")
47857
- );
47858
- const steps = [
47859
- ...beforeResidualSteps,
47860
- ...residualStep ? [residualStep] : [],
47861
- ...afterResidualSteps
47862
- ];
47863
- return ok(syncPlanWithSteps(steps));
47864
- }
47865
- function syncPlanWithResidualOnly(input) {
47866
- return syncPlanWithSteps([{
47867
- kind: "residual-settings-sync",
47868
- onFailure: "continue",
47869
- residual: {
47870
- diff: withoutCommandSurfaceDiff(input.diff, baselineResidualOmittedCommandSurfaceSet),
47871
- local: withoutCommandSurfaceLocal(input.local, baselineResidualOmittedCommandSurfaceSet)
47872
- }
47873
- }]);
47874
- }
47875
- async function executePushExecutionSteps(steps, input) {
47876
- const results = [];
47877
- for (const step of steps) {
47878
- switch (step.kind) {
47879
- case "residual-settings-sync": {
47880
- const result = await executeResidualSettingsSync(input, step.residual);
47881
- results.push(result);
47882
- if (step.onFailure === "stop" && result.errors.length > 0) {
47883
- return mergeManySyncResults(results);
47884
- }
47885
- break;
47886
- }
47887
- case "command-surface": {
47888
- const result = await executeCommandSurfaceAsSyncResult(step.surface, input);
47889
- results.push(result);
47890
- if (step.onFailure === "stop" && result.errors.length > 0) {
47891
- return mergeManySyncResults(results);
47892
- }
47893
- break;
47894
- }
47895
- default:
47896
- assertNever(step);
47897
- }
47898
- }
47899
- return mergeManySyncResults(results);
47900
- }
47901
- function executeResidualSettingsSync(input, residual) {
47902
- return executeResidualSettingsSyncPlan(
47903
- input.client,
47904
- residual.diff,
47905
- residual.local,
47906
- {
47907
- dryRun: false
47908
- },
47909
- input.output
47910
- );
47911
- }
47912
- function commandSurfacesForPushAll(input) {
47913
- const surfaces = [];
47914
- if (hasEntryChanges(input.diff)) {
47915
- surfaces.push({
47916
- surface: "entry",
47917
- compileResult: compileEntryPushCommands({
47918
- source: "push_entries",
47919
- siteId: input.siteId,
47920
- targetEnv: input.target,
47921
- diff: input.diff,
47922
- local: input.local
47923
- })
47924
- });
47925
- }
47926
- if (input.pageRouting.kind === "command_backed") {
47927
- surfaces.push({
47928
- surface: "page",
47929
- compileResult: compilePagePushCommands({
47930
- source: "push_pages",
47931
- siteId: input.siteId,
47932
- targetEnv: input.target,
47933
- diff: input.diff,
47934
- local: input.local,
47935
- blockFieldExtensions: input.blockFieldExtensions
47936
- })
47937
- });
47938
- }
47939
- if (hasFormChanges(input.diff)) {
47940
- surfaces.push({
47941
- surface: "form",
47942
- compileResult: compileFormPushCommands({
47943
- source: "push_forms",
47944
- siteId: input.siteId,
47945
- targetEnv: input.target,
47946
- diff: input.diff,
47947
- local: input.local
47948
- })
47949
- });
47950
- }
47951
- if (hasNavigationChanges(input.diff)) {
47952
- surfaces.push({
47953
- surface: "navigation",
47954
- compileResult: compileNavigationPushCommands({
47955
- source: "push_navigation",
47956
- siteId: input.siteId,
47957
- targetEnv: input.target,
47958
- diff: input.diff.navigation,
47959
- local: input.local
47960
- })
47961
- });
48843
+ assertNever(surface);
47962
48844
  }
47963
- return surfaces;
47964
- }
47965
- function commandSurfacesToOmitFromResidualSync(surfaces) {
47966
- return [
47967
- ...baselineResidualOmittedCommandSurfaces,
47968
- ...surfaces.map((surface) => surface.surface).filter((surface) => !baselineResidualOmittedCommandSurfaceSet.has(surface))
47969
- ];
47970
- }
47971
- function residualSettingsPlan(input, commandSurfaces) {
47972
- const residualSurfaces = commandSurfaceSet(commandSurfacesToOmitFromResidualSync(commandSurfaces));
47973
- const residual = {
47974
- diff: withoutCommandSurfaceDiff(input.diff, residualSurfaces),
47975
- local: withoutCommandSurfaceLocal(input.local, residualSurfaces)
47976
- };
47977
- return hasResidualSettingsChanges(residual.diff) ? residual : null;
47978
- }
47979
- function commandSurfaceStep(surface, onFailure) {
47980
- return { kind: "command-surface", surface, onFailure };
47981
- }
47982
- function syncPlanWithSteps(steps) {
47983
- return { kind: "sync-steps", steps };
47984
48845
  }
47985
48846
  function commandSurfaceCompileSuccess(surface) {
47986
48847
  switch (surface.surface) {
47987
48848
  case "entry":
47988
- return surface.compileResult.ok ? ok({ surface: "entry", compileValue: surface.compileResult.value }) : err(syncResultForEntryCommandCompileError(surface.compileResult.error));
48849
+ return surface.compileResult.ok ? ok({ surface: "entry", compileValue: surface.compileResult.value }) : err(contentPushReportWithCommandReport({
48850
+ surface: "entry",
48851
+ report: entryCommandCompileErrorToReport(surface.compileResult.error)
48852
+ }));
47989
48853
  case "page":
47990
- return surface.compileResult.ok ? ok({ surface: "page", compileValue: surface.compileResult.value }) : err(syncResultForPageCommandCompileError(surface.compileResult.error));
48854
+ return surface.compileResult.ok ? ok({ surface: "page", compileValue: surface.compileResult.value }) : err(contentPushReportWithCommandReport({
48855
+ surface: "page",
48856
+ report: pageCommandCompileErrorToReport(surface.compileResult.error)
48857
+ }));
47991
48858
  case "form":
47992
- return surface.compileResult.ok ? ok({ surface: "form", compileValue: surface.compileResult.value }) : err(syncResultForFormCommandCompileError(surface.compileResult.error));
48859
+ return surface.compileResult.ok ? ok({ surface: "form", compileValue: surface.compileResult.value }) : err(contentPushReportWithCommandReport({
48860
+ surface: "form",
48861
+ report: formCommandCompileErrorToReport(surface.compileResult.error)
48862
+ }));
47993
48863
  case "navigation":
47994
- return surface.compileResult.ok ? ok({ surface: "navigation", compileValue: surface.compileResult.value }) : err(syncResultForNavigationCommandCompileError(surface.compileResult.error));
48864
+ return surface.compileResult.ok ? ok({ surface: "navigation", compileValue: surface.compileResult.value }) : err(contentPushReportWithCommandReport({
48865
+ surface: "navigation",
48866
+ report: navigationCommandCompileErrorToReport(surface.compileResult.error)
48867
+ }));
47995
48868
  default:
47996
48869
  assertNever(surface);
47997
48870
  }
47998
48871
  }
47999
- async function executeCommandSurfaceAsSyncResult(surface, input) {
48872
+ function contentPushReportWithCommandReport(commandReport) {
48873
+ return {
48874
+ commandReports: [commandReport],
48875
+ residualSyncResults: []
48876
+ };
48877
+ }
48878
+ function skippedCommandSurfaceReport(surface) {
48000
48879
  switch (surface.surface) {
48001
- case "entry": {
48002
- return executeEntryCommandPlanAsSyncResult({
48003
- client: input.client,
48004
- compiledPlan: surface.compileValue,
48005
- onBeforeExecute: input.onEntryCommandCount
48006
- });
48007
- }
48008
- case "page": {
48009
- return executePageCommandPlanAsSyncResult({
48010
- client: input.client,
48011
- compiledPlan: surface.compileValue,
48012
- onBeforeExecute: input.onPageCommandCount
48013
- });
48014
- }
48015
- case "form": {
48016
- return executeFormCommandPlanAsSyncResult({
48017
- client: input.client,
48018
- compiledPlan: surface.compileValue,
48019
- onBeforeExecute: input.onFormCommandCount
48020
- });
48021
- }
48022
- case "navigation": {
48023
- return executeNavigationCommandPlanAsSyncResult({
48024
- client: input.client,
48025
- compiledPlan: surface.compileValue,
48026
- onBeforeExecute: input.onNavigationCommandCount
48027
- });
48028
- }
48880
+ case "entry":
48881
+ return {
48882
+ surface: "entry",
48883
+ report: reportFromOutcomes({
48884
+ outcomes: skippedOutcomes(
48885
+ surface.compileValue.reportedCommands,
48886
+ entrySkippedIdentifier
48887
+ )
48888
+ })
48889
+ };
48890
+ case "page":
48891
+ return {
48892
+ surface: "page",
48893
+ report: reportFromOutcomes({
48894
+ outcomes: skippedOutcomes(
48895
+ surface.compileValue.reportedCommands,
48896
+ pageSkippedIdentifier
48897
+ ),
48898
+ warnings: surface.compileValue.warnings
48899
+ })
48900
+ };
48901
+ case "form":
48902
+ return {
48903
+ surface: "form",
48904
+ report: reportFromOutcomes({
48905
+ outcomes: skippedOutcomes(
48906
+ surface.compileValue.reportedCommands,
48907
+ formSkippedIdentifier
48908
+ )
48909
+ })
48910
+ };
48911
+ case "navigation":
48912
+ return {
48913
+ surface: "navigation",
48914
+ report: reportFromOutcomes({
48915
+ outcomes: skippedOutcomes(
48916
+ surface.compileValue.reportedCommands,
48917
+ navigationSkippedIdentifier
48918
+ )
48919
+ })
48920
+ };
48029
48921
  default:
48030
48922
  assertNever(surface);
48031
48923
  }
48032
48924
  }
48033
- function commandSurfaceSet(surfaces) {
48034
- return new Set(surfaces);
48925
+ function skippedOutcomes(reportedCommands, identifierForSubject) {
48926
+ return reportedCommands.map((reportedCommand) => ({
48927
+ status: "skipped_by_stop_policy",
48928
+ commandRef: reportedCommand.plannedCommand.command.ref,
48929
+ commandType: reportedCommand.plannedCommand.command.type,
48930
+ identifier: identifierForSubject(reportedCommand.reportSubject),
48931
+ subject: reportedCommand.reportSubject
48932
+ }));
48035
48933
  }
48036
- function hasNavigationChanges(diff) {
48037
- return diff.navigation.some((item) => item.type !== "unchanged");
48934
+ function entrySkippedIdentifier(subject) {
48935
+ return `${subject.contentType}/${subject.identifier}`;
48038
48936
  }
48039
- function hasEntryChanges(diff) {
48040
- for (const entryDiffs of diff.entries.values()) {
48041
- if (entryDiffs.some((item) => item.type !== "unchanged" || Boolean(item.statusChange))) {
48042
- return true;
48043
- }
48937
+ function pageSkippedIdentifier(subject) {
48938
+ switch (subject.resource) {
48939
+ case "page":
48940
+ return subject.identifier;
48941
+ case "block":
48942
+ return `${subject.pageIdentifier}/${subject.identifier}`;
48943
+ default:
48944
+ assertNever(subject);
48044
48945
  }
48045
- return false;
48046
48946
  }
48047
- function hasFormChanges(diff) {
48048
- return diff.forms.some((item) => item.type !== "unchanged");
48947
+ function formSkippedIdentifier(subject) {
48948
+ return subject.slug;
48049
48949
  }
48050
- function hasResidualSettingsChanges(diff) {
48051
- return diff.summary.settings.update > 0;
48950
+ function navigationSkippedIdentifier(subject) {
48951
+ return subject.name;
48052
48952
  }
48053
- function orderCommandSurfacesForPushAll(surfaces) {
48953
+
48954
+ // src/cli/site-commands/pushExecutionPlan.ts
48955
+ init_src();
48956
+
48957
+ // src/cli/site-commands/residualSettingsTrimming.ts
48958
+ var baselineResidualOmittedCommandSurfaces = ["navigation"];
48959
+ var baselineResidualOmittedCommandSurfaceSet = new Set(
48960
+ baselineResidualOmittedCommandSurfaces
48961
+ );
48962
+ function syncPlanResidual(input) {
48054
48963
  return {
48055
- beforeResidualSync: surfaces.filter((surface) => surface.surface === "entry"),
48056
- afterResidualSync: surfaces.filter((surface) => surface.surface !== "entry")
48964
+ diff: withoutCommandSurfaceDiff(input.diff, input.omitSurfaces),
48965
+ local: withoutCommandSurfaceLocal(input.local, input.omitSurfaces)
48057
48966
  };
48058
48967
  }
48059
- function withoutNavigationDiff(diff) {
48060
- return {
48061
- ...diff,
48062
- navigation: [],
48063
- summary: {
48064
- ...diff.summary,
48065
- navigation: { create: 0, update: 0, unchanged: 0 }
48066
- }
48067
- };
48968
+ function residualSettingsPlan(input) {
48969
+ const residualSurfaces = commandSurfaceSet(commandSurfacesToOmitFromResidualSync(input.commandSurfaces));
48970
+ const residual = syncPlanResidual({
48971
+ diff: input.diff,
48972
+ local: input.local,
48973
+ omitSurfaces: residualSurfaces
48974
+ });
48975
+ return hasResidualSettingsChanges(residual.diff) ? residual : null;
48976
+ }
48977
+ function commandSurfacesToOmitFromResidualSync(surfaces) {
48978
+ return [
48979
+ ...baselineResidualOmittedCommandSurfaces,
48980
+ ...surfaces.filter((surface) => !baselineResidualOmittedCommandSurfaceSet.has(surface))
48981
+ ];
48982
+ }
48983
+ function commandSurfaceSet(surfaces) {
48984
+ return new Set(surfaces);
48985
+ }
48986
+ function hasResidualSettingsChanges(diff) {
48987
+ return diff.summary.settings.update > 0;
48068
48988
  }
48069
48989
  function withoutCommandSurfaceDiff(diff, surfaces) {
48070
48990
  let next = diff;
@@ -48105,6 +49025,16 @@ function withoutFormsDiff(diff) {
48105
49025
  }
48106
49026
  };
48107
49027
  }
49028
+ function withoutNavigationDiff(diff) {
49029
+ return {
49030
+ ...diff,
49031
+ navigation: [],
49032
+ summary: {
49033
+ ...diff.summary,
49034
+ navigation: { create: 0, update: 0, unchanged: 0 }
49035
+ }
49036
+ };
49037
+ }
48108
49038
  function withoutCommandSurfaceLocal(local, surfaces) {
48109
49039
  return {
48110
49040
  ...local,
@@ -48117,58 +49047,157 @@ function withoutCommandSurfaceLocal(local, surfaces) {
48117
49047
  function emptyLocalEntries() {
48118
49048
  return /* @__PURE__ */ new Map();
48119
49049
  }
48120
- function mergeManySyncResults(results) {
48121
- return results.reduce(
48122
- (merged, result) => mergeSyncResults(merged, result),
48123
- createEmptySyncResult()
49050
+
49051
+ // src/cli/site-commands/pushExecutionPlan.ts
49052
+ function planContentPushExecution(input) {
49053
+ switch (input.pushScope) {
49054
+ case "entries":
49055
+ return syncPlanWithSteps([commandSurfaceStep("entry", "continue")]);
49056
+ case "forms":
49057
+ return syncPlanWithSteps([commandSurfaceStep("form", "continue")]);
49058
+ case "navigation":
49059
+ return syncPlanWithSteps([commandSurfaceStep("navigation", "continue")]);
49060
+ case "pages":
49061
+ return pageCommandRouting(input.diff).kind === "command_backed" ? syncPlanWithSteps([commandSurfaceStep("page", "continue")]) : syncPlanWithResidualOnly(input);
49062
+ case "all":
49063
+ return pushAllExecutionPlan(input);
49064
+ default:
49065
+ assertNever(input.pushScope);
49066
+ }
49067
+ }
49068
+ function pushAllExecutionPlan(input) {
49069
+ const pageRouting = pageCommandRouting(input.diff);
49070
+ const commandSurfaces = commandSurfacesForPushAll({ ...input, pageRouting });
49071
+ const orderedSurfaces = orderCommandSurfacesForPushAll(commandSurfaces);
49072
+ const beforeResidualSteps = orderedSurfaces.beforeResidualSync.map(
49073
+ (surface) => commandSurfaceStep(surface, "stop")
48124
49074
  );
49075
+ const residualPlan = residualSettingsPlan({
49076
+ diff: input.diff,
49077
+ local: input.local,
49078
+ commandSurfaces
49079
+ });
49080
+ const residualStep = residualPlan ? { kind: "residual-settings-sync", residual: residualPlan, onFailure: "continue" } : null;
49081
+ const afterResidualSteps = orderedSurfaces.afterResidualSync.map(
49082
+ (surface) => commandSurfaceStep(surface, "continue")
49083
+ );
49084
+ return syncPlanWithSteps([
49085
+ ...beforeResidualSteps,
49086
+ ...residualStep ? [residualStep] : [],
49087
+ ...afterResidualSteps
49088
+ ]);
48125
49089
  }
48126
- function mergeSyncResults(first, second) {
49090
+ function syncPlanWithResidualOnly(input) {
49091
+ return syncPlanWithSteps([{
49092
+ kind: "residual-settings-sync",
49093
+ onFailure: "continue",
49094
+ residual: syncPlanResidual({
49095
+ diff: input.diff,
49096
+ local: input.local,
49097
+ omitSurfaces: baselineResidualOmittedCommandSurfaceSet
49098
+ })
49099
+ }]);
49100
+ }
49101
+ function commandSurfacesForPushAll(input) {
49102
+ return [
49103
+ ...hasEntryChanges(input.diff) ? ["entry"] : [],
49104
+ ...input.pageRouting.kind === "command_backed" ? ["page"] : [],
49105
+ ...hasFormChanges(input.diff) ? ["form"] : [],
49106
+ ...hasNavigationChanges(input.diff) ? ["navigation"] : []
49107
+ ];
49108
+ }
49109
+ function commandSurfaceStep(surface, onFailure) {
49110
+ return { kind: "command-surface", surface, onFailure };
49111
+ }
49112
+ function syncPlanWithSteps(steps) {
49113
+ return { kind: "sync-steps", steps };
49114
+ }
49115
+ function hasNavigationChanges(diff) {
49116
+ return diff.navigation.some((item) => item.type !== "unchanged");
49117
+ }
49118
+ function hasEntryChanges(diff) {
49119
+ for (const entryDiffs of diff.entries.values()) {
49120
+ if (entryDiffs.some((item) => item.type !== "unchanged" || Boolean(item.statusChange))) {
49121
+ return true;
49122
+ }
49123
+ }
49124
+ return false;
49125
+ }
49126
+ function hasFormChanges(diff) {
49127
+ return diff.forms.some((item) => item.type !== "unchanged");
49128
+ }
49129
+ function orderCommandSurfacesForPushAll(surfaces) {
48127
49130
  return {
48128
- entries: {
48129
- created: first.entries.created + second.entries.created,
48130
- updated: first.entries.updated + second.entries.updated,
48131
- deleted: first.entries.deleted + second.entries.deleted,
48132
- failed: first.entries.failed + second.entries.failed,
48133
- published: first.entries.published + second.entries.published,
48134
- unpublished: first.entries.unpublished + second.entries.unpublished
48135
- },
48136
- pages: {
48137
- created: first.pages.created + second.pages.created,
48138
- updated: first.pages.updated + second.pages.updated,
48139
- failed: first.pages.failed + second.pages.failed,
48140
- published: first.pages.published + second.pages.published,
48141
- unpublished: first.pages.unpublished + second.pages.unpublished
48142
- },
48143
- blocks: {
48144
- created: first.blocks.created + second.blocks.created,
48145
- updated: first.blocks.updated + second.blocks.updated,
48146
- deleted: first.blocks.deleted + second.blocks.deleted,
48147
- failed: first.blocks.failed + second.blocks.failed
48148
- },
48149
- navigation: {
48150
- created: first.navigation.created + second.navigation.created,
48151
- updated: first.navigation.updated + second.navigation.updated,
48152
- failed: first.navigation.failed + second.navigation.failed
48153
- },
48154
- settings: {
48155
- updated: first.settings.updated + second.settings.updated,
48156
- failed: first.settings.failed + second.settings.failed
48157
- },
48158
- forms: {
48159
- created: first.forms.created + second.forms.created,
48160
- updated: first.forms.updated + second.forms.updated,
48161
- failed: first.forms.failed + second.forms.failed
48162
- },
48163
- footer: {
48164
- updated: first.footer.updated + second.footer.updated,
48165
- failed: first.footer.failed + second.footer.failed
48166
- },
48167
- errors: [...first.errors, ...second.errors],
48168
- warnings: [...first.warnings, ...second.warnings]
49131
+ beforeResidualSync: surfaces.filter((surface) => surface === "entry"),
49132
+ afterResidualSync: surfaces.filter((surface) => surface !== "entry")
48169
49133
  };
48170
49134
  }
48171
49135
 
49136
+ // src/cli/site-commands/pushExecution.ts
49137
+ async function executeContentPushPlan(input) {
49138
+ const report = await executeContentPushPlanAsCommandReport(input);
49139
+ return contentPushExecutionReportToSyncResult(report);
49140
+ }
49141
+ async function executeContentPushPlanAsCommandReport(input, dependencies = {}) {
49142
+ const executionPlan = planContentPushExecution({
49143
+ pushScope: input.pushScope,
49144
+ diff: input.diff,
49145
+ local: input.local
49146
+ });
49147
+ const compiled = compileContentPushExecutionPlan(executionPlan, input, dependencies);
49148
+ if (!compiled.ok) return compiled.error;
49149
+ return executePushExecutionSteps(compiled.value.steps, input, dependencies);
49150
+ }
49151
+ async function executePushExecutionSteps(steps, input, dependencies) {
49152
+ const commandReports = [];
49153
+ const residualSyncResults = [];
49154
+ for (const [index, step] of steps.entries()) {
49155
+ switch (step.kind) {
49156
+ case "residual-settings-sync": {
49157
+ const result = await executeResidualSettingsSync(input, step.residual);
49158
+ residualSyncResults.push(result);
49159
+ if (step.onFailure === "stop" && result.errors.length > 0) {
49160
+ commandReports.push(...skippedRemainingCommandReports(steps.slice(index + 1)));
49161
+ return { commandReports, residualSyncResults };
49162
+ }
49163
+ break;
49164
+ }
49165
+ case "command-surface": {
49166
+ const report = await (dependencies.executeCommandSurfaceAsReport ?? executeCommandSurfaceAsReport)(
49167
+ step.surface,
49168
+ input
49169
+ );
49170
+ commandReports.push(report);
49171
+ if (step.onFailure === "stop" && commandReportHasFailures(report.report)) {
49172
+ commandReports.push(...skippedRemainingCommandReports(steps.slice(index + 1)));
49173
+ return { commandReports, residualSyncResults };
49174
+ }
49175
+ break;
49176
+ }
49177
+ default:
49178
+ assertNever(step);
49179
+ }
49180
+ }
49181
+ return { commandReports, residualSyncResults };
49182
+ }
49183
+ function executeResidualSettingsSync(input, residual) {
49184
+ return executeResidualSettingsSyncPlan(
49185
+ input.client,
49186
+ residual.diff,
49187
+ residual.local,
49188
+ {
49189
+ dryRun: false
49190
+ },
49191
+ input.output
49192
+ );
49193
+ }
49194
+ function contentPushExecutionReportToSyncResult(report) {
49195
+ return mergeManySyncResults([
49196
+ ...report.commandReports.map(commandSurfaceReportToSyncResult),
49197
+ ...report.residualSyncResults
49198
+ ]);
49199
+ }
49200
+
48172
49201
  // src/cli/commands/push/execute/footer.ts
48173
49202
  function footerPushDecision(diff, dryRun) {
48174
49203
  if (!diff) return { kind: "unchanged" };
@@ -48440,87 +49469,67 @@ ${errors}`
48440
49469
  output.error(message);
48441
49470
  }
48442
49471
  }
48443
- async function pushScopeGeneric(ctx, config2) {
48444
- const { output, contentDir, dryRun, force, isJsonOutput, deleteOrphaned, autoPullStale, skipMeta, humanDiff } = ctx;
48445
- const {
48446
- scopeName,
48447
- itemLabelSingular,
48448
- scopeCommand,
48449
- getIdentifier,
48450
- getDisplayLabel,
48451
- shouldPushItem,
48452
- readLocal,
48453
- readMeta,
48454
- fetchRemote,
48455
- getRemoteUpdatedAt,
48456
- orphanDeletion,
48457
- findRemote,
48458
- checkExists,
48459
- pushItem,
48460
- updateLocalMeta
48461
- } = config2;
49472
+ async function pushCommandBackedDatedOfferingScope(ctx, config2) {
48462
49473
  const noopResult = {
48463
49474
  status: "noop",
48464
- scopeCommand,
48465
- scopeName,
49475
+ scopeCommand: config2.scopeCommand,
49476
+ scopeName: config2.scopeName,
48466
49477
  created: 0,
48467
49478
  updated: 0,
48468
49479
  deleted: 0,
48469
49480
  failed: 0,
48470
49481
  errors: []
48471
49482
  };
48472
- const allLocalItems = await readLocal(contentDir);
48473
- if (allLocalItems.length === 0 && !deleteOrphaned) {
48474
- output.warn(`No ${scopeName} found to push`);
49483
+ const allLocalItems = await config2.readLocal(ctx.contentDir);
49484
+ if (allLocalItems.length === 0 && !ctx.deleteOrphaned) {
49485
+ ctx.output.warn(`No ${config2.scopeName} found to push`);
48475
49486
  return noopResult;
48476
49487
  }
48477
- const localItems = shouldPushItem ? allLocalItems.filter(shouldPushItem) : allLocalItems;
49488
+ const localItems = config2.shouldPushItem ? allLocalItems.filter(config2.shouldPushItem) : allLocalItems;
48478
49489
  const skippedUnchanged = allLocalItems.length - localItems.length;
48479
- if (localItems.length === 0 && !deleteOrphaned) {
48480
- output.info(`No ${scopeName} changes to push`);
49490
+ if (localItems.length === 0 && !ctx.deleteOrphaned) {
49491
+ ctx.output.info(`No ${config2.scopeName} changes to push`);
48481
49492
  return noopResult;
48482
49493
  }
48483
49494
  let remoteItems = null;
48484
- if (!force && localItems.length > 0) {
48485
- const meta = await readMeta(contentDir);
49495
+ if (!ctx.force && localItems.length > 0) {
49496
+ const meta = await config2.readMeta(ctx.contentDir);
48486
49497
  if (meta) {
48487
- remoteItems = await fetchRemote();
49498
+ remoteItems = await config2.fetchRemote();
48488
49499
  const staleItems = [];
48489
49500
  for (const localItem of localItems) {
48490
- const identifier = getIdentifier(localItem);
48491
- const remoteItem = findRemote(remoteItems, identifier);
49501
+ const identifier = config2.getIdentifier(localItem);
49502
+ const remoteItem = config2.findRemote(remoteItems, identifier);
48492
49503
  const localBaseTime = meta[identifier]?.updatedAt;
48493
- if (remoteItem && localBaseTime) {
48494
- const remoteTime = getRemoteUpdatedAt(remoteItem);
48495
- if (new Date(remoteTime) > new Date(localBaseTime)) {
48496
- staleItems.push(`${scopeName}: ${identifier} (Remote updated: ${remoteTime})`);
48497
- }
49504
+ if (!remoteItem || !localBaseTime) continue;
49505
+ const remoteTime = config2.getRemoteUpdatedAt(remoteItem);
49506
+ if (new Date(remoteTime) > new Date(localBaseTime)) {
49507
+ staleItems.push(`${config2.scopeName}: ${identifier} (Remote updated: ${remoteTime})`);
48498
49508
  }
48499
49509
  }
48500
49510
  if (staleItems.length > 0) {
48501
- output.warn("Stale content detected! Remote has newer changes:");
48502
- if (!isJsonOutput) {
49511
+ ctx.output.warn("Stale content detected! Remote has newer changes:");
49512
+ if (!ctx.isJsonOutput) {
48503
49513
  for (const item of staleItems) {
48504
- output.warn(` - ${item}`);
49514
+ ctx.output.warn(` - ${item}`);
48505
49515
  }
48506
49516
  }
48507
- if (dryRun) {
48508
- output.warn("Continuing anyway (dry-run mode \u2014 no changes will be made).");
49517
+ if (ctx.dryRun) {
49518
+ ctx.output.warn("Continuing anyway (dry-run mode - no changes will be made).");
48509
49519
  } else {
48510
49520
  const resolution = await resolveStaleOrAbort({
48511
- autoPullStale,
49521
+ autoPullStale: ctx.autoPullStale,
48512
49522
  yes: false
48513
- // scoped pushes don't use --yes for stale; they use it for remote
48514
49523
  });
48515
49524
  if (resolution === "abort") {
48516
- output.warn(
49525
+ ctx.output.warn(
48517
49526
  `
48518
- Run "riverbankcms pull ${scopeCommand}" first to get latest, or use --force to overwrite.`
49527
+ Run "riverbankcms pull ${config2.scopeCommand}" first to get latest, or use --force to overwrite.`
48519
49528
  );
48520
49529
  return {
48521
49530
  status: "aborted",
48522
- scopeCommand,
48523
- scopeName,
49531
+ scopeCommand: config2.scopeCommand,
49532
+ scopeName: config2.scopeName,
48524
49533
  created: 0,
48525
49534
  updated: 0,
48526
49535
  deleted: 0,
@@ -48528,67 +49537,64 @@ Run "riverbankcms pull ${scopeCommand}" first to get latest, or use --force to o
48528
49537
  errors: []
48529
49538
  };
48530
49539
  }
48531
- output.info("Stale content acknowledged. Continuing push...");
49540
+ ctx.output.info("Stale content acknowledged. Continuing push...");
48532
49541
  }
48533
49542
  }
48534
49543
  }
48535
49544
  }
48536
- let orphanIdentifiers = [];
48537
- if (deleteOrphaned && orphanDeletion && !shouldPushItem) {
48538
- if (!remoteItems) {
48539
- remoteItems = await fetchRemote();
48540
- }
48541
- const localIdentifierSet = new Set(allLocalItems.map(getIdentifier));
48542
- orphanIdentifiers = remoteItems.map(orphanDeletion.getRemoteIdentifier).filter((id) => !localIdentifierSet.has(id));
49545
+ if (!remoteItems && (localItems.length > 0 || ctx.deleteOrphaned)) {
49546
+ remoteItems = await config2.fetchRemote();
48543
49547
  }
48544
- if (dryRun) {
49548
+ const allLocalIdentifierSet = new Set(allLocalItems.map(config2.getIdentifier));
49549
+ const orphanIdentifiers = ctx.deleteOrphaned && !config2.shouldPushItem && remoteItems ? remoteItems.map(config2.getRemoteIdentifier).filter((identifier) => !allLocalIdentifierSet.has(identifier)) : [];
49550
+ if (ctx.dryRun) {
48545
49551
  if (localItems.length > 0) {
48546
- output.info(`[DRY RUN] Would push ${localItems.length} ${scopeName}`);
49552
+ ctx.output.info(`[DRY RUN] Would push ${localItems.length} ${config2.scopeName}`);
48547
49553
  if (skippedUnchanged > 0) {
48548
- output.info(` (skipping ${skippedUnchanged} unchanged)`);
49554
+ ctx.output.info(` (skipping ${skippedUnchanged} unchanged)`);
48549
49555
  }
48550
- if (humanDiff && remoteItems) {
49556
+ if (ctx.humanDiff && remoteItems) {
48551
49557
  for (const item of localItems) {
48552
- const identifier = getIdentifier(item);
48553
- const remoteItem = findRemote(remoteItems, identifier);
49558
+ const identifier = config2.getIdentifier(item);
49559
+ const remoteItem = config2.findRemote(remoteItems, identifier);
48554
49560
  if (!remoteItem) {
48555
- output.info(` + ${identifier}: ${getDisplayLabel(item)} (new)`);
49561
+ ctx.output.info(` + ${identifier}: ${config2.getDisplayLabel(item)} (new)`);
49562
+ continue;
49563
+ }
49564
+ const localObject = JSON.parse(JSON.stringify(item));
49565
+ const remoteObject = JSON.parse(JSON.stringify(remoteItem));
49566
+ delete remoteObject.createdAt;
49567
+ delete remoteObject.updatedAt;
49568
+ delete remoteObject.contentUpdatedAt;
49569
+ if (equal(localObject, remoteObject)) {
49570
+ ctx.output.info(` = ${identifier}: ${config2.getDisplayLabel(item)} (unchanged)`);
48556
49571
  } else {
48557
- const localObj = JSON.parse(JSON.stringify(item));
48558
- const remoteObj = JSON.parse(JSON.stringify(remoteItem));
48559
- delete remoteObj.createdAt;
48560
- delete remoteObj.updatedAt;
48561
- delete remoteObj.contentUpdatedAt;
48562
- if (equal(localObj, remoteObj)) {
48563
- output.info(` = ${identifier}: ${getDisplayLabel(item)} (unchanged)`);
48564
- } else {
48565
- output.info(` ~ ${identifier}: ${getDisplayLabel(item)}`);
48566
- const changes = findChangedFieldsWithValues(localObj, remoteObj);
48567
- for (const fc of changes) {
48568
- output.info(` ${fc.path}: ${formatValue(fc.before)} -> ${formatValue(fc.after)}`);
48569
- }
49572
+ ctx.output.info(` ~ ${identifier}: ${config2.getDisplayLabel(item)}`);
49573
+ const changes = findChangedFieldsWithValues(localObject, remoteObject);
49574
+ for (const change of changes) {
49575
+ ctx.output.info(` ${change.path}: ${formatValue(change.before)} -> ${formatValue(change.after)}`);
48570
49576
  }
48571
49577
  }
48572
49578
  }
48573
49579
  } else {
48574
49580
  for (const item of localItems) {
48575
- output.info(` - ${getIdentifier(item)}: ${getDisplayLabel(item)}`);
49581
+ ctx.output.info(` - ${config2.getIdentifier(item)}: ${config2.getDisplayLabel(item)}`);
48576
49582
  }
48577
49583
  }
48578
49584
  }
48579
49585
  if (orphanIdentifiers.length > 0) {
48580
- output.info(`[DRY RUN] Would delete ${orphanIdentifiers.length} orphaned ${scopeName}:`);
48581
- for (const id of orphanIdentifiers) {
48582
- output.info(` - ${id}`);
49586
+ ctx.output.info(`[DRY RUN] Would delete ${orphanIdentifiers.length} orphaned ${config2.scopeName}:`);
49587
+ for (const identifier of orphanIdentifiers) {
49588
+ ctx.output.info(` - ${identifier}`);
48583
49589
  }
48584
49590
  }
48585
49591
  if (localItems.length > 0 || orphanIdentifiers.length > 0) {
48586
- output.info("\nUse --yes (for remote) or remove --dry-run (for local) to apply changes.");
49592
+ ctx.output.info("\nUse --yes (for remote) or remove --dry-run (for local) to apply changes.");
48587
49593
  }
48588
49594
  return {
48589
49595
  status: "dry-run",
48590
- scopeCommand,
48591
- scopeName,
49596
+ scopeCommand: config2.scopeCommand,
49597
+ scopeName: config2.scopeName,
48592
49598
  created: 0,
48593
49599
  updated: 0,
48594
49600
  deleted: orphanIdentifiers.length,
@@ -48596,71 +49602,110 @@ Run "riverbankcms pull ${scopeCommand}" first to get latest, or use --force to o
48596
49602
  errors: []
48597
49603
  };
48598
49604
  }
48599
- let created = 0;
48600
- let updated = 0;
48601
- let deleted = 0;
48602
- let failed = 0;
48603
- const errors = [];
49605
+ const upserts = localItems.map((item) => ({
49606
+ item,
49607
+ exists: Boolean(remoteItems?.some((remote) => config2.getRemoteIdentifier(remote) === config2.getIdentifier(item)))
49608
+ }));
48604
49609
  if (localItems.length > 0) {
48605
- output.info(`Pushing ${localItems.length} ${scopeName}...`);
48606
- for (const item of localItems) {
48607
- const identifier = getIdentifier(item);
48608
- try {
48609
- const exists = await checkExists(identifier);
48610
- await pushItem(item);
48611
- if (exists) {
48612
- updated++;
48613
- } else {
48614
- created++;
48615
- }
48616
- } catch (error) {
48617
- failed++;
48618
- const message = error instanceof Error ? error.message : String(error);
48619
- errors.push({ identifier, error: message });
48620
- if (!isJsonOutput) {
48621
- output.warn(` Failed to push ${itemLabelSingular} ${identifier}: ${message}`);
48622
- }
48623
- }
48624
- }
49610
+ ctx.output.info(`Pushing ${localItems.length} ${config2.scopeName}...`);
48625
49611
  }
48626
- if (orphanIdentifiers.length > 0 && orphanDeletion) {
49612
+ if (orphanIdentifiers.length > 0) {
48627
49613
  if (orphanIdentifiers.length > 5) {
48628
- output.warn(`Warning: ${orphanIdentifiers.length} ${scopeName} will be deleted from CMS`);
48629
- }
48630
- output.info(`Deleting ${orphanIdentifiers.length} orphaned ${scopeName}...`);
48631
- for (const id of orphanIdentifiers) {
48632
- try {
48633
- await orphanDeletion.deleteItem(id);
48634
- deleted++;
48635
- } catch (error) {
48636
- failed++;
48637
- const message = error instanceof Error ? error.message : String(error);
48638
- errors.push({ identifier: id, error: message });
48639
- if (!isJsonOutput) {
48640
- output.warn(` Failed to delete ${itemLabelSingular} ${id}: ${message}`);
48641
- }
48642
- }
49614
+ ctx.output.warn(`Warning: ${orphanIdentifiers.length} ${config2.scopeName} will be deleted from CMS`);
48643
49615
  }
49616
+ ctx.output.info(`Deleting ${orphanIdentifiers.length} orphaned ${config2.scopeName}...`);
48644
49617
  }
48645
- if (failed === 0) {
48646
- await updateLocalMeta(contentDir, { skipMeta });
48647
- } else {
48648
- if (!isJsonOutput) {
48649
- output.warn(
48650
- `Not updating local files due to ${failed} failed ${scopeName} pushes. Run "riverbankcms pull ${scopeCommand}" to resync.`
49618
+ const result = await executePlansResiliently({
49619
+ ctx,
49620
+ config: config2,
49621
+ upserts,
49622
+ orphanIdentifiers
49623
+ });
49624
+ if (result.failed === 0) {
49625
+ await config2.updateLocalMeta(ctx.contentDir, { skipMeta: ctx.skipMeta });
49626
+ } else if (!ctx.isJsonOutput) {
49627
+ for (const itemError of result.errors) {
49628
+ ctx.output.warn(
49629
+ ` Failed to push ${config2.itemLabelSingular} ${itemError.identifier}: ${itemError.error}`
48651
49630
  );
48652
49631
  }
49632
+ ctx.output.warn(
49633
+ `Not updating local files due to ${result.failed} failed ${config2.scopeName} pushes. Run "riverbankcms pull ${config2.scopeCommand}" to resync.`
49634
+ );
48653
49635
  }
48654
- return {
49636
+ return result;
49637
+ }
49638
+ async function executePlansResiliently(input) {
49639
+ const result = {
48655
49640
  status: "pushed",
48656
- scopeCommand,
48657
- scopeName,
48658
- created,
48659
- updated,
48660
- deleted,
48661
- failed,
48662
- errors
49641
+ scopeCommand: input.config.scopeCommand,
49642
+ scopeName: input.config.scopeName,
49643
+ created: 0,
49644
+ updated: 0,
49645
+ deleted: 0,
49646
+ failed: 0,
49647
+ errors: []
48663
49648
  };
49649
+ for (const upsert of input.upserts) {
49650
+ const warning = input.config.readOnlyStatusWarning?.(upsert.item);
49651
+ if (warning) input.ctx.output.warn(warning);
49652
+ const partialResult = await compileAndExecutePartial({
49653
+ ...input,
49654
+ upserts: [upsert],
49655
+ deletes: [],
49656
+ fallbackIdentifier: input.config.getIdentifier(upsert.item)
49657
+ });
49658
+ mergePushScopeResult(result, partialResult);
49659
+ }
49660
+ for (const identifier of input.orphanIdentifiers) {
49661
+ const partialResult = await compileAndExecutePartial({
49662
+ ...input,
49663
+ upserts: [],
49664
+ deletes: [identifier],
49665
+ fallbackIdentifier: identifier
49666
+ });
49667
+ mergePushScopeResult(result, partialResult);
49668
+ }
49669
+ if (result.failed > 0 && result.created === 0 && result.updated === 0 && result.deleted === 0) {
49670
+ result.status = "failed";
49671
+ }
49672
+ return result;
49673
+ }
49674
+ async function compileAndExecutePartial(input) {
49675
+ const compiled = compileDatedOfferingPushCommands(input.config.buildCompileInput({
49676
+ source: input.config.source,
49677
+ siteId: input.ctx.siteId,
49678
+ targetEnv: input.ctx.targetEnv,
49679
+ upserts: input.upserts,
49680
+ deletes: input.deletes
49681
+ }));
49682
+ if (!compiled.ok) {
49683
+ const compileResult = syncResultForDatedOfferingCommandCompileError(
49684
+ compiled.error,
49685
+ input.config.scopeCommand,
49686
+ input.config.scopeName
49687
+ );
49688
+ return {
49689
+ ...compileResult,
49690
+ errors: compileResult.errors.map((itemError) => ({
49691
+ identifier: itemError.identifier === "command-validation" ? input.fallbackIdentifier : itemError.identifier,
49692
+ error: itemError.error
49693
+ }))
49694
+ };
49695
+ }
49696
+ return executeDatedOfferingCommandPlanAsPushScopeResult({
49697
+ client: input.ctx.client,
49698
+ compiledPlan: compiled.value,
49699
+ scopeCommand: input.config.scopeCommand,
49700
+ scopeName: input.config.scopeName
49701
+ });
49702
+ }
49703
+ function mergePushScopeResult(target, source) {
49704
+ target.created += source.created;
49705
+ target.updated += source.updated;
49706
+ target.deleted += source.deleted;
49707
+ target.failed += source.failed;
49708
+ target.errors.push(...source.errors);
48664
49709
  }
48665
49710
 
48666
49711
  // src/cli/commands/push/scopes/mediaPrep.ts
@@ -48698,9 +49743,6 @@ async function syncLocalMediaForScopePush(ctx, content) {
48698
49743
  }
48699
49744
 
48700
49745
  // src/cli/commands/push/scopes/courses.ts
48701
- function preserveUndefined(value) {
48702
- return value === void 0 ? void 0 : value;
48703
- }
48704
49746
  async function pushCoursesScope(ctx, options) {
48705
49747
  const { client } = ctx;
48706
49748
  const only = options?.only;
@@ -48722,7 +49764,8 @@ async function pushCoursesScope(ctx, options) {
48722
49764
  errors: []
48723
49765
  };
48724
49766
  }
48725
- return pushScopeGeneric(ctx, {
49767
+ return pushCommandBackedDatedOfferingScope(ctx, {
49768
+ source: "push_courses",
48726
49769
  scopeName: "courses",
48727
49770
  itemLabelSingular: "course",
48728
49771
  scopeCommand: "courses",
@@ -48740,63 +49783,19 @@ async function pushCoursesScope(ctx, options) {
48740
49783
  },
48741
49784
  getRemoteUpdatedAt: (course) => course.updatedAt,
48742
49785
  findRemote: (courses2, identifier) => courses2.find((course) => course.identifier === identifier),
48743
- checkExists: async (identifier) => {
48744
- const existing = await client.courses.get(identifier);
48745
- return existing !== null;
48746
- },
48747
- pushItem: async (course) => {
48748
- if (course.identifier !== course.slug) {
48749
- throw new Error(
48750
- `Course identifier "${course.identifier}" must match slug "${course.slug}".`
48751
- );
48752
- }
48753
- const program2 = course.program === void 0 ? void 0 : course.program === null ? null : {
48754
- identifier: preserveUndefined(course.program.identifier) ?? null,
48755
- data: course.program.data
48756
- };
48757
- try {
48758
- const status = preserveUndefined(
48759
- course.status === "completed" ? void 0 : course.status
48760
- );
48761
- if (course.status === "completed") {
48762
- ctx.output.warn(
48763
- `Course ${course.identifier}: status "completed" is read-only; omitting status on push.`
48764
- );
48765
- }
48766
- await client.courses.upsert({
48767
- identifier: course.identifier,
48768
- title: course.title,
48769
- slug: course.slug,
48770
- status,
48771
- visibility: preserveUndefined(course.visibility),
48772
- venueRef: preserveUndefined(course.venueRef),
48773
- categoryRef: preserveUndefined(course.categoryRef),
48774
- formRef: preserveUndefined(course.formRef),
48775
- capacity: preserveUndefined(course.capacity),
48776
- enrollmentCapacity: preserveUndefined(course.enrollmentCapacity),
48777
- acceptsMemberships: preserveUndefined(course.acceptsMemberships),
48778
- priceCents: preserveUndefined(course.priceCents),
48779
- currency: preserveUndefined(course.currency),
48780
- sessions: course.sessions,
48781
- programRef: preserveUndefined(course.programRef),
48782
- program: program2
48783
- });
48784
- } catch (error) {
48785
- if (error instanceof CourseSessionConflictError) {
48786
- const detail = error.conflicts.map((conflict) => conflict.message).join("; ");
48787
- throw new Error(detail || error.message);
48788
- }
48789
- throw error;
48790
- }
48791
- },
48792
- orphanDeletion: {
48793
- getRemoteIdentifier: (course) => course.identifier,
48794
- deleteItem: (identifier) => client.courses.delete(identifier)
48795
- },
49786
+ getRemoteIdentifier: (course) => course.identifier,
48796
49787
  updateLocalMeta: async (dir, opts) => {
48797
49788
  const pulledCourses = await client.pull.courses();
48798
49789
  await writeCourses(dir, pulledCourses, opts);
48799
- }
49790
+ },
49791
+ readOnlyStatusWarning: (course) => course.status === "completed" ? `Course ${course.identifier}: status "completed" is read-only; omitting status on push.` : null,
49792
+ buildCompileInput: ({ source, siteId, targetEnv, upserts, deletes }) => ({
49793
+ source,
49794
+ siteId,
49795
+ targetEnv,
49796
+ courses: { items: upserts },
49797
+ delete: { courses: deletes }
49798
+ })
48800
49799
  });
48801
49800
  }
48802
49801
 
@@ -48804,7 +49803,8 @@ async function pushCoursesScope(ctx, options) {
48804
49803
  async function pushEventCategoriesScope(ctx, options) {
48805
49804
  const { client } = ctx;
48806
49805
  const only = options?.only;
48807
- return pushScopeGeneric(ctx, {
49806
+ return pushCommandBackedDatedOfferingScope(ctx, {
49807
+ source: "push_event_categories",
48808
49808
  scopeName: "event categories",
48809
49809
  itemLabelSingular: "event category",
48810
49810
  scopeCommand: "event-categories",
@@ -48822,34 +49822,22 @@ async function pushEventCategoriesScope(ctx, options) {
48822
49822
  },
48823
49823
  getRemoteUpdatedAt: (category) => category.updatedAt,
48824
49824
  findRemote: (categories, identifier) => categories.find((c) => c.identifier === identifier),
48825
- checkExists: async (identifier) => {
48826
- const existing = await client.eventCategories.get(identifier);
48827
- return existing !== null;
48828
- },
48829
- pushItem: async (category) => {
48830
- await client.eventCategories.upsert({
48831
- identifier: category.identifier,
48832
- name: category.name,
48833
- description: category.description,
48834
- color: category.color,
48835
- sortOrder: category.sortOrder
48836
- });
48837
- },
48838
- orphanDeletion: {
48839
- getRemoteIdentifier: (category) => category.identifier,
48840
- deleteItem: (identifier) => client.eventCategories.delete(identifier)
48841
- },
49825
+ getRemoteIdentifier: (category) => category.identifier,
48842
49826
  updateLocalMeta: async (dir, opts) => {
48843
49827
  const pulledCategories = await client.pull.eventCategories();
48844
49828
  await writeEventCategories(dir, pulledCategories, opts);
48845
- }
49829
+ },
49830
+ buildCompileInput: ({ source, siteId, targetEnv, upserts, deletes }) => ({
49831
+ source,
49832
+ siteId,
49833
+ targetEnv,
49834
+ eventCategories: { items: upserts },
49835
+ delete: { eventCategories: deletes }
49836
+ })
48846
49837
  });
48847
49838
  }
48848
49839
 
48849
49840
  // src/cli/commands/push/scopes/events.ts
48850
- function preserveUndefined2(value) {
48851
- return value === void 0 ? void 0 : value;
48852
- }
48853
49841
  async function pushEventsScope(ctx, options) {
48854
49842
  const { client } = ctx;
48855
49843
  const only = options?.only;
@@ -48871,7 +49859,8 @@ async function pushEventsScope(ctx, options) {
48871
49859
  errors: []
48872
49860
  };
48873
49861
  }
48874
- return pushScopeGeneric(ctx, {
49862
+ return pushCommandBackedDatedOfferingScope(ctx, {
49863
+ source: "push_events",
48875
49864
  scopeName: "events",
48876
49865
  itemLabelSingular: "event",
48877
49866
  scopeCommand: "events",
@@ -48895,61 +49884,19 @@ async function pushEventsScope(ctx, options) {
48895
49884
  return event.updatedAt;
48896
49885
  },
48897
49886
  findRemote: (events2, identifier) => events2.find((e) => e.identifier === identifier),
48898
- checkExists: async (identifier) => {
48899
- const existing = await client.events.get(identifier);
48900
- return existing !== null;
48901
- },
48902
- pushItem: async (event) => {
48903
- if (event.identifier !== event.slug) {
48904
- throw new Error(
48905
- `Event identifier "${event.identifier}" must match slug "${event.slug}".`
48906
- );
48907
- }
48908
- const schedule = {
48909
- recurrenceRule: event.schedule?.recurrenceRule ?? null,
48910
- startDate: event.schedule?.startDate ?? null,
48911
- defaultStartTime: event.schedule?.defaultStartTime ?? "09:00:00",
48912
- durationMinutes: event.schedule?.durationMinutes ?? 60
48913
- };
48914
- const content = event.content ? {
48915
- summary: event.content.summary ?? void 0,
48916
- body: event.content.body ?? void 0,
48917
- image: event.content.image ?? void 0
48918
- } : void 0;
48919
- const status = preserveUndefined2(
48920
- event.status === "completed" ? void 0 : event.status
48921
- );
48922
- if (event.status === "completed") {
48923
- ctx.output.warn(
48924
- `Event ${event.identifier}: status "completed" is read-only; omitting status on push.`
48925
- );
48926
- }
48927
- await client.events.upsert({
48928
- identifier: event.identifier,
48929
- title: event.title,
48930
- slug: event.slug,
48931
- status,
48932
- visibility: preserveUndefined2(event.visibility),
48933
- schedule,
48934
- capacity: preserveUndefined2(event.capacity),
48935
- pricing: event.pricing,
48936
- venueRef: preserveUndefined2(event.venueRef),
48937
- categoryRef: preserveUndefined2(event.categoryRef),
48938
- content,
48939
- formRef: preserveUndefined2(event.formRef),
48940
- settings: event.settings,
48941
- presentation: event.presentation,
48942
- tags: event.tags
48943
- });
48944
- },
48945
- orphanDeletion: {
48946
- getRemoteIdentifier: (event) => event.identifier,
48947
- deleteItem: (identifier) => client.events.delete(identifier)
48948
- },
49887
+ getRemoteIdentifier: (event) => event.identifier,
48949
49888
  updateLocalMeta: async (dir, opts) => {
48950
49889
  const pulledEvents = await client.pull.events();
48951
49890
  await writeEvents(dir, pulledEvents, opts);
48952
- }
49891
+ },
49892
+ readOnlyStatusWarning: (event) => event.status === "completed" ? `Event ${event.identifier}: status "completed" is read-only; omitting status on push.` : null,
49893
+ buildCompileInput: ({ source, siteId, targetEnv, upserts, deletes }) => ({
49894
+ source,
49895
+ siteId,
49896
+ targetEnv,
49897
+ events: { items: upserts },
49898
+ delete: { events: deletes }
49899
+ })
48953
49900
  });
48954
49901
  }
48955
49902
 
@@ -48957,7 +49904,8 @@ async function pushEventsScope(ctx, options) {
48957
49904
  async function pushVenuesScope(ctx, options) {
48958
49905
  const { client } = ctx;
48959
49906
  const only = options?.only;
48960
- return pushScopeGeneric(ctx, {
49907
+ return pushCommandBackedDatedOfferingScope(ctx, {
49908
+ source: "push_venues",
48961
49909
  scopeName: "venues",
48962
49910
  itemLabelSingular: "venue",
48963
49911
  scopeCommand: "venues",
@@ -48975,42 +49923,18 @@ async function pushVenuesScope(ctx, options) {
48975
49923
  },
48976
49924
  getRemoteUpdatedAt: (venue) => venue.updatedAt,
48977
49925
  findRemote: (venues, slug) => venues.find((v) => v.slug === slug),
48978
- checkExists: async (slug) => {
48979
- const existing = await client.venues.get(slug);
48980
- return existing !== null;
48981
- },
48982
- pushItem: async (venue) => {
48983
- const convertedAddress = venue.address ? {
48984
- line1: venue.address.line1 ?? void 0,
48985
- line2: venue.address.line2 ?? void 0,
48986
- city: venue.address.city ?? void 0,
48987
- region: venue.address.region ?? void 0,
48988
- postcode: venue.address.postcode ?? void 0,
48989
- country: venue.address.country ?? void 0
48990
- } : void 0;
48991
- const convertedLocation = venue.location ? {
48992
- lat: venue.location.lat,
48993
- lng: venue.location.lng
48994
- } : void 0;
48995
- await client.venues.upsert({
48996
- slug: venue.slug,
48997
- title: venue.title,
48998
- description: venue.description ?? void 0,
48999
- timezone: venue.timezone ?? void 0,
49000
- capacity: venue.capacity ?? void 0,
49001
- address: convertedAddress,
49002
- location: convertedLocation,
49003
- mapEmbed: venue.mapEmbed ?? void 0
49004
- });
49005
- },
49006
- orphanDeletion: {
49007
- getRemoteIdentifier: (venue) => venue.slug,
49008
- deleteItem: (slug) => client.venues.delete(slug)
49009
- },
49926
+ getRemoteIdentifier: (venue) => venue.slug,
49010
49927
  updateLocalMeta: async (dir, opts) => {
49011
49928
  const pulledVenues = await client.pull.venues();
49012
49929
  await writeVenues(dir, pulledVenues, opts);
49013
- }
49930
+ },
49931
+ buildCompileInput: ({ source, siteId, targetEnv, upserts, deletes }) => ({
49932
+ source,
49933
+ siteId,
49934
+ targetEnv,
49935
+ venues: { items: upserts },
49936
+ delete: { venues: deletes }
49937
+ })
49014
49938
  });
49015
49939
  }
49016
49940
 
@@ -49019,37 +49943,6 @@ init_src();
49019
49943
 
49020
49944
  // src/cli/merge-remote/entryMerge.ts
49021
49945
  init_src();
49022
-
49023
- // src/cli/merge-remote/stableJson.ts
49024
- init_src();
49025
- function stableStringify(value) {
49026
- const sorted = sortValue(value);
49027
- switch (typeof sorted) {
49028
- case "bigint":
49029
- case "function":
49030
- case "symbol":
49031
- case "undefined":
49032
- return String(sorted);
49033
- case "boolean":
49034
- case "number":
49035
- case "object":
49036
- case "string":
49037
- return JSON.stringify(sorted);
49038
- }
49039
- return assertNever(sorted);
49040
- }
49041
- function sortValue(value) {
49042
- if (Array.isArray(value)) return value.map(sortValue);
49043
- if (value && typeof value === "object") return sortRecord(value);
49044
- return value;
49045
- }
49046
- function sortRecord(record) {
49047
- return Object.fromEntries(
49048
- Object.entries(record).sort(([left], [right]) => left.localeCompare(right)).map(([key, value]) => [key, sortValue(value)])
49049
- );
49050
- }
49051
-
49052
- // src/cli/merge-remote/entryMerge.ts
49053
49946
  function planEntryMerge(input) {
49054
49947
  const { subject, base, local, remote } = input;
49055
49948
  if (!base) {
@@ -49843,6 +50736,8 @@ async function executeScopedPush(output, isRemote, options, globalOpts, scopeLab
49843
50736
  const result = await pushFn({
49844
50737
  output,
49845
50738
  contentDir,
50739
+ siteId: env.siteId,
50740
+ targetEnv: isRemote ? "remote" : "local",
49846
50741
  client,
49847
50742
  dryRun: options.dryRun,
49848
50743
  force: options.force ?? false,
@@ -49853,7 +50748,7 @@ async function executeScopedPush(output, isRemote, options, globalOpts, scopeLab
49853
50748
  skipMeta: !(options.meta ?? true),
49854
50749
  humanDiff: options.diff ?? false
49855
50750
  });
49856
- if (result.status === "pushed" && result.failed > 0) {
50751
+ if (result.status === "pushed" && result.failed > 0 || result.status === "failed") {
49857
50752
  process.exitCode = 1;
49858
50753
  output.result(false, `${scopeLabel} push had failures`, result);
49859
50754
  return { success: false };
@@ -50547,6 +51442,8 @@ ${errors}`
50547
51442
  const pushAllCtx = {
50548
51443
  output,
50549
51444
  contentDir,
51445
+ siteId: env.siteId,
51446
+ targetEnv: target,
50550
51447
  client,
50551
51448
  dryRun: false,
50552
51449
  force: options.force ?? false,
@@ -50579,10 +51476,30 @@ Pushing ${label.toLowerCase()}...`);
50579
51476
  if (hasOrphans) {
50580
51477
  let deleteFailed = 0;
50581
51478
  const deleteScopes = [
50582
- { name: "events", items: pushAllExtraChanges.events.toDelete ?? /* @__PURE__ */ new Set(), deleteFn: (id) => client.events.delete(id) },
50583
- { name: "courses", items: pushAllExtraChanges.courses.toDelete ?? /* @__PURE__ */ new Set(), deleteFn: (id) => client.courses.delete(id) },
50584
- { name: "venues", items: pushAllExtraChanges.venues.toDelete ?? /* @__PURE__ */ new Set(), deleteFn: (slug) => client.venues.delete(slug) },
50585
- { name: "event categories", items: pushAllExtraChanges.eventCategories.toDelete ?? /* @__PURE__ */ new Set(), deleteFn: (id) => client.eventCategories.delete(id) }
51479
+ {
51480
+ name: "events",
51481
+ scopeCommand: "events",
51482
+ items: pushAllExtraChanges.events.toDelete ?? /* @__PURE__ */ new Set(),
51483
+ buildDelete: (events) => ({ events })
51484
+ },
51485
+ {
51486
+ name: "courses",
51487
+ scopeCommand: "courses",
51488
+ items: pushAllExtraChanges.courses.toDelete ?? /* @__PURE__ */ new Set(),
51489
+ buildDelete: (courses) => ({ courses })
51490
+ },
51491
+ {
51492
+ name: "venues",
51493
+ scopeCommand: "venues",
51494
+ items: pushAllExtraChanges.venues.toDelete ?? /* @__PURE__ */ new Set(),
51495
+ buildDelete: (venues) => ({ venues })
51496
+ },
51497
+ {
51498
+ name: "event categories",
51499
+ scopeCommand: "event-categories",
51500
+ items: pushAllExtraChanges.eventCategories.toDelete ?? /* @__PURE__ */ new Set(),
51501
+ buildDelete: (eventCategories) => ({ eventCategories })
51502
+ }
50586
51503
  ];
50587
51504
  for (const scope2 of deleteScopes) {
50588
51505
  if (scope2.items.size === 0) continue;
@@ -50590,14 +51507,30 @@ Pushing ${label.toLowerCase()}...`);
50590
51507
  output.warn(`Warning: ${scope2.items.size} ${scope2.name} will be deleted from CMS`);
50591
51508
  }
50592
51509
  output.info(`Deleting ${scope2.items.size} orphaned ${scope2.name}...`);
50593
- for (const id of scope2.items) {
50594
- try {
50595
- await scope2.deleteFn(id);
50596
- } catch (error) {
50597
- deleteFailed++;
50598
- const message = error instanceof Error ? error.message : String(error);
50599
- if (!isJsonOutput) {
50600
- output.warn(` Failed to delete ${scope2.name} ${id}: ${message}`);
51510
+ const compiledDeletes = compileDatedOfferingPushCommands({
51511
+ source: "push_all_dated_offerings",
51512
+ siteId: env.siteId,
51513
+ targetEnv: target,
51514
+ delete: scope2.buildDelete([...scope2.items])
51515
+ });
51516
+ if (!compiledDeletes.ok) {
51517
+ deleteFailed++;
51518
+ if (!isJsonOutput) {
51519
+ output.warn(` Failed to plan ${scope2.name} deletes: ${compiledDeletes.error.message}`);
51520
+ }
51521
+ continue;
51522
+ }
51523
+ const deleteResult = await executeDatedOfferingCommandPlanAsPushScopeResult({
51524
+ client,
51525
+ compiledPlan: compiledDeletes.value,
51526
+ scopeCommand: scope2.scopeCommand,
51527
+ scopeName: scope2.name
51528
+ });
51529
+ if (deleteResult.failed > 0) {
51530
+ deleteFailed += deleteResult.failed;
51531
+ if (!isJsonOutput) {
51532
+ for (const itemError of deleteResult.errors) {
51533
+ output.warn(` Failed to delete ${scope2.name} ${itemError.identifier}: ${itemError.error}`);
50601
51534
  }
50602
51535
  }
50603
51536
  }
@@ -51677,7 +52610,7 @@ var THEME_FIELD_CATEGORY_MAP = {
51677
52610
  };
51678
52611
 
51679
52612
  // src/cli/init-docs/zod-to-markdown.ts
51680
- function isRecord11(value) {
52613
+ function isRecord12(value) {
51681
52614
  return typeof value === "object" && value !== null && !Array.isArray(value);
51682
52615
  }
51683
52616
  function isZodTypeAny(value) {
@@ -51803,7 +52736,7 @@ function extractLiteralValue(schema) {
51803
52736
  const typeName = getTypeName(schema);
51804
52737
  if (typeName !== ZodTypeName.ZodLiteral) return void 0;
51805
52738
  const def = schema._def;
51806
- if (!isRecord11(def)) return void 0;
52739
+ if (!isRecord12(def)) return void 0;
51807
52740
  return String(def.value);
51808
52741
  }
51809
52742
  function extractSchemaInfo(schema, skipFields = []) {
@@ -51873,7 +52806,7 @@ function extractFieldInfo(name, schema) {
51873
52806
  }
51874
52807
  if (typeName === ZodTypeName.ZodRecord) {
51875
52808
  const def = inner._def;
51876
- const valueSchema = isRecord11(def) ? def.valueType : void 0;
52809
+ const valueSchema = isRecord12(def) ? def.valueType : void 0;
51877
52810
  if (!isZodTypeAny(valueSchema)) {
51878
52811
  info.recordValueType = "unknown";
51879
52812
  return info;
@@ -51888,7 +52821,7 @@ function extractFieldInfo(name, schema) {
51888
52821
  }
51889
52822
  } else if (getTypeName(valueInner) === ZodTypeName.ZodRecord) {
51890
52823
  const nestedDef = valueInner._def;
51891
- const nestedValueSchema = isRecord11(nestedDef) ? nestedDef.valueType : void 0;
52824
+ const nestedValueSchema = isRecord12(nestedDef) ? nestedDef.valueType : void 0;
51892
52825
  if (!isZodTypeAny(nestedValueSchema)) {
51893
52826
  info.recordValueType = "record<string, unknown>";
51894
52827
  return info;
@@ -51899,7 +52832,7 @@ function extractFieldInfo(name, schema) {
51899
52832
  }
51900
52833
  if (typeName === ZodTypeName.ZodUnion || typeName === ZodTypeName.ZodDiscriminatedUnion) {
51901
52834
  const def = inner._def;
51902
- const optionsValue = isRecord11(def) ? def.options : void 0;
52835
+ const optionsValue = isRecord12(def) ? def.options : void 0;
51903
52836
  const options = Array.isArray(optionsValue) ? optionsValue.filter(isZodTypeAny) : [];
51904
52837
  const optionTypes = options.map((opt) => {
51905
52838
  const { inner: optInner } = unwrapSchema(opt);
@@ -53059,7 +53992,7 @@ var SimpleCache = class {
53059
53992
  };
53060
53993
 
53061
53994
  // src/version.ts
53062
- var SDK_VERSION = "0.67.0";
53995
+ var SDK_VERSION = "0.68.0";
53063
53996
 
53064
53997
  // src/client/error.ts
53065
53998
  var RiverbankApiError = class _RiverbankApiError extends Error {
@@ -59461,7 +60394,7 @@ var cancelCommand2 = new Command("cancel").description("Cancel a course run").ar
59461
60394
  }
59462
60395
  })
59463
60396
  );
59464
- var courseCommand = new Command("course").description("Manage courses").addHelpText(
60397
+ var courseCommand2 = new Command("course").description("Manage courses").addHelpText(
59465
60398
  "after",
59466
60399
  `
59467
60400
  Examples:
@@ -59742,7 +60675,7 @@ program.addCommand(publishAllCommand);
59742
60675
  program.addCommand(auditCommand);
59743
60676
  program.addCommand(compareCommand);
59744
60677
  program.addCommand(eventCommand);
59745
- program.addCommand(courseCommand);
60678
+ program.addCommand(courseCommand2);
59746
60679
  program.addCommand(manifestCommand);
59747
60680
  program.addCommand(envCommand);
59748
60681
  program.addCommand(migrateCommand);