@riverbankcms/sdk 0.90.1 → 0.91.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 (70) hide show
  1. package/dist/{PreviewEditorSidebar-FNFRVSIM.mjs → PreviewEditorSidebar-3TT47WCF.mjs} +3 -3
  2. package/dist/{PreviewEditorUI-3WXJFQXG.mjs → PreviewEditorUI-ORCLLUNZ.mjs} +3 -3
  3. package/dist/SdkPreviewModeRuntime-GMCDQPZZ.mjs +8 -0
  4. package/dist/_dts/blocks/src/system/manifest/fieldValidation/index.d.ts +17 -0
  5. package/dist/_dts/core/src/string.d.ts +12 -0
  6. package/dist/_dts/sdk/src/cli/sync/validation.d.ts +2 -2
  7. package/dist/_dts/sdk/src/version.d.ts +1 -1
  8. package/dist/{chunk-SYYJZPKU.mjs → chunk-AFPMCLS7.mjs} +2 -2
  9. package/dist/{chunk-H6TT5ZXI.mjs → chunk-GDT2QGIL.mjs} +1 -1
  10. package/dist/{chunk-CR2VX432.mjs → chunk-RQUZYSES.mjs} +48 -36
  11. package/dist/{chunk-FA6LVZ7C.mjs → chunk-S3YHJWEU.mjs} +7 -7
  12. package/dist/{chunk-UG7I7S7W.mjs → chunk-U5YM4AWE.mjs} +1 -1
  13. package/dist/{chunk-BOQXMCSP.mjs → chunk-ZA2S7H34.mjs} +3 -3
  14. package/dist/cli/index.mjs +204 -335
  15. package/dist/cli/init-docs/content/workflow-add-block.md +48 -0
  16. package/dist/cli/init-docs/content/workflow-custom-block.md +10 -0
  17. package/dist/client/{accordion-4K7VGZ3I.mjs → accordion-AFX37652.mjs} +2 -2
  18. package/dist/client/{bookingForm-3QXA3CIS.mjs → bookingForm-32V5QCOW.mjs} +6 -6
  19. package/dist/client/bookings.mjs +16 -15
  20. package/dist/client/{carousel-BEJKNGQ7.mjs → carousel-TJGQJ7ER.mjs} +3 -3
  21. package/dist/client/{cart-44BBM6XG.mjs → cart-JUU2JEW4.mjs} +6 -6
  22. package/dist/client/{checkout-THMHEYKF.mjs → checkout-RD6BTFX4.mjs} +6 -6
  23. package/dist/client/{chunk-JV7ZNAOU.mjs → chunk-6QZIBNGV.mjs} +8 -8
  24. package/dist/client/{chunk-DQIRKNZE.mjs → chunk-6RN62XBV.mjs} +1 -1
  25. package/dist/client/{chunk-ZIAF2DA4.mjs → chunk-C4LP6BPG.mjs} +1 -1
  26. package/dist/client/{chunk-SLY6UDAS.mjs → chunk-CKXEUWWA.mjs} +2 -2
  27. package/dist/client/{chunk-5AJIMWKS.mjs → chunk-E6VIWZUG.mjs} +3 -3
  28. package/dist/client/{chunk-PEDNDLPB.mjs → chunk-FMZZHAIR.mjs} +2 -2
  29. package/dist/client/{chunk-KNTLBQ3N.mjs → chunk-ISAUXU5R.mjs} +1 -1
  30. package/dist/client/{chunk-HIHOQGIP.mjs → chunk-LJCX6V7Q.mjs} +9 -9
  31. package/dist/client/{chunk-B4H6QMPY.mjs → chunk-MLBNVN4H.mjs} +7 -5
  32. package/dist/client/{chunk-EJBHK74Y.mjs → chunk-PMNAV6LO.mjs} +1 -1
  33. package/dist/client/{chunk-4COPESPO.mjs → chunk-RMOFBBNA.mjs} +5 -5
  34. package/dist/client/{chunk-3H5CLFKT.mjs → chunk-RWYFG625.mjs} +9 -8
  35. package/dist/client/client.mjs +34 -31
  36. package/dist/client/{courseRegistration-URX7RCCK.mjs → courseRegistration-X63QAIVV.mjs} +6 -6
  37. package/dist/client/{eventCalendar-GTENOQCE.mjs → eventCalendar-5T24GCZL.mjs} +9 -9
  38. package/dist/client/{eventCombined-EZVB72MF.mjs → eventCombined-AZVTF22X.mjs} +9 -9
  39. package/dist/client/{eventDetails-CH4BJR5Z.mjs → eventDetails-7GPFNLGF.mjs} +9 -9
  40. package/dist/client/{eventListing-4BVOI5HS.mjs → eventListing-QEUMTMUM.mjs} +9 -9
  41. package/dist/client/{eventRegistration-37LPIKIE.mjs → eventRegistration-P2EDKCQZ.mjs} +9 -9
  42. package/dist/client/{form-FX3Y54YK.mjs → form-NUJ7H4IN.mjs} +3 -3
  43. package/dist/client/{headerSection-UOZZGVYL.mjs → headerSection-JB7LECPL.mjs} +3 -3
  44. package/dist/client/hooks.mjs +7 -7
  45. package/dist/client/{locationMap-VSIPKV35.mjs → locationMap-UEYWUCSW.mjs} +3 -3
  46. package/dist/client/{newsletterForm-6FRJKNAF.mjs → newsletterForm-S2YZQ2X7.mjs} +3 -3
  47. package/dist/client/{productDetail-6AHMLXCO.mjs → productDetail-H5MADGG7.mjs} +6 -6
  48. package/dist/client/{productList-M2CYIZVH.mjs → productList-DK7YON7H.mjs} +6 -6
  49. package/dist/client/rendering/client.mjs +31 -28
  50. package/dist/client/rendering/islands.mjs +19 -19
  51. package/dist/client/rendering.mjs +33 -30
  52. package/dist/client/{shop-AUOT6GEX.mjs → shop-6PA7RDRJ.mjs} +6 -6
  53. package/dist/client/spam-protection.mjs +10 -10
  54. package/dist/preview-next/client/runtime.mjs +5 -5
  55. package/dist/{sdk-runtime-6GPJNLU6.mjs → sdk-runtime-JP5347OB.mjs} +6 -6
  56. package/dist/server/components.mjs +13 -11
  57. package/dist/server/config-validation.mjs +7 -7
  58. package/dist/server/config.mjs +7 -7
  59. package/dist/server/data.mjs +7 -7
  60. package/dist/server/index.mjs +1 -1
  61. package/dist/server/navigation.mjs +2 -2
  62. package/dist/server/next.mjs +14 -12
  63. package/dist/server/page-converter.mjs +5 -5
  64. package/dist/server/prebuild.mjs +1 -1
  65. package/dist/server/rendering/server.mjs +13 -11
  66. package/dist/server/rendering.mjs +13 -11
  67. package/dist/server/routing.mjs +14 -14
  68. package/dist/server/server.mjs +8 -8
  69. package/package.json +1 -1
  70. package/dist/SdkPreviewModeRuntime-2UCIMKUB.mjs +0 -8
@@ -49,6 +49,16 @@ riverbankcms block list home
49
49
  riverbankcms block upsert <page-id> <block-id> --kind <block-kind> --data '<json>'
50
50
  ```
51
51
 
52
+ ### Authoring Block JSON
53
+
54
+ Use `block-types.md` and `block-types-site.md` as the source of truth for fields.
55
+
56
+ - Fields marked `required` must be present with a valid value.
57
+ - Fields not marked `required` may be omitted. You do not need to include every optional key or set unused optional values to `null`.
58
+ - Defaults shown in the block reference are applied by the editor/rendering contract. Include an optional field only when you want to override that default.
59
+ - For nested objects and repeaters, required child fields apply once you include the parent value. For example, an omitted `images` repeater is valid, but `images: [{}]` is not because the item is present and its required `image` field is missing.
60
+ - `null` is only valid for field types that explicitly accept clearing to no value. When in doubt, omit optional fields instead of sending `null`.
61
+
52
62
  **Examples:**
53
63
 
54
64
  Add a hero block:
@@ -59,6 +69,44 @@ riverbankcms block upsert home main-hero \
59
69
  --data '{"heading": "Welcome", "subheading": "to our website"}'
60
70
  ```
61
71
 
72
+ Add a minimal media and text block:
73
+
74
+ `block.media-text` has many display and carousel fields, but most are optional controls with defaults. A minimal content-only block only needs rich text:
75
+
76
+ ```json
77
+ {
78
+ "text": {
79
+ "type": "doc",
80
+ "content": [
81
+ {
82
+ "type": "paragraph",
83
+ "content": [{ "type": "text", "text": "Welcome to our space." }]
84
+ }
85
+ ]
86
+ }
87
+ }
88
+ ```
89
+
90
+ Add media only when you have a complete media item:
91
+
92
+ ```json
93
+ {
94
+ "text": {
95
+ "type": "doc",
96
+ "content": [{ "type": "paragraph", "content": [] }]
97
+ },
98
+ "images": [
99
+ {
100
+ "image": {
101
+ "type": "image",
102
+ "src": "/images/studio.jpg",
103
+ "alt": "A bright studio room"
104
+ }
105
+ }
106
+ ]
107
+ }
108
+ ```
109
+
62
110
  Add a body text block:
63
111
 
64
112
  ```bash
@@ -105,6 +105,16 @@ Common field types for custom blocks:
105
105
  | `repeater` | List of nested fields | `schema`, `minItems`, `maxItems` |
106
106
  | `group` | Grouped fields | `schema` |
107
107
 
108
+ ### Step 2.5: Model Required Fields Carefully
109
+
110
+ The same content authoring rules apply to custom blocks and system blocks:
111
+
112
+ - Leave `required` unset or `false` for fields that can be omitted from pushed JSON.
113
+ - Use `defaultValue` for optional controls that should have a stable editor/rendering default.
114
+ - Set `required: true` only when every pushed block must provide that field.
115
+ - For repeaters and groups, required child fields apply when the parent item/object is present. If a repeater item has `{ id: 'title', required: true }`, then every item in that repeater must include `title`.
116
+ - In React overrides, type optional fields as optional and handle missing values with defaults or conditional rendering.
117
+
108
118
  ### Step 3: Create React Override Component
109
119
 
110
120
  Create a component to render your block:
@@ -1,5 +1,5 @@
1
- import { defineIslandPropsDecoder } from './chunk-B4H6QMPY.mjs';
2
- import './chunk-3H5CLFKT.mjs';
1
+ import { defineIslandPropsDecoder } from './chunk-MLBNVN4H.mjs';
2
+ import './chunk-RWYFG625.mjs';
3
3
 
4
4
  // src/rendering/islands/enhancers/accordion.ts
5
5
  var decode = defineIslandPropsDecoder("accordion");
@@ -1,15 +1,15 @@
1
1
  "use client";
2
- import { buildBookingPaymentSelectionViewModel, usePolling } from './chunk-5AJIMWKS.mjs';
3
- import { SpinnerNode } from './chunk-KNTLBQ3N.mjs';
2
+ import { buildBookingPaymentSelectionViewModel, usePolling } from './chunk-E6VIWZUG.mjs';
3
+ import { SpinnerNode } from './chunk-ISAUXU5R.mjs';
4
4
  import { buildRouteIslandApiConfig } from './chunk-L4J5Y62O.mjs';
5
- import { scrollToBlock, useDiscountCodeUi, buildCheckoutReturnUrls, DiscountCodeDisclosure } from './chunk-SLY6UDAS.mjs';
5
+ import { scrollToBlock, useDiscountCodeUi, buildCheckoutReturnUrls, DiscountCodeDisclosure } from './chunk-CKXEUWWA.mjs';
6
6
  import { FieldValidationMessage, getFieldValidationControlProps } from './chunk-3DCJ45Z2.mjs';
7
7
  import './chunk-WBQG7VJA.mjs';
8
- import { isSpamProtectionEnabled, getChallengeUrl, AltchaWidget } from './chunk-HIHOQGIP.mjs';
8
+ import { isSpamProtectionEnabled, getChallengeUrl, AltchaWidget } from './chunk-LJCX6V7Q.mjs';
9
9
  import { BlockApiProvider, useBlockApi, FeedbackMessage } from './chunk-WHZQDPBZ.mjs';
10
10
  import { mountReactIsland } from './chunk-N7PBWBWQ.mjs';
11
- import { defineIslandPropsDecoder, resolveBookingSiteId, resolveDefaultBookingServiceId, getBookingRedirectStateFromLocation, deriveBookingFormViewState, logger, getBookingSuccessMessage, resolveAppointmentCheckoutVerificationState, themeButtonClassName, toSelectedCollectionOptionKind, assertNever, prepareBookingSubmission, formatBookingSubmissionPreparationError, resolveBookingPaymentStep, BOOKING_FORM_DATA_RESERVED_KEYS, clearWorkflowFeedback, reportWorkflowError, reportWorkflowSuccess, okWith, err } from './chunk-B4H6QMPY.mjs';
12
- import { resolveBookingTimeZoneId, DEFAULT_BOOKING_TIME_ZONE, unsafeAsFormId, unsafeAsAppointmentResourceId, unsafeAsCustomerPassId, unsafeAsAppointmentServiceId, formatLocalScheduleDate, addLocalScheduleDays, parseBookingLocalDate, unsafeAsPassId, formatBookingInstant } from './chunk-3H5CLFKT.mjs';
11
+ import { defineIslandPropsDecoder, resolveBookingSiteId, resolveDefaultBookingServiceId, getBookingRedirectStateFromLocation, deriveBookingFormViewState, logger, getBookingSuccessMessage, resolveAppointmentCheckoutVerificationState, themeButtonClassName, toSelectedCollectionOptionKind, assertNever, prepareBookingSubmission, formatBookingSubmissionPreparationError, resolveBookingPaymentStep, BOOKING_FORM_DATA_RESERVED_KEYS, clearWorkflowFeedback, reportWorkflowError, reportWorkflowSuccess, okWith, err } from './chunk-MLBNVN4H.mjs';
12
+ import { resolveBookingTimeZoneId, DEFAULT_BOOKING_TIME_ZONE, unsafeAsFormId, unsafeAsAppointmentResourceId, unsafeAsCustomerPassId, unsafeAsAppointmentServiceId, formatLocalScheduleDate, addLocalScheduleDays, parseBookingLocalDate, unsafeAsPassId, formatBookingInstant } from './chunk-RWYFG625.mjs';
13
13
  import React2, { useRef, useState, useMemo, useReducer, useEffect, useCallback, useLayoutEffect } from 'react';
14
14
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
15
15
 
@@ -5414,10 +5414,11 @@ function omitZeroAmountFutureRows(rows) {
5414
5414
  if (rows.length <= 1) {
5415
5415
  return rows;
5416
5416
  }
5417
- const [firstRow, ...futureRows] = rows;
5418
- if (!firstRow) {
5417
+ const firstRow = rows[0];
5418
+ if (firstRow === void 0) {
5419
5419
  return [];
5420
5420
  }
5421
+ const futureRows = rows.slice(1);
5421
5422
  return [
5422
5423
  firstRow,
5423
5424
  ...futureRows.filter((row) => row.amountCents > 0)
@@ -5460,11 +5461,11 @@ function isValidTimeZone(timeZone) {
5460
5461
  }
5461
5462
  function getSafeTimeZone(timeZone) {
5462
5463
  const normalized = typeof timeZone === "string" ? timeZone.trim() : "";
5463
- return normalized && isValidTimeZone(normalized) ? normalized : FALLBACK_TIMEZONE;
5464
+ return normalized.length > 0 && isValidTimeZone(normalized) ? normalized : FALLBACK_TIMEZONE;
5464
5465
  }
5465
5466
  function parseStrictBookingTimeZone(timeZone) {
5466
5467
  const normalized = timeZone.trim();
5467
- if (!normalized || !isValidTimeZone(normalized)) {
5468
+ if (normalized.length === 0 || !isValidTimeZone(normalized)) {
5468
5469
  return null;
5469
5470
  }
5470
5471
  return normalized;
@@ -5551,7 +5552,7 @@ function parseScheduledBookingDateTime(input) {
5551
5552
  try {
5552
5553
  const startsAt = toUtcIsoDateTimeString(input.startsAt);
5553
5554
  const timeZone = parseStrictBookingTimeZone(input.timeZone);
5554
- if (!timeZone) {
5555
+ if (timeZone === null) {
5555
5556
  return {
5556
5557
  ok: false,
5557
5558
  field: "timeZone",
@@ -5598,7 +5599,7 @@ function getBookingLocalDateKey(input) {
5598
5599
  }
5599
5600
  function parseBookingLocalDate(value) {
5600
5601
  const match = LOCAL_DATE_PATTERN.exec(value.trim());
5601
- if (!match?.groups) {
5602
+ if (match === null || match.groups === void 0) {
5602
5603
  throw new Error(`Invalid booking date format: "${value}" (expected YYYY-MM-DD)`);
5603
5604
  }
5604
5605
  const year = Number(match.groups.year);
@@ -12452,22 +12453,22 @@ function AltchaWidget({
12452
12453
  if (typeof window === "undefined") return;
12453
12454
  let widget = null;
12454
12455
  Promise.resolve().then(() => (init_altcha(), altcha_exports)).then(() => {
12455
- if (!containerRef.current) return;
12456
+ if (containerRef.current === null) return;
12456
12457
  widget = document.createElement("altcha-widget");
12457
12458
  widget.setAttribute("challengeurl", challengeUrl);
12458
- if (auto) {
12459
+ if (auto === true) {
12459
12460
  widget.setAttribute("auto", "onload");
12460
12461
  }
12461
- if (hidelogo) {
12462
+ if (hidelogo === true) {
12462
12463
  widget.setAttribute("hidelogo", "true");
12463
12464
  }
12464
12465
  widget.setAttribute("hidefooter", "true");
12465
- if (className) {
12466
+ if (className !== void 0 && className.length > 0) {
12466
12467
  widget.className = className;
12467
12468
  }
12468
12469
  widget.addEventListener("statechange", ((event) => {
12469
12470
  const { state, payload } = event.detail;
12470
- if (state === "verified" && payload) {
12471
+ if (state === "verified" && payload !== void 0 && payload.length > 0) {
12471
12472
  onSolutionChange?.(payload);
12472
12473
  } else if (state === "error" || state === "expired") {
12473
12474
  onSolutionChange?.(null);
@@ -12478,7 +12479,7 @@ function AltchaWidget({
12478
12479
  console.error("Failed to load ALTCHA widget:", err3);
12479
12480
  });
12480
12481
  return () => {
12481
- if (widget && containerRef.current) {
12482
+ if (widget !== null && containerRef.current !== null) {
12482
12483
  containerRef.current.removeChild(widget);
12483
12484
  }
12484
12485
  };
@@ -12533,15 +12534,15 @@ var encoder = new TextEncoder();
12533
12534
  // ../altcha/src/index.ts
12534
12535
  function getCmsApiUrl() {
12535
12536
  const env = process.env.RIVERBANK_ENV;
12536
- if (env) {
12537
+ if (env !== void 0 && env.length > 0) {
12537
12538
  const envKey = `RIVERBANK_${env.toUpperCase()}_DASHBOARD_URL`;
12538
12539
  const dashboardUrl2 = process.env[envKey];
12539
- if (dashboardUrl2) {
12540
+ if (dashboardUrl2 !== void 0 && dashboardUrl2.length > 0) {
12540
12541
  return `${dashboardUrl2.replace(/\/$/, "")}/api`;
12541
12542
  }
12542
12543
  }
12543
12544
  const dashboardUrl = process.env.NEXT_PUBLIC_DASHBOARD_URL;
12544
- if (dashboardUrl) {
12545
+ if (dashboardUrl !== void 0 && dashboardUrl.length > 0) {
12545
12546
  return `${dashboardUrl.replace(/\/$/, "")}/api`;
12546
12547
  }
12547
12548
  throw new Error("Dashboard URL not configured. Set NEXT_PUBLIC_DASHBOARD_URL");
@@ -1,8 +1,8 @@
1
- import { normalizeCarouselProps, CarouselNodeClient } from './chunk-EJBHK74Y.mjs';
1
+ import { normalizeCarouselProps, CarouselNodeClient } from './chunk-PMNAV6LO.mjs';
2
2
  import './chunk-6N7YRNYU.mjs';
3
3
  import { mountReactIsland } from './chunk-N7PBWBWQ.mjs';
4
- import { defineIslandPropsDecoder } from './chunk-B4H6QMPY.mjs';
5
- import './chunk-3H5CLFKT.mjs';
4
+ import { defineIslandPropsDecoder } from './chunk-MLBNVN4H.mjs';
5
+ import './chunk-RWYFG625.mjs';
6
6
  import { jsx } from 'react/jsx-runtime';
7
7
 
8
8
  var decode = defineIslandPropsDecoder("carousel");
@@ -1,15 +1,15 @@
1
- import { mountShopBlockIsland, CartClient } from './chunk-4COPESPO.mjs';
2
- import './chunk-DQIRKNZE.mjs';
3
- import './chunk-EJBHK74Y.mjs';
1
+ import { mountShopBlockIsland, CartClient } from './chunk-RMOFBBNA.mjs';
2
+ import './chunk-6RN62XBV.mjs';
3
+ import './chunk-PMNAV6LO.mjs';
4
4
  import './chunk-6N7YRNYU.mjs';
5
5
  import './chunk-L4J5Y62O.mjs';
6
- import './chunk-SLY6UDAS.mjs';
6
+ import './chunk-CKXEUWWA.mjs';
7
7
  import './chunk-3DCJ45Z2.mjs';
8
8
  import './chunk-WBQG7VJA.mjs';
9
9
  import './chunk-WHZQDPBZ.mjs';
10
10
  import './chunk-N7PBWBWQ.mjs';
11
- import { defineIslandPropsDecoder } from './chunk-B4H6QMPY.mjs';
12
- import './chunk-3H5CLFKT.mjs';
11
+ import { defineIslandPropsDecoder } from './chunk-MLBNVN4H.mjs';
12
+ import './chunk-RWYFG625.mjs';
13
13
 
14
14
  // src/rendering/islands/enhancers/cart.tsx
15
15
  var decode = defineIslandPropsDecoder("cart");
@@ -1,15 +1,15 @@
1
- import { mountShopBlockIsland, CheckoutClient } from './chunk-4COPESPO.mjs';
2
- import './chunk-DQIRKNZE.mjs';
3
- import './chunk-EJBHK74Y.mjs';
1
+ import { mountShopBlockIsland, CheckoutClient } from './chunk-RMOFBBNA.mjs';
2
+ import './chunk-6RN62XBV.mjs';
3
+ import './chunk-PMNAV6LO.mjs';
4
4
  import './chunk-6N7YRNYU.mjs';
5
5
  import './chunk-L4J5Y62O.mjs';
6
- import './chunk-SLY6UDAS.mjs';
6
+ import './chunk-CKXEUWWA.mjs';
7
7
  import './chunk-3DCJ45Z2.mjs';
8
8
  import './chunk-WBQG7VJA.mjs';
9
9
  import './chunk-WHZQDPBZ.mjs';
10
10
  import './chunk-N7PBWBWQ.mjs';
11
- import { defineIslandPropsDecoder } from './chunk-B4H6QMPY.mjs';
12
- import './chunk-3H5CLFKT.mjs';
11
+ import { defineIslandPropsDecoder } from './chunk-MLBNVN4H.mjs';
12
+ import './chunk-RWYFG625.mjs';
13
13
 
14
14
  // src/rendering/islands/enhancers/checkout.tsx
15
15
  var decode = defineIslandPropsDecoder("checkout");
@@ -1,16 +1,16 @@
1
1
  "use client";
2
- import { LeafletStaticMap } from './chunk-ZIAF2DA4.mjs';
3
- import { resolveCoursePricingState, useWaitlistClaim, MagicLinkForm, formatCoursePriceAmount, formatCoursePriceDisplay } from './chunk-PEDNDLPB.mjs';
2
+ import { LeafletStaticMap } from './chunk-C4LP6BPG.mjs';
3
+ import { resolveCoursePricingState, useWaitlistClaim, MagicLinkForm, formatCoursePriceAmount, formatCoursePriceDisplay } from './chunk-FMZZHAIR.mjs';
4
4
  import { CreditCard, Ticket, Star, Sparkles } from './chunk-6N7YRNYU.mjs';
5
- import { usePolling, buildBookingPaymentSelectionViewModel } from './chunk-5AJIMWKS.mjs';
6
- import { SpinnerNode } from './chunk-KNTLBQ3N.mjs';
7
- import { createBodyThemePortalRoot, TabBarFragment, useDiscountCodeUi, logoutPortal, consumeSearchParam, StepIndicator, DiscountCodeDisclosure, TerminalPanel, StateIcon, formatPrice, CrossIcon, ClockIcon, LoggedInAsUser, CheckIcon } from './chunk-SLY6UDAS.mjs';
5
+ import { usePolling, buildBookingPaymentSelectionViewModel } from './chunk-E6VIWZUG.mjs';
6
+ import { SpinnerNode } from './chunk-ISAUXU5R.mjs';
7
+ import { createBodyThemePortalRoot, TabBarFragment, useDiscountCodeUi, logoutPortal, consumeSearchParam, StepIndicator, DiscountCodeDisclosure, TerminalPanel, StateIcon, formatPrice, CrossIcon, ClockIcon, LoggedInAsUser, CheckIcon } from './chunk-CKXEUWWA.mjs';
8
8
  import { getFieldValidationControlProps, FieldValidationMessage } from './chunk-3DCJ45Z2.mjs';
9
9
  import { ModalShell } from './chunk-WBQG7VJA.mjs';
10
- import { isSpamProtectionEnabled, AltchaWidget, getChallengeUrl } from './chunk-HIHOQGIP.mjs';
10
+ import { isSpamProtectionEnabled, AltchaWidget, getChallengeUrl } from './chunk-LJCX6V7Q.mjs';
11
11
  import { useBlockApi, FeedbackMessage } from './chunk-WHZQDPBZ.mjs';
12
- import { buildEventRuntimeFilters, buildEventCalendarListingRender, groupEventsByDate, getOrderedDayNames, formatDateKey, getEventRuntimeFiltersKey, themeButtonClassName, normalizeCsvIds, normalizeOptionalId, normalizeEventBlockKind, normalizeCsvString, EventCompactRow, EmptyState, getContainerClass, getCardOrientation, isToday, MAX_EVENTS_PER_DAY, formatTime, WIZARD_STEPS, getWizardStepsForContext, getStepNumber, formatEventPriceDisplay, resolveRuntimeEventPricing, formatEventPrice, formatEventDateParts, resolveEventLinkProps, DateTimeTile, assertNever, EventCard, buildCalendarViewport, shiftCalendarAnchorDate, addMonths, getThreeMonthRange, buildTimetableModel, formatDate, MONTH_NAMES, getEventAvailability, formatEventTeacherLine, toRegistrationEvents, isEventContentType, findPreSelectedEvent, resolveRegistrationTarget, findEventByOccurrenceId, resolveEventRequiresPayment, resolveDiscountContext } from './chunk-B4H6QMPY.mjs';
13
- import { publicEventPricingType, getBookingLocalDateKey, toScheduledBookingDateTime, toBookingTimeZone, publicEventPricingCurrency, formatBookingDateTime, publicEventPricingMode, publicEventScalarPrice, publicEventTicketTypes, formatCurrencyAmount, formatBookingDate, formatBookingTime } from './chunk-3H5CLFKT.mjs';
12
+ import { buildEventRuntimeFilters, buildEventCalendarListingRender, groupEventsByDate, getOrderedDayNames, formatDateKey, getEventRuntimeFiltersKey, themeButtonClassName, normalizeCsvIds, normalizeOptionalId, normalizeEventBlockKind, normalizeCsvString, EventCompactRow, EmptyState, getContainerClass, getCardOrientation, isToday, MAX_EVENTS_PER_DAY, formatTime, WIZARD_STEPS, getWizardStepsForContext, getStepNumber, formatEventPriceDisplay, resolveRuntimeEventPricing, formatEventPrice, formatEventDateParts, resolveEventLinkProps, DateTimeTile, assertNever, EventCard, buildCalendarViewport, shiftCalendarAnchorDate, addMonths, getThreeMonthRange, buildTimetableModel, formatDate, MONTH_NAMES, getEventAvailability, formatEventTeacherLine, toRegistrationEvents, isEventContentType, findPreSelectedEvent, resolveRegistrationTarget, findEventByOccurrenceId, resolveEventRequiresPayment, resolveDiscountContext } from './chunk-MLBNVN4H.mjs';
13
+ import { publicEventPricingType, getBookingLocalDateKey, toScheduledBookingDateTime, toBookingTimeZone, publicEventPricingCurrency, formatBookingDateTime, publicEventPricingMode, publicEventScalarPrice, publicEventTicketTypes, formatCurrencyAmount, formatBookingDate, formatBookingTime } from './chunk-RWYFG625.mjs';
14
14
  import React9, { createContext, useId, useMemo, useReducer, useState, useRef, useEffect, useCallback, useContext } from 'react';
15
15
  import { createPortal } from 'react-dom';
16
16
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
@@ -1,4 +1,4 @@
1
- import { EMPTY_COMMERCE_CART_STATE, parseStoredCommerceCartState, reduceCommerceCart, buildPassCartItem } from './chunk-B4H6QMPY.mjs';
1
+ import { EMPTY_COMMERCE_CART_STATE, parseStoredCommerceCartState, reduceCommerceCart, buildPassCartItem } from './chunk-MLBNVN4H.mjs';
2
2
  import * as React from 'react';
3
3
 
4
4
  var EMPTY_STATE = EMPTY_COMMERCE_CART_STATE;
@@ -1,5 +1,5 @@
1
1
  "use client";
2
- import { isRecord } from './chunk-B4H6QMPY.mjs';
2
+ import { isRecord } from './chunk-MLBNVN4H.mjs';
3
3
  import { useRef, useState, useEffect } from 'react';
4
4
  import { jsx } from 'react/jsx-runtime';
5
5
 
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
  import { FeedbackMessage, discountAvailabilityHasDiscounts, getAutoAppliedDiscountPreview, discountAvailabilityAllowsManualEntry } from './chunk-WHZQDPBZ.mjs';
3
- import { themeButtonClassName } from './chunk-B4H6QMPY.mjs';
4
- import { formatCurrencyAmount, clsx_default } from './chunk-3H5CLFKT.mjs';
3
+ import { themeButtonClassName } from './chunk-MLBNVN4H.mjs';
4
+ import { formatCurrencyAmount, clsx_default } from './chunk-RWYFG625.mjs';
5
5
  import { useReducer, useEffect, useId, useRef } from 'react';
6
6
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
7
7
 
@@ -1,7 +1,7 @@
1
1
  "use client";
2
- import { formatPrice } from './chunk-SLY6UDAS.mjs';
3
- import { assertNever } from './chunk-B4H6QMPY.mjs';
4
- import { resolveFlexibleBalanceInitialPaymentCents, resolveFlexibleBalanceDueAt, getBookingInstalmentDepositRefundability, splitAmountWithRemainderInFirst, addIntervalPreservingMonthAnchor, clampConfiguredAmount, getBookingInstalmentPlanIntervalCount, omitZeroAmountFutureRows } from './chunk-3H5CLFKT.mjs';
2
+ import { formatPrice } from './chunk-CKXEUWWA.mjs';
3
+ import { assertNever } from './chunk-MLBNVN4H.mjs';
4
+ import { resolveFlexibleBalanceInitialPaymentCents, resolveFlexibleBalanceDueAt, getBookingInstalmentDepositRefundability, splitAmountWithRemainderInFirst, addIntervalPreservingMonthAnchor, clampConfiguredAmount, getBookingInstalmentPlanIntervalCount, omitZeroAmountFutureRows } from './chunk-RWYFG625.mjs';
5
5
  import { useReducer, useRef, useCallback, useEffect } from 'react';
6
6
 
7
7
  // ../blocks/src/system/runtime/shared/bookingPaymentOptionCopy.ts
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
  import { useBlockApi } from './chunk-WHZQDPBZ.mjs';
3
- import { themeButtonClassName, assertNever } from './chunk-B4H6QMPY.mjs';
4
- import { resolvePlanningDateInput, formatBookingPriceDisplay } from './chunk-3H5CLFKT.mjs';
3
+ import { themeButtonClassName, assertNever } from './chunk-MLBNVN4H.mjs';
4
+ import { resolvePlanningDateInput, formatBookingPriceDisplay } from './chunk-RWYFG625.mjs';
5
5
  import { useState, useReducer, useSyncExternalStore, useEffect } from 'react';
6
6
  import { jsxs, jsx } from 'react/jsx-runtime';
7
7
 
@@ -1,4 +1,4 @@
1
- import { clsx_default } from './chunk-3H5CLFKT.mjs';
1
+ import { clsx_default } from './chunk-RWYFG625.mjs';
2
2
  import { jsxs, jsx } from 'react/jsx-runtime';
3
3
 
4
4
  function resolveColorStyle(color) {
@@ -14,22 +14,22 @@ function AltchaWidget({
14
14
  if (typeof window === "undefined") return;
15
15
  let widget = null;
16
16
  import('./altcha-LIGLPZS5.mjs').then(() => {
17
- if (!containerRef.current) return;
17
+ if (containerRef.current === null) return;
18
18
  widget = document.createElement("altcha-widget");
19
19
  widget.setAttribute("challengeurl", challengeUrl);
20
- if (auto) {
20
+ if (auto === true) {
21
21
  widget.setAttribute("auto", "onload");
22
22
  }
23
- if (hidelogo) {
23
+ if (hidelogo === true) {
24
24
  widget.setAttribute("hidelogo", "true");
25
25
  }
26
26
  widget.setAttribute("hidefooter", "true");
27
- if (className) {
27
+ if (className !== void 0 && className.length > 0) {
28
28
  widget.className = className;
29
29
  }
30
30
  widget.addEventListener("statechange", ((event) => {
31
31
  const { state, payload } = event.detail;
32
- if (state === "verified" && payload) {
32
+ if (state === "verified" && payload !== void 0 && payload.length > 0) {
33
33
  onSolutionChange?.(payload);
34
34
  } else if (state === "error" || state === "expired") {
35
35
  onSolutionChange?.(null);
@@ -40,7 +40,7 @@ function AltchaWidget({
40
40
  console.error("Failed to load ALTCHA widget:", err);
41
41
  });
42
42
  return () => {
43
- if (widget && containerRef.current) {
43
+ if (widget !== null && containerRef.current !== null) {
44
44
  containerRef.current.removeChild(widget);
45
45
  }
46
46
  };
@@ -59,15 +59,15 @@ new TextEncoder();
59
59
  // ../altcha/src/index.ts
60
60
  function getCmsApiUrl() {
61
61
  const env = process.env.RIVERBANK_ENV;
62
- if (env) {
62
+ if (env !== void 0 && env.length > 0) {
63
63
  const envKey = `RIVERBANK_${env.toUpperCase()}_DASHBOARD_URL`;
64
64
  const dashboardUrl2 = process.env[envKey];
65
- if (dashboardUrl2) {
65
+ if (dashboardUrl2 !== void 0 && dashboardUrl2.length > 0) {
66
66
  return `${dashboardUrl2.replace(/\/$/, "")}/api`;
67
67
  }
68
68
  }
69
69
  const dashboardUrl = process.env.NEXT_PUBLIC_DASHBOARD_URL;
70
- if (dashboardUrl) {
70
+ if (dashboardUrl !== void 0 && dashboardUrl.length > 0) {
71
71
  return `${dashboardUrl.replace(/\/$/, "")}/api`;
72
72
  }
73
73
  throw new Error("Dashboard URL not configured. Set NEXT_PUBLIC_DASHBOARD_URL");
@@ -1,4 +1,4 @@
1
- import { parseAspectRatioValue, parseColorTokenParts, toBookingTimeZone, formatBookingDate, toScheduledBookingDateTime, formatBookingTime, toScheduledBookingDateRange, formatBookingDateParts, formatEventPricing, ImagePresets, getBookingLocalDateKey, publicEventPricingType, formatCurrencyAmount, getCurrentResolveImageUrlContext, renderVideo, renderAudio, resolveMediaNodeResponsiveImage, MediaPlaceholder, computeMediaTransformStyle, rgbColorValue } from './chunk-3H5CLFKT.mjs';
1
+ import { parseAspectRatioValue, parseColorTokenParts, toBookingTimeZone, formatBookingDate, toScheduledBookingDateTime, formatBookingTime, toScheduledBookingDateRange, formatBookingDateParts, formatEventPricing, ImagePresets, getBookingLocalDateKey, publicEventPricingType, formatCurrencyAmount, getCurrentResolveImageUrlContext, renderVideo, renderAudio, resolveMediaNodeResponsiveImage, MediaPlaceholder, computeMediaTransformStyle, rgbColorValue } from './chunk-RWYFG625.mjs';
2
2
  import z2, { z } from 'zod';
3
3
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
4
4
 
@@ -5309,7 +5309,7 @@ function formatCalendarTitle(viewDate, view, days, monthNames = MONTH_NAMES) {
5309
5309
  if (view === "week") {
5310
5310
  const weekStart = days[0];
5311
5311
  const weekEnd = days[6];
5312
- if (!weekStart || !weekEnd) {
5312
+ if (weekStart === void 0 || weekEnd === void 0) {
5313
5313
  return `${monthNames[viewDate.getMonth()] ?? ""} ${viewDate.getFullYear()}`;
5314
5314
  }
5315
5315
  const startMonth = monthNames[weekStart.getMonth()] ?? "";
@@ -5415,7 +5415,9 @@ function getLocalDateKey(isoTimestamp, timeZone) {
5415
5415
  const year = parts.find((part) => part.type === "year")?.value;
5416
5416
  const month = parts.find((part) => part.type === "month")?.value;
5417
5417
  const day = parts.find((part) => part.type === "day")?.value;
5418
- if (!year || !month || !day) return null;
5418
+ if (year === void 0 || year.length === 0) return null;
5419
+ if (month === void 0 || month.length === 0) return null;
5420
+ if (day === void 0 || day.length === 0) return null;
5419
5421
  return `${year}-${month}-${day}`;
5420
5422
  }
5421
5423
  var validTimeZoneCache = /* @__PURE__ */ new Map();
@@ -5672,7 +5674,7 @@ function enumerateDateKeys(startDateKey, endDateKey) {
5672
5674
  }
5673
5675
  function parseDateKey(dateKey) {
5674
5676
  const match = /^(\d{4})-(\d{2})-(\d{2})$/.exec(dateKey);
5675
- if (!match) {
5677
+ if (match === null) {
5676
5678
  throw new Error(`Invalid timetable date key: ${dateKey}`);
5677
5679
  }
5678
5680
  const [, year, month, day] = match;
@@ -5692,7 +5694,7 @@ function groupItemsByDate(items, accessors) {
5692
5694
  const dateKey = getLocalDateKey(startsAt, timeZone);
5693
5695
  if (dateKey == null) continue;
5694
5696
  const existing = grouped.get(dateKey);
5695
- if (existing) {
5697
+ if (existing !== void 0) {
5696
5698
  existing.push(item);
5697
5699
  } else {
5698
5700
  grouped.set(dateKey, [item]);
@@ -1,6 +1,6 @@
1
1
  "use client";
2
2
  import { ChevronLeft, ChevronRight } from './chunk-6N7YRNYU.mjs';
3
- import { clsx_default } from './chunk-3H5CLFKT.mjs';
3
+ import { clsx_default } from './chunk-RWYFG625.mjs';
4
4
  import React, { useRef, useState, useCallback, useEffect } from 'react';
5
5
  import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
6
6
 
@@ -1,13 +1,13 @@
1
1
  "use client";
2
- import { addPassToCommerceCart, useCommerceCart } from './chunk-DQIRKNZE.mjs';
3
- import { CarouselNodeClient } from './chunk-EJBHK74Y.mjs';
2
+ import { addPassToCommerceCart, useCommerceCart } from './chunk-6RN62XBV.mjs';
3
+ import { CarouselNodeClient } from './chunk-PMNAV6LO.mjs';
4
4
  import { buildRouteIslandApiConfig } from './chunk-L4J5Y62O.mjs';
5
- import { useDiscountCodeUi, createBodyThemePortalRoot, consumeSearchParams, scrollToBlock, TerminalPanel, StateIcon, CheckIcon, CrossIcon, ActionRow, DiscountCodeDisclosure, consumeSearchParam, buildCheckoutReturnUrls } from './chunk-SLY6UDAS.mjs';
5
+ import { useDiscountCodeUi, createBodyThemePortalRoot, consumeSearchParams, scrollToBlock, TerminalPanel, StateIcon, CheckIcon, CrossIcon, ActionRow, DiscountCodeDisclosure, consumeSearchParam, buildCheckoutReturnUrls } from './chunk-CKXEUWWA.mjs';
6
6
  import { ModalShell, resolveDedicatedCheckoutPath } from './chunk-WBQG7VJA.mjs';
7
7
  import { useBlockApi, FeedbackMessage, BlockApiProvider, discountAvailabilityHasDiscounts, discountAvailabilityAllowsManualEntry, getAutoAppliedDiscountPreview } from './chunk-WHZQDPBZ.mjs';
8
8
  import { mountReactIsland } from './chunk-N7PBWBWQ.mjs';
9
- import { themeButtonClassName, formatCommercePrice, formatInterval, getShopDisplayForItems, deriveCommerceCheckoutState, buildProductDetailDisplay, productItemKey, buildProductCartItem, buildProductCardDisplay, assertNever as assertNever$1, reportWorkflowError, clearWorkflowFeedback, unwrapRichTextRoot, createRichTextDocFromMarkdown, isRecord } from './chunk-B4H6QMPY.mjs';
10
- import { assertNever, ok, err, getCurrentResolveImageUrlContext, resolveImageUrlWithContext, ImagePresets } from './chunk-3H5CLFKT.mjs';
9
+ import { themeButtonClassName, formatCommercePrice, formatInterval, getShopDisplayForItems, deriveCommerceCheckoutState, buildProductDetailDisplay, productItemKey, buildProductCartItem, buildProductCardDisplay, assertNever as assertNever$1, reportWorkflowError, clearWorkflowFeedback, unwrapRichTextRoot, createRichTextDocFromMarkdown, isRecord } from './chunk-MLBNVN4H.mjs';
10
+ import { assertNever, ok, err, getCurrentResolveImageUrlContext, resolveImageUrlWithContext, ImagePresets } from './chunk-RWYFG625.mjs';
11
11
  import * as React3 from 'react';
12
12
  import React3__default, { useState, useRef, useCallback, useEffect } from 'react';
13
13
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
@@ -264,10 +264,11 @@ function omitZeroAmountFutureRows(rows) {
264
264
  if (rows.length <= 1) {
265
265
  return rows;
266
266
  }
267
- const [firstRow, ...futureRows] = rows;
268
- if (!firstRow) {
267
+ const firstRow = rows[0];
268
+ if (firstRow === void 0) {
269
269
  return [];
270
270
  }
271
+ const futureRows = rows.slice(1);
271
272
  return [
272
273
  firstRow,
273
274
  ...futureRows.filter((row) => row.amountCents > 0)
@@ -310,11 +311,11 @@ function isValidTimeZone(timeZone) {
310
311
  }
311
312
  function getSafeTimeZone(timeZone) {
312
313
  const normalized = typeof timeZone === "string" ? timeZone.trim() : "";
313
- return normalized && isValidTimeZone(normalized) ? normalized : FALLBACK_TIMEZONE;
314
+ return normalized.length > 0 && isValidTimeZone(normalized) ? normalized : FALLBACK_TIMEZONE;
314
315
  }
315
316
  function parseStrictBookingTimeZone(timeZone) {
316
317
  const normalized = timeZone.trim();
317
- if (!normalized || !isValidTimeZone(normalized)) {
318
+ if (normalized.length === 0 || !isValidTimeZone(normalized)) {
318
319
  return null;
319
320
  }
320
321
  return normalized;
@@ -401,7 +402,7 @@ function parseScheduledBookingDateTime(input) {
401
402
  try {
402
403
  const startsAt = toUtcIsoDateTimeString(input.startsAt);
403
404
  const timeZone = parseStrictBookingTimeZone(input.timeZone);
404
- if (!timeZone) {
405
+ if (timeZone === null) {
405
406
  return {
406
407
  ok: false,
407
408
  field: "timeZone",
@@ -540,7 +541,7 @@ function getBookingLocalDateKey(input) {
540
541
  }
541
542
  function parseBookingLocalDate(value) {
542
543
  const match = LOCAL_DATE_PATTERN.exec(value.trim());
543
- if (!match?.groups) {
544
+ if (match === null || match.groups === void 0) {
544
545
  throw new Error(`Invalid booking date format: "${value}" (expected YYYY-MM-DD)`);
545
546
  }
546
547
  const year = Number(match.groups.year);
@@ -574,10 +575,10 @@ function normalizeLocationAddressText(value) {
574
575
  return null;
575
576
  }
576
577
  const trimmed = value.trim();
577
- return trimmed ? trimmed : null;
578
+ return trimmed.length > 0 ? trimmed : null;
578
579
  }
579
580
  function hasLocationCoordinates(value) {
580
- return typeof value?.lat === "number" && typeof value?.lng === "number";
581
+ return value != null && typeof value.lat === "number" && typeof value.lng === "number";
581
582
  }
582
583
  function toLocationCoordinates(value) {
583
584
  if (!hasLocationCoordinates(value)) {