@riverbankcms/sdk 0.88.0 → 0.90.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 (198) hide show
  1. package/README.md +27 -4
  2. package/dist/{PreviewEditorSidebar-EVRS3C7T.mjs → PreviewEditorSidebar-KVXNF3VW.mjs} +3 -3
  3. package/dist/{PreviewEditorUI-54WD4IGE.mjs → PreviewEditorUI-J3JN5Z7T.mjs} +3 -3
  4. package/dist/SdkPreviewModeRuntime-UBL6MSNP.mjs +8 -0
  5. package/dist/_dts/ai/src/contracts/proposals.d.ts +216 -0
  6. package/dist/_dts/altcha/src/AltchaWidget.d.ts +1 -1
  7. package/dist/_dts/api/src/accessAdmin.d.ts +7 -0
  8. package/dist/_dts/api/src/bookingOperations.d.ts +2 -0
  9. package/dist/_dts/api/src/bookingRecords.d.ts +4 -2
  10. package/dist/_dts/api/src/bookings.d.ts +3 -1
  11. package/dist/_dts/api/src/endpoints.d.ts +8 -0
  12. package/dist/_dts/api/src/index.d.ts +7 -6
  13. package/dist/_dts/api/src/publicExperienceEndpoints.d.ts +15 -5
  14. package/dist/_dts/api/src/request.d.ts +21 -0
  15. package/dist/_dts/api/src/sdk-event-upsert.d.ts +3 -1
  16. package/dist/_dts/api/src/sdkContracts.d.ts +2 -0
  17. package/dist/_dts/api/src/siteManagementEndpoints.d.ts +5 -1
  18. package/dist/_dts/api/src/siteMembers.d.ts +6 -1
  19. package/dist/_dts/api/src/types.d.ts +4 -2
  20. package/dist/_dts/api/src/url.d.ts +6 -3
  21. package/dist/_dts/block-form/src/utils/visibleWhen.d.ts +1 -0
  22. package/dist/_dts/block-form/src/widgets/RepeaterField/components/RepeaterThumbnailCard.d.ts +5 -1
  23. package/dist/_dts/block-form/src/widgets/RepeaterField/components/RepeaterThumbnailGrid.d.ts +9 -1
  24. package/dist/_dts/block-form/src/widgets/RepeaterField/components/index.d.ts +1 -0
  25. package/dist/_dts/blocks/src/contracts/non-block-islands.d.ts +7 -11
  26. package/dist/_dts/blocks/src/contracts/proof-block-islands.d.ts +6 -0
  27. package/dist/_dts/blocks/src/index.d.ts +2 -1
  28. package/dist/_dts/blocks/src/system/blocks/events/event-calendar.d.ts +14 -6
  29. package/dist/_dts/blocks/src/system/blocks/events/shared/types.d.ts +4 -4
  30. package/dist/_dts/blocks/src/system/blocks/hero.d.ts +0 -2
  31. package/dist/_dts/blocks/src/system/blocks/shop.d.ts +3 -3
  32. package/dist/_dts/blocks/src/system/blocks/shop.shared.d.ts +8 -0
  33. package/dist/_dts/blocks/src/system/constants/events.d.ts +4 -1
  34. package/dist/_dts/blocks/src/system/icons/cta.d.ts +3 -3
  35. package/dist/_dts/blocks/src/system/icons/index.d.ts +1 -0
  36. package/dist/_dts/blocks/src/system/icons/registry.d.ts +2 -2
  37. package/dist/_dts/blocks/src/system/icons/semantic.d.ts +3 -3
  38. package/dist/_dts/blocks/src/system/icons/svg.d.ts +72 -0
  39. package/dist/_dts/blocks/src/system/manifest/schema.d.ts +3 -1
  40. package/dist/_dts/blocks/src/system/runtime/api/index.d.ts +1 -0
  41. package/dist/_dts/blocks/src/system/runtime/api/types.d.ts +18 -5
  42. package/dist/_dts/blocks/src/system/runtime/components/registry.client.d.ts +51 -6
  43. package/dist/_dts/blocks/src/system/runtime/components/runtime-backed-blocks.d.ts +24 -0
  44. package/dist/_dts/blocks/src/system/runtime/hooks/loadStateError.d.ts +1 -0
  45. package/dist/_dts/blocks/src/system/runtime/hooks/useAvailableDates.d.ts +1 -1
  46. package/dist/_dts/blocks/src/system/runtime/hooks/useAvailableDates.state.d.ts +55 -0
  47. package/dist/_dts/blocks/src/system/runtime/hooks/useAvailableSlots.state.d.ts +39 -0
  48. package/dist/_dts/blocks/src/system/runtime/hooks/useBookingFormConfig.d.ts +4 -27
  49. package/dist/_dts/blocks/src/system/runtime/hooks/useBookingFormConfig.state.d.ts +40 -0
  50. package/dist/_dts/blocks/src/system/runtime/hooks/useCalendarEvents.state.d.ts +20 -0
  51. package/dist/_dts/blocks/src/system/runtime/hooks/useEventFilters.state.d.ts +31 -0
  52. package/dist/_dts/blocks/src/system/runtime/hooks/useEventPagination.d.ts +3 -3
  53. package/dist/_dts/blocks/src/system/runtime/hooks/useEventPagination.state.d.ts +39 -0
  54. package/dist/_dts/blocks/src/system/runtime/nodes/course-registration/useCourseRegistrationWizard.d.ts +2 -2
  55. package/dist/_dts/blocks/src/system/runtime/nodes/event-details/logic.d.ts +1 -17
  56. package/dist/_dts/blocks/src/system/runtime/nodes/event-details.client.d.ts +5 -9
  57. package/dist/_dts/blocks/src/system/runtime/nodes/event-details.server.d.ts +5 -9
  58. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/event-registration.headless.contract.d.ts +2 -1
  59. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/eventPaymentOptions.d.ts +24 -0
  60. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/types.d.ts +5 -0
  61. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/useDiscountCodeUi.d.ts +4 -4
  62. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/useDiscountCodeUi.state.d.ts +50 -0
  63. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/useEventRegistrationWizard.d.ts +2 -2
  64. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration.interactive.d.ts +21 -0
  65. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration.server.d.ts +1 -1
  66. package/dist/_dts/blocks/src/system/runtime/nodes/events/EventCalendar.interactive.d.ts +11 -1
  67. package/dist/_dts/blocks/src/system/runtime/nodes/events/EventCombined.client.d.ts +2 -1
  68. package/dist/_dts/blocks/src/system/runtime/nodes/events/EventCombined.interactive.d.ts +11 -1
  69. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/EventPaginatedListView.client.d.ts +1 -1
  70. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/calendarViewOptions.d.ts +10 -0
  71. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/eventProductEligibility.d.ts +24 -0
  72. package/dist/_dts/blocks/src/system/runtime/nodes/newsletter-form.client.state.d.ts +24 -2
  73. package/dist/_dts/blocks/src/system/runtime/nodes/shared/MagicLinkForm.state.d.ts +24 -0
  74. package/dist/_dts/blocks/src/system/runtime/nodes/shared/contract-schemas.d.ts +5 -2
  75. package/dist/_dts/blocks/src/system/runtime/nodes/shop-checkout-form.d.ts +2 -2
  76. package/dist/_dts/blocks/src/system/runtime/shared/useWaitlistClaim.state.d.ts +35 -0
  77. package/dist/_dts/content-model/src/entry-slots/index.d.ts +1 -0
  78. package/dist/_dts/content-model/src/entry-slots/sdkBlocks.d.ts +21 -0
  79. package/dist/_dts/content-model/src/entry-slots/types.d.ts +61 -0
  80. package/dist/_dts/core/src/branded.d.ts +7 -0
  81. package/dist/_dts/core/src/index.d.ts +1 -0
  82. package/dist/_dts/core/src/money-input.d.ts +18 -0
  83. package/dist/_dts/core/src/site-route-target.d.ts +40 -0
  84. package/dist/_dts/db/src/generated/supabase/database.types.d.ts +209 -2
  85. package/dist/_dts/media-core/src/fileDomain.d.ts +4 -0
  86. package/dist/_dts/media-editor/src/MediaEditor.d.ts +2 -1
  87. package/dist/_dts/media-editor/src/fieldUi.d.ts +6 -0
  88. package/dist/_dts/media-editor/src/index.d.ts +1 -1
  89. package/dist/_dts/preview-next/src/client/index.d.ts +1 -0
  90. package/dist/_dts/preview-next/src/client/preview/PreviewShell.d.ts +3 -2
  91. package/dist/_dts/preview-next/src/client/preview/PreviewShellLayout.d.ts +3 -2
  92. package/dist/_dts/preview-next/src/client/preview/PreviewThemedSiteDocument.d.ts +3 -2
  93. package/dist/_dts/preview-next/src/client/preview/SiteChromeEditableSurface.d.ts +2 -2
  94. package/dist/_dts/preview-next/src/client/preview/themeRuntime.d.ts +6 -0
  95. package/dist/_dts/preview-next/src/client/sdk/SdkPreviewMode.d.ts +2 -1
  96. package/dist/_dts/sdk/src/cli/commands/pull-dated-offering-scope.d.ts +10 -0
  97. package/dist/_dts/sdk/src/cli/content/reader.d.ts +12 -5
  98. package/dist/_dts/sdk/src/client/management/types.d.ts +6 -55
  99. package/dist/_dts/sdk/src/client/runtimeCachePolicy.d.ts +160 -0
  100. package/dist/_dts/sdk/src/client/types.d.ts +26 -1
  101. package/dist/_dts/sdk/src/components.d.ts +1 -0
  102. package/dist/_dts/sdk/src/config/field-definitions.d.ts +3 -1
  103. package/dist/_dts/sdk/src/contracts/system-block-content.d.ts +3 -1
  104. package/dist/_dts/sdk/src/index.d.ts +3 -1
  105. package/dist/_dts/sdk/src/next/types.d.ts +8 -11
  106. package/dist/_dts/sdk/src/preview-next/client/index.d.ts +1 -1
  107. package/dist/_dts/sdk/src/rendering/blocks-theme-scope.d.ts +2 -1
  108. package/dist/_dts/sdk/src/rendering/components/Layout.d.ts +8 -7
  109. package/dist/_dts/sdk/src/rendering/components/pageShared.d.ts +5 -6
  110. package/dist/_dts/sdk/src/rendering/index.d.ts +1 -0
  111. package/dist/_dts/sdk/src/rendering/server.d.ts +1 -0
  112. package/dist/_dts/sdk/src/rendering/themeRuntime.d.ts +26 -0
  113. package/dist/_dts/sdk/src/version.d.ts +1 -1
  114. package/dist/_dts/site-commands/src/commands.d.ts +18 -0
  115. package/dist/_dts/theme-core/src/ResponsiveScope.d.ts +12 -0
  116. package/dist/_dts/theme-core/src/accordions/types.d.ts +1 -1
  117. package/dist/_dts/theme-core/src/buttons/personalities/types.d.ts +2 -2
  118. package/dist/_dts/theme-core/src/buttons/types.d.ts +5 -5
  119. package/dist/_dts/theme-core/src/cards/types.d.ts +2 -2
  120. package/dist/_dts/theme-core/src/generated/containerResponsiveThemeCss.d.ts +1 -1
  121. package/dist/_dts/theme-core/src/index.d.ts +2 -0
  122. package/dist/_dts/theme-core/src/mock-themes/all.d.ts +21 -21
  123. package/dist/_dts/theme-core/src/schema.d.ts +18 -18
  124. package/dist/_dts/theme-core/src/site-styles/designState.d.ts +2 -2
  125. package/dist/_dts/theme-core/src/site-styles/generatedSchemas.d.ts +2 -2
  126. package/dist/_dts/theme-core/src/site-styles/logoBranding.d.ts +4 -4
  127. package/dist/_dts/theme-core/src/themeRuntime.d.ts +11 -0
  128. package/dist/{chunk-ER4UIW4X.mjs → chunk-AEOYWPE4.mjs} +91 -55
  129. package/dist/{chunk-O4LVYUVH.mjs → chunk-BOQXMCSP.mjs} +147 -101
  130. package/dist/{chunk-HVOBXA3Y.mjs → chunk-GSPFFUVB.mjs} +2 -2
  131. package/dist/{chunk-7KOO7RPP.mjs → chunk-PMBB6MQ7.mjs} +2273 -1113
  132. package/dist/{chunk-K3JWH6HE.mjs → chunk-RQ3XZ4SJ.mjs} +9 -1
  133. package/dist/{chunk-YDMBIIS5.mjs → chunk-UG7I7S7W.mjs} +1 -1
  134. package/dist/cli/index.mjs +1564 -546
  135. package/dist/cli/init-docs/content/cli-reference.md +6 -1
  136. package/dist/cli/init-docs/content/content-management.md +27 -0
  137. package/dist/client/{accordion-PT5CGW5N.mjs → accordion-GXQNWQ6O.mjs} +2 -2
  138. package/dist/client/{bookingForm-2HLRTEYS.mjs → bookingForm-STLUJ36H.mjs} +206 -335
  139. package/dist/client/bookings.mjs +821 -413
  140. package/dist/client/{carousel-Z2LKYSWA.mjs → carousel-CVRN6EPP.mjs} +4 -3
  141. package/dist/client/{cart-ND5IK4A6.mjs → cart-IYIBA5CL.mjs} +8 -8
  142. package/dist/client/{checkout-EYUSGAY7.mjs → checkout-O3BGM4GS.mjs} +8 -8
  143. package/dist/client/chunk-4RTFGHZN.mjs +433 -0
  144. package/dist/client/{chunk-DIRW2LNG.mjs → chunk-6DPXDOIL.mjs} +336 -225
  145. package/dist/client/chunk-6N7YRNYU.mjs +183 -0
  146. package/dist/client/{chunk-O5JNI3E4.mjs → chunk-7DH35FGA.mjs} +2 -2
  147. package/dist/client/{chunk-S4G65LGR.mjs → chunk-D3ETC2SU.mjs} +1 -1
  148. package/dist/client/{chunk-BAWHZ5GM.mjs → chunk-DAS5CIER.mjs} +460 -157
  149. package/dist/client/{chunk-6DVPO44G.mjs → chunk-FHU6PFPM.mjs} +1 -1
  150. package/dist/client/{chunk-SDIYSQAY.mjs → chunk-HIHOQGIP.mjs} +2 -3
  151. package/dist/client/{chunk-BL66UWGD.mjs → chunk-MFPKS6QS.mjs} +13 -16
  152. package/dist/client/{chunk-X7GVFB7Y.mjs → chunk-NBFRJ5NB.mjs} +157 -5
  153. package/dist/client/{chunk-WCVK4MBJ.mjs → chunk-VFHZLZAC.mjs} +1 -1
  154. package/dist/client/{chunk-GOFO7HRH.mjs → chunk-WHZQDPBZ.mjs} +19 -1
  155. package/dist/client/{chunk-MHBEWDT7.mjs → chunk-Z62JYS5O.mjs} +122 -50
  156. package/dist/client/client.mjs +5979 -5198
  157. package/dist/client/{courseRegistration-H3AZBUEG.mjs → courseRegistration-2D3ACMJR.mjs} +20 -58
  158. package/dist/client/{eventCalendar-FPKJGLGS.mjs → eventCalendar-QY4UZUFF.mjs} +11 -11
  159. package/dist/client/{eventCombined-QCGIZBUY.mjs → eventCombined-RRCDKJC2.mjs} +11 -11
  160. package/dist/client/{eventDetails-HIT3BJWU.mjs → eventDetails-YO335BUT.mjs} +11 -11
  161. package/dist/client/{eventListing-R4HNWJDN.mjs → eventListing-PXA6GFQ3.mjs} +11 -11
  162. package/dist/client/{eventRegistration-Q7BYY5HF.mjs → eventRegistration-2ZHEDDXO.mjs} +11 -11
  163. package/dist/client/{form-NI6YOG6S.mjs → form-ZS6KX4U2.mjs} +7 -7
  164. package/dist/client/{headerSection-SDYGII36.mjs → headerSection-QK5SLIIB.mjs} +3 -3
  165. package/dist/client/hooks.mjs +1102 -1029
  166. package/dist/client/{locationMap-BDETEUQD.mjs → locationMap-GFNIUD2X.mjs} +3 -3
  167. package/dist/client/{newsletterForm-EKYIU67X.mjs → newsletterForm-PGLTTCUG.mjs} +61 -25
  168. package/dist/client/{productDetail-5UTGNN76.mjs → productDetail-OPBE5ZPI.mjs} +8 -8
  169. package/dist/client/{productList-7YA5KXZQ.mjs → productList-NI72Q62Z.mjs} +8 -8
  170. package/dist/client/rendering/client.mjs +4390 -4245
  171. package/dist/client/rendering/islands.mjs +19 -19
  172. package/dist/client/rendering.mjs +3327 -3181
  173. package/dist/client/{shop-AIMUMZYC.mjs → shop-3ZQPEWYI.mjs} +8 -8
  174. package/dist/client/spam-protection.mjs +4 -5
  175. package/dist/preview-next/before-render.mjs +20 -2
  176. package/dist/preview-next/client/runtime.mjs +5 -5
  177. package/dist/preview-next/middleware.mjs +18 -0
  178. package/dist/{sdk-runtime-NW472WNT.mjs → sdk-runtime-FSHXCWDS.mjs} +6 -6
  179. package/dist/server/components.mjs +2580 -2783
  180. package/dist/server/config-validation.mjs +1334 -1261
  181. package/dist/server/config.mjs +1334 -1261
  182. package/dist/server/data.mjs +1102 -1029
  183. package/dist/server/index.mjs +1097 -476
  184. package/dist/server/navigation.mjs +20 -30
  185. package/dist/server/next.mjs +3282 -2847
  186. package/dist/server/page-converter.mjs +1009 -946
  187. package/dist/server/prebuild.mjs +1 -1
  188. package/dist/server/rendering/server.mjs +2580 -2783
  189. package/dist/server/rendering.mjs +2586 -2789
  190. package/dist/server/routing.mjs +1440 -1053
  191. package/dist/server/server.mjs +1886 -1153
  192. package/dist/server/theme-bridge.mjs +34 -5
  193. package/dist/styles/index.css +26 -0
  194. package/package.json +3 -2
  195. package/dist/SdkPreviewModeRuntime-ZALZDJEK.mjs +0 -8
  196. package/dist/client/chunk-H4MHEXYS.mjs +0 -184
  197. package/dist/client/chunk-ZFHRN6W2.mjs +0 -66
  198. /package/dist/client/{chunk-LI2C6M5O.mjs → chunk-25W2EQUN.mjs} +0 -0
@@ -1832,6 +1832,24 @@ var ENDPOINT_DEFINITIONS = {
1832
1832
  auth: "user",
1833
1833
  responseKind: "json"
1834
1834
  },
1835
+ resendSiteInvitation: {
1836
+ path: "/sites/{siteId}/members/invitations/{invitationId}/resend",
1837
+ method: "POST",
1838
+ errors: [
1839
+ "auth:forbidden",
1840
+ "resource:not_found",
1841
+ "validation:invalid_input",
1842
+ "external:service_error",
1843
+ "server:internal_error"
1844
+ ],
1845
+ tags: [
1846
+ "site-{siteId}",
1847
+ "site-members-{siteId}",
1848
+ "site-invite-{invitationId}"
1849
+ ],
1850
+ auth: "user",
1851
+ responseKind: "json"
1852
+ },
1835
1853
  transferSiteOwnership: {
1836
1854
  path: "/sites/{siteId}/members/transfer-ownership",
1837
1855
  method: "POST",
@@ -6468,19 +6486,23 @@ function normalizeDashboardOrigin(input) {
6468
6486
  }
6469
6487
  function deriveCmsApiUrlFromDashboardUrl(input) {
6470
6488
  const origin = normalizeDashboardOrigin(input);
6471
- return origin ? `${origin}/api` : "";
6489
+ return origin ? normalizeCmsApiBaseUrl(`${origin}/api`) : "";
6490
+ }
6491
+ function normalizeCmsApiBaseUrl(input) {
6492
+ return input.trim().replace(/\/+$/, "").replace(/(?:\/api)+$/i, "/api");
6472
6493
  }
6473
6494
  function getCmsApiUrl() {
6474
6495
  if (typeof window !== "undefined") {
6475
- return "/api";
6496
+ return normalizeCmsApiBaseUrl("/api");
6476
6497
  }
6477
6498
  const internalUrl = process.env.CMS_API_URL;
6478
6499
  if (internalUrl) {
6479
- return internalUrl.replace(/\/$/, "");
6500
+ return normalizeCmsApiBaseUrl(internalUrl);
6480
6501
  }
6481
6502
  const dashboardUrl = process.env.NEXT_PUBLIC_DASHBOARD_URL;
6482
6503
  if (dashboardUrl) {
6483
- return deriveCmsApiUrlFromDashboardUrl(dashboardUrl);
6504
+ const apiUrl = deriveCmsApiUrlFromDashboardUrl(dashboardUrl);
6505
+ if (apiUrl) return apiUrl;
6484
6506
  }
6485
6507
  throw new Error(
6486
6508
  "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)"
@@ -6589,6 +6611,27 @@ function serializeQueryValue(value) {
6589
6611
  if (value instanceof Date) return value.toISOString();
6590
6612
  return null;
6591
6613
  }
6614
+ function normalizeHeaders(source) {
6615
+ const normalized = {};
6616
+ if (!source) return normalized;
6617
+ new Headers(source).forEach((value, key) => {
6618
+ normalized[key] = value;
6619
+ });
6620
+ return normalized;
6621
+ }
6622
+ function buildRequestHeaders(input) {
6623
+ const headers = {
6624
+ ...normalizeHeaders(input.optionsHeaders),
6625
+ ...normalizeHeaders(input.authHeaders)
6626
+ };
6627
+ if (input.sdkVersion) {
6628
+ headers["x-sdk-version"] = input.sdkVersion;
6629
+ }
6630
+ if (input.includeJsonContentType) {
6631
+ headers["Content-Type"] = "application/json";
6632
+ }
6633
+ return headers;
6634
+ }
6592
6635
  function serializePathParam(endpoint, key, value) {
6593
6636
  if (typeof value === "string") {
6594
6637
  return value;
@@ -6724,104 +6767,20 @@ function createRawCMSClient(headers = {}, baseUrl) {
6724
6767
  params,
6725
6768
  options = {}
6726
6769
  }) => {
6727
- const resolvedBaseUrl = baseUrl ?? resolveApiBaseUrl();
6728
- let url = buildEndpointURL(resolvedBaseUrl, endpoint);
6729
- const originalPath = API_ENDPOINTS[endpoint].path;
6730
- const unusedParams = {};
6731
- if (params) {
6732
- Object.entries(params).forEach(([key, value]) => {
6733
- const bracePlaceholder = `{${key}}`;
6734
- const colonPlaceholder = `:${key}`;
6735
- if (originalPath.includes(bracePlaceholder) || originalPath.includes(colonPlaceholder)) {
6736
- const stringValue = serializePathParam(endpoint, key, value);
6737
- url = url.replace(bracePlaceholder, stringValue);
6738
- url = url.replace(colonPlaceholder, stringValue);
6739
- } else {
6740
- unusedParams[key] = value;
6741
- }
6742
- });
6743
- }
6744
- const unresolvedPathParams = [
6745
- ...url.match(/\{[^}]+\}/g) ?? [],
6746
- ...url.match(/(^|\/):([A-Za-z][A-Za-z0-9_]*)\b/g) ?? []
6747
- ];
6748
- if (unresolvedPathParams.length > 0) {
6749
- const missingParams = Array.from(
6750
- new Set(
6751
- unresolvedPathParams.map((token) => {
6752
- if (token.startsWith("{") && token.endsWith("}")) {
6753
- return token.slice(1, -1);
6754
- }
6755
- return token.replace(/^\//, "").slice(1);
6756
- })
6757
- )
6758
- );
6759
- throw new Error(
6760
- `Missing required path params for endpoint ${String(endpoint)}: ${missingParams.join(", ")}`
6761
- );
6762
- }
6763
- const endpointConfig = API_ENDPOINTS[endpoint];
6764
- const method = endpointConfig.method;
6765
- const isGetOrHead = method === "GET" || method === "HEAD";
6766
- const queryParams = new URLSearchParams();
6767
- Object.entries(unusedParams).forEach(([key, value]) => {
6768
- appendQueryParam(queryParams, key, value);
6770
+ const plan = buildApiRequestPlan({
6771
+ endpoint,
6772
+ body,
6773
+ params,
6774
+ options,
6775
+ headers,
6776
+ baseUrl: normalizeCmsApiBaseUrl(baseUrl ?? resolveApiBaseUrl()),
6777
+ sdkVersion
6769
6778
  });
6770
- if (isGetOrHead && typeof body === "object" && body !== null && !isFormDataBody(body)) {
6771
- Object.entries(body).forEach(([key, value]) => {
6772
- appendQueryParam(queryParams, key, value);
6773
- });
6774
- }
6775
- const queryString = queryParams.toString();
6776
- if (queryString) {
6777
- url += (url.includes("?") ? "&" : "?") + queryString;
6778
- }
6779
- const formDataBody = isFormDataBody(body) ? body : void 0;
6780
- const optionsNext = options?.next;
6781
- const nextOptions = { ...optionsNext ?? {} };
6782
- const cacheIsNoStore = options?.cache === "no-store";
6783
- if (cacheIsNoStore) {
6784
- delete nextOptions.revalidate;
6785
- } else if (isGetOrHead && nextOptions.revalidate === void 0 && "revalidate" in endpointConfig && typeof endpointConfig.revalidate === "number") {
6786
- nextOptions.revalidate = endpointConfig.revalidate;
6787
- }
6788
- if ("tags" in endpointConfig && Array.isArray(endpointConfig.tags)) {
6789
- const processedTags = endpointConfig.tags.map((tag) => {
6790
- let processedTag = tag;
6791
- if (params) {
6792
- Object.entries(params).forEach(([key, value]) => {
6793
- processedTag = processedTag.replace(`{${key}}`, String(value));
6794
- });
6795
- }
6796
- return /\{[^}]+\}/.test(processedTag) ? null : processedTag;
6797
- }).filter((tag) => tag !== null);
6798
- nextOptions.tags = Array.from(/* @__PURE__ */ new Set([...nextOptions.tags ?? [], ...processedTags]));
6799
- }
6800
- const requestInit = {
6801
- method,
6802
- ...options,
6803
- // Include credentials for same-origin requests (sends cookies for auth)
6804
- credentials: "same-origin",
6805
- // Don't include body for GET/HEAD requests
6806
- // FormData is pre-narrowed via isFormDataBody() above
6807
- body: isGetOrHead || body == null ? void 0 : formDataBody ?? JSON.stringify(body),
6808
- headers: {
6809
- ...options.headers,
6810
- ...headers,
6811
- // Include SDK version if set
6812
- ...sdkVersion && { "x-sdk-version": sdkVersion },
6813
- // Don't set Content-Type for GET/HEAD requests without body
6814
- ...isGetOrHead ? {} : formDataBody ? {} : { "Content-Type": "application/json" }
6815
- },
6816
- // Add Next.js caching options
6817
- next: Object.keys(nextOptions).length > 0 ? nextOptions : void 0
6818
- };
6819
- const fetchPromise = fetch(url, requestInit);
6820
- if (!isGetOrHead && "tags" in endpointConfig && Array.isArray(endpointConfig.tags)) {
6821
- const tags = endpointConfig.tags.map((tag) => tag);
6779
+ const fetchPromise = fetch(plan.url, plan.init);
6780
+ if (plan.cacheInvalidationTags) {
6822
6781
  return fetchPromise.then((response) => {
6823
6782
  if (response.ok) {
6824
- invalidateCacheTags(tags, params);
6783
+ invalidateCacheTags(plan.cacheInvalidationTags, params);
6825
6784
  }
6826
6785
  return response;
6827
6786
  });
@@ -6829,6 +6788,100 @@ function createRawCMSClient(headers = {}, baseUrl) {
6829
6788
  return fetchPromise;
6830
6789
  };
6831
6790
  }
6791
+ function buildApiRequestPlan(input) {
6792
+ const { endpoint, body, params, headers = {}, baseUrl } = input;
6793
+ const options = input.options ?? {};
6794
+ let url = buildEndpointURL(baseUrl, endpoint);
6795
+ const originalPath = API_ENDPOINTS[endpoint].path;
6796
+ const unusedParams = {};
6797
+ if (params) {
6798
+ Object.entries(params).forEach(([key, value]) => {
6799
+ const bracePlaceholder = `{${key}}`;
6800
+ const colonPlaceholder = `:${key}`;
6801
+ if (originalPath.includes(bracePlaceholder) || originalPath.includes(colonPlaceholder)) {
6802
+ const stringValue = serializePathParam(endpoint, key, value);
6803
+ url = url.replace(bracePlaceholder, stringValue);
6804
+ url = url.replace(colonPlaceholder, stringValue);
6805
+ } else {
6806
+ unusedParams[key] = value;
6807
+ }
6808
+ });
6809
+ }
6810
+ const unresolvedPathParams = [
6811
+ ...url.match(/\{[^}]+\}/g) ?? [],
6812
+ ...url.match(/(^|\/):([A-Za-z][A-Za-z0-9_]*)\b/g) ?? []
6813
+ ];
6814
+ if (unresolvedPathParams.length > 0) {
6815
+ const missingParams = Array.from(
6816
+ new Set(
6817
+ unresolvedPathParams.map((token) => {
6818
+ if (token.startsWith("{") && token.endsWith("}")) {
6819
+ return token.slice(1, -1);
6820
+ }
6821
+ return token.replace(/^\//, "").slice(1);
6822
+ })
6823
+ )
6824
+ );
6825
+ throw new Error(
6826
+ `Missing required path params for endpoint ${String(endpoint)}: ${missingParams.join(", ")}`
6827
+ );
6828
+ }
6829
+ const endpointConfig = API_ENDPOINTS[endpoint];
6830
+ const method = endpointConfig.method;
6831
+ const isGetOrHead = method === "GET" || method === "HEAD";
6832
+ const queryParams = new URLSearchParams();
6833
+ Object.entries(unusedParams).forEach(([key, value]) => {
6834
+ appendQueryParam(queryParams, key, value);
6835
+ });
6836
+ if (isGetOrHead && typeof body === "object" && body !== null && !isFormDataBody(body)) {
6837
+ Object.entries(body).forEach(([key, value]) => {
6838
+ appendQueryParam(queryParams, key, value);
6839
+ });
6840
+ }
6841
+ const queryString = queryParams.toString();
6842
+ if (queryString) {
6843
+ url += (url.includes("?") ? "&" : "?") + queryString;
6844
+ }
6845
+ const formDataBody = isFormDataBody(body) ? body : void 0;
6846
+ const optionsNext = options?.next;
6847
+ const nextOptions = { ...optionsNext ?? {} };
6848
+ const cacheIsNoStore = options?.cache === "no-store";
6849
+ if (cacheIsNoStore) {
6850
+ delete nextOptions.revalidate;
6851
+ } else if (isGetOrHead && nextOptions.revalidate === void 0 && "revalidate" in endpointConfig && typeof endpointConfig.revalidate === "number") {
6852
+ nextOptions.revalidate = endpointConfig.revalidate;
6853
+ }
6854
+ if ("tags" in endpointConfig && Array.isArray(endpointConfig.tags)) {
6855
+ const processedTags = endpointConfig.tags.map((tag) => {
6856
+ let processedTag = tag;
6857
+ if (params) {
6858
+ Object.entries(params).forEach(([key, value]) => {
6859
+ processedTag = processedTag.replace(`{${key}}`, String(value));
6860
+ });
6861
+ }
6862
+ return /\{[^}]+\}/.test(processedTag) ? null : processedTag;
6863
+ }).filter((tag) => tag !== null);
6864
+ nextOptions.tags = Array.from(/* @__PURE__ */ new Set([...nextOptions.tags ?? [], ...processedTags]));
6865
+ }
6866
+ const init = {
6867
+ method,
6868
+ ...options,
6869
+ credentials: "same-origin",
6870
+ body: isGetOrHead || body == null ? void 0 : formDataBody ?? JSON.stringify(body),
6871
+ headers: buildRequestHeaders({
6872
+ optionsHeaders: options.headers,
6873
+ authHeaders: headers,
6874
+ sdkVersion: input.sdkVersion,
6875
+ includeJsonContentType: !isGetOrHead && !formDataBody
6876
+ }),
6877
+ ...Object.keys(nextOptions).length > 0 ? { next: nextOptions } : {}
6878
+ };
6879
+ return {
6880
+ url,
6881
+ init,
6882
+ ...!isGetOrHead && "tags" in endpointConfig && Array.isArray(endpointConfig.tags) ? { cacheInvalidationTags: endpointConfig.tags.map((tag) => tag) } : {}
6883
+ };
6884
+ }
6832
6885
  function createParsedClient(rawClient) {
6833
6886
  return async (params) => {
6834
6887
  const response = await rawClient(params);
@@ -7009,7 +7062,7 @@ var SimpleCache = class {
7009
7062
  };
7010
7063
 
7011
7064
  // src/version.ts
7012
- var SDK_VERSION = "0.88.0";
7065
+ var SDK_VERSION = "0.90.0";
7013
7066
 
7014
7067
  // src/client/error.ts
7015
7068
  var RiverbankApiError = class _RiverbankApiError extends Error {
@@ -7172,194 +7225,768 @@ function getResilienceStatusFromError(error) {
7172
7225
  return error[resilienceStatusSymbol];
7173
7226
  }
7174
7227
 
7175
- // src/client/resilience.ts
7176
- var DEFAULT_RETRY_CONFIG = {
7177
- maxAttempts: 3,
7178
- baseDelayMs: 200,
7179
- maxDelayMs: 2e3,
7180
- jitter: "full"
7181
- };
7182
- var DEFAULT_CIRCUIT_BREAKER_CONFIG = {
7183
- failureThreshold: 5,
7184
- resetTimeoutMs: 3e4,
7185
- halfOpenMaxRequests: 2
7186
- };
7187
- var PERMANENT_NETWORK_ERROR_CODES = /* @__PURE__ */ new Set([
7188
- "ECONNREFUSED",
7189
- // Server is not running / port not listening
7190
- "ENOTFOUND",
7191
- // DNS lookup failed - hostname doesn't exist
7192
- "EAI_AGAIN"
7193
- // DNS lookup timeout (usually permanent for invalid hosts)
7194
- ]);
7195
- var TRANSIENT_NETWORK_ERROR_CODES = /* @__PURE__ */ new Set([
7196
- "ECONNRESET",
7197
- // Connection was reset mid-request (server dropped it)
7198
- "EPIPE",
7199
- // Broken pipe (connection closed while writing)
7200
- "ETIMEDOUT",
7201
- // Connection timed out (could be temporary congestion)
7202
- "ESOCKETTIMEDOUT"
7203
- // Socket timeout
7204
- ]);
7205
- var NODE_NETWORK_ERROR_CODES = /* @__PURE__ */ new Set([
7206
- // Permanent
7207
- "ECONNREFUSED",
7208
- "ENOTFOUND",
7209
- "EAI_AGAIN",
7210
- // Transient
7211
- "ECONNRESET",
7212
- "EPIPE",
7213
- "ETIMEDOUT",
7214
- "ESOCKETTIMEDOUT"
7215
- ]);
7216
- function isNodeNetworkErrorCode(code) {
7217
- return !code.includes(":") && NODE_NETWORK_ERROR_CODES.has(code);
7218
- }
7219
- function getErrorCodeFromCause(error) {
7220
- let current = error;
7221
- while (current) {
7222
- const nodeError = current;
7223
- if (nodeError.code && typeof nodeError.code === "string") {
7224
- if (isNodeNetworkErrorCode(nodeError.code)) {
7225
- return nodeError.code;
7226
- }
7227
- }
7228
- const errorWithCause = current;
7229
- current = errorWithCause.cause;
7230
- }
7231
- return void 0;
7232
- }
7233
- function isTransientError(error) {
7234
- if (error instanceof RiverbankApiError) {
7235
- const errorCode = getErrorCodeFromCause(error);
7236
- if (errorCode && PERMANENT_NETWORK_ERROR_CODES.has(errorCode)) {
7237
- return false;
7238
- }
7239
- if (error.status === 0) return true;
7240
- if (error.status === 429) return true;
7241
- if (error.status >= 500) return true;
7242
- return false;
7243
- }
7244
- if (error instanceof TypeError) {
7245
- const errorCode = getErrorCodeFromCause(error);
7246
- if (errorCode) {
7247
- if (PERMANENT_NETWORK_ERROR_CODES.has(errorCode)) {
7248
- return false;
7249
- }
7250
- if (TRANSIENT_NETWORK_ERROR_CODES.has(errorCode)) {
7251
- return true;
7252
- }
7253
- }
7254
- return true;
7255
- }
7256
- return true;
7257
- }
7258
- function calculateBackoff(attempt, config) {
7259
- const baseDelayMs = config.baseDelayMs ?? DEFAULT_RETRY_CONFIG.baseDelayMs;
7260
- const maxDelayMs = config.maxDelayMs ?? DEFAULT_RETRY_CONFIG.maxDelayMs;
7261
- const jitter = config.jitter ?? DEFAULT_RETRY_CONFIG.jitter;
7262
- const exponential = baseDelayMs * Math.pow(2, attempt - 1);
7263
- const capped = Math.min(exponential, maxDelayMs);
7264
- if (jitter === "full") {
7265
- return Math.random() * capped;
7266
- }
7267
- return capped;
7268
- }
7269
- var CircuitBreaker = class {
7270
- constructor(config) {
7271
- this.state = "closed";
7272
- this.failureCount = 0;
7273
- this.successCount = 0;
7274
- this.openUntil = 0;
7275
- this.halfOpenRequests = 0;
7276
- this.config = {
7277
- failureThreshold: config?.failureThreshold ?? DEFAULT_CIRCUIT_BREAKER_CONFIG.failureThreshold,
7278
- resetTimeoutMs: config?.resetTimeoutMs ?? DEFAULT_CIRCUIT_BREAKER_CONFIG.resetTimeoutMs,
7279
- halfOpenMaxRequests: config?.halfOpenMaxRequests ?? DEFAULT_CIRCUIT_BREAKER_CONFIG.halfOpenMaxRequests
7280
- };
7281
- }
7282
- /**
7283
- * Check if circuit is open (requests should be blocked)
7284
- * Also handles automatic transition from open to half-open after timeout
7285
- */
7286
- isOpen() {
7287
- if (this.state === "open" && Date.now() >= this.openUntil) {
7288
- this.transitionTo("half-open");
7289
- }
7290
- return this.state === "open";
7291
- }
7292
- /**
7293
- * Check if a request can be attempted
7294
- * - closed: always yes
7295
- * - open: always no
7296
- * - half-open: limited number of probes
7297
- */
7298
- canAttempt() {
7299
- if (this.state === "closed") return true;
7300
- if (this.state === "open") return false;
7301
- return this.halfOpenRequests < this.config.halfOpenMaxRequests;
7302
- }
7303
- /**
7304
- * Increment half-open request counter (call before making request in half-open)
7305
- */
7306
- incrementHalfOpenRequests() {
7307
- if (this.state === "half-open") {
7308
- this.halfOpenRequests++;
7309
- }
7310
- }
7311
- /**
7312
- * Record a successful request
7313
- */
7314
- recordSuccess() {
7315
- if (this.state === "half-open") {
7316
- this.successCount++;
7317
- if (this.successCount >= this.config.halfOpenMaxRequests) {
7318
- this.transitionTo("closed");
7319
- }
7320
- } else {
7321
- this.failureCount = 0;
7322
- }
7323
- }
7324
- /**
7325
- * Record a failed request
7326
- * Only counts transient failures toward circuit breaker threshold
7327
- */
7328
- recordFailure(error) {
7329
- if (!isTransientError(error)) return;
7330
- this.failureCount++;
7331
- if (this.state === "half-open") {
7332
- this.transitionTo("open");
7333
- } else if (this.failureCount >= this.config.failureThreshold) {
7334
- this.transitionTo("open");
7335
- }
7336
- }
7337
- /**
7338
- * Get current circuit state
7339
- */
7340
- getState() {
7341
- return {
7342
- state: this.state,
7343
- failureCount: this.failureCount,
7344
- openUntil: this.state === "open" ? this.openUntil : void 0
7345
- };
7346
- }
7347
- /**
7348
- * Transition to a new state
7349
- */
7350
- transitionTo(newState) {
7351
- this.state = newState;
7352
- if (newState === "open") {
7353
- this.openUntil = Date.now() + this.config.resetTimeoutMs;
7354
- } else if (newState === "half-open") {
7355
- this.halfOpenRequests = 0;
7356
- this.successCount = 0;
7357
- } else if (newState === "closed") {
7358
- this.failureCount = 0;
7359
- this.successCount = 0;
7360
- this.halfOpenRequests = 0;
7361
- }
7362
- }
7228
+ // src/public-api/runtime.ts
7229
+ var PUBLIC_ENDPOINT_NAMES2 = [
7230
+ "getSite",
7231
+ "getContentByPath",
7232
+ "listPublishedEntries",
7233
+ "getPublishedEntryPreview",
7234
+ "getPublicFormById",
7235
+ "listPublicForms",
7236
+ "getPublicBookingServices",
7237
+ "getPublicChallenge",
7238
+ "listPublicEvents",
7239
+ "batchBlockLoaders",
7240
+ "listPublicCourses",
7241
+ "listPublicTeamMembers",
7242
+ "listPublicProducts",
7243
+ "listPublicPasses",
7244
+ "listPublicMemberships",
7245
+ "resolveEntrySubroute",
7246
+ "resolveEventOccurrence",
7247
+ "checkRedirect",
7248
+ "getRoutableContent",
7249
+ "getPublicRoutableContent",
7250
+ "getPublicSitemapRoutes"
7251
+ ];
7252
+ var API_ENDPOINTS2 = Object.freeze({
7253
+ getSite: {
7254
+ path: "/sites",
7255
+ method: "GET",
7256
+ revalidate: 900,
7257
+ tags: ["riverbank:site", "riverbank:site:id:{id}", "riverbank:site:slug:{slug}", "riverbank:site:domain:{domain}"],
7258
+ auth: "public",
7259
+ responseKind: "json"
7260
+ },
7261
+ getContentByPath: {
7262
+ path: "/sites/{siteId}/pages",
7263
+ method: "GET",
7264
+ tags: ["riverbank:site:{siteId}:routable-content"],
7265
+ auth: "public",
7266
+ responseKind: "json"
7267
+ },
7268
+ listPublishedEntries: {
7269
+ path: "/public/content/{siteId}/{type}/entries",
7270
+ method: "GET",
7271
+ revalidate: 60,
7272
+ tags: ["content-{siteId}-{type}"],
7273
+ auth: "public",
7274
+ responseKind: "json"
7275
+ },
7276
+ getPublishedEntryPreview: {
7277
+ path: "/public/content/{siteId}/{type}/{slug}/preview",
7278
+ method: "GET",
7279
+ revalidate: 60,
7280
+ tags: ["content-{siteId}-{type}-{slug}"],
7281
+ auth: "public",
7282
+ responseKind: "json"
7283
+ },
7284
+ getPublicFormById: {
7285
+ path: "/public/forms/{formId}",
7286
+ method: "GET",
7287
+ revalidate: 60,
7288
+ tags: ["riverbank:form:{formId}"],
7289
+ auth: "public",
7290
+ responseKind: "json"
7291
+ },
7292
+ listPublicForms: {
7293
+ path: "/public/sites/{siteId}/forms",
7294
+ method: "GET",
7295
+ revalidate: 60,
7296
+ tags: ["riverbank:site:{siteId}:forms"],
7297
+ auth: "public",
7298
+ responseKind: "json"
7299
+ },
7300
+ getPublicBookingServices: {
7301
+ path: "/public/bookings/services",
7302
+ method: "GET",
7303
+ revalidate: 60,
7304
+ tags: ["site-{siteId}"],
7305
+ auth: "public",
7306
+ responseKind: "json"
7307
+ },
7308
+ getPublicChallenge: {
7309
+ path: "/public/challenge",
7310
+ method: "GET",
7311
+ auth: "public",
7312
+ responseKind: "text"
7313
+ },
7314
+ listPublicEvents: {
7315
+ path: "/public/sites/{siteId}/events",
7316
+ method: "GET",
7317
+ revalidate: 60,
7318
+ tags: ["riverbank:site:{siteId}:public-events"],
7319
+ auth: "public",
7320
+ responseKind: "json"
7321
+ },
7322
+ batchBlockLoaders: {
7323
+ path: "/public/sites/{siteId}/block-loaders/batch",
7324
+ method: "POST",
7325
+ auth: "public",
7326
+ responseKind: "json"
7327
+ },
7328
+ listPublicCourses: {
7329
+ path: "/public/sites/{siteId}/courses",
7330
+ method: "GET",
7331
+ revalidate: 60,
7332
+ tags: ["riverbank:site:{siteId}:public-courses"],
7333
+ auth: "public",
7334
+ responseKind: "json"
7335
+ },
7336
+ listPublicTeamMembers: {
7337
+ path: "/public/sites/{siteId}/team-members",
7338
+ method: "GET",
7339
+ revalidate: 60,
7340
+ tags: ["riverbank:site:{siteId}:public-team-members"],
7341
+ auth: "public",
7342
+ responseKind: "json"
7343
+ },
7344
+ listPublicProducts: {
7345
+ path: "/public/sites/{siteId}/products",
7346
+ method: "GET",
7347
+ revalidate: 300,
7348
+ tags: ["riverbank:site:{siteId}:public-products"],
7349
+ auth: "public",
7350
+ responseKind: "json"
7351
+ },
7352
+ listPublicPasses: {
7353
+ path: "/public/sites/{siteId}/bookings/products/passes",
7354
+ method: "GET",
7355
+ revalidate: 300,
7356
+ tags: ["riverbank:site:{siteId}:public-passes"],
7357
+ auth: "public",
7358
+ responseKind: "json"
7359
+ },
7360
+ listPublicMemberships: {
7361
+ path: "/public/sites/{siteId}/bookings/products/memberships",
7362
+ method: "GET",
7363
+ revalidate: 300,
7364
+ tags: ["riverbank:site:{siteId}:public-memberships"],
7365
+ auth: "public",
7366
+ responseKind: "json"
7367
+ },
7368
+ resolveEntrySubroute: {
7369
+ path: "/public/sites/{siteId}/routing/subroutes/resolve",
7370
+ method: "GET",
7371
+ revalidate: 60,
7372
+ tags: ["site-{siteId}", "entry-subroute"],
7373
+ auth: "public",
7374
+ responseKind: "json"
7375
+ },
7376
+ resolveEventOccurrence: {
7377
+ path: "/public/sites/{siteId}/events/occurrences/resolve",
7378
+ method: "GET",
7379
+ revalidate: 60,
7380
+ tags: ["riverbank:site:{siteId}:public-events", "event-occurrence"],
7381
+ auth: "public",
7382
+ responseKind: "json"
7383
+ },
7384
+ checkRedirect: {
7385
+ path: "/public/content/redirect",
7386
+ method: "GET",
7387
+ revalidate: 86400,
7388
+ tags: ["redirect"],
7389
+ auth: "public",
7390
+ responseKind: "json"
7391
+ },
7392
+ getRoutableContent: {
7393
+ path: "/sites/{siteId}/routable-content",
7394
+ method: "GET",
7395
+ revalidate: 60,
7396
+ tags: ["riverbank:site:{siteId}:routable-content"],
7397
+ auth: "user",
7398
+ responseKind: "json"
7399
+ },
7400
+ getPublicRoutableContent: {
7401
+ path: "/public/sites/{siteId}/routable-content",
7402
+ method: "GET",
7403
+ revalidate: 60,
7404
+ tags: ["riverbank:site:{siteId}:routable-content"],
7405
+ auth: "public",
7406
+ responseKind: "json"
7407
+ },
7408
+ getPublicSitemapRoutes: {
7409
+ path: "/public/sites/{siteId}/sitemap",
7410
+ method: "GET",
7411
+ revalidate: 60,
7412
+ tags: ["riverbank:site:{siteId}:routable-content", "riverbank:site:{siteId}:settings"],
7413
+ auth: "public",
7414
+ responseKind: "json"
7415
+ }
7416
+ });
7417
+ function buildEndpointURL2(baseURL, endpoint) {
7418
+ return baseURL + API_ENDPOINTS2[endpoint].path;
7419
+ }
7420
+
7421
+ // src/client/runtimeCachePolicy.ts
7422
+ var DEFAULT_PUBLISHED_RUNTIME_CACHE_PAYLOAD_SCHEMA_VERSION = 1;
7423
+ var DEFAULT_STALE_TTL_SEC = 24 * 60 * 60;
7424
+ var DEFAULT_MEMORY_TTL_SEC = 60;
7425
+ var RUNTIME_CACHE_DURABILITY_OVERRIDES = {
7426
+ getSite: {
7427
+ kind: "durable-public-stale",
7428
+ staleTtlSec: DEFAULT_STALE_TTL_SEC
7429
+ },
7430
+ getContentByPath: {
7431
+ kind: "durable-public-stale",
7432
+ staleTtlSec: DEFAULT_STALE_TTL_SEC
7433
+ },
7434
+ listPublishedEntries: {
7435
+ kind: "memory-only",
7436
+ reason: "durable_rollout_pending"
7437
+ },
7438
+ getPublishedEntryPreview: {
7439
+ kind: "memory-only",
7440
+ reason: "durable_rollout_pending"
7441
+ },
7442
+ getPublicFormById: {
7443
+ kind: "memory-only",
7444
+ reason: "durable_rollout_pending"
7445
+ },
7446
+ listPublicForms: {
7447
+ kind: "memory-only",
7448
+ reason: "durable_rollout_pending"
7449
+ },
7450
+ getPublicBookingServices: {
7451
+ kind: "live-only",
7452
+ reason: "safety_sensitive_booking"
7453
+ },
7454
+ getPublicChallenge: {
7455
+ kind: "live-only",
7456
+ reason: "challenge_endpoint"
7457
+ },
7458
+ listPublicEvents: {
7459
+ kind: "memory-only",
7460
+ reason: "durable_rollout_pending"
7461
+ },
7462
+ batchBlockLoaders: {
7463
+ kind: "live-only",
7464
+ reason: "opaque_batch_loader"
7465
+ },
7466
+ listPublicCourses: {
7467
+ kind: "memory-only",
7468
+ reason: "durable_rollout_pending"
7469
+ },
7470
+ listPublicTeamMembers: {
7471
+ kind: "memory-only",
7472
+ reason: "durable_rollout_pending"
7473
+ },
7474
+ listPublicProducts: {
7475
+ kind: "memory-only",
7476
+ reason: "durable_rollout_pending"
7477
+ },
7478
+ listPublicPasses: {
7479
+ kind: "live-only",
7480
+ reason: "safety_sensitive_booking"
7481
+ },
7482
+ listPublicMemberships: {
7483
+ kind: "live-only",
7484
+ reason: "safety_sensitive_booking"
7485
+ },
7486
+ resolveEntrySubroute: {
7487
+ kind: "memory-only",
7488
+ reason: "durable_rollout_pending"
7489
+ },
7490
+ resolveEventOccurrence: {
7491
+ kind: "memory-only",
7492
+ reason: "durable_rollout_pending"
7493
+ },
7494
+ checkRedirect: {
7495
+ kind: "memory-only",
7496
+ reason: "durable_rollout_pending"
7497
+ },
7498
+ getRoutableContent: {
7499
+ kind: "live-only",
7500
+ reason: "auth_required"
7501
+ },
7502
+ getPublicRoutableContent: {
7503
+ kind: "memory-only",
7504
+ reason: "durable_rollout_pending"
7505
+ },
7506
+ getPublicSitemapRoutes: {
7507
+ kind: "memory-only",
7508
+ reason: "durable_rollout_pending"
7509
+ }
7510
+ };
7511
+ var PUBLIC_ENDPOINT_NAME_SET = new Set(PUBLIC_ENDPOINT_NAMES2);
7512
+ function isPublicEndpointName(endpoint) {
7513
+ return PUBLIC_ENDPOINT_NAME_SET.has(endpoint);
7514
+ }
7515
+ function isTruthyParam(value) {
7516
+ return value === true || value === "true" || value === 1 || value === "1";
7517
+ }
7518
+ function isPreviewRequest(endpoint, params) {
7519
+ if (endpoint === "getContentByPath") {
7520
+ return isTruthyParam(params.preview);
7521
+ }
7522
+ if (endpoint === "listPublishedEntries" || endpoint === "resolveEntrySubroute" || endpoint === "resolveEventOccurrence") {
7523
+ return params.stage === "preview";
7524
+ }
7525
+ return false;
7526
+ }
7527
+ function getEndpointFreshTtlSec(endpoint) {
7528
+ return API_ENDPOINTS2[endpoint].revalidate ?? DEFAULT_MEMORY_TTL_SEC;
7529
+ }
7530
+ function assertNever(value) {
7531
+ throw new Error(`Unhandled runtime cache policy override: ${String(value)}`);
7532
+ }
7533
+ function resolveKnownEndpointPolicy(endpoint, params) {
7534
+ if (isPreviewRequest(endpoint, params)) {
7535
+ return { kind: "live-only", endpoint, reason: "preview_request" };
7536
+ }
7537
+ if (endpoint === "getSite" && isTruthyParam(params.force)) {
7538
+ return { kind: "live-only", endpoint, reason: "force_refresh" };
7539
+ }
7540
+ const override = RUNTIME_CACHE_DURABILITY_OVERRIDES[endpoint];
7541
+ if (override.kind === "live-only") {
7542
+ return { kind: "live-only", endpoint, reason: override.reason };
7543
+ }
7544
+ const endpointDefinition = API_ENDPOINTS2[endpoint];
7545
+ if (endpointDefinition.method !== "GET") {
7546
+ return { kind: "live-only", endpoint, reason: "non_get_request" };
7547
+ }
7548
+ if (endpointDefinition.auth === "user") {
7549
+ return { kind: "live-only", endpoint, reason: "auth_required" };
7550
+ }
7551
+ switch (override.kind) {
7552
+ case "durable-public-stale":
7553
+ return {
7554
+ kind: "durable-public-stale",
7555
+ endpoint,
7556
+ freshTtlSec: getEndpointFreshTtlSec(endpoint),
7557
+ staleTtlSec: override.staleTtlSec
7558
+ };
7559
+ case "memory-only":
7560
+ return {
7561
+ kind: "memory-only",
7562
+ endpoint,
7563
+ freshTtlSec: getEndpointFreshTtlSec(endpoint),
7564
+ reason: override.reason
7565
+ };
7566
+ default:
7567
+ return assertNever(override);
7568
+ }
7569
+ }
7570
+ function resolveRuntimeCachePolicy(input) {
7571
+ if (input.method && input.method.toUpperCase() !== "GET") {
7572
+ return {
7573
+ kind: "live-only",
7574
+ endpoint: input.endpoint,
7575
+ reason: "non_get_request"
7576
+ };
7577
+ }
7578
+ if (!isPublicEndpointName(input.endpoint)) {
7579
+ return {
7580
+ kind: "live-only",
7581
+ endpoint: input.endpoint,
7582
+ reason: "unknown_endpoint"
7583
+ };
7584
+ }
7585
+ return resolveKnownEndpointPolicy(input.endpoint, input.params ?? {});
7586
+ }
7587
+ function toNonEmptyString(value) {
7588
+ if (value === null || value === void 0) return null;
7589
+ if (typeof value !== "string" && typeof value !== "number" && typeof value !== "boolean") {
7590
+ return null;
7591
+ }
7592
+ const normalized = String(value).trim();
7593
+ return normalized.length > 0 ? normalized : null;
7594
+ }
7595
+ function normalizeRuntimePublicPath(value) {
7596
+ const raw = toNonEmptyString(value) ?? "/";
7597
+ const withoutQuery = raw.split(/[?#]/, 1)[0] ?? "/";
7598
+ const withLeadingSlash = withoutQuery.startsWith("/") ? withoutQuery : `/${withoutQuery}`;
7599
+ const collapsed = withLeadingSlash.replace(/\/{2,}/g, "/");
7600
+ const withoutTrailingSlash = collapsed.length > 1 ? collapsed.replace(/\/+$/g, "") : collapsed;
7601
+ return withoutTrailingSlash || "/";
7602
+ }
7603
+ function normalizeRuntimeHostname(value) {
7604
+ const trimmed = value.trim().toLowerCase();
7605
+ const url = /^[a-z][a-z0-9+.-]*:\/\//.test(trimmed) ? new URL(trimmed) : new URL(`http://${trimmed}`);
7606
+ return url.hostname.replace(/\.$/, "");
7607
+ }
7608
+ function normalizeScalar(value) {
7609
+ return value.trim().toLowerCase();
7610
+ }
7611
+ function encodeKeyPart(key, value) {
7612
+ return `${encodeURIComponent(key)}=${encodeURIComponent(value)}`;
7613
+ }
7614
+ function unsafeAsPublishedRuntimeCacheKey(value) {
7615
+ return value;
7616
+ }
7617
+ function buildPublishedRuntimeCacheKey(endpoint, normalizedParams) {
7618
+ const encodedParams = Object.entries(normalizedParams).sort(([left], [right]) => left.localeCompare(right)).map(([key, value]) => encodeKeyPart(key, value)).join(":");
7619
+ return unsafeAsPublishedRuntimeCacheKey(
7620
+ `published-runtime:v1:${endpoint}:${encodedParams}`
7621
+ );
7622
+ }
7623
+ function selectSiteRuntimeIdentity(params) {
7624
+ const slug = toNonEmptyString(params.slug);
7625
+ if (slug !== null) return { slug: normalizeScalar(slug) };
7626
+ const domain = toNonEmptyString(params.domain);
7627
+ if (domain !== null) return { domain: normalizeRuntimeHostname(domain) };
7628
+ const id = toNonEmptyString(params.id);
7629
+ if (id !== null) return { id: normalizeScalar(id) };
7630
+ return null;
7631
+ }
7632
+ function deriveGetSiteKey(params) {
7633
+ const identity = selectSiteRuntimeIdentity(params);
7634
+ if (identity === null) {
7635
+ return {
7636
+ ok: false,
7637
+ error: {
7638
+ kind: "missing_site_identity",
7639
+ acceptedParams: ["slug", "domain", "id"]
7640
+ }
7641
+ };
7642
+ }
7643
+ const normalizedParams = {
7644
+ ...identity,
7645
+ currentPath: normalizeRuntimePublicPath(params.currentPath)
7646
+ };
7647
+ return {
7648
+ ok: true,
7649
+ endpoint: "getSite",
7650
+ key: buildPublishedRuntimeCacheKey("getSite", normalizedParams),
7651
+ normalizedParams
7652
+ };
7653
+ }
7654
+ function deriveGetContentByPathKey(params) {
7655
+ const siteId = toNonEmptyString(params.siteId);
7656
+ if (siteId === null) {
7657
+ return {
7658
+ ok: false,
7659
+ error: {
7660
+ kind: "missing_required_param",
7661
+ endpoint: "getContentByPath",
7662
+ param: "siteId"
7663
+ }
7664
+ };
7665
+ }
7666
+ const normalizedParams = {
7667
+ siteId: normalizeScalar(siteId),
7668
+ path: normalizeRuntimePublicPath(params.path)
7669
+ };
7670
+ return {
7671
+ ok: true,
7672
+ endpoint: "getContentByPath",
7673
+ key: buildPublishedRuntimeCacheKey("getContentByPath", normalizedParams),
7674
+ normalizedParams
7675
+ };
7676
+ }
7677
+ var DURABLE_RUNTIME_CACHE_KEY_DERIVERS = {
7678
+ getSite: deriveGetSiteKey,
7679
+ getContentByPath: deriveGetContentByPathKey
7680
+ };
7681
+ function isPublishedRuntimeCacheKeyEndpoint(value) {
7682
+ return typeof value === "string" && Object.prototype.hasOwnProperty.call(DURABLE_RUNTIME_CACHE_KEY_DERIVERS, value);
7683
+ }
7684
+ function parsePublishedRuntimeCacheKey(value) {
7685
+ const details = parsePublishedRuntimeCacheKeyDetails(value);
7686
+ if (!details.ok) {
7687
+ return details;
7688
+ }
7689
+ return {
7690
+ ok: true,
7691
+ key: details.key,
7692
+ endpoint: details.endpoint
7693
+ };
7694
+ }
7695
+ function parsePublishedRuntimeCacheKeyDetails(value) {
7696
+ if (typeof value !== "string") {
7697
+ return { ok: false, error: "not_string" };
7698
+ }
7699
+ const parts = value.split(":");
7700
+ if (parts[0] !== "published-runtime" || parts[1] !== "v1") {
7701
+ return { ok: false, error: "invalid_prefix" };
7702
+ }
7703
+ const endpoint = parts[2];
7704
+ if (!isPublishedRuntimeCacheKeyEndpoint(endpoint)) {
7705
+ return { ok: false, error: "unknown_endpoint" };
7706
+ }
7707
+ const normalizedParams = {};
7708
+ for (const part of parts.slice(3)) {
7709
+ const separatorIndex = part.indexOf("=");
7710
+ if (separatorIndex <= 0) {
7711
+ return { ok: false, error: "invalid_param_encoding" };
7712
+ }
7713
+ try {
7714
+ const key = decodeURIComponent(part.slice(0, separatorIndex));
7715
+ const paramValue = decodeURIComponent(part.slice(separatorIndex + 1));
7716
+ normalizedParams[key] = paramValue;
7717
+ } catch {
7718
+ return { ok: false, error: "invalid_param_encoding" };
7719
+ }
7720
+ }
7721
+ if (!hasExpectedPublishedRuntimeCacheKeyParams(endpoint, normalizedParams)) {
7722
+ return { ok: false, error: "invalid_param_encoding" };
7723
+ }
7724
+ return {
7725
+ ok: true,
7726
+ key: unsafeAsPublishedRuntimeCacheKey(value),
7727
+ endpoint,
7728
+ normalizedParams
7729
+ };
7730
+ }
7731
+ function hasExpectedPublishedRuntimeCacheKeyParams(endpoint, normalizedParams) {
7732
+ const keys = Object.keys(normalizedParams).sort();
7733
+ switch (endpoint) {
7734
+ case "getSite": {
7735
+ const identityKeys = ["domain", "id", "slug"].filter(
7736
+ (key) => normalizedParams[key] !== void 0
7737
+ );
7738
+ return identityKeys.length === 1 && normalizedParams.currentPath !== void 0 && keys.every(
7739
+ (key) => ["currentPath", "domain", "id", "slug"].includes(key)
7740
+ );
7741
+ }
7742
+ case "getContentByPath":
7743
+ return normalizedParams.path !== void 0 && normalizedParams.siteId !== void 0 && keys.every((key) => ["path", "siteId"].includes(key));
7744
+ }
7745
+ }
7746
+ function parsePublishedRuntimeCachePayloadSchemaVersion(value) {
7747
+ if (typeof value !== "number") {
7748
+ return { ok: false, error: "not_number" };
7749
+ }
7750
+ if (!Number.isInteger(value)) {
7751
+ return { ok: false, error: "not_integer" };
7752
+ }
7753
+ if (value <= 0) {
7754
+ return { ok: false, error: "not_positive" };
7755
+ }
7756
+ return {
7757
+ ok: true,
7758
+ value
7759
+ };
7760
+ }
7761
+ function classifyPublishedRuntimeCacheFreshness(input) {
7762
+ const freshUntilMs = Date.parse(input.freshUntil);
7763
+ const staleUntilMs = Date.parse(input.staleUntil);
7764
+ if (Number.isNaN(freshUntilMs)) {
7765
+ return { kind: "invalid_timestamp", field: "freshUntil" };
7766
+ }
7767
+ if (Number.isNaN(staleUntilMs)) {
7768
+ return { kind: "invalid_timestamp", field: "staleUntil" };
7769
+ }
7770
+ const nowMs = input.now.getTime();
7771
+ if (nowMs > staleUntilMs) {
7772
+ return { kind: "expired" };
7773
+ }
7774
+ if (nowMs <= freshUntilMs) {
7775
+ return { kind: "fresh", staleAgeSec: 0 };
7776
+ }
7777
+ return {
7778
+ kind: "stale",
7779
+ staleAgeSec: Math.floor((nowMs - freshUntilMs) / 1e3)
7780
+ };
7781
+ }
7782
+ function derivePublishedRuntimeCacheKey(input) {
7783
+ const policy = resolveRuntimeCachePolicy({
7784
+ endpoint: input.endpoint,
7785
+ method: "GET",
7786
+ params: input.params
7787
+ });
7788
+ if (policy.kind !== "durable-public-stale") {
7789
+ return {
7790
+ ok: false,
7791
+ error: { kind: "not_durable_eligible", policy }
7792
+ };
7793
+ }
7794
+ switch (input.endpoint) {
7795
+ case "getSite":
7796
+ return DURABLE_RUNTIME_CACHE_KEY_DERIVERS.getSite(input.params);
7797
+ case "getContentByPath":
7798
+ return DURABLE_RUNTIME_CACHE_KEY_DERIVERS.getContentByPath(input.params);
7799
+ }
7800
+ }
7801
+
7802
+ // src/client/resilience.ts
7803
+ var DEFAULT_RETRY_CONFIG = {
7804
+ maxAttempts: 3,
7805
+ baseDelayMs: 200,
7806
+ maxDelayMs: 2e3,
7807
+ jitter: "full"
7808
+ };
7809
+ var DEFAULT_CIRCUIT_BREAKER_CONFIG = {
7810
+ failureThreshold: 5,
7811
+ resetTimeoutMs: 3e4,
7812
+ halfOpenMaxRequests: 2
7813
+ };
7814
+ var PERMANENT_NETWORK_ERROR_CODES = /* @__PURE__ */ new Set([
7815
+ "ECONNREFUSED",
7816
+ // Server is not running / port not listening
7817
+ "ENOTFOUND",
7818
+ // DNS lookup failed - hostname doesn't exist
7819
+ "EAI_AGAIN"
7820
+ // DNS lookup timeout (usually permanent for invalid hosts)
7821
+ ]);
7822
+ var TRANSIENT_NETWORK_ERROR_CODES = /* @__PURE__ */ new Set([
7823
+ "ECONNRESET",
7824
+ // Connection was reset mid-request (server dropped it)
7825
+ "EPIPE",
7826
+ // Broken pipe (connection closed while writing)
7827
+ "ETIMEDOUT",
7828
+ // Connection timed out (could be temporary congestion)
7829
+ "ESOCKETTIMEDOUT"
7830
+ // Socket timeout
7831
+ ]);
7832
+ var NODE_NETWORK_ERROR_CODES = /* @__PURE__ */ new Set([
7833
+ // Permanent
7834
+ "ECONNREFUSED",
7835
+ "ENOTFOUND",
7836
+ "EAI_AGAIN",
7837
+ // Transient
7838
+ "ECONNRESET",
7839
+ "EPIPE",
7840
+ "ETIMEDOUT",
7841
+ "ESOCKETTIMEDOUT"
7842
+ ]);
7843
+ function isNodeNetworkErrorCode(code) {
7844
+ return !code.includes(":") && NODE_NETWORK_ERROR_CODES.has(code);
7845
+ }
7846
+ function getErrorCodeFromCause(error) {
7847
+ let current = error;
7848
+ while (current) {
7849
+ const nodeError = current;
7850
+ if (nodeError.code && typeof nodeError.code === "string") {
7851
+ if (isNodeNetworkErrorCode(nodeError.code)) {
7852
+ return nodeError.code;
7853
+ }
7854
+ }
7855
+ const errorWithCause = current;
7856
+ current = errorWithCause.cause;
7857
+ }
7858
+ return void 0;
7859
+ }
7860
+ function isTransientError(error) {
7861
+ if (error instanceof RiverbankApiError) {
7862
+ const errorCode = getErrorCodeFromCause(error);
7863
+ if (errorCode && PERMANENT_NETWORK_ERROR_CODES.has(errorCode)) {
7864
+ return false;
7865
+ }
7866
+ if (error.status === 0) return true;
7867
+ if (error.status === 429) return true;
7868
+ if (error.status >= 500) return true;
7869
+ return false;
7870
+ }
7871
+ if (error instanceof TypeError) {
7872
+ const errorCode = getErrorCodeFromCause(error);
7873
+ if (errorCode) {
7874
+ if (PERMANENT_NETWORK_ERROR_CODES.has(errorCode)) {
7875
+ return false;
7876
+ }
7877
+ if (TRANSIENT_NETWORK_ERROR_CODES.has(errorCode)) {
7878
+ return true;
7879
+ }
7880
+ }
7881
+ return true;
7882
+ }
7883
+ return true;
7884
+ }
7885
+ function calculateBackoff(attempt, config) {
7886
+ const baseDelayMs = config.baseDelayMs ?? DEFAULT_RETRY_CONFIG.baseDelayMs;
7887
+ const maxDelayMs = config.maxDelayMs ?? DEFAULT_RETRY_CONFIG.maxDelayMs;
7888
+ const jitter = config.jitter ?? DEFAULT_RETRY_CONFIG.jitter;
7889
+ const exponential = baseDelayMs * Math.pow(2, attempt - 1);
7890
+ const capped = Math.min(exponential, maxDelayMs);
7891
+ if (jitter === "full") {
7892
+ return Math.random() * capped;
7893
+ }
7894
+ return capped;
7895
+ }
7896
+ var CircuitBreaker = class {
7897
+ constructor(config) {
7898
+ this.state = "closed";
7899
+ this.failureCount = 0;
7900
+ this.successCount = 0;
7901
+ this.openUntil = 0;
7902
+ this.halfOpenRequests = 0;
7903
+ this.config = {
7904
+ failureThreshold: config?.failureThreshold ?? DEFAULT_CIRCUIT_BREAKER_CONFIG.failureThreshold,
7905
+ resetTimeoutMs: config?.resetTimeoutMs ?? DEFAULT_CIRCUIT_BREAKER_CONFIG.resetTimeoutMs,
7906
+ halfOpenMaxRequests: config?.halfOpenMaxRequests ?? DEFAULT_CIRCUIT_BREAKER_CONFIG.halfOpenMaxRequests
7907
+ };
7908
+ }
7909
+ /**
7910
+ * Check if circuit is open (requests should be blocked)
7911
+ * Also handles automatic transition from open to half-open after timeout
7912
+ */
7913
+ isOpen() {
7914
+ if (this.state === "open" && Date.now() >= this.openUntil) {
7915
+ this.transitionTo("half-open");
7916
+ }
7917
+ return this.state === "open";
7918
+ }
7919
+ /**
7920
+ * Check if a request can be attempted
7921
+ * - closed: always yes
7922
+ * - open: always no
7923
+ * - half-open: limited number of probes
7924
+ */
7925
+ canAttempt() {
7926
+ if (this.state === "closed") return true;
7927
+ if (this.state === "open") return false;
7928
+ return this.halfOpenRequests < this.config.halfOpenMaxRequests;
7929
+ }
7930
+ /**
7931
+ * Increment half-open request counter (call before making request in half-open)
7932
+ */
7933
+ incrementHalfOpenRequests() {
7934
+ if (this.state === "half-open") {
7935
+ this.halfOpenRequests++;
7936
+ }
7937
+ }
7938
+ /**
7939
+ * Record a successful request
7940
+ */
7941
+ recordSuccess() {
7942
+ if (this.state === "half-open") {
7943
+ this.successCount++;
7944
+ if (this.successCount >= this.config.halfOpenMaxRequests) {
7945
+ this.transitionTo("closed");
7946
+ }
7947
+ } else {
7948
+ this.failureCount = 0;
7949
+ }
7950
+ }
7951
+ /**
7952
+ * Record a failed request
7953
+ * Only counts transient failures toward circuit breaker threshold
7954
+ */
7955
+ recordFailure(error) {
7956
+ if (!isTransientError(error)) return;
7957
+ this.failureCount++;
7958
+ if (this.state === "half-open") {
7959
+ this.transitionTo("open");
7960
+ } else if (this.failureCount >= this.config.failureThreshold) {
7961
+ this.transitionTo("open");
7962
+ }
7963
+ }
7964
+ /**
7965
+ * Get current circuit state
7966
+ */
7967
+ getState() {
7968
+ return {
7969
+ state: this.state,
7970
+ failureCount: this.failureCount,
7971
+ openUntil: this.state === "open" ? this.openUntil : void 0
7972
+ };
7973
+ }
7974
+ /**
7975
+ * Transition to a new state
7976
+ */
7977
+ transitionTo(newState) {
7978
+ this.state = newState;
7979
+ if (newState === "open") {
7980
+ this.openUntil = Date.now() + this.config.resetTimeoutMs;
7981
+ } else if (newState === "half-open") {
7982
+ this.halfOpenRequests = 0;
7983
+ this.successCount = 0;
7984
+ } else if (newState === "closed") {
7985
+ this.failureCount = 0;
7986
+ this.successCount = 0;
7987
+ this.halfOpenRequests = 0;
7988
+ }
7989
+ }
7363
7990
  };
7364
7991
  async function fetchWithTimeoutAndRetry(fetcher, config) {
7365
7992
  const maxAttempts = config.maxAttempts ?? DEFAULT_RETRY_CONFIG.maxAttempts;
@@ -7481,12 +8108,57 @@ setSdkVersion(SDK_VERSION);
7481
8108
  var DEFAULT_BROWSER_TIMEOUT_MS = 5e3;
7482
8109
  var DEFAULT_SERVER_TIMEOUT_MS = 8e3;
7483
8110
  var MAX_GET_ENTRIES_BY_IDENTIFIERS_REFS = 50;
8111
+ function isDurableRuntimeCacheTier(cacheTier) {
8112
+ return cacheTier === "durable-fresh" || cacheTier === "durable-stale";
8113
+ }
8114
+ function isDegradedResilienceStatus(source, details) {
8115
+ return source === "stale" || source === "error" || isDurableRuntimeCacheTier(details.cacheTier) && details.error !== void 0;
8116
+ }
7484
8117
  function generateRequestId2() {
7485
8118
  return `req-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
7486
8119
  }
7487
8120
  function toRecord(value) {
7488
8121
  return value && typeof value === "object" && !Array.isArray(value) ? value : {};
7489
8122
  }
8123
+ function getRuntimePayloadSiteId(value) {
8124
+ const site = toRecord(value).site;
8125
+ if (!site || typeof site !== "object" || Array.isArray(site)) {
8126
+ return null;
8127
+ }
8128
+ const id = site.id;
8129
+ return typeof id === "string" && id.trim().length > 0 ? id : null;
8130
+ }
8131
+ function getRiverbankErrorInfo(error) {
8132
+ if (error instanceof RiverbankApiError) {
8133
+ return { code: error.code, message: error.message, status: error.status };
8134
+ }
8135
+ if (error instanceof Error) {
8136
+ return { message: error.message };
8137
+ }
8138
+ return { message: String(error) };
8139
+ }
8140
+ function planPublishedRuntimeCache(input) {
8141
+ const policy = resolveRuntimeCachePolicy({
8142
+ endpoint: input.endpoint,
8143
+ method: "GET",
8144
+ params: input.params
8145
+ });
8146
+ if (policy.kind !== "durable-public-stale") {
8147
+ return null;
8148
+ }
8149
+ const keyResult = derivePublishedRuntimeCacheKey(input);
8150
+ if (!keyResult.ok) {
8151
+ return null;
8152
+ }
8153
+ return {
8154
+ cacheKey: keyResult.key,
8155
+ endpoint: keyResult.endpoint,
8156
+ normalizedParams: keyResult.normalizedParams,
8157
+ freshTtlSec: policy.freshTtlSec,
8158
+ staleTtlSec: policy.staleTtlSec,
8159
+ siteId: input.siteId ?? null
8160
+ };
8161
+ }
7490
8162
  function normalizeEntryIdentifierRefs(identifiers) {
7491
8163
  const trimmed = identifiers.map((identifier) => identifier.trim()).filter((identifier) => identifier.length > 0);
7492
8164
  if (trimmed.length === 0) {
@@ -7720,6 +8392,8 @@ function createRiverbankClient(config) {
7720
8392
  source,
7721
8393
  isPreview: details.isPreview,
7722
8394
  cacheKey: details.cacheKey,
8395
+ cacheTier: details.cacheTier,
8396
+ durableCache: details.durableCache,
7723
8397
  error: details.error,
7724
8398
  staleAgeSec: details.staleAgeSec,
7725
8399
  prebuildAgeSec: details.prebuildAgeSec,
@@ -7729,7 +8403,7 @@ function createRiverbankClient(config) {
7729
8403
  };
7730
8404
  lastStatus = status;
7731
8405
  config.resilience?.onStatusChange?.(status);
7732
- const nowDegraded = source === "stale" || source === "error";
8406
+ const nowDegraded = isDegradedResilienceStatus(source, details);
7733
8407
  if (nowDegraded !== isDegraded) {
7734
8408
  isDegraded = nowDegraded;
7735
8409
  config.resilience?.onDegradedMode?.(nowDegraded, status);
@@ -7739,6 +8413,80 @@ function createRiverbankClient(config) {
7739
8413
  resilience: status
7740
8414
  };
7741
8415
  }
8416
+ async function tryPublishedRuntimeCacheFallback(plan, statusDetails, errorInfo) {
8417
+ const reader = config.publishedRuntimeCache?.read;
8418
+ if (!plan || !reader) {
8419
+ return null;
8420
+ }
8421
+ try {
8422
+ const result = await reader({
8423
+ cacheKey: plan.cacheKey,
8424
+ endpoint: plan.endpoint,
8425
+ payloadSchemaVersion: DEFAULT_PUBLISHED_RUNTIME_CACHE_PAYLOAD_SCHEMA_VERSION
8426
+ });
8427
+ if (result.kind === "miss") {
8428
+ return {
8429
+ kind: "miss",
8430
+ diagnostic: {
8431
+ outcome: "miss",
8432
+ reason: result.reason
8433
+ }
8434
+ };
8435
+ }
8436
+ if (result.kind === "error") {
8437
+ return {
8438
+ kind: "error",
8439
+ diagnostic: {
8440
+ outcome: "error",
8441
+ error: result.error
8442
+ }
8443
+ };
8444
+ }
8445
+ return {
8446
+ kind: "hit",
8447
+ result: emitStatus(
8448
+ result.freshness === "fresh" ? "cache" : "stale",
8449
+ result.payload,
8450
+ statusDetails({
8451
+ error: errorInfo,
8452
+ staleAgeSec: result.staleAgeSec,
8453
+ cacheTier: result.freshness === "fresh" ? "durable-fresh" : "durable-stale"
8454
+ })
8455
+ )
8456
+ };
8457
+ } catch (error) {
8458
+ return {
8459
+ kind: "error",
8460
+ diagnostic: {
8461
+ outcome: "error",
8462
+ error: {
8463
+ kind: "adapter_exception",
8464
+ message: error instanceof Error ? error.message : String(error)
8465
+ }
8466
+ }
8467
+ };
8468
+ }
8469
+ }
8470
+ async function writePublishedRuntimeCache(plan, payload) {
8471
+ const writer = config.publishedRuntimeCache?.write;
8472
+ if (!plan || !writer) {
8473
+ return;
8474
+ }
8475
+ try {
8476
+ await writer({
8477
+ cacheKey: plan.cacheKey,
8478
+ endpoint: plan.endpoint,
8479
+ normalizedParams: plan.normalizedParams,
8480
+ payload,
8481
+ siteId: plan.siteId ?? getRuntimePayloadSiteId(payload),
8482
+ freshTtlSec: plan.freshTtlSec,
8483
+ staleTtlSec: plan.staleTtlSec,
8484
+ payloadSchemaVersion: DEFAULT_PUBLISHED_RUNTIME_CACHE_PAYLOAD_SCHEMA_VERSION,
8485
+ writeReason: "live_success"
8486
+ });
8487
+ } catch {
8488
+ }
8489
+ }
7742
8490
  async function resilientFetch(cacheKey, fetcher, options) {
7743
8491
  const requestId = generateRequestId2();
7744
8492
  const startTime = Date.now();
@@ -7754,7 +8502,11 @@ function createRiverbankClient(config) {
7754
8502
  if (cacheEnabled && !options.force) {
7755
8503
  const fresh = cache.getFresh(cacheKey);
7756
8504
  if (fresh !== null) {
7757
- return emitStatus("cache", fresh, statusDetails());
8505
+ return emitStatus(
8506
+ "cache",
8507
+ fresh,
8508
+ statusDetails({ cacheTier: "memory-fresh" })
8509
+ );
7758
8510
  }
7759
8511
  }
7760
8512
  if (resilienceEnabled && circuitBreaker.isOpen()) {
@@ -7766,6 +8518,7 @@ function createRiverbankClient(config) {
7766
8518
  stale.value,
7767
8519
  statusDetails({
7768
8520
  staleAgeSec: stale.staleAgeSec,
8521
+ cacheTier: "memory-stale",
7769
8522
  error: {
7770
8523
  code: "circuit_open",
7771
8524
  message: "Circuit breaker is open"
@@ -7774,6 +8527,15 @@ function createRiverbankClient(config) {
7774
8527
  );
7775
8528
  }
7776
8529
  }
8530
+ const durableFallback = allowFallbacks && !isPreview ? await tryPublishedRuntimeCacheFallback(
8531
+ options.publishedRuntimeCache,
8532
+ statusDetails,
8533
+ { code: "circuit_open", message: "Circuit breaker is open" }
8534
+ ) : null;
8535
+ const durableCache = durableFallback?.kind === "miss" || durableFallback?.kind === "error" ? durableFallback.diagnostic : void 0;
8536
+ if (durableFallback?.kind === "hit") {
8537
+ return durableFallback.result;
8538
+ }
7777
8539
  if (allowFallbacks && !isPreview && options.prebuildFallback) {
7778
8540
  const prebuildResult = options.prebuildFallback();
7779
8541
  if (prebuildResult) {
@@ -7782,6 +8544,8 @@ function createRiverbankClient(config) {
7782
8544
  prebuildResult.data,
7783
8545
  statusDetails({
7784
8546
  prebuildAgeSec: prebuildResult.prebuildAgeSec,
8547
+ cacheTier: "prebuild",
8548
+ durableCache,
7785
8549
  error: {
7786
8550
  code: "circuit_open",
7787
8551
  message: "Circuit breaker is open"
@@ -7795,6 +8559,7 @@ function createRiverbankClient(config) {
7795
8559
  "error",
7796
8560
  null,
7797
8561
  statusDetails({
8562
+ durableCache,
7798
8563
  error: { code: "circuit_open", message: "Circuit breaker is open" }
7799
8564
  })
7800
8565
  );
@@ -7835,6 +8600,9 @@ function createRiverbankClient(config) {
7835
8600
  if (cacheEnabled) {
7836
8601
  cache.set(cacheKey, data);
7837
8602
  }
8603
+ if (allowFallbacks && !isPreview) {
8604
+ await writePublishedRuntimeCache(options.publishedRuntimeCache, data);
8605
+ }
7838
8606
  return emitStatus("live", data, statusDetails());
7839
8607
  } catch (error) {
7840
8608
  if (resilienceEnabled && error instanceof Error) {
@@ -7843,44 +8611,47 @@ function createRiverbankClient(config) {
7843
8611
  if (allowFallbacks && !isPreview && staleIfError && cacheEnabled) {
7844
8612
  const stale = cache.getStale(cacheKey);
7845
8613
  if (stale) {
7846
- const errorInfo2 = error instanceof RiverbankApiError ? {
7847
- code: error.code,
7848
- message: error.message,
7849
- status: error.status
7850
- } : { message: error.message };
8614
+ const errorInfo2 = getRiverbankErrorInfo(error);
7851
8615
  return emitStatus(
7852
8616
  "stale",
7853
8617
  stale.value,
7854
8618
  statusDetails({
7855
8619
  staleAgeSec: stale.staleAgeSec,
8620
+ cacheTier: "memory-stale",
7856
8621
  error: errorInfo2
7857
8622
  })
7858
8623
  );
7859
8624
  }
7860
8625
  }
8626
+ const errorInfo = getRiverbankErrorInfo(error);
8627
+ const durableFallback = allowFallbacks && !isPreview ? await tryPublishedRuntimeCacheFallback(
8628
+ options.publishedRuntimeCache,
8629
+ statusDetails,
8630
+ errorInfo
8631
+ ) : null;
8632
+ const durableCache = durableFallback?.kind === "miss" || durableFallback?.kind === "error" ? durableFallback.diagnostic : void 0;
8633
+ if (durableFallback?.kind === "hit") {
8634
+ return durableFallback.result;
8635
+ }
7861
8636
  if (allowFallbacks && !isPreview && options.prebuildFallback) {
7862
8637
  const prebuildResult = options.prebuildFallback();
7863
8638
  if (prebuildResult) {
7864
- const errorInfo2 = error instanceof RiverbankApiError ? {
7865
- code: error.code,
7866
- message: error.message,
7867
- status: error.status
7868
- } : { message: error.message };
7869
8639
  return emitStatus(
7870
8640
  "prebuild",
7871
8641
  prebuildResult.data,
7872
8642
  statusDetails({
7873
8643
  prebuildAgeSec: prebuildResult.prebuildAgeSec,
7874
- error: errorInfo2
8644
+ cacheTier: "prebuild",
8645
+ durableCache,
8646
+ error: errorInfo
7875
8647
  })
7876
8648
  );
7877
8649
  }
7878
8650
  }
7879
- const errorInfo = error instanceof RiverbankApiError ? { code: error.code, message: error.message, status: error.status } : { message: error.message };
7880
8651
  const failure = emitStatus(
7881
8652
  "error",
7882
8653
  null,
7883
- statusDetails({ error: errorInfo })
8654
+ statusDetails({ error: errorInfo, durableCache })
7884
8655
  );
7885
8656
  throw attachResilienceStatusToError(error, failure.resilience);
7886
8657
  }
@@ -7930,8 +8701,12 @@ function createRiverbankClient(config) {
7930
8701
  );
7931
8702
  }
7932
8703
  const siteIdentifier = slug || domain || id;
7933
- const cacheKey = `site:${siteIdentifier ?? "unknown"}:${currentPath ?? ""}`;
7934
8704
  const siteId = id || slug || domain;
8705
+ const publishedRuntimeCache = planPublishedRuntimeCache({
8706
+ endpoint: "getSite",
8707
+ params: { slug, domain, id, currentPath, force }
8708
+ });
8709
+ const cacheKey = publishedRuntimeCache?.cacheKey ?? `site:${siteIdentifier ?? "unknown"}:${currentPath ?? ""}`;
7935
8710
  return resilientFetch(
7936
8711
  cacheKey,
7937
8712
  async (sig) => {
@@ -7954,13 +8729,19 @@ function createRiverbankClient(config) {
7954
8729
  {
7955
8730
  signal,
7956
8731
  force,
8732
+ publishedRuntimeCache,
7957
8733
  prebuildFallback: prebuildLoader && siteId ? () => prebuildLoader.loadSite(siteId) : void 0
7958
8734
  }
7959
8735
  );
7960
8736
  }
7961
8737
  async function getPageWithResilienceInternal(params) {
7962
8738
  const { siteId, path: path3, preview = false, signal } = params;
7963
- const cacheKey = `page:${siteId}:${path3}:${preview}`;
8739
+ const publishedRuntimeCache = planPublishedRuntimeCache({
8740
+ endpoint: "getContentByPath",
8741
+ params: { siteId, path: path3, preview },
8742
+ siteId
8743
+ });
8744
+ const cacheKey = publishedRuntimeCache?.cacheKey ?? `page:${siteId}:${path3}:${preview}`;
7964
8745
  return resilientFetch(
7965
8746
  cacheKey,
7966
8747
  async (sig) => {
@@ -7973,6 +8754,7 @@ function createRiverbankClient(config) {
7973
8754
  {
7974
8755
  preview,
7975
8756
  signal,
8757
+ publishedRuntimeCache,
7976
8758
  // Prebuild fallback only for published pages (not preview)
7977
8759
  prebuildFallback: prebuildLoader && !preview ? () => prebuildLoader.loadPage(siteId, path3) : void 0
7978
8760
  }
@@ -9106,176 +9888,6 @@ function createPrebuildLoader(config) {
9106
9888
  return new PrebuildLoader(config);
9107
9889
  }
9108
9890
 
9109
- // src/public-api/runtime.ts
9110
- var API_ENDPOINTS2 = Object.freeze({
9111
- getSite: {
9112
- path: "/sites",
9113
- method: "GET",
9114
- revalidate: 900,
9115
- tags: ["riverbank:site", "riverbank:site:id:{id}", "riverbank:site:slug:{slug}", "riverbank:site:domain:{domain}"],
9116
- auth: "public",
9117
- responseKind: "json"
9118
- },
9119
- getContentByPath: {
9120
- path: "/sites/{siteId}/pages",
9121
- method: "GET",
9122
- tags: ["riverbank:site:{siteId}:routable-content"],
9123
- auth: "public",
9124
- responseKind: "json"
9125
- },
9126
- listPublishedEntries: {
9127
- path: "/public/content/{siteId}/{type}/entries",
9128
- method: "GET",
9129
- revalidate: 60,
9130
- tags: ["content-{siteId}-{type}"],
9131
- auth: "public",
9132
- responseKind: "json"
9133
- },
9134
- getPublishedEntryPreview: {
9135
- path: "/public/content/{siteId}/{type}/{slug}/preview",
9136
- method: "GET",
9137
- revalidate: 60,
9138
- tags: ["content-{siteId}-{type}-{slug}"],
9139
- auth: "public",
9140
- responseKind: "json"
9141
- },
9142
- getPublicFormById: {
9143
- path: "/public/forms/{formId}",
9144
- method: "GET",
9145
- revalidate: 60,
9146
- tags: ["riverbank:form:{formId}"],
9147
- auth: "public",
9148
- responseKind: "json"
9149
- },
9150
- listPublicForms: {
9151
- path: "/public/sites/{siteId}/forms",
9152
- method: "GET",
9153
- revalidate: 60,
9154
- tags: ["riverbank:site:{siteId}:forms"],
9155
- auth: "public",
9156
- responseKind: "json"
9157
- },
9158
- getPublicBookingServices: {
9159
- path: "/public/bookings/services",
9160
- method: "GET",
9161
- revalidate: 60,
9162
- tags: ["site-{siteId}"],
9163
- auth: "public",
9164
- responseKind: "json"
9165
- },
9166
- getPublicChallenge: {
9167
- path: "/public/challenge",
9168
- method: "GET",
9169
- auth: "public",
9170
- responseKind: "text"
9171
- },
9172
- listPublicEvents: {
9173
- path: "/public/sites/{siteId}/events",
9174
- method: "GET",
9175
- revalidate: 60,
9176
- tags: ["riverbank:site:{siteId}:public-events"],
9177
- auth: "public",
9178
- responseKind: "json"
9179
- },
9180
- batchBlockLoaders: {
9181
- path: "/public/sites/{siteId}/block-loaders/batch",
9182
- method: "POST",
9183
- auth: "public",
9184
- responseKind: "json"
9185
- },
9186
- listPublicCourses: {
9187
- path: "/public/sites/{siteId}/courses",
9188
- method: "GET",
9189
- revalidate: 60,
9190
- tags: ["riverbank:site:{siteId}:public-courses"],
9191
- auth: "public",
9192
- responseKind: "json"
9193
- },
9194
- listPublicTeamMembers: {
9195
- path: "/public/sites/{siteId}/team-members",
9196
- method: "GET",
9197
- revalidate: 60,
9198
- tags: ["riverbank:site:{siteId}:public-team-members"],
9199
- auth: "public",
9200
- responseKind: "json"
9201
- },
9202
- listPublicProducts: {
9203
- path: "/public/sites/{siteId}/products",
9204
- method: "GET",
9205
- revalidate: 300,
9206
- tags: ["riverbank:site:{siteId}:public-products"],
9207
- auth: "public",
9208
- responseKind: "json"
9209
- },
9210
- listPublicPasses: {
9211
- path: "/public/sites/{siteId}/bookings/products/passes",
9212
- method: "GET",
9213
- revalidate: 300,
9214
- tags: ["riverbank:site:{siteId}:public-passes"],
9215
- auth: "public",
9216
- responseKind: "json"
9217
- },
9218
- listPublicMemberships: {
9219
- path: "/public/sites/{siteId}/bookings/products/memberships",
9220
- method: "GET",
9221
- revalidate: 300,
9222
- tags: ["riverbank:site:{siteId}:public-memberships"],
9223
- auth: "public",
9224
- responseKind: "json"
9225
- },
9226
- resolveEntrySubroute: {
9227
- path: "/public/sites/{siteId}/routing/subroutes/resolve",
9228
- method: "GET",
9229
- revalidate: 60,
9230
- tags: ["site-{siteId}", "entry-subroute"],
9231
- auth: "public",
9232
- responseKind: "json"
9233
- },
9234
- resolveEventOccurrence: {
9235
- path: "/public/sites/{siteId}/events/occurrences/resolve",
9236
- method: "GET",
9237
- revalidate: 60,
9238
- tags: ["riverbank:site:{siteId}:public-events", "event-occurrence"],
9239
- auth: "public",
9240
- responseKind: "json"
9241
- },
9242
- checkRedirect: {
9243
- path: "/public/content/redirect",
9244
- method: "GET",
9245
- revalidate: 86400,
9246
- tags: ["redirect"],
9247
- auth: "public",
9248
- responseKind: "json"
9249
- },
9250
- getRoutableContent: {
9251
- path: "/sites/{siteId}/routable-content",
9252
- method: "GET",
9253
- revalidate: 60,
9254
- tags: ["riverbank:site:{siteId}:routable-content"],
9255
- auth: "user",
9256
- responseKind: "json"
9257
- },
9258
- getPublicRoutableContent: {
9259
- path: "/public/sites/{siteId}/routable-content",
9260
- method: "GET",
9261
- revalidate: 60,
9262
- tags: ["riverbank:site:{siteId}:routable-content"],
9263
- auth: "public",
9264
- responseKind: "json"
9265
- },
9266
- getPublicSitemapRoutes: {
9267
- path: "/public/sites/{siteId}/sitemap",
9268
- method: "GET",
9269
- revalidate: 60,
9270
- tags: ["riverbank:site:{siteId}:routable-content", "riverbank:site:{siteId}:settings"],
9271
- auth: "public",
9272
- responseKind: "json"
9273
- }
9274
- });
9275
- function buildEndpointURL2(baseURL, endpoint) {
9276
- return baseURL + API_ENDPOINTS2[endpoint].path;
9277
- }
9278
-
9279
9891
  // src/types/block-kinds.ts
9280
9892
  var SYSTEM_BLOCK_KINDS = [
9281
9893
  // Layout blocks
@@ -9329,14 +9941,23 @@ var SYSTEM_BLOCK_KINDS = [
9329
9941
  ];
9330
9942
  export {
9331
9943
  API_ENDPOINTS2 as API_ENDPOINTS,
9944
+ DEFAULT_PUBLISHED_RUNTIME_CACHE_PAYLOAD_SCHEMA_VERSION,
9332
9945
  PrebuildLoader,
9333
9946
  RiverbankApiError,
9334
9947
  SDK_CORRELATION_HEADER_NAMES,
9335
9948
  SYSTEM_BLOCK_KINDS,
9336
9949
  buildEndpointURL2 as buildEndpointURL,
9337
9950
  canUsePrebuild,
9951
+ classifyPublishedRuntimeCacheFreshness,
9338
9952
  createPrebuildLoader,
9339
9953
  createRiverbankClient,
9954
+ derivePublishedRuntimeCacheKey,
9340
9955
  getResilienceStatusFromError,
9341
- prebuildCache
9956
+ isPublishedRuntimeCacheKeyEndpoint,
9957
+ normalizeRuntimePublicPath,
9958
+ parsePublishedRuntimeCacheKey,
9959
+ parsePublishedRuntimeCacheKeyDetails,
9960
+ parsePublishedRuntimeCachePayloadSchemaVersion,
9961
+ prebuildCache,
9962
+ resolveRuntimeCachePolicy
9342
9963
  };