@riverbankcms/sdk 0.84.0 → 0.84.2

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 (97) hide show
  1. package/dist/{PreviewEditorSidebar-HML67UDA.mjs → PreviewEditorSidebar-4PH35ZIE.mjs} +3 -3
  2. package/dist/{PreviewEditorUI-I4BQUU6K.mjs → PreviewEditorUI-WHMCRJGM.mjs} +11 -6
  3. package/dist/SdkPreviewModeRuntime-4FGSVUYI.mjs +8 -0
  4. package/dist/_dts/api/src/bookingConfig.d.ts +2 -0
  5. package/dist/_dts/api/src/index.d.ts +2 -2
  6. package/dist/_dts/api/src/publicExperienceEndpoints.d.ts +2 -1
  7. package/dist/_dts/api/src/sdk-event-payment-terms.d.ts +16 -0
  8. package/dist/_dts/api/src/sdk-event-upsert.d.ts +11 -2
  9. package/dist/_dts/api/src/sdkContracts.d.ts +3 -0
  10. package/dist/_dts/api/src/types.d.ts +1 -0
  11. package/dist/_dts/api/src/url.d.ts +12 -4
  12. package/dist/_dts/blocks/src/contracts/proof-block-islands.d.ts +4 -4
  13. package/dist/_dts/blocks/src/system/runtime/api/types.d.ts +2 -0
  14. package/dist/_dts/blocks/src/system/runtime/components/registry.client.d.ts +6 -6
  15. package/dist/_dts/blocks/src/system/runtime/components/runtime-backed-blocks.d.ts +3 -3
  16. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/EventRegistrationWizard.d.ts +0 -2
  17. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/constants.d.ts +1 -0
  18. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/event-registration.headless.contract.d.ts +275 -0
  19. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/event-registration.headless.override.d.ts +10 -0
  20. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/event-registration.headless.planning.d.ts +22 -0
  21. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/event-registration.headless.state.d.ts +3 -303
  22. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/types.d.ts +3 -1
  23. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/useEventRegistrationWizard.d.ts +9 -1
  24. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration.interactive.d.ts +8 -6
  25. package/dist/_dts/content-editor/src/hooks/useSimpleAutosave.d.ts +8 -0
  26. package/dist/_dts/editor-blocks/src/BlockForm.d.ts +6 -4
  27. package/dist/_dts/preview-next/src/client/preview/MaintenanceModeBadge.d.ts +3 -2
  28. package/dist/_dts/preview-next/src/client/preview/PreviewEditorUI.d.ts +2 -1
  29. package/dist/_dts/sdk/src/client/management/index.d.ts +1 -1
  30. package/dist/_dts/sdk/src/client/management/types.d.ts +6 -0
  31. package/dist/_dts/sdk/src/version.d.ts +1 -1
  32. package/dist/{chunk-LBBPD2IW.mjs → chunk-4QNLOTES.mjs} +11 -16
  33. package/dist/{chunk-5E33VO6J.mjs → chunk-NFWGLRZZ.mjs} +1 -70
  34. package/dist/{chunk-HFMGVJCE.mjs → chunk-OCGTXHSO.mjs} +8 -7
  35. package/dist/{chunk-3LXFQS7T.mjs → chunk-PYDHOMEO.mjs} +1 -1
  36. package/dist/{chunk-6X2OVO3S.mjs → chunk-WFPYN7KA.mjs} +2 -2
  37. package/dist/{chunk-MSHZO4SL.mjs → chunk-ZR2GQK2A.mjs} +274 -223
  38. package/dist/cli/index.mjs +332 -45
  39. package/dist/cli/init-docs/content/agents-section.md +5 -0
  40. package/dist/cli/init-docs/content/cli-reference.md +13 -0
  41. package/dist/cli/init-docs/content/content-management.md +31 -0
  42. package/dist/cli/init-docs/content/getting-started.md +12 -0
  43. package/dist/cli/init-docs/content/workflow-add-block.md +3 -1
  44. package/dist/cli/init-docs/content/workflow-agent-safe-sync.md +81 -0
  45. package/dist/cli/init-docs/content/workflow-create-page.md +13 -3
  46. package/dist/cli/init-docs/content/workflow-custom-block.md +9 -0
  47. package/dist/cli/init-docs/content/workflow-templates.md +14 -0
  48. package/dist/client/{accordion-ESY65T56.mjs → accordion-2UZPBMYM.mjs} +1 -1
  49. package/dist/client/{bookingForm-JRFNZUHD.mjs → bookingForm-36CWQUMV.mjs} +4 -4
  50. package/dist/client/bookings.mjs +156 -138
  51. package/dist/client/{carousel-CPR5VWIP.mjs → carousel-QH77HR6X.mjs} +2 -2
  52. package/dist/client/{cart-ZUX5BA7O.mjs → cart-X4YK4FTW.mjs} +5 -5
  53. package/dist/client/{checkout-RULGBADZ.mjs → checkout-OM2BEPWD.mjs} +5 -5
  54. package/dist/client/{chunk-RDJFCPY3.mjs → chunk-3C2VTPWI.mjs} +34 -117
  55. package/dist/client/{chunk-BT6AEIKN.mjs → chunk-3DTWLTXM.mjs} +1 -1
  56. package/dist/client/{chunk-JWEYB4V6.mjs → chunk-4OXKTA3D.mjs} +1 -1
  57. package/dist/client/{chunk-URQCZD5W.mjs → chunk-52CGCQ7B.mjs} +4 -4
  58. package/dist/client/{chunk-52I7BGEK.mjs → chunk-7UCLJ5SP.mjs} +1 -1
  59. package/dist/client/{chunk-Z5OBQ5I4.mjs → chunk-F5VRX5Y6.mjs} +1 -1
  60. package/dist/client/{chunk-GFSQNTRW.mjs → chunk-SDIYSQAY.mjs} +0 -4
  61. package/dist/client/{chunk-HXPWP5EN.mjs → chunk-VGDBVNOO.mjs} +175 -14
  62. package/dist/client/{chunk-5ZEAZ33K.mjs → chunk-ZKUO52W3.mjs} +1 -1
  63. package/dist/client/client.mjs +348 -232
  64. package/dist/client/{courseRegistration-QTUDC35T.mjs → courseRegistration-TMKU6ABO.mjs} +4 -4
  65. package/dist/client/{eventCalendar-Q7NS4XLD.mjs → eventCalendar-G6TI32X6.mjs} +6 -6
  66. package/dist/client/{eventCombined-QAO7VUO5.mjs → eventCombined-SCKEMNAR.mjs} +6 -6
  67. package/dist/client/{eventDetails-WTNNU6Q3.mjs → eventDetails-XPIFXXPK.mjs} +6 -6
  68. package/dist/client/{eventListing-5TA2ELDT.mjs → eventListing-7QFMEMGT.mjs} +6 -6
  69. package/dist/client/{eventRegistration-M6USZGRF.mjs → eventRegistration-TOODSZUI.mjs} +6 -6
  70. package/dist/client/{form-DGVGXLMH.mjs → form-MTCMVCZT.mjs} +2 -2
  71. package/dist/client/{headerSection-O2AGMPCU.mjs → headerSection-Y5TMR3TW.mjs} +2 -2
  72. package/dist/client/hooks.mjs +315 -35
  73. package/dist/client/{locationMap-EJRNRIKJ.mjs → locationMap-RH2LG7FZ.mjs} +1 -1
  74. package/dist/client/{newsletterForm-7NTC2DTR.mjs → newsletterForm-PCAIPFMA.mjs} +2 -2
  75. package/dist/client/{productDetail-HH4LP53D.mjs → productDetail-OIGDR4YE.mjs} +5 -5
  76. package/dist/client/{productList-YVHYM2AF.mjs → productList-4MA5S2CX.mjs} +5 -5
  77. package/dist/client/rendering/client.mjs +312 -195
  78. package/dist/client/rendering/islands.mjs +18 -18
  79. package/dist/client/rendering.mjs +312 -195
  80. package/dist/client/{shop-UIFX7XRK.mjs → shop-WXSYV5QO.mjs} +5 -5
  81. package/dist/client/spam-protection.mjs +0 -4
  82. package/dist/preview-next/client/runtime.mjs +5 -5
  83. package/dist/{sdk-runtime-ZENAOYMN.mjs → sdk-runtime-QLOCYKVU.mjs} +6 -6
  84. package/dist/server/components.mjs +188 -61
  85. package/dist/server/config-validation.mjs +313 -33
  86. package/dist/server/config.mjs +313 -33
  87. package/dist/server/data.mjs +315 -35
  88. package/dist/server/index.mjs +10 -11
  89. package/dist/server/next.mjs +198 -72
  90. package/dist/server/page-converter.mjs +315 -35
  91. package/dist/server/prebuild.mjs +1 -1
  92. package/dist/server/rendering/server.mjs +188 -61
  93. package/dist/server/rendering.mjs +188 -61
  94. package/dist/server/routing.mjs +334 -34
  95. package/dist/server/server.mjs +331 -52
  96. package/package.json +1 -1
  97. package/dist/SdkPreviewModeRuntime-MCKMVDTK.mjs +0 -8
@@ -110,6 +110,30 @@ var init_collections = __esm({
110
110
  });
111
111
 
112
112
  // ../core/src/event-pricing.ts
113
+ function publicEventPricingType(pricing) {
114
+ switch (pricing.kind) {
115
+ case "drop_in":
116
+ case "free_registration":
117
+ return "free";
118
+ case "single_paid":
119
+ case "ticket_types":
120
+ case "course":
121
+ return isFreePublicEventPriceDisplay(pricing.display) ? "free" : "paid";
122
+ }
123
+ }
124
+ function isFreePublicEventPriceDisplay(display) {
125
+ switch (display.kind) {
126
+ case "free":
127
+ return true;
128
+ case "course":
129
+ return display.display.kind === "free";
130
+ case "exact":
131
+ case "from":
132
+ case "mixed":
133
+ case "unavailable":
134
+ return false;
135
+ }
136
+ }
113
137
  var init_event_pricing = __esm({
114
138
  "../core/src/event-pricing.ts"() {
115
139
  }
@@ -140,8 +164,139 @@ var init_booking_instalments = __esm({
140
164
  });
141
165
 
142
166
  // ../core/src/booking-date-time.ts
167
+ function isValidTimeZone(timeZone) {
168
+ try {
169
+ new Intl.DateTimeFormat(DEFAULT_LOCALE, { timeZone }).format(/* @__PURE__ */ new Date());
170
+ return true;
171
+ } catch {
172
+ return false;
173
+ }
174
+ }
175
+ function getSafeTimeZone(timeZone) {
176
+ const normalized = typeof timeZone === "string" ? timeZone.trim() : "";
177
+ return normalized && isValidTimeZone(normalized) ? normalized : FALLBACK_TIMEZONE;
178
+ }
179
+ function parseStrictBookingTimeZone(timeZone) {
180
+ const normalized = timeZone.trim();
181
+ if (!normalized || !isValidTimeZone(normalized)) {
182
+ return null;
183
+ }
184
+ return normalized;
185
+ }
186
+ function formatParseError(error) {
187
+ switch (error.reason) {
188
+ case "invalid_starts_at":
189
+ return `Expected a valid UTC/offset-aware ISO datetime in startsAt, received "${error.value}"`;
190
+ case "invalid_ends_at":
191
+ return `Expected a valid UTC/offset-aware ISO datetime in endsAt, received "${error.value ?? ""}"`;
192
+ case "invalid_time_zone":
193
+ return `Expected a valid IANA timezone in timeZone, received "${error.value}"`;
194
+ }
195
+ }
196
+ function formatToPartsLookup(date, locale, timeZone, format) {
197
+ return new Map(
198
+ new Intl.DateTimeFormat(locale, {
199
+ ...format,
200
+ timeZone
201
+ }).formatToParts(date).map((part) => [part.type, part.value])
202
+ );
203
+ }
204
+ function getZonedDateTimeParts(date, timeZone) {
205
+ const parts = formatToPartsLookup(date, "en-GB", timeZone, {
206
+ year: "numeric",
207
+ month: "2-digit",
208
+ day: "2-digit",
209
+ hour: "2-digit",
210
+ minute: "2-digit",
211
+ second: "2-digit",
212
+ hour12: false
213
+ });
214
+ const read = (type) => Number(parts.get(type) ?? "");
215
+ return {
216
+ year: read("year"),
217
+ month: read("month"),
218
+ day: read("day"),
219
+ hour: read("hour"),
220
+ minute: read("minute"),
221
+ second: read("second")
222
+ };
223
+ }
224
+ function formatDateKey(date) {
225
+ const year = String(date.year).padStart(4, "0");
226
+ const month = String(date.month).padStart(2, "0");
227
+ const day = String(date.day).padStart(2, "0");
228
+ return `${year}-${month}-${day}`;
229
+ }
230
+ function parseUtcIsoDateTimeString(value) {
231
+ const normalized = value.trim();
232
+ const hasUtcSuffix = normalized.endsWith("Z");
233
+ const hasExplicitOffset = /[+-]\d{2}:\d{2}$/u.test(normalized);
234
+ if (!hasUtcSuffix && !hasExplicitOffset) {
235
+ return err("missing-timezone-offset");
236
+ }
237
+ const date = new Date(normalized);
238
+ if (Number.isNaN(date.getTime())) {
239
+ return err("invalid-date-time");
240
+ }
241
+ return ok(date.toISOString());
242
+ }
243
+ function toUtcIsoDateTimeString(value) {
244
+ const parsed = parseUtcIsoDateTimeString(value);
245
+ if (!parsed.ok) {
246
+ const message = parsed.error === "missing-timezone-offset" ? `Expected an offset-aware ISO datetime, received "${value}"` : `Expected a valid ISO datetime, received "${value}"`;
247
+ throw new Error(message);
248
+ }
249
+ return parsed.value;
250
+ }
251
+ function parseScheduledBookingDateTime(input) {
252
+ try {
253
+ const startsAt = toUtcIsoDateTimeString(input.startsAt);
254
+ const timeZone = parseStrictBookingTimeZone(input.timeZone);
255
+ if (!timeZone) {
256
+ return {
257
+ ok: false,
258
+ field: "timeZone",
259
+ reason: "invalid_time_zone",
260
+ value: input.timeZone
261
+ };
262
+ }
263
+ return {
264
+ ok: true,
265
+ value: {
266
+ startsAt,
267
+ timeZone,
268
+ locale: input.locale
269
+ }
270
+ };
271
+ } catch {
272
+ return {
273
+ ok: false,
274
+ field: "startsAt",
275
+ reason: "invalid_starts_at",
276
+ value: input.startsAt
277
+ };
278
+ }
279
+ }
280
+ function toScheduledBookingDateTime(input) {
281
+ const result = parseScheduledBookingDateTime(input);
282
+ if (result.ok) {
283
+ return result.value;
284
+ }
285
+ throw new Error(formatParseError(result));
286
+ }
287
+ function getBookingLocalDateKey(input) {
288
+ return formatDateKey(getLocalScheduleDate(new Date(input.startsAt), input.timeZone));
289
+ }
290
+ function getLocalScheduleDate(date, timeZone) {
291
+ const parts = getZonedDateTimeParts(date, getSafeTimeZone(timeZone));
292
+ return { year: parts.year, month: parts.month, day: parts.day };
293
+ }
294
+ var DEFAULT_LOCALE, FALLBACK_TIMEZONE;
143
295
  var init_booking_date_time = __esm({
144
296
  "../core/src/booking-date-time.ts"() {
297
+ init_result();
298
+ DEFAULT_LOCALE = "en-US";
299
+ FALLBACK_TIMEZONE = "UTC";
145
300
  }
146
301
  });
147
302
 
@@ -18912,6 +19067,31 @@ var init_event_registration_shared = __esm({
18912
19067
  }
18913
19068
  });
18914
19069
 
19070
+ // ../blocks/src/system/constants/events.ts
19071
+ function isEventCalendarDisplayMode(value) {
19072
+ return typeof value === "string" && eventCalendarDisplayModeValues.includes(value);
19073
+ }
19074
+ function isEventCalendarListLayout(value) {
19075
+ return typeof value === "string" && eventCalendarListLayoutValues.includes(value);
19076
+ }
19077
+ function isEventContentType(slug) {
19078
+ if (!slug) return false;
19079
+ return EVENT_CONTENT_TYPE_SLUGS.includes(slug);
19080
+ }
19081
+ var EVENT_CONTENT_TYPE_SLUGS, eventCalendarDisplayModeValues, eventCalendarListLayoutValues, eventCalendarListLayoutOptions;
19082
+ var init_events = __esm({
19083
+ "../blocks/src/system/constants/events.ts"() {
19084
+ EVENT_CONTENT_TYPE_SLUGS = ["event", "events"];
19085
+ eventCalendarDisplayModeValues = ["combined", "month", "week", "list", "timetable"];
19086
+ eventCalendarListLayoutValues = ["stack", "grid", "compact"];
19087
+ eventCalendarListLayoutOptions = [
19088
+ { id: "stack", label: "Stack" },
19089
+ { id: "grid", label: "Grid" },
19090
+ { id: "compact", label: "Compact" }
19091
+ ];
19092
+ }
19093
+ });
19094
+
18915
19095
  // ../blocks/src/system/runtime/nodes/events/shared/pricing.ts
18916
19096
  function resolveRuntimeEventPricing(event) {
18917
19097
  if (isPublicEventPricing(event.pricing)) {
@@ -19036,26 +19216,6 @@ var init_pricing = __esm({
19036
19216
  DEFAULT_EVENT_CURRENCY = "USD";
19037
19217
  }
19038
19218
  });
19039
-
19040
- // ../blocks/src/system/constants/events.ts
19041
- function isEventCalendarDisplayMode(value) {
19042
- return typeof value === "string" && eventCalendarDisplayModeValues.includes(value);
19043
- }
19044
- function isEventCalendarListLayout(value) {
19045
- return typeof value === "string" && eventCalendarListLayoutValues.includes(value);
19046
- }
19047
- var eventCalendarDisplayModeValues, eventCalendarListLayoutValues, eventCalendarListLayoutOptions;
19048
- var init_events = __esm({
19049
- "../blocks/src/system/constants/events.ts"() {
19050
- eventCalendarDisplayModeValues = ["combined", "month", "week", "list", "timetable"];
19051
- eventCalendarListLayoutValues = ["stack", "grid", "compact"];
19052
- eventCalendarListLayoutOptions = [
19053
- { id: "stack", label: "Stack" },
19054
- { id: "grid", label: "Grid" },
19055
- { id: "compact", label: "Compact" }
19056
- ];
19057
- }
19058
- });
19059
19219
  var previewStageSchema, registrationButtonVariantSchema, eventButtonVariantSchema, eventLayoutSchema, eventCalendarDisplayModeSchema, columnOptionSchema, weekStartSchema, filterAutoShowSchema, calendarTabViewsSchema;
19060
19220
  var init_contract_schemas = __esm({
19061
19221
  "../blocks/src/system/runtime/nodes/shared/contract-schemas.ts"() {
@@ -19071,17 +19231,148 @@ var init_contract_schemas = __esm({
19071
19231
  calendarTabViewsSchema = z.enum(["both", "month", "week"]);
19072
19232
  }
19073
19233
  });
19234
+
19235
+ // ../blocks/src/system/runtime/nodes/event-registration/wizardSteps.ts
19236
+ function getWizardStepsForContext(hasPreSelectedContext, needsPaymentStep) {
19237
+ const baseSteps = hasPreSelectedContext ? ["select-tickets", "enter-details"] : ["select-event", "select-tickets", "enter-details"];
19238
+ if (!needsPaymentStep) {
19239
+ return baseSteps;
19240
+ }
19241
+ return [...baseSteps, "select-payment"];
19242
+ }
19243
+ var init_wizardSteps = __esm({
19244
+ "../blocks/src/system/runtime/nodes/event-registration/wizardSteps.ts"() {
19245
+ }
19246
+ });
19247
+
19248
+ // ../blocks/src/system/runtime/nodes/event-registration/registrationDerivations.ts
19249
+ function eventMatchesOccurrenceId(event, occurrenceId) {
19250
+ return event.registrationOccurrenceId === occurrenceId || event.publicEventId === occurrenceId;
19251
+ }
19252
+ function findPreSelectedEvent(input) {
19253
+ const occurrenceContext = input.occurrenceContext;
19254
+ if (!occurrenceContext) {
19255
+ return null;
19256
+ }
19257
+ const contextDate = getBookingLocalDateKey(toScheduledBookingDateTime({
19258
+ startsAt: occurrenceContext.startsAt,
19259
+ timeZone: occurrenceContext.timeZone
19260
+ }));
19261
+ return input.scopedEvents.find(
19262
+ (event) => eventMatchesOccurrenceId(event, occurrenceContext.id) || getBookingLocalDateKey(toScheduledBookingDateTime({
19263
+ startsAt: event.startsAt,
19264
+ timeZone: event.timeZone
19265
+ })) === contextDate
19266
+ ) ?? null;
19267
+ }
19268
+ function resolveEventRequiresPayment(input) {
19269
+ if (input.eligibility) {
19270
+ return input.eligibility.requiresPayment;
19271
+ }
19272
+ if (!input.event) {
19273
+ return false;
19274
+ }
19275
+ return publicEventPricingType(resolveRuntimeEventPricing(input.event)) !== "free";
19276
+ }
19277
+ var init_registrationDerivations = __esm({
19278
+ "../blocks/src/system/runtime/nodes/event-registration/registrationDerivations.ts"() {
19279
+ init_src();
19280
+ init_pricing();
19281
+ }
19282
+ });
19283
+
19284
+ // ../blocks/src/system/runtime/nodes/event-registration/registrationEventAdapter.ts
19285
+ function toRegistrationEvent(event) {
19286
+ return {
19287
+ ...event,
19288
+ pricing: resolveRuntimeEventPricing(event),
19289
+ publicEventId: event.id,
19290
+ registrationOccurrenceId: event.occurrenceId
19291
+ };
19292
+ }
19293
+ function toRegistrationEvents(events) {
19294
+ return events.map(toRegistrationEvent);
19295
+ }
19296
+ var init_registrationEventAdapter = __esm({
19297
+ "../blocks/src/system/runtime/nodes/event-registration/registrationEventAdapter.ts"() {
19298
+ init_pricing();
19299
+ }
19300
+ });
19074
19301
  function buildEventRegistrationDisplay(source) {
19302
+ const stepLabels = buildEventRegistrationShellStepLabels(source);
19075
19303
  return {
19076
19304
  kind: "event-registration",
19077
19305
  state: "generic-shell",
19078
19306
  className: source.className ?? null,
19079
19307
  titleText: "Event registration",
19080
- bodyText: "Preparing dates, tickets, and booking details.",
19081
- stepLabels: EVENT_REGISTRATION_GENERIC_SHELL_STEP_LABELS,
19308
+ bodyText: buildEventRegistrationShellBodyText(stepLabels),
19309
+ stepLabels,
19082
19310
  summaryButtonText: source.buttonText?.trim() || "Register"
19083
19311
  };
19084
19312
  }
19313
+ function buildEventRegistrationShellStepLabels(source) {
19314
+ const scopedEvents = scopeEventRegistrationEvents(source);
19315
+ if (scopedEvents.length === 0) {
19316
+ return EVENT_REGISTRATION_GENERIC_SHELL_STEP_LABELS;
19317
+ }
19318
+ const preSelectedEvent = findPreSelectedEvent({
19319
+ scopedEvents,
19320
+ occurrenceContext: source.occurrenceContext
19321
+ });
19322
+ const hasPreSelectedContext = Boolean(source.occurrenceContext || preSelectedEvent);
19323
+ const needsPaymentStep = hasPreSelectedContext && preSelectedEvent ? resolveEventRequiresPayment({
19324
+ eligibility: null,
19325
+ event: preSelectedEvent
19326
+ }) : false;
19327
+ return getWizardStepsForContext(hasPreSelectedContext, needsPaymentStep).map((step) => shellLabelForRegistrationStep(step, scopedEvents));
19328
+ }
19329
+ function scopeEventRegistrationEvents(source) {
19330
+ const events = toRegistrationEvents(source.events ?? []);
19331
+ if (source.occurrenceContext?.seriesId) {
19332
+ return events.filter((event) => event.seriesId === source.occurrenceContext?.seriesId);
19333
+ }
19334
+ const entrySlug = source.contentEntry?.slug;
19335
+ const entryContentType = source.contentEntry?.contentTypeSlug;
19336
+ if (entrySlug && entryContentType && isEventContentType(entryContentType)) {
19337
+ return events.filter((event) => event.slug === entrySlug);
19338
+ }
19339
+ return events;
19340
+ }
19341
+ function shellLabelForRegistrationStep(step, events) {
19342
+ switch (step) {
19343
+ case "select-event":
19344
+ return isDateSelection(events) ? "Date" : "Event";
19345
+ case "select-tickets":
19346
+ return "Tickets";
19347
+ case "enter-details":
19348
+ return "Details";
19349
+ case "select-payment":
19350
+ return "Payment";
19351
+ case "error":
19352
+ case "success":
19353
+ case "submitting":
19354
+ case "redirecting":
19355
+ case "verifying-payment":
19356
+ case "verifying-timeout":
19357
+ case "payment-failed":
19358
+ return "Details";
19359
+ }
19360
+ }
19361
+ function isDateSelection(events) {
19362
+ const firstSeriesId = events[0]?.seriesId;
19363
+ return Boolean(
19364
+ events.length > 1 && firstSeriesId && events.every((event) => event.seriesId === firstSeriesId)
19365
+ );
19366
+ }
19367
+ function buildEventRegistrationShellBodyText(stepLabels) {
19368
+ if (stepLabels.includes("Payment")) {
19369
+ return "Preparing tickets, details, and payment options.";
19370
+ }
19371
+ if (stepLabels[0] === "Tickets") {
19372
+ return "Preparing tickets and booking details.";
19373
+ }
19374
+ return "Preparing dates, tickets, and booking details.";
19375
+ }
19085
19376
  function normalizeEventRegistrationEventInput(value) {
19086
19377
  if (!isRecord5(value)) {
19087
19378
  return value;
@@ -19094,21 +19385,21 @@ function normalizeEventRegistrationEventInput(value) {
19094
19385
  function isRecord5(value) {
19095
19386
  return typeof value === "object" && value !== null && !Array.isArray(value);
19096
19387
  }
19097
- var EVENT_REGISTRATION_GENERIC_SHELL_STEP_LABELS, eventRegistrationGenericDateStepLabel, eventRegistrationGenericTicketsStepLabel, eventRegistrationGenericDetailsStepLabel, contentEntrySchema, eventRegistrationPublicEventSchema, eventRegistrationSourceSchema, eventRegistrationDisplaySchema, eventRegistrationHydrationSchema, eventRegistrationRenderSchema, eventRegistrationBlockRuntime;
19388
+ var EVENT_REGISTRATION_GENERIC_SHELL_STEP_LABELS, EVENT_REGISTRATION_SHELL_STEP_LABELS, contentEntrySchema, eventRegistrationPublicEventSchema, eventRegistrationSourceSchema, eventRegistrationDisplaySchema, eventRegistrationHydrationSchema, eventRegistrationRenderSchema, eventRegistrationBlockRuntime;
19098
19389
  var init_event_registration_interactive = __esm({
19099
19390
  "../blocks/src/system/runtime/nodes/event-registration.interactive.ts"() {
19100
19391
  init_schemas2();
19101
19392
  init_event_registration_shared();
19393
+ init_events();
19102
19394
  init_pricing();
19103
19395
  init_islands();
19104
19396
  init_runtime();
19105
19397
  init_contract_schemas();
19398
+ init_wizardSteps();
19399
+ init_registrationDerivations();
19400
+ init_registrationEventAdapter();
19106
19401
  EVENT_REGISTRATION_GENERIC_SHELL_STEP_LABELS = ["Date", "Tickets", "Details"];
19107
- [
19108
- eventRegistrationGenericDateStepLabel,
19109
- eventRegistrationGenericTicketsStepLabel,
19110
- eventRegistrationGenericDetailsStepLabel
19111
- ] = EVENT_REGISTRATION_GENERIC_SHELL_STEP_LABELS;
19402
+ EVENT_REGISTRATION_SHELL_STEP_LABELS = ["Event", "Date", "Tickets", "Details", "Payment"];
19112
19403
  contentEntrySchema = z.object({
19113
19404
  id: z.string(),
19114
19405
  slug: z.string(),
@@ -19144,11 +19435,7 @@ var init_event_registration_interactive = __esm({
19144
19435
  className: z.string().nullable(),
19145
19436
  titleText: z.string(),
19146
19437
  bodyText: z.string(),
19147
- stepLabels: z.tuple([
19148
- z.literal(eventRegistrationGenericDateStepLabel),
19149
- z.literal(eventRegistrationGenericTicketsStepLabel),
19150
- z.literal(eventRegistrationGenericDetailsStepLabel)
19151
- ]),
19438
+ stepLabels: z.array(z.enum(EVENT_REGISTRATION_SHELL_STEP_LABELS)).min(1),
19152
19439
  summaryButtonText: z.string()
19153
19440
  });
19154
19441
  eventRegistrationHydrationSchema = z.object({
@@ -41926,17 +42213,21 @@ function looksLikeLocalAuthority(authority) {
41926
42213
  const normalized = authority.toLowerCase();
41927
42214
  return normalized === "localhost" || normalized.startsWith("localhost:") || normalized.startsWith("127.") || normalized.startsWith("0.0.0.0") || normalized.includes(".localhost") || normalized.endsWith(".local") || normalized.endsWith(".test");
41928
42215
  }
41929
- function normalizeDashboardUrlBase(input) {
42216
+ function normalizeDashboardOrigin(input) {
41930
42217
  const trimmed = input.trim();
41931
42218
  if (!trimmed) return "";
41932
42219
  const withoutTrailingSlash = trimmed.replace(/\/+$/, "");
41933
42220
  const withoutApiSuffix = withoutTrailingSlash.replace(/\/api\/?$/, "");
41934
42221
  if (/^https?:\/\//i.test(withoutApiSuffix)) {
41935
- return withoutApiSuffix;
42222
+ return new URL(withoutApiSuffix).origin;
41936
42223
  }
41937
42224
  const authority = withoutApiSuffix.replace(/^\/+/, "");
41938
42225
  const protocol = looksLikeLocalAuthority(authority) ? "http" : "https";
41939
- return `${protocol}://${authority}`;
42226
+ return new URL(`${protocol}://${authority}`).origin;
42227
+ }
42228
+ function deriveCmsApiUrlFromDashboardUrl(input) {
42229
+ const origin = normalizeDashboardOrigin(input);
42230
+ return origin ? `${origin}/api` : "";
41940
42231
  }
41941
42232
  function getCmsApiUrl() {
41942
42233
  if (typeof window !== "undefined") {
@@ -41948,15 +42239,10 @@ function getCmsApiUrl() {
41948
42239
  }
41949
42240
  const dashboardUrl = process.env.NEXT_PUBLIC_DASHBOARD_URL;
41950
42241
  if (dashboardUrl) {
41951
- const base = normalizeDashboardUrlBase(dashboardUrl);
41952
- return `${base}/api`;
41953
- }
41954
- const legacyApiUrl = process.env.NEXT_PUBLIC_CMS_API_URL;
41955
- if (legacyApiUrl) {
41956
- return legacyApiUrl.replace(/\/$/, "");
42242
+ return deriveCmsApiUrlFromDashboardUrl(dashboardUrl);
41957
42243
  }
41958
42244
  throw new Error(
41959
- "NEXT_PUBLIC_DASHBOARD_URL is not configured. Set it to your dashboard URL (e.g., http://localhost:4000)"
42245
+ "CMS_API_URL or NEXT_PUBLIC_DASHBOARD_URL is not configured. Set NEXT_PUBLIC_DASHBOARD_URL to your dashboard URL (e.g., http://localhost:4000)"
41960
42246
  );
41961
42247
  }
41962
42248
  function resolveApiBaseUrl() {
@@ -63780,7 +64066,8 @@ async function initDocs(options) {
63780
64066
  { filename: "cmsify-page.md", template: "workflow-cmsify-page" },
63781
64067
  { filename: "editor-workflows.md", template: "workflow-editor-workflows" },
63782
64068
  { filename: "preview-mode.md", template: "workflow-preview-mode" },
63783
- { filename: "isr-revalidation.md", template: "workflow-isr-revalidation" }
64069
+ { filename: "isr-revalidation.md", template: "workflow-isr-revalidation" },
64070
+ { filename: "agent-safe-sync.md", template: "workflow-agent-safe-sync" }
63784
64071
  ];
63785
64072
  await Promise.all(
63786
64073
  coreWorkflows.map(
@@ -64108,7 +64395,7 @@ var SimpleCache = class {
64108
64395
  };
64109
64396
 
64110
64397
  // src/version.ts
64111
- var SDK_VERSION = "0.84.0";
64398
+ var SDK_VERSION = "0.84.2";
64112
64399
 
64113
64400
  // src/client/error.ts
64114
64401
  var RiverbankApiError = class _RiverbankApiError extends Error {
@@ -25,6 +25,7 @@ Detailed documentation is available in `.riverbank/docs/`:
25
25
  - `block-types.md` - Available block types (auto-generated)
26
26
  - `theme-schema.md` - Theme schema reference (auto-generated from Zod)
27
27
  - `workflows/` - Step-by-step guides for common tasks, including editor workflows
28
+ - `workflows/agent-safe-sync.md` - Agent-safe dry-run, scoped push, and `--env` guidance
28
29
  - `site-workflows/` - Site-specific workflows and customizations
29
30
 
30
31
  ### Quick Commands
@@ -36,6 +37,8 @@ riverbankcms push # Push local changes to CMS
36
37
  riverbankcms push-config # Sync riverbank.config.ts schema/config to CMS
37
38
  ```
38
39
 
40
+ Use CLI `--env=remote` / `--env=local` for CMS commands rather than relying on `RIVERBANK_ENV=...` shell prefixes. Site `.env.local` files may set `RIVERBANK_ENV`, and the CLI flag is the explicit source of truth for sync operations.
41
+
39
42
  ### Working with Content
40
43
 
41
44
  1. **Pull latest**: `riverbankcms pull` downloads content to `content/` directory
@@ -43,6 +46,8 @@ riverbankcms push-config # Sync riverbank.config.ts schema/config to CMS
43
46
  3. **Preview**: `riverbankcms push --dry-run` shows what would change
44
47
  4. **Push**: `riverbankcms push` applies changes to CMS
45
48
 
49
+ For narrow edits, push the narrowest scope possible, for example `riverbankcms push pages privacy-policy --env=remote --dry-run`. If broad local content is stale or contains unrelated differences, see `.riverbank/docs/workflows/agent-safe-sync.md`.
50
+
46
51
  ### Editing Page Content Directly
47
52
 
48
53
  Page content lives in `content/pages/[identifier].json`. Each page has a `blocks` array containing the actual content. To edit copy:
@@ -25,6 +25,8 @@ All commands support these options:
25
25
  - Remote operations default to dry-run and require `--yes` to execute
26
26
  - When using `--env=both`, local runs first, then remote with the same safety rules
27
27
 
28
+ Prefer the CLI `--env` flag over shell prefixes such as `RIVERBANK_ENV=remote riverbankcms ...`. Site `.env.local` files may define `RIVERBANK_ENV`, and command-specific `--env` is the reliable way to target local or remote CMS sync.
29
+
28
30
  ## Environment Variables
29
31
 
30
32
  ### Local Environment (default)
@@ -148,6 +150,15 @@ riverbankcms push --dry-run --json-diff=summary
148
150
  riverbankcms push --dry-run --json-diff=full
149
151
  ```
150
152
 
153
+ **Agent-safe scoped push example:**
154
+
155
+ ```bash
156
+ riverbankcms push pages privacy-policy --env=remote --dry-run
157
+ riverbankcms push pages privacy-policy --env=remote --yes
158
+ ```
159
+
160
+ If unrelated local files would be included by a broad scope, stage a temporary content directory containing only the intended file(s) and use `--content-dir`; see `workflows/agent-safe-sync.md`.
161
+
151
162
  **Options:**
152
163
 
153
164
  | Option | Description |
@@ -284,6 +295,8 @@ riverbankcms push-config --config ./src/riverbank.config.ts
284
295
 
285
296
  Syncs SDK schema/config surfaces such as custom blocks, block field options/extensions, content type definitions/templates, SDK-managed site settings, and footer blocks. Pages, entries, and navigation menus are synced with explicit `riverbankcms push` scopes.
286
297
 
298
+ If `push-config` returns template binding validation errors, treat them as schema feedback. For example, a content type `reference` field should bind to a custom block `reference` field with the same `referenceKind`, not to a plain `text` field.
299
+
287
300
  This syncs:
288
301
 
289
302
  - Custom blocks
@@ -314,6 +314,35 @@ riverbankcms push --dry-run
314
314
  riverbankcms push
315
315
  ```
316
316
 
317
+ For agent work, prefer scoped pushes over broad pushes:
318
+
319
+ ```bash
320
+ # One page
321
+ riverbankcms push pages privacy-policy --env=remote --dry-run
322
+ riverbankcms push pages privacy-policy --env=remote --yes
323
+
324
+ # One content type or entry
325
+ riverbankcms push entries blog-post --env=remote --dry-run
326
+ riverbankcms push entries blog-post welcome --env=remote --dry-run
327
+ ```
328
+
329
+ Use CLI `--env=local` / `--env=remote` rather than `RIVERBANK_ENV=...` shell prefixes for sync commands. Site `.env.local` files may set `RIVERBANK_ENV`, while the CLI flag explicitly selects the sync target.
330
+
331
+ If local files include unrelated page or entry differences, isolate the changed files with `--content-dir`:
332
+
333
+ ```bash
334
+ tmpdir=$(mktemp -d)
335
+ mkdir -p "$tmpdir/pages"
336
+ cp content/pages/privacy-policy.json "$tmpdir/pages/privacy-policy.json"
337
+
338
+ riverbankcms push pages --content-dir "$tmpdir" --env=remote --dry-run
339
+ riverbankcms push pages --content-dir "$tmpdir" --env=remote --yes
340
+
341
+ rm -rf "$tmpdir"
342
+ ```
343
+
344
+ See `workflows/agent-safe-sync.md` for the full safe-push checklist.
345
+
317
346
  ### Sync Configuration
318
347
 
319
348
  Configure sync behavior in `riverbank.config.ts`:
@@ -328,6 +357,8 @@ export default defineConfig({
328
357
  });
329
358
  ```
330
359
 
360
+ `push-config` syncs schema/config surfaces such as custom blocks, block extensions/options, content type schemas/templates, SDK-managed settings, and footer blocks. It does not replace `push pages`, `push entries`, or `push navigation` for file-backed content.
361
+
331
362
  | Option | Values | Description |
332
363
  | ----------------- | ---------------- | -------------------------------------------- |
333
364
  | `existingEntries` | `skip`, `update` | Whether to update entries that already exist |
@@ -92,6 +92,7 @@ Event registration blocks need both the SDK base stylesheet and a runtime theme
92
92
  | `block-types.md` | Available block types (auto-generated) |
93
93
  | `theme-schema.md` | Theme schema reference (auto-generated from Zod) |
94
94
  | `workflows/` | Step-by-step guides for common tasks, including editor workflows |
95
+ | `workflows/agent-safe-sync.md` | Agent-safe dry-run, scoped push, and stale-content handling |
95
96
 
96
97
  ## Common Tasks
97
98
 
@@ -138,6 +139,17 @@ riverbankcms push --env=remote --yes
138
139
 
139
140
  **Safety note:** Remote push requires `--yes` flag to prevent accidental production changes.
140
141
 
142
+ Prefer the CLI `--env` flag over shell prefixes such as `RIVERBANK_ENV=remote riverbankcms ...`. Site `.env.local` files often contain their own `RIVERBANK_ENV` value, while `--env=remote` is explicit and reliable for CLI sync commands.
143
+
144
+ For narrow production edits, dry-run and apply the smallest scope:
145
+
146
+ ```bash
147
+ riverbankcms push pages privacy-policy --env=remote --dry-run
148
+ riverbankcms push pages privacy-policy --env=remote --yes
149
+ ```
150
+
151
+ If local content includes unrelated differences, see `workflows/agent-safe-sync.md` for the temporary `--content-dir` pattern.
152
+
141
153
  ## Media Safety (Avoid Broken Images)
142
154
 
143
155
  - Portable content JSON should store media as **identifier-only** (no `assetId` / storage paths / `src`).
@@ -25,6 +25,8 @@ View built-in blocks in `block-types.md`. Common block kinds:
25
25
 
26
26
  Check `schema.md` for custom blocks specific to this site.
27
27
 
28
+ Prefer built-in blocks before creating a custom block. For a simple policy/terms/about page, use `block.body-text` and put the page title, intro, and section headings in the rich text body. Only create a custom block when the needed structure or behavior cannot be represented by built-in blocks plus styling.
29
+
28
30
  ### 2. List Existing Blocks
29
31
 
30
32
  See what blocks are already on the page:
@@ -62,7 +64,7 @@ Add a body text block:
62
64
  ```bash
63
65
  riverbankcms block upsert home intro-content \
64
66
  --kind block.body-text \
65
- --data '{"content": "<p>Welcome to our site. We offer...</p>"}'
67
+ --data '{"body": {"type": "doc", "content": [{"type": "paragraph", "content": [{"type": "text", "text": "Welcome to our site. We offer..."}]}]}}'
66
68
  ```
67
69
 
68
70
  Add an image block: