@riverbankcms/sdk 0.107.0 → 0.108.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 (159) hide show
  1. package/dist/{PreviewEditorSidebar-DpAbAl08.mjs → PreviewEditorSidebar-BBT-kZAM.mjs} +46 -11
  2. package/dist/{PreviewEditorUI-O7cn6Xxv.mjs → PreviewEditorUI-D69xNKT2.mjs} +10 -9
  3. package/dist/{PreviewQueryProvider-D0tnKl0t.mjs → PreviewQueryProvider-RRu7wyQ5.mjs} +1 -1
  4. package/dist/{SdkPreviewModeRuntime-CVB7urtl.mjs → SdkPreviewModeRuntime-CuDjXH6o.mjs} +426 -72
  5. package/dist/{SiteChromeCustomizeContext-C_sizso-.mjs → SiteChromeCustomizeContext-BQUY2dEk.mjs} +3865 -544
  6. package/dist/_dts/ai/src/contracts/proposals.d.ts +3712 -220
  7. package/dist/_dts/api/src/blocks.d.ts +41 -7
  8. package/dist/_dts/api/src/bookingRecords.d.ts +180 -115
  9. package/dist/_dts/api/src/cache-tags.d.ts +3 -0
  10. package/dist/_dts/api/src/contentRuntime.d.ts +19 -1
  11. package/dist/_dts/api/src/endpoints.d.ts +99 -0
  12. package/dist/_dts/api/src/footer-settings.d.ts +1 -0
  13. package/dist/_dts/api/src/footerSettings.d.ts +8 -0
  14. package/dist/_dts/api/src/index.d.ts +5 -2
  15. package/dist/_dts/api/src/navigation/contracts.d.ts +3 -3
  16. package/dist/_dts/api/src/previewContentContract.d.ts +4 -0
  17. package/dist/_dts/api/src/sdkContracts.d.ts +62 -0
  18. package/dist/_dts/api/src/siteBanner.d.ts +2 -2
  19. package/dist/_dts/api/src/siteManagementEndpoints.d.ts +143 -55
  20. package/dist/_dts/api/src/sitePlatformEndpoints.d.ts +7 -1
  21. package/dist/_dts/api/src/siteRuntimeEndpoints.d.ts +41 -1
  22. package/dist/_dts/blocks/src/primitives/layout/Section.d.ts +0 -1
  23. package/dist/_dts/blocks/src/rendering/server.d.ts +1 -0
  24. package/dist/_dts/blocks/src/system/blocks/site-footer-runtime.d.ts +50 -0
  25. package/dist/_dts/blocks/src/system/blocks/site-footer.d.ts +9 -48
  26. package/dist/_dts/blocks/src/system/constants/background.d.ts +1 -1
  27. package/dist/_dts/blocks/src/system/icons/registry.d.ts +2 -1
  28. package/dist/_dts/blocks/src/system/icons/social.d.ts +5 -0
  29. package/dist/_dts/blocks/src/system/icons/svg.d.ts +1 -0
  30. package/dist/_dts/blocks/src/system/manifest/schema.d.ts +2 -2
  31. package/dist/_dts/blocks/src/system/node/fragments/backgroundLayer.d.ts +13 -0
  32. package/dist/_dts/blocks/src/system/node/fragments/footerNav.d.ts +2 -0
  33. package/dist/_dts/blocks/src/system/node/fragments/styledContainer.d.ts +4 -4
  34. package/dist/_dts/blocks/src/system/node/fragments/styledSection.d.ts +3 -12
  35. package/dist/_dts/blocks/src/system/node/validation-constants.d.ts +1 -1
  36. package/dist/_dts/blocks/src/system/runtime/nodes/shared/contract-schemas.d.ts +1 -1
  37. package/dist/_dts/blocks/src/system/types/link.d.ts +3 -3
  38. package/dist/_dts/content-editor/src/FooterComposerPanel.d.ts +14 -0
  39. package/dist/_dts/content-editor/src/controller/EntryControllerProvider.d.ts +27 -8
  40. package/dist/_dts/content-editor/src/footerComposer.d.ts +56 -0
  41. package/dist/_dts/content-editor/src/hooks/useEntryActions.d.ts +1 -1
  42. package/dist/_dts/content-editor/src/hooks/useEntryMutations.d.ts +5 -5
  43. package/dist/_dts/content-editor/src/index.d.ts +2 -0
  44. package/dist/_dts/content-editor/src/primitives/PreviewRichTextEditor.d.ts +3 -1
  45. package/dist/_dts/content-editor/src/services/contentEntryServices.d.ts +20 -36
  46. package/dist/_dts/content-editor/src/ui/editorSnapshot.d.ts +5 -1
  47. package/dist/_dts/content-editor/src/ui/editorUiStore.d.ts +11 -0
  48. package/dist/_dts/content-model/src/content-types/schema.d.ts +1 -1
  49. package/dist/_dts/content-model/src/definitions/shared.d.ts +3 -0
  50. package/dist/_dts/core/src/branded.d.ts +3 -0
  51. package/dist/_dts/core/src/editor-state.d.ts +4 -0
  52. package/dist/_dts/core/src/footer-composition.d.ts +143 -0
  53. package/dist/_dts/core/src/index.d.ts +2 -0
  54. package/dist/_dts/core/src/public-profile.d.ts +73 -0
  55. package/dist/_dts/db/src/generated/supabase/database.types.d.ts +3043 -2941
  56. package/dist/_dts/db/src/schemas/forms.d.ts +10 -10
  57. package/dist/_dts/editor/src/primitives/rich-text/RichTextEditorSurface.d.ts +5 -0
  58. package/dist/_dts/editor-blocks/src/BlockEditor.d.ts +1 -0
  59. package/dist/_dts/editor-blocks/src/block-editor/hooks/useBlockCreation.d.ts +2 -1
  60. package/dist/_dts/editor-blocks/src/block-editor/hooks/useBlockDuplication.d.ts +2 -1
  61. package/dist/_dts/editor-blocks/src/block-editor/hooks/useBlockReorder.d.ts +2 -1
  62. package/dist/_dts/editor-blocks/src/block-editor/owner.d.ts +10 -0
  63. package/dist/_dts/editor-blocks/src/block-editor/types.d.ts +1 -0
  64. package/dist/_dts/path-utils/src/index.d.ts +5 -0
  65. package/dist/_dts/preview-next/src/client/preview/PreviewChromeLayer.d.ts +5 -0
  66. package/dist/_dts/preview-next/src/client/preview/PreviewEditorSidebar.d.ts +2 -1
  67. package/dist/_dts/preview-next/src/client/preview/PreviewEntryControllerProvider.d.ts +1 -0
  68. package/dist/_dts/preview-next/src/client/preview/PreviewShell.d.ts +2 -1
  69. package/dist/_dts/preview-next/src/client/preview/PreviewShellLayout.d.ts +2 -1
  70. package/dist/_dts/preview-next/src/client/preview/previewErrorMessages.d.ts +4 -0
  71. package/dist/_dts/sdk/src/cli/content/reader.d.ts +1 -0
  72. package/dist/_dts/sdk/src/client/management/blocks.d.ts +14 -1
  73. package/dist/_dts/sdk/src/client/management/index.d.ts +1 -0
  74. package/dist/_dts/sdk/src/client/management/types.d.ts +15 -1
  75. package/dist/_dts/sdk/src/config/content-types.d.ts +2 -0
  76. package/dist/_dts/sdk/src/config/content-validation.d.ts +4 -0
  77. package/dist/_dts/sdk/src/navigation/index.d.ts +2 -0
  78. package/dist/_dts/sdk/src/public-api/contracts.d.ts +3 -2
  79. package/dist/_dts/sdk/src/rendering/components/Layout.d.ts +2 -1
  80. package/dist/_dts/sdk/src/rendering/helpers/loadContent.d.ts +1 -1
  81. package/dist/_dts/sdk/src/version.d.ts +1 -1
  82. package/dist/_dts/site-commands/src/commands.d.ts +13 -10
  83. package/dist/_dts/theme-core/src/accordions/types.d.ts +2 -2
  84. package/dist/_dts/theme-core/src/buttons/personalities/index.d.ts +11 -0
  85. package/dist/_dts/theme-core/src/buttons/personalities/two-tone-pill.d.ts +17 -0
  86. package/dist/_dts/theme-core/src/buttons/personalities/types.d.ts +1 -1
  87. package/dist/_dts/theme-core/src/buttons/types.d.ts +3 -3
  88. package/dist/_dts/theme-core/src/cards/types.d.ts +3 -3
  89. package/dist/_dts/theme-core/src/footer/mode.d.ts +15 -0
  90. package/dist/_dts/theme-core/src/generated/containerResponsiveThemeCss.d.ts +1 -1
  91. package/dist/_dts/theme-core/src/interactive/baseSchema.d.ts +1 -1
  92. package/dist/_dts/theme-core/src/mock-themes/all.d.ts +36 -30
  93. package/dist/_dts/theme-core/src/navigation/types.d.ts +1 -1
  94. package/dist/_dts/theme-core/src/schema.d.ts +1186 -34
  95. package/dist/_dts/theme-core/src/site-styles/headerLooks.d.ts +12 -1
  96. package/dist/_dts/theme-core/src/site-styles/siteChromeNavPreferences.d.ts +15 -0
  97. package/dist/cli/index.mjs +760 -374
  98. package/dist/client/{DiscountCodeDisclosure-BwGkvmVH.mjs → DiscountCodeDisclosure-D6TOf6Hi.mjs} +1 -1
  99. package/dist/client/{EventCombined.client-JnWE6Hzc.mjs → EventCombined.client-Dao3zxRk.mjs} +3 -3
  100. package/dist/client/{EventListing.client-DQewc_kg.mjs → EventListing.client-B2NNt4y1.mjs} +2 -2
  101. package/dist/client/{LeafletStaticMap-DPAU3SFt.mjs → LeafletStaticMap-BhwFo16w.mjs} +1 -1
  102. package/dist/client/{MagicLinkForm-D4kpWCbW.mjs → MagicLinkForm-BWnB7cMR.mjs} +2 -2
  103. package/dist/client/{StepIndicator-CBlkb4rA.mjs → StepIndicator-TzRiQ0BY.mjs} +2 -2
  104. package/dist/client/{accordion-DAIBVpTS.mjs → accordion-BPy-AJ4_.mjs} +1 -1
  105. package/dist/client/{bookingForm-DZ-4l5_1.mjs → bookingForm-BL4PGZds.mjs} +6 -6
  106. package/dist/client/bookings.mjs +143 -94
  107. package/dist/client/{buttons-DJgynGHQ.mjs → buttons-EBjyslaX.mjs} +144 -95
  108. package/dist/client/{carousel-D-SLfX8r.mjs → carousel-C2b7Cn9-.mjs} +1 -1
  109. package/dist/client/{cart-CEgbgJhX.mjs → cart-BQcbXIVD.mjs} +3 -3
  110. package/dist/client/{checkout-CXWrCRAA.mjs → checkout-DEmpGRJu.mjs} +3 -3
  111. package/dist/client/client.mjs +827 -434
  112. package/dist/client/{courseRegistration-DVmLrRVz.mjs → courseRegistration-BqRZPmsq.mjs} +7 -7
  113. package/dist/client/{eventCalendar-DCuyPY_c.mjs → eventCalendar-B8N_tSl5.mjs} +5 -5
  114. package/dist/client/{eventCombined-kP2CA2D4.mjs → eventCombined-Gjn6gtq7.mjs} +2 -2
  115. package/dist/client/{eventDetails-DU0LeF5e.mjs → eventDetails-M-VCxA-r.mjs} +3 -3
  116. package/dist/client/{eventListing-CcHF87BI.mjs → eventListing-DR19hqYi.mjs} +2 -2
  117. package/dist/client/{eventRegistration-DJnR0yFH.mjs → eventRegistration-BR02a0k3.mjs} +7 -7
  118. package/dist/client/{form-CH1lCusH.mjs → form-LY2xIbwg.mjs} +2 -2
  119. package/dist/client/{headerSection-CBPFZoku.mjs → headerSection-CYwwXJfh.mjs} +3 -3
  120. package/dist/client/hooks.mjs +377 -362
  121. package/dist/client/{locationMap-Cx1hBg5n.mjs → locationMap-DWnBXrFq.mjs} +2 -2
  122. package/dist/client/{newsletterForm-1ZL_ti9u.mjs → newsletterForm-D9s-fQ2P.mjs} +2 -2
  123. package/dist/client/{pricing-BIbzmV0G.mjs → pricing-DDq80oYc.mjs} +1 -1
  124. package/dist/client/{productDetail-BTh5gHBV.mjs → productDetail-B0SbWd45.mjs} +3 -3
  125. package/dist/client/{productList-Cc7OMrqN.mjs → productList-PwYlZn0y.mjs} +3 -3
  126. package/dist/client/{propsDecoder-oR-M-ISN.mjs → propsDecoder-BRWBiH7i.mjs} +33 -9
  127. package/dist/client/rendering/client.mjs +247 -40
  128. package/dist/client/rendering/islands.mjs +18 -18
  129. package/dist/client/rendering.mjs +478 -270
  130. package/dist/client/{shop-CQ_YbCnn.mjs → shop-CMwZPYME.mjs} +6 -6
  131. package/dist/client/{shop-commerce-BM-AoD3M.mjs → shop-commerce-BuxsFate.mjs} +5 -5
  132. package/dist/client/{shop-commerce-store-DFMQhU5p.mjs → shop-commerce-store-boYlEJ91.mjs} +1 -1
  133. package/dist/client/{shopShared-D0SKO2Cu.mjs → shopShared-D2naaOes.mjs} +2 -2
  134. package/dist/client/{useDiscountCodeUi-CrG4_ARt.mjs → useDiscountCodeUi-D9RHpVoj.mjs} +1 -1
  135. package/dist/client/{useEventFilters-CxK8Fekl.mjs → useEventFilters-igGiK1re.mjs} +3 -3
  136. package/dist/client/{usePolling-jcVryNgZ.mjs → usePolling-CI7MbsFB.mjs} +2 -2
  137. package/dist/preview-next/before-render.mjs +178 -0
  138. package/dist/preview-next/client/runtime.mjs +4 -4
  139. package/dist/preview-next/middleware.mjs +178 -0
  140. package/dist/{previewAuthStore-BPcJPzdz.mjs → previewAuthStore-a_cBD28m.mjs} +178 -0
  141. package/dist/{sdk-runtime-C39Rsk-x.mjs → sdk-runtime-MBzD-GmP.mjs} +2 -2
  142. package/dist/{separator-BoMSQnsP.mjs → separator-5ahRBC85.mjs} +1 -1
  143. package/dist/server/components.mjs +556 -366
  144. package/dist/server/config-validation.mjs +384 -363
  145. package/dist/server/config.mjs +384 -364
  146. package/dist/server/data.mjs +377 -362
  147. package/dist/server/index.mjs +179 -1
  148. package/dist/server/navigation.mjs +9 -3
  149. package/dist/server/next.mjs +1384 -995
  150. package/dist/server/page-converter.mjs +368 -355
  151. package/dist/server/prebuild.mjs +1 -1
  152. package/dist/server/rendering/server.mjs +539 -360
  153. package/dist/server/rendering.mjs +556 -366
  154. package/dist/server/routing.mjs +613 -543
  155. package/dist/server/server.mjs +554 -361
  156. package/dist/server/theme-bridge.mjs +189 -98
  157. package/dist/server/theme.mjs +161 -95
  158. package/dist/styles/index.css +7 -1
  159. package/package.json +1 -1
@@ -1,11 +1,11 @@
1
1
  import { createRequire } from "node:module";
2
2
  import { notFound, permanentRedirect, redirect } from "next/navigation";
3
3
  import { cookies } from "next/headers";
4
- import { BlocksIslandsHydrator } from "#sdk-rendering-client";
5
4
  import z, { z as z$1 } from "zod";
6
5
  import * as React$1 from "react";
7
6
  import React, { forwardRef } from "react";
8
7
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
8
+ import { BlocksIslandsHydrator } from "#sdk-rendering-client";
9
9
  //#region \0rolldown/runtime.js
10
10
  var __commonJSMin = (cb, mod) => () => (mod || (cb((mod = { exports: {} }).exports, mod), cb = null), mod.exports);
11
11
  var __require = /* #__PURE__ */ (() => createRequire(import.meta.url))();
@@ -40,529 +40,13 @@ function isPreviewMode() {
40
40
  return detectPreviewMode();
41
41
  }
42
42
  //#endregion
43
- //#region src/portal/constants.ts
44
- /**
45
- * Portal Authentication Constants
46
- */
47
- /** Cookie name for storing the portal session token */
48
- const PORTAL_TOKEN_COOKIE = "portal_token";
49
- //#endregion
50
- //#region ../path-utils/src/index.ts
51
- const PATH_SEPARATOR_REGEX$1 = /\./g;
52
- const BRACKET_ACCESS_REGEX$1 = /\[([^\]]+)\]/g;
53
- function isRecord$32(value) {
54
- return typeof value === "object" && value !== null && !Array.isArray(value);
55
- }
56
- function isPathContainer(value) {
57
- return Array.isArray(value) || isRecord$32(value);
58
- }
59
- function getContainerValue(container, segment) {
60
- if (typeof segment === "number") return Array.isArray(container) ? container[segment] : void 0;
61
- if (segment in container) return Reflect.get(container, segment);
62
- }
63
- function parsePath(path) {
64
- if (Array.isArray(path)) return path;
65
- const segments = [];
66
- const parts = path.split(PATH_SEPARATOR_REGEX$1);
67
- for (const raw of parts) {
68
- if (!raw) continue;
69
- const baseMatch = raw.match(/^[^\[]+/);
70
- if (baseMatch !== null) {
71
- const base = baseMatch[1] ?? baseMatch[0];
72
- if (/^\d+$/.test(base)) segments.push(Number(base));
73
- else segments.push(base);
74
- }
75
- const bracketMatches = raw.matchAll(BRACKET_ACCESS_REGEX$1);
76
- for (const match of bracketMatches) {
77
- const token = match[1] ?? "";
78
- if (token.startsWith("\"") || token.startsWith("'")) segments.push(token.slice(1, -1));
79
- else if (/^\d+$/.test(token)) segments.push(Number(token));
80
- else segments.push(token);
81
- }
82
- if (baseMatch === null && !raw.includes("[")) segments.push(raw);
83
- }
84
- return segments;
85
- }
86
- function getAtPath(source, path) {
87
- return parsePath(path).reduce((current, segment) => {
88
- if (current === void 0 || current === null) return void 0;
89
- if (!isPathContainer(current)) return void 0;
90
- return getContainerValue(current, segment);
91
- }, source);
92
- }
93
- //#endregion
94
- //#region src/portal/token.ts
95
- /**
96
- * Portal Token Utilities
97
- *
98
- * Provides functions for reading the portal token from cookies
99
- * in server components.
100
- *
101
- * Usage:
102
- * ```ts
103
- * import { getPortalToken } from '@riverbankcms/sdk/portal';
104
- * import { cookies } from 'next/headers';
105
- *
106
- * export default async function PortalPage() {
107
- * const cookieStore = await cookies();
108
- * const token = getPortalToken(cookieStore);
109
- *
110
- * if (!token) {
111
- * return <LoginForm />;
112
- * }
113
- *
114
- * return <CustomerPortal token={token} />;
115
- * }
116
- * ```
117
- */
118
- /**
119
- * Get the portal token from the cookie store.
120
- *
121
- * @param cookieStore - The cookie store from `await cookies()`
122
- * @returns The portal token, or null if not present
123
- */
124
- function getPortalToken(cookieStore) {
125
- return cookieStore.get(PORTAL_TOKEN_COOKIE)?.value ?? null;
126
- }
127
- //#endregion
128
- //#region src/data/defineOwnDataProperty.ts
129
- /** Define a string key as ordinary data without invoking legacy prototype setters. */
130
- function defineOwnDataProperty(target, key, value) {
131
- Object.defineProperty(target, key, {
132
- value,
133
- enumerable: true,
134
- configurable: true,
135
- writable: true
136
- });
137
- }
138
- //#endregion
139
- //#region src/data/dataLoaderContext.ts
140
- function assertNever$26(value) {
141
- throw new Error(`Unhandled data loader render target: ${String(value)}`);
142
- }
143
- function getDataLoaderOwnerPageId(target) {
144
- switch (target.kind) {
145
- case "page": return target.pageId;
146
- case "entry-template":
147
- case "page-surface-template": return target.templateId;
148
- default: return assertNever$26(target);
149
- }
150
- }
151
- function normalizeDataLoaderSearchParams(input) {
152
- if (!input) return Object.freeze({});
153
- const normalized = {};
154
- for (const [key, value] of Object.entries(input)) defineOwnDataProperty(normalized, key, value === void 0 || typeof value === "string" ? value : Object.freeze([...value]));
155
- return Object.freeze(normalized);
156
- }
157
- function resolveDataLoaderBlockContent(block, previewStage) {
158
- if (previewStage === "preview" && block.draftContent) return block.draftContent;
159
- return block.content ?? {};
160
- }
161
- function createDataLoaderContext(input) {
43
+ //#region ../api/src/apiEndpointTypes.ts
44
+ function allowedDemoMutationPolicy() {
162
45
  return {
163
- siteId: input.siteId,
164
- pageId: getDataLoaderOwnerPageId(input.renderTarget),
165
- blockId: input.blockId,
166
- blockKind: input.blockKind,
167
- content: input.content,
168
- previewStage: input.previewStage,
169
- searchParams: input.searchParams,
170
- renderTarget: input.renderTarget
46
+ classification: "allowed",
47
+ publicMessage: ""
171
48
  };
172
49
  }
173
- //#endregion
174
- //#region src/types/block-kinds.ts
175
- /**
176
- * System block kind identifiers.
177
- *
178
- * SDK-owned copy of the system block kind list.
179
- *
180
- * Rationale: SDK consumers must be able to typecheck without installing
181
- * `@riverbankcms/blocks` (which is not a public dependency). This list is a
182
- * stable public contract; keep it in sync with the internal blocks runtime.
183
- */
184
- const SYSTEM_BLOCK_KINDS$1 = [
185
- "block.hero",
186
- "block.intro",
187
- "block.columns",
188
- "block.collection",
189
- "block.feature-cards",
190
- "block.media-text",
191
- "block.cta-full",
192
- "block.single-button",
193
- "block.body-text",
194
- "block.location-map",
195
- "block.faq",
196
- "block.testimonials",
197
- "block.team-members",
198
- "block.embed",
199
- "block.blog-post",
200
- "block.blog-listing",
201
- "block.site-header",
202
- "block.site-footer",
203
- "block.form",
204
- "block.contact-newsletter",
205
- "block.appointment-booking",
206
- "block.weekly-slot-availability",
207
- "block.event-registration",
208
- "block.event-details",
209
- "block.course-registration",
210
- "block.course-details",
211
- "block.event-spotlight",
212
- "block.event-listing",
213
- "block.event-calendar",
214
- "block.recurring-schedule",
215
- "block.offerings-preview",
216
- "block.shop",
217
- "block.product-list",
218
- "block.product-detail",
219
- "block.cart",
220
- "block.checkout",
221
- "block.gifting",
222
- "block.newsletter-signup",
223
- "block.image-gallery",
224
- "block.video-grid",
225
- "block.audio-player",
226
- "block.file-download"
227
- ];
228
- //#endregion
229
- //#region src/data/dataLoaderValue.ts
230
- const MAX_DATA_LOADER_VALUE_NODES = 1e4;
231
- const MAX_DATA_LOADER_VALUE_DEPTH = 100;
232
- function failure(issue) {
233
- return {
234
- ok: false,
235
- issue
236
- };
237
- }
238
- function inspectArray(value) {
239
- try {
240
- if (Object.getPrototypeOf(value) !== Array.prototype) return {
241
- ok: false,
242
- issue: { kind: "non-plain-object" }
243
- };
244
- const descriptors = Object.getOwnPropertyDescriptors(value);
245
- const ownKeys = Reflect.ownKeys(descriptors);
246
- if (ownKeys.some((key) => typeof key === "symbol")) return {
247
- ok: false,
248
- issue: { kind: "symbol-key" }
249
- };
250
- const lengthDescriptor = descriptors.length;
251
- if (!lengthDescriptor || !("value" in lengthDescriptor) || typeof lengthDescriptor.value !== "number") return {
252
- ok: false,
253
- issue: { kind: "invalid-array" }
254
- };
255
- const length = lengthDescriptor.value;
256
- if (!Number.isSafeInteger(length) || length < 0 || length > MAX_DATA_LOADER_VALUE_NODES) return {
257
- ok: false,
258
- issue: { kind: "complexity-limit-exceeded" }
259
- };
260
- const children = [];
261
- for (const key of ownKeys) {
262
- if (key === "length") continue;
263
- if (typeof key !== "string" || !/^(0|[1-9]\d*)$/.test(key)) return {
264
- ok: false,
265
- issue: { kind: "invalid-array" }
266
- };
267
- const index = Number(key);
268
- if (!Number.isSafeInteger(index) || index < 0 || index >= length) return {
269
- ok: false,
270
- issue: { kind: "invalid-array" }
271
- };
272
- const descriptor = descriptors[key];
273
- if (!descriptor || !descriptor.enumerable || !("value" in descriptor)) return {
274
- ok: false,
275
- issue: { kind: "accessor-property" }
276
- };
277
- }
278
- for (let index = 0; index < length; index += 1) {
279
- const descriptor = descriptors[String(index)];
280
- if (!descriptor || !descriptor.enumerable || !("value" in descriptor)) return {
281
- ok: false,
282
- issue: { kind: "invalid-array" }
283
- };
284
- children.push({
285
- key: String(index),
286
- value: descriptor.value
287
- });
288
- }
289
- return {
290
- ok: true,
291
- containerKind: "array",
292
- length,
293
- children
294
- };
295
- } catch {
296
- return {
297
- ok: false,
298
- issue: { kind: "inspection-failed" }
299
- };
300
- }
301
- }
302
- function inspectPlainObject(value) {
303
- try {
304
- if (Object.getPrototypeOf(value) !== Object.prototype) return {
305
- ok: false,
306
- issue: { kind: "non-plain-object" }
307
- };
308
- const descriptors = Object.getOwnPropertyDescriptors(value);
309
- const ownKeys = Reflect.ownKeys(descriptors);
310
- if (ownKeys.length > MAX_DATA_LOADER_VALUE_NODES) return {
311
- ok: false,
312
- issue: { kind: "complexity-limit-exceeded" }
313
- };
314
- if (ownKeys.some((key) => typeof key === "symbol")) return {
315
- ok: false,
316
- issue: { kind: "symbol-key" }
317
- };
318
- const children = [];
319
- for (const key of ownKeys) {
320
- if (typeof key !== "string") return {
321
- ok: false,
322
- issue: { kind: "symbol-key" }
323
- };
324
- const descriptor = descriptors[key];
325
- if (!descriptor || !descriptor.enumerable || !("value" in descriptor)) return {
326
- ok: false,
327
- issue: { kind: "accessor-property" }
328
- };
329
- children.push({
330
- key,
331
- value: descriptor.value
332
- });
333
- }
334
- return {
335
- ok: true,
336
- containerKind: "object",
337
- children
338
- };
339
- } catch {
340
- return {
341
- ok: false,
342
- issue: { kind: "inspection-failed" }
343
- };
344
- }
345
- }
346
- /**
347
- * Validates and snapshots arbitrary loader output without invoking getters,
348
- * setters, or conversion hooks. Reflection failures are returned as data,
349
- * never thrown, and accepted containers are detached and frozen.
350
- */
351
- function validateDataLoaderValue(input) {
352
- const pending = [{
353
- kind: "visit",
354
- value: input,
355
- depth: 0,
356
- target: { kind: "root" }
357
- }];
358
- const activeAncestors = /* @__PURE__ */ new WeakSet();
359
- let validatedRoot = null;
360
- let visitedNodes = 0;
361
- const assignOutput = (target, value) => {
362
- switch (target.kind) {
363
- case "root":
364
- validatedRoot = value;
365
- return;
366
- case "object-property":
367
- defineOwnDataProperty(target.parent, target.key, value);
368
- return;
369
- case "array-index":
370
- target.parent[target.index] = value;
371
- return;
372
- }
373
- };
374
- while (pending.length > 0) {
375
- const next = pending.pop();
376
- if (!next) continue;
377
- if (next.kind === "leave") {
378
- activeAncestors.delete(next.source);
379
- Object.freeze(next.output);
380
- continue;
381
- }
382
- visitedNodes += 1;
383
- if (visitedNodes > MAX_DATA_LOADER_VALUE_NODES || next.depth > MAX_DATA_LOADER_VALUE_DEPTH) return failure({ kind: "complexity-limit-exceeded" });
384
- let objectValue;
385
- switch (typeof next.value) {
386
- case "undefined": return failure({
387
- kind: "unsupported-type",
388
- valueType: "undefined"
389
- });
390
- case "bigint": return failure({
391
- kind: "unsupported-type",
392
- valueType: "bigint"
393
- });
394
- case "symbol": return failure({
395
- kind: "unsupported-type",
396
- valueType: "symbol"
397
- });
398
- case "function": return failure({
399
- kind: "unsupported-type",
400
- valueType: "function"
401
- });
402
- case "string":
403
- case "boolean":
404
- assignOutput(next.target, next.value);
405
- continue;
406
- case "number":
407
- if (!Number.isFinite(next.value)) return failure({ kind: "non-finite-number" });
408
- assignOutput(next.target, next.value);
409
- continue;
410
- case "object":
411
- if (next.value === null) {
412
- assignOutput(next.target, null);
413
- continue;
414
- }
415
- objectValue = next.value;
416
- break;
417
- }
418
- if (activeAncestors.has(objectValue)) return failure({ kind: "cycle" });
419
- activeAncestors.add(objectValue);
420
- let isArray;
421
- try {
422
- isArray = Array.isArray(objectValue);
423
- } catch {
424
- return failure({ kind: "inspection-failed" });
425
- }
426
- const inspection = isArray ? inspectArray(objectValue) : inspectPlainObject(objectValue);
427
- if (!inspection.ok) return failure(inspection.issue);
428
- if (inspection.containerKind === "array") {
429
- const output = new Array(inspection.length);
430
- assignOutput(next.target, output);
431
- pending.push({
432
- kind: "leave",
433
- source: objectValue,
434
- output
435
- });
436
- for (const child of inspection.children) pending.push({
437
- kind: "visit",
438
- value: child.value,
439
- depth: next.depth + 1,
440
- target: {
441
- kind: "array-index",
442
- parent: output,
443
- index: Number(child.key)
444
- }
445
- });
446
- continue;
447
- }
448
- const output = {};
449
- assignOutput(next.target, output);
450
- pending.push({
451
- kind: "leave",
452
- source: objectValue,
453
- output
454
- });
455
- for (const child of inspection.children) pending.push({
456
- kind: "visit",
457
- value: child.value,
458
- depth: next.depth + 1,
459
- target: {
460
- kind: "object-property",
461
- parent: output,
462
- key: child.key
463
- }
464
- });
465
- }
466
- return {
467
- ok: true,
468
- value: validatedRoot
469
- };
470
- }
471
- //#endregion
472
- //#region src/data/executeCodeLoaders.ts
473
- const systemBlockKindSet = new Set(SYSTEM_BLOCK_KINDS$1);
474
- function isBlockKind(value) {
475
- return value.startsWith("custom.") || systemBlockKindSet.has(value);
476
- }
477
- function toFailureBase(context, loaderKey) {
478
- return {
479
- siteId: context.siteId,
480
- pageId: context.pageId,
481
- blockId: context.blockId,
482
- blockKind: context.blockKind,
483
- loaderKey,
484
- previewStage: context.previewStage,
485
- renderTargetKind: context.renderTarget.kind
486
- };
487
- }
488
- /**
489
- * Runs all matching host loaders concurrently. The function returns closed
490
- * outcomes and never logs; warning ownership belongs to the shared resolver.
491
- */
492
- async function executeCodeLoaders(page, context, overrides) {
493
- const tasks = [];
494
- for (const block of page.blocks) {
495
- const blockId = block.id;
496
- if (!blockId || !isBlockKind(block.kind)) continue;
497
- const blockLoaders = overrides[block.kind];
498
- if (!blockLoaders) continue;
499
- for (const [loaderKey, loader] of Object.entries(blockLoaders)) {
500
- const loaderContext = createDataLoaderContext({
501
- siteId: context.siteId,
502
- renderTarget: context.renderTarget,
503
- blockId,
504
- blockKind: block.kind,
505
- content: resolveDataLoaderBlockContent(block, context.previewStage),
506
- previewStage: context.previewStage,
507
- searchParams: context.searchParams
508
- });
509
- tasks.push((async () => {
510
- let output;
511
- try {
512
- output = await loader(loaderContext);
513
- } catch {
514
- return {
515
- ok: false,
516
- failure: {
517
- kind: "execution-failed",
518
- ...toFailureBase(loaderContext, loaderKey)
519
- }
520
- };
521
- }
522
- const validation = validateDataLoaderValue(output);
523
- if (!validation.ok) return {
524
- ok: false,
525
- failure: {
526
- kind: "invalid-result",
527
- ...toFailureBase(loaderContext, loaderKey),
528
- validationIssueKind: validation.issue.kind
529
- }
530
- };
531
- return {
532
- ok: true,
533
- blockId,
534
- loaderKey,
535
- value: validation.value
536
- };
537
- })());
538
- }
539
- }
540
- const outcomes = await Promise.all(tasks);
541
- const data = {};
542
- const failures = [];
543
- for (const outcome of outcomes) {
544
- if (!outcome.ok) {
545
- failures.push(outcome.failure);
546
- continue;
547
- }
548
- const blockData = { ...data[outcome.blockId] };
549
- defineOwnDataProperty(blockData, outcome.loaderKey, outcome.value);
550
- defineOwnDataProperty(data, outcome.blockId, blockData);
551
- }
552
- return {
553
- data,
554
- failures
555
- };
556
- }
557
- /** Successful host values take precedence on per-block loader-key collisions. */
558
- function mergeLoaderResults(configResults, codeResults) {
559
- const merged = { ...configResults };
560
- for (const [blockId, loaderData] of Object.entries(codeResults)) defineOwnDataProperty(merged, blockId, {
561
- ...merged[blockId],
562
- ...loaderData
563
- });
564
- return merged;
565
- }
566
50
  function blockedDemoMutationPolicy(classification, publicMessage) {
567
51
  if (publicMessage.trim() === "") throw new Error(`Demo mutation policy ${classification} requires publicMessage.`);
568
52
  return {
@@ -588,6 +72,7 @@ const TAG_TEMPLATES = {
588
72
  siteRouteOutcomes: "riverbank:site:{siteId}:route-outcomes",
589
73
  routeById: "riverbank:route:{routeId}",
590
74
  pageById: "riverbank:page:{pageId}",
75
+ pageSurfaceById: "riverbank:page-surface:{pageSurfaceId}",
591
76
  workflowRunById: "riverbank:workflow-run:{runId}",
592
77
  siteForms: "riverbank:site:{siteId}:forms",
593
78
  formById: "riverbank:form:{formId}",
@@ -613,6 +98,7 @@ const TAG_TEMPLATES = {
613
98
  const DEMO_MUTATION_BLOCKED_HIDDEN = blockedDemoMutationPolicy("blocked-hidden", "This action is not available in demo sites.");
614
99
  const DEMO_MUTATION_BLOCKED_DISABLED = blockedDemoMutationPolicy("blocked-disabled", "This setting is disabled in demo sites.");
615
100
  const DEMO_MUTATION_INTERNAL_ONLY = blockedDemoMutationPolicy("internal-only", "This internal operation is not available in demo sites.");
101
+ const DEMO_MUTATION_ALLOWED = allowedDemoMutationPolicy();
616
102
  const API_ENDPOINTS$1 = {
617
103
  aiContentUpdateChat: {
618
104
  path: "/ai/content-update-chat",
@@ -2751,6 +2237,49 @@ const API_ENDPOINTS$1 = {
2751
2237
  auth: "user",
2752
2238
  responseKind: "json"
2753
2239
  },
2240
+ updatePageSurfaceDraftContent: {
2241
+ path: "/sites/{siteId}/page-surfaces/{pageSurfaceId}/content",
2242
+ method: "PUT",
2243
+ errors: [
2244
+ "validation:invalid_input",
2245
+ "resource:not_found",
2246
+ "resource:conflict",
2247
+ "server:internal_error"
2248
+ ],
2249
+ tags: [TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.pageSurfaceById],
2250
+ auth: "user",
2251
+ responseKind: "json"
2252
+ },
2253
+ discardPageSurfaceDraftContent: {
2254
+ path: "/sites/{siteId}/page-surfaces/{pageSurfaceId}/content/draft",
2255
+ method: "DELETE",
2256
+ errors: [
2257
+ "validation:invalid_input",
2258
+ "resource:not_found",
2259
+ "resource:conflict",
2260
+ "server:internal_error"
2261
+ ],
2262
+ tags: [TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.pageSurfaceById],
2263
+ auth: "user",
2264
+ responseKind: "json"
2265
+ },
2266
+ updatePageSurfaceRouteMetadata: {
2267
+ path: "/sites/{siteId}/page-surfaces/{pageSurfaceId}/metadata",
2268
+ method: "PATCH",
2269
+ errors: [
2270
+ "validation:invalid_input",
2271
+ "resource:not_found",
2272
+ "resource:conflict",
2273
+ "server:internal_error"
2274
+ ],
2275
+ tags: [
2276
+ TAG_TEMPLATES.siteCollection,
2277
+ TAG_TEMPLATES.siteRoutableContent,
2278
+ TAG_TEMPLATES.pageSurfaceById
2279
+ ],
2280
+ auth: "user",
2281
+ responseKind: "json"
2282
+ },
2754
2283
  runSdkWorkflow: {
2755
2284
  path: "/sites/{siteId}/content/{type}/{entryId}/workflows/{workflowId}/run",
2756
2285
  method: "POST",
@@ -3131,6 +2660,50 @@ const API_ENDPOINTS$1 = {
3131
2660
  errors: [],
3132
2661
  responseKind: "json"
3133
2662
  },
2663
+ getFooterComposition: {
2664
+ path: "/sites/{siteId}/settings/footer-composition",
2665
+ method: "GET",
2666
+ revalidate: 120,
2667
+ tags: [TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings],
2668
+ auth: "user",
2669
+ errors: ["resource:not_found", "server:internal_error"],
2670
+ responseKind: "json"
2671
+ },
2672
+ updateFooterComposition: {
2673
+ path: "/sites/{siteId}/settings/footer-composition",
2674
+ method: "POST",
2675
+ tags: [TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings],
2676
+ auth: "user",
2677
+ demoMutation: DEMO_MUTATION_ALLOWED,
2678
+ errors: [
2679
+ "validation:invalid_input",
2680
+ "resource:not_found",
2681
+ "server:internal_error"
2682
+ ],
2683
+ responseKind: "json"
2684
+ },
2685
+ getPublicProfile: {
2686
+ path: "/sites/{siteId}/settings/public-profile",
2687
+ method: "GET",
2688
+ revalidate: 120,
2689
+ tags: [TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings],
2690
+ auth: "user",
2691
+ errors: ["resource:not_found", "server:internal_error"],
2692
+ responseKind: "json"
2693
+ },
2694
+ updatePublicProfile: {
2695
+ path: "/sites/{siteId}/settings/public-profile",
2696
+ method: "POST",
2697
+ tags: [TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings],
2698
+ auth: "user",
2699
+ demoMutation: DEMO_MUTATION_ALLOWED,
2700
+ errors: [
2701
+ "validation:invalid_input",
2702
+ "resource:not_found",
2703
+ "server:internal_error"
2704
+ ],
2705
+ responseKind: "json"
2706
+ },
3134
2707
  updateSiteLayoutSettings: {
3135
2708
  path: "/sites/{siteId}/settings/layout",
3136
2709
  method: "POST",
@@ -4203,6 +3776,76 @@ const API_ENDPOINTS$1 = {
4203
3776
  responseKind: "json",
4204
3777
  errors: ["resource:not_found"]
4205
3778
  },
3779
+ listPageSurfaceContentSlots: {
3780
+ path: "/sites/{siteId}/page-surfaces/{pageSurfaceId}/slots",
3781
+ method: "GET",
3782
+ tags: [
3783
+ TAG_TEMPLATES.siteCollection,
3784
+ TAG_TEMPLATES.pageSurfaceById,
3785
+ "surface-slots",
3786
+ "blocks"
3787
+ ],
3788
+ auth: "user",
3789
+ responseKind: "json",
3790
+ errors: [
3791
+ "resource:not_found",
3792
+ "resource:conflict",
3793
+ "server:internal_error"
3794
+ ]
3795
+ },
3796
+ createPageSurfaceSlotBlock: {
3797
+ path: "/sites/{siteId}/page-surfaces/{pageSurfaceId}/slots/{slotKey}/blocks",
3798
+ method: "POST",
3799
+ tags: [
3800
+ TAG_TEMPLATES.siteCollection,
3801
+ TAG_TEMPLATES.pageSurfaceById,
3802
+ "surface-slot-{slotKey}",
3803
+ "blocks"
3804
+ ],
3805
+ auth: "user",
3806
+ responseKind: "json",
3807
+ errors: [
3808
+ "validation:invalid_input",
3809
+ "resource:not_found",
3810
+ "resource:conflict",
3811
+ "server:internal_error"
3812
+ ]
3813
+ },
3814
+ reorderPageSurfaceSlotBlocks: {
3815
+ path: "/sites/{siteId}/page-surfaces/{pageSurfaceId}/slots/{slotKey}/blocks/reorder",
3816
+ method: "POST",
3817
+ tags: [
3818
+ TAG_TEMPLATES.siteCollection,
3819
+ TAG_TEMPLATES.pageSurfaceById,
3820
+ "surface-slot-{slotKey}",
3821
+ "blocks"
3822
+ ],
3823
+ auth: "user",
3824
+ responseKind: "json",
3825
+ errors: [
3826
+ "validation:invalid_input",
3827
+ "resource:not_found",
3828
+ "resource:conflict",
3829
+ "server:internal_error"
3830
+ ]
3831
+ },
3832
+ deletePageSurfaceSlotBlock: {
3833
+ path: "/sites/{siteId}/page-surfaces/{pageSurfaceId}/slots/{slotKey}/blocks/{blockId}",
3834
+ method: "DELETE",
3835
+ tags: [
3836
+ TAG_TEMPLATES.siteCollection,
3837
+ TAG_TEMPLATES.pageSurfaceById,
3838
+ "surface-slot-{slotKey}",
3839
+ "blocks"
3840
+ ],
3841
+ auth: "user",
3842
+ responseKind: "json",
3843
+ errors: [
3844
+ "resource:not_found",
3845
+ "resource:conflict",
3846
+ "server:internal_error"
3847
+ ]
3848
+ },
4206
3849
  createBlock: {
4207
3850
  path: "/sites/{siteId}/pages/{pageId}/blocks",
4208
3851
  method: "POST",
@@ -6815,6 +6458,19 @@ const API_ENDPOINTS$1 = {
6815
6458
  auth: "service",
6816
6459
  responseKind: "json"
6817
6460
  },
6461
+ sdkPatchPageBlock: {
6462
+ path: "/sdk/{siteId}/pages/{identifier}/blocks/{blockIdentifier}",
6463
+ method: "PATCH",
6464
+ errors: [
6465
+ "validation:invalid_input",
6466
+ "resource:not_found",
6467
+ "resource:conflict",
6468
+ "billing:plan_limit_exceeded",
6469
+ "server:internal_error"
6470
+ ],
6471
+ auth: "service",
6472
+ responseKind: "json"
6473
+ },
6818
6474
  sdkReorderPageBlocks: {
6819
6475
  path: "/sdk/{siteId}/pages/{identifier}/blocks/reorder",
6820
6476
  method: "POST",
@@ -7478,6 +7134,115 @@ const API_ENDPOINTS$1 = {
7478
7134
  }
7479
7135
  };
7480
7136
  //#endregion
7137
+ //#region ../api/src/previewContentContract.ts
7138
+ const PREVIEW_CONTENT_CONTRACT_PARAM = "__riverbank_content_contract";
7139
+ function parsePreviewContentContract(value) {
7140
+ const candidate = Array.isArray(value) ? value[0] : value;
7141
+ return candidate === "compat" || candidate === "native" ? candidate : null;
7142
+ }
7143
+ const API_ERROR_CODE_SET = /* @__PURE__ */ new Set([
7144
+ "auth:unauthenticated",
7145
+ "auth:token_expired",
7146
+ "auth:token_invalid",
7147
+ "auth:forbidden",
7148
+ "auth:mfa_required",
7149
+ "auth:sudo_required",
7150
+ "auth:insufficient_permissions",
7151
+ "auth:impersonation_restricted",
7152
+ "validation:invalid_input",
7153
+ "validation:missing_field",
7154
+ "validation:invalid_format",
7155
+ "validation:payload_too_large",
7156
+ "resource:not_found",
7157
+ "resource:already_exists",
7158
+ "resource:conflict",
7159
+ "resource:gone",
7160
+ "rate_limit:exceeded",
7161
+ "billing:payment_required",
7162
+ "billing:plan_limit_exceeded",
7163
+ "billing:pass_redemption_failed",
7164
+ "server:internal_error",
7165
+ "server:unavailable",
7166
+ "external:service_error",
7167
+ "external:registrar_orphaned_contact_profile",
7168
+ "network:connection_error",
7169
+ "network:timeout",
7170
+ "network:dns_error"
7171
+ ]);
7172
+ function isApiErrorCode(value) {
7173
+ return typeof value === "string" && API_ERROR_CODE_SET.has(value);
7174
+ }
7175
+ function isApiError(result) {
7176
+ return result.success === false;
7177
+ }
7178
+ function isApiSuccess(result) {
7179
+ return result.success === true;
7180
+ }
7181
+ function isRecord$34(value) {
7182
+ return typeof value === "object" && value !== null && !Array.isArray(value);
7183
+ }
7184
+ function isFieldError(value) {
7185
+ return isRecord$34(value) && typeof value.field === "string" && typeof value.code === "string" && typeof value.message === "string";
7186
+ }
7187
+ function fieldErrorsFromUnknown(value) {
7188
+ if (!Array.isArray(value)) return null;
7189
+ return value.every(isFieldError) ? value : null;
7190
+ }
7191
+ function extractEnvelopeErrorObject(body) {
7192
+ if (!isRecord$34(body)) return null;
7193
+ const error = body.error;
7194
+ if (!isRecord$34(error)) return null;
7195
+ if ("success" in body && body.success !== false) return null;
7196
+ return error;
7197
+ }
7198
+ function extractApiEnvelopeErrorDetails(body) {
7199
+ const error = extractEnvelopeErrorObject(body);
7200
+ if (!error) return {
7201
+ rawCode: null,
7202
+ code: null,
7203
+ message: null,
7204
+ status: null,
7205
+ fieldErrors: null
7206
+ };
7207
+ const rawCode = typeof error.code === "string" ? error.code : null;
7208
+ const message = typeof error.message === "string" && error.message.trim().length > 0 ? error.message : null;
7209
+ return {
7210
+ rawCode,
7211
+ code: isApiErrorCode(rawCode) ? rawCode : null,
7212
+ message,
7213
+ status: typeof error.status === "number" && Number.isFinite(error.status) ? error.status : null,
7214
+ fieldErrors: fieldErrorsFromUnknown(error.fieldErrors)
7215
+ };
7216
+ }
7217
+ /**
7218
+ * Error class for API failures that can be thrown from unwrapResponse.
7219
+ * Preserves all error metadata from the envelope.
7220
+ */
7221
+ var ApiEnvelopeError = class extends Error {
7222
+ constructor(error) {
7223
+ super(error.message);
7224
+ this.name = "ApiEnvelopeError";
7225
+ this.code = error.code;
7226
+ this.requestId = error.requestId;
7227
+ this.timestamp = error.timestamp;
7228
+ this.status = error.status;
7229
+ this.fieldErrors = error.fieldErrors;
7230
+ }
7231
+ };
7232
+ /**
7233
+ * Unwrap a successful API response or throw on error.
7234
+ *
7235
+ * @example
7236
+ * ```typescript
7237
+ * const response = await apiClient({ endpoint: 'getUser', params: { id } });
7238
+ * const user = unwrapResponse(response); // Throws if not success
7239
+ * ```
7240
+ */
7241
+ function unwrapResponse(result) {
7242
+ if (isApiSuccess(result)) return result.data;
7243
+ throw new ApiEnvelopeError(result.error);
7244
+ }
7245
+ //#endregion
7481
7246
  //#region ../core/src/result.ts
7482
7247
  function ok$3(value) {
7483
7248
  return {
@@ -7632,7 +7397,7 @@ function formatEventPricing(pricing, options = {}) {
7632
7397
  //#endregion
7633
7398
  //#region ../core/src/event-page-surface-subject.ts
7634
7399
  function parseEventPageSurfaceSubject(value) {
7635
- if (!isRecord$31(value)) return err$3({ kind: "notObject" });
7400
+ if (!isRecord$33(value)) return err$3({ kind: "notObject" });
7636
7401
  switch (value.kind) {
7637
7402
  case "eventSeries": {
7638
7403
  const eventSeriesId = parseEventSeriesId(value.eventSeriesId);
@@ -7675,7 +7440,7 @@ function parseEventPageSurfaceSubject(value) {
7675
7440
  });
7676
7441
  }
7677
7442
  }
7678
- function isRecord$31(value) {
7443
+ function isRecord$33(value) {
7679
7444
  return typeof value === "object" && value !== null && !Array.isArray(value);
7680
7445
  }
7681
7446
  //#endregion
@@ -7890,6 +7655,17 @@ function toLocationCoordinates(value) {
7890
7655
  lng: value.lng
7891
7656
  };
7892
7657
  }
7658
+ new Map([
7659
+ "brand",
7660
+ "supporting-text",
7661
+ "social-links",
7662
+ "navigation",
7663
+ "business-address",
7664
+ "contact",
7665
+ "opening-hours",
7666
+ "legal-navigation",
7667
+ "legal"
7668
+ ].map((kind, index) => [kind, index]));
7893
7669
  function sortStableJsonValue(value) {
7894
7670
  if (value === null) return null;
7895
7671
  if (typeof value === "string" || typeof value === "boolean") return value;
@@ -7901,7 +7677,7 @@ function sortStableJsonValue(value) {
7901
7677
  if (typeof value === "object") {
7902
7678
  const prototype = Object.getPrototypeOf(value);
7903
7679
  if (prototype !== Object.prototype && prototype !== null) throw new TypeError("Stable JSON only supports plain objects");
7904
- return Object.fromEntries(Object.entries(value).sort(([left], [right]) => left.localeCompare(right)).map(([key, child]) => [key, sortStableJsonValue(child)]));
7680
+ return Object.fromEntries(Object.entries(value).sort(([left], [right]) => left < right ? -1 : left > right ? 1 : 0).map(([key, child]) => [key, sortStableJsonValue(child)]));
7905
7681
  }
7906
7682
  throw new TypeError(`Stable JSON does not support ${typeof value}`);
7907
7683
  }
@@ -8206,7 +7982,7 @@ function containsUnsafePathSegmentCharacter(value) {
8206
7982
  function isReservedPathSegment(value) {
8207
7983
  return value === "." || value === "..";
8208
7984
  }
8209
- function isUnsafePathSegment(segment) {
7985
+ function isUnsafePathSegment$1(segment) {
8210
7986
  return segment.trim().length === 0 || segment !== segment.trim() || isReservedPathSegment(segment) || containsUnsafePathSegmentCharacter(segment);
8211
7987
  }
8212
7988
  ({
@@ -8222,7 +7998,7 @@ function parseStoragePath(value) {
8222
7998
  * that every tenant/site identifier remains one segment, never a nested path.
8223
7999
  */
8224
8000
  function joinStoragePathSegments(segments) {
8225
- if (segments.some(isUnsafePathSegment)) return err$3("unsafe-path-segment");
8001
+ if (segments.some(isUnsafePathSegment$1)) return err$3("unsafe-path-segment");
8226
8002
  return ok$3(unsafeAsStoragePath(segments.join("/")));
8227
8003
  }
8228
8004
  //#endregion
@@ -8882,7 +8658,7 @@ const ALLOWED_TRANSFORM_IDS = [
8882
8658
  "media.fromUrl",
8883
8659
  "background.resolveStyle",
8884
8660
  "background.resolveColorsStyle",
8885
- "background.resolveAllowOverflow",
8661
+ "background.resolveFrameClassName",
8886
8662
  "background.resolveImageStyle",
8887
8663
  "background.resolveImageClassName",
8888
8664
  "background.resolveOverlayStyle",
@@ -8912,7 +8688,7 @@ function mqBetween(minPx, maxPx) {
8912
8688
  return `${mqUp(minPx)} and ${mqDown(maxPx)}`;
8913
8689
  }
8914
8690
  const MQ_SM_UP = mqUp(640);
8915
- mqUp(768);
8691
+ const MQ_MD_UP = mqUp(768);
8916
8692
  const MQ_LG_UP = mqUp(BREAKPOINT_LG);
8917
8693
  mqUp(BREAKPOINT_XL);
8918
8694
  const MQ_SM_DOWN = mqDown(639);
@@ -17956,104 +17732,153 @@ const showtimePill = defineButtonPersonality({
17956
17732
  }
17957
17733
  });
17958
17734
  //#endregion
17959
- //#region ../theme-core/src/buttons/personalities/index.ts
17960
- const buttonPersonalities = [
17961
- defineButtonPersonality({
17962
- id: "soft-pill",
17963
- name: "Soft Pill",
17964
- description: "Rounded pills with a gentle lift on hover. Quietly modern.",
17965
- tags: {
17966
- tone: "classic",
17967
- energy: "calm",
17968
- motion: "subtle",
17969
- era: "organic"
17735
+ //#region ../theme-core/src/buttons/personalities/soft-pill.ts
17736
+ /**
17737
+ * Soft Pill — rounded-full pill buttons with a hover lift. The default for
17738
+ * Calm Studio and Modern Wellness; reads as quietly modern and welcoming.
17739
+ */
17740
+ const softPill = defineButtonPersonality({
17741
+ id: "soft-pill",
17742
+ name: "Soft Pill",
17743
+ description: "Rounded pills with a gentle lift on hover. Quietly modern.",
17744
+ tags: {
17745
+ tone: "classic",
17746
+ energy: "calm",
17747
+ motion: "subtle",
17748
+ era: "organic"
17749
+ },
17750
+ buttonSystem: {
17751
+ global: {
17752
+ cornerStyle: "pill",
17753
+ shadow: "low",
17754
+ textTransform: "none",
17755
+ fontWeight: 500,
17756
+ borderWidth: 2,
17757
+ hoverTransform: "lift",
17758
+ hoverColor: "none"
17970
17759
  },
17971
- buttonSystem: {
17972
- global: {
17973
- cornerStyle: "pill",
17974
- shadow: "low",
17975
- textTransform: "none",
17976
- fontWeight: 500,
17977
- borderWidth: 2,
17978
- hoverTransform: "lift",
17979
- hoverColor: "none"
17980
- },
17981
- variants: [
17982
- {
17983
- id: "primary",
17984
- name: "Primary",
17985
- enabled: true,
17986
- priority: 1,
17987
- background: {
17988
- type: "solid",
17989
- colorToken: "primary"
17990
- },
17991
- textColorToken: "primaryForeground",
17992
- borderRadius: "rounded-full",
17993
- shadow: {
17994
- elevation: "low",
17995
- softness: "soft",
17996
- position: "bottom"
17997
- },
17998
- effects: {
17999
- hover: [{
18000
- effectId: "lift",
18001
- options: { translateY: "-1px" }
18002
- }],
18003
- active: [{
18004
- effectId: "scale-down",
18005
- options: { scale: "0.98" }
18006
- }]
18007
- }
18008
- },
18009
- {
18010
- id: "secondary",
18011
- name: "Secondary",
18012
- enabled: true,
18013
- priority: 2,
18014
- background: { type: "transparent" },
18015
- textColorToken: "primary",
18016
- borderRadius: "rounded-full",
18017
- border: {
18018
- widthClass: "border-2",
18019
- colorToken: "primary"
18020
- },
18021
- effects: { hover: [{
18022
- effectId: "background-on-hover",
18023
- options: { colorToken: "surface" }
18024
- }] }
17760
+ variants: [
17761
+ {
17762
+ id: "primary",
17763
+ name: "Primary",
17764
+ enabled: true,
17765
+ priority: 1,
17766
+ background: {
17767
+ type: "solid",
17768
+ colorToken: "primary"
18025
17769
  },
18026
- {
18027
- id: "outline",
18028
- name: "Outline",
18029
- enabled: true,
18030
- priority: 3,
18031
- background: { type: "transparent" },
18032
- textColorToken: "text",
18033
- borderRadius: "rounded-full",
18034
- border: {
18035
- widthClass: "border",
18036
- colorToken: "border"
18037
- },
18038
- effects: { hover: [{
18039
- effectId: "background-on-hover",
18040
- options: { colorToken: "surface" }
18041
- }] }
17770
+ textColorToken: "primaryForeground",
17771
+ borderRadius: "rounded-full",
17772
+ shadow: {
17773
+ elevation: "low",
17774
+ softness: "soft",
17775
+ position: "bottom"
18042
17776
  },
18043
- {
18044
- id: "ghost",
18045
- name: "Ghost",
18046
- enabled: true,
18047
- priority: 3,
18048
- background: { type: "transparent" },
18049
- textColorToken: "text",
18050
- borderRadius: "rounded-full",
18051
- effects: { hover: [{
18052
- effectId: "background-on-hover",
18053
- options: { colorToken: "surface" }
18054
- }] }
17777
+ effects: {
17778
+ hover: [{
17779
+ effectId: "lift",
17780
+ options: { translateY: "-1px" }
17781
+ }],
17782
+ active: [{
17783
+ effectId: "scale-down",
17784
+ options: { scale: "0.98" }
17785
+ }]
18055
17786
  }
18056
- ]
17787
+ },
17788
+ {
17789
+ id: "secondary",
17790
+ name: "Secondary",
17791
+ enabled: true,
17792
+ priority: 2,
17793
+ background: { type: "transparent" },
17794
+ textColorToken: "primary",
17795
+ borderRadius: "rounded-full",
17796
+ border: {
17797
+ widthClass: "border-2",
17798
+ colorToken: "primary"
17799
+ },
17800
+ effects: { hover: [{
17801
+ effectId: "background-on-hover",
17802
+ options: { colorToken: "surface" }
17803
+ }] }
17804
+ },
17805
+ {
17806
+ id: "outline",
17807
+ name: "Outline",
17808
+ enabled: true,
17809
+ priority: 3,
17810
+ background: { type: "transparent" },
17811
+ textColorToken: "text",
17812
+ borderRadius: "rounded-full",
17813
+ border: {
17814
+ widthClass: "border",
17815
+ colorToken: "border"
17816
+ },
17817
+ effects: { hover: [{
17818
+ effectId: "background-on-hover",
17819
+ options: { colorToken: "surface" }
17820
+ }] }
17821
+ },
17822
+ {
17823
+ id: "ghost",
17824
+ name: "Ghost",
17825
+ enabled: true,
17826
+ priority: 3,
17827
+ background: { type: "transparent" },
17828
+ textColorToken: "text",
17829
+ borderRadius: "rounded-full",
17830
+ effects: { hover: [{
17831
+ effectId: "background-on-hover",
17832
+ options: { colorToken: "surface" }
17833
+ }] }
17834
+ }
17835
+ ]
17836
+ }
17837
+ });
17838
+ //#endregion
17839
+ //#region ../theme-core/src/buttons/personalities/two-tone-pill.ts
17840
+ const solidSecondary = {
17841
+ id: "secondary",
17842
+ name: "Secondary",
17843
+ enabled: true,
17844
+ priority: 2,
17845
+ background: {
17846
+ type: "solid",
17847
+ colorToken: "secondary"
17848
+ },
17849
+ textColorToken: "onSecondary",
17850
+ borderRadius: "rounded-full",
17851
+ shadow: {
17852
+ elevation: "none",
17853
+ softness: null,
17854
+ position: "bottom"
17855
+ },
17856
+ effects: {
17857
+ hover: [{
17858
+ effectId: "background-on-hover-alpha",
17859
+ options: {
17860
+ colorToken: "secondary",
17861
+ opacity: 88
17862
+ }
17863
+ }],
17864
+ active: [{
17865
+ effectId: "scale-down",
17866
+ options: { scale: "0.98" }
17867
+ }]
17868
+ }
17869
+ };
17870
+ //#endregion
17871
+ //#region ../theme-core/src/buttons/personalities/index.ts
17872
+ const buttonPersonalities = [
17873
+ softPill,
17874
+ defineButtonPersonality({
17875
+ id: "two-tone-pill",
17876
+ name: "Two-tone Pill",
17877
+ description: "Rounded pills with distinct solid primary and secondary brand colours.",
17878
+ tags: softPill.tags,
17879
+ buttonSystem: {
17880
+ ...softPill.buttonSystem,
17881
+ variants: softPill.buttonSystem.variants.map((variant) => variant.id === "secondary" ? solidSecondary : variant)
18057
17882
  }
18058
17883
  }),
18059
17884
  earthPill,
@@ -18675,7 +18500,7 @@ const overlayLogoAccommodations = [
18675
18500
  * optional nested styling fields that would otherwise leak from another Look.
18676
18501
  */
18677
18502
  function baseHeader(theme) {
18678
- const { navLinkStyle: _navLinkStyle, navTypography: _navTypography, navTextSize: _navTextSize, dropdownStyle: _dropdownStyle, ctaVariant: _ctaVariant, navContainer: _navContainer, container: _container, shadow: _shadow, logo: _logo, logoText: _logoText, border: _border, ...header } = theme.header;
18503
+ const { navLinkStyle: _navLinkStyle, navFontRole: _navFontRole, navTypography: _navTypography, navTextSize: _navTextSize, dropdownStyle: _dropdownStyle, ctaVariant: _ctaVariant, navContainer: _navContainer, container: _container, shadow: _shadow, logo: _logo, logoText: _logoText, border: _border, ...header } = theme.header;
18679
18504
  return {
18680
18505
  ...header,
18681
18506
  navContainer: {
@@ -18824,6 +18649,17 @@ const headerStyleCatalog = defineExactCatalog()([
18824
18649
  navTypography: "brand-caps",
18825
18650
  moods: ["expressive"]
18826
18651
  },
18652
+ {
18653
+ id: asHeaderStyleId("brand-capsule"),
18654
+ label: "Brand Capsule",
18655
+ description: "Solid brand chrome designed as a floating capsule, with quiet-caps nav, a soft pill active state, and an inverted CTA pill.",
18656
+ supportedLayoutIds: supportedLayouts(["classic"]),
18657
+ navInteraction: "pill-background",
18658
+ surface: "brand-solid",
18659
+ defaultDepth: "shadow",
18660
+ navTypography: "quiet-caps",
18661
+ moods: ["expressive", "professional"]
18662
+ },
18827
18663
  {
18828
18664
  id: asHeaderStyleId("serif-line"),
18829
18665
  label: "Serif Line",
@@ -18917,6 +18753,7 @@ const headerStyleCompatibilityOrder = /* @__PURE__ */ new Map([
18917
18753
  "brand-bar",
18918
18754
  "brand-underline",
18919
18755
  "brand-pill",
18756
+ "brand-capsule",
18920
18757
  "serif-line",
18921
18758
  "flat-tabs"
18922
18759
  ])],
@@ -18954,6 +18791,11 @@ headerStyleRepairChain([
18954
18791
  "brand-pill",
18955
18792
  "brand-bar",
18956
18793
  "minimal"
18794
+ ]), headerStyleRepairChain([
18795
+ "brand-capsule",
18796
+ "brand-pill",
18797
+ "brand-bar",
18798
+ "minimal"
18957
18799
  ]), headerStyleRepairChain([
18958
18800
  "pill-nav",
18959
18801
  "soft-bar",
@@ -22887,7 +22729,7 @@ function generateVariantCSS(variant, themeId, tokens, theme) {
22887
22729
  rules.push(`display: flex`);
22888
22730
  rules.push(`flex-direction: column`);
22889
22731
  rules.push(`position: relative`);
22890
- rules.push(`overflow: hidden`);
22732
+ rules.push(`overflow: visible`);
22891
22733
  const mediaRadius = MEDIA_CORNER_MAP[corners];
22892
22734
  const mediaRules = [`border-top-left-radius: ${mediaRadius}`, `border-top-right-radius: ${mediaRadius}`];
22893
22735
  const contentRules = [`padding: ${CONTENT_PADDING_MAP[variant.spacing] || CONTENT_PADDING_MAP.comfortable}`];
@@ -24411,6 +24253,7 @@ const navFontWeight = z$1.enum([
24411
24253
  "bold"
24412
24254
  ]);
24413
24255
  const headerMaxWidth = z$1.enum(["container", "full"]);
24256
+ const headerBarFrame = z$1.enum(["full-bleed", "inset-shell"]);
24414
24257
  const headerContainerSchema = z$1.object({
24415
24258
  rounded: z$1.enum([
24416
24259
  "none",
@@ -24555,6 +24398,7 @@ const headerSchema = z$1.object({
24555
24398
  positioning: headerPositioning,
24556
24399
  shrinkOnScroll: z$1.boolean(),
24557
24400
  maxWidth: headerMaxWidth,
24401
+ barFrame: headerBarFrame.optional(),
24558
24402
  logoOverride: mediaSchema$1.nullable().optional(),
24559
24403
  background: headerBackgroundSchema.default({
24560
24404
  type: "color",
@@ -24564,6 +24408,7 @@ const headerSchema = z$1.object({
24564
24408
  navStyle: headerNavStyle,
24565
24409
  navColor: themeColorTokenSchema.nullable().optional(),
24566
24410
  navWeight: navFontWeight.default("medium"),
24411
+ navFontRole: z$1.enum(["body", "heading"]).optional(),
24567
24412
  navTypography: z$1.enum(["body", "heading"]).optional(),
24568
24413
  navTextSize: navLinkStyleSchema.shape.textSize,
24569
24414
  navPlacement: z$1.enum(["end", "center"]).optional(),
@@ -24579,7 +24424,21 @@ const headerSchema = z$1.object({
24579
24424
  ctaTreatment: headerCtaTreatmentSchema.optional(),
24580
24425
  ctaVariant: z$1.string().min(1).optional(),
24581
24426
  dropdownStyle: dropdownStyleSchema
24582
- });
24427
+ }).transform(normaliseHeaderNavFontRole);
24428
+ /**
24429
+ * Normalises the legacy `navTypography` font-role alias into the canonical
24430
+ * `navFontRole` field so persisted themes migrate at the parse boundary without
24431
+ * a data migration. `navFontRole` always wins when both are present; the legacy
24432
+ * field is dropped so we never carry a dual write forward.
24433
+ */
24434
+ function normaliseHeaderNavFontRole(header) {
24435
+ if (header.navTypography === void 0) return header;
24436
+ const { navTypography, ...rest } = header;
24437
+ return header.navFontRole === void 0 ? {
24438
+ ...rest,
24439
+ navFontRole: navTypography
24440
+ } : rest;
24441
+ }
24583
24442
  const footerVariant = z$1.enum([
24584
24443
  "simple",
24585
24444
  "columns",
@@ -25611,6 +25470,7 @@ const curatedSiteStyles = [
25611
25470
  ],
25612
25471
  buttonPersonalityChoices: [
25613
25472
  buttonChoice("soft-pill"),
25473
+ buttonChoice("two-tone-pill"),
25614
25474
  buttonChoice("pebble"),
25615
25475
  buttonChoice("editorial-link"),
25616
25476
  buttonChoice("brushed-wash")
@@ -26790,6 +26650,7 @@ const curatedSiteStyles = [
26790
26650
  ],
26791
26651
  buttonPersonalityChoices: [
26792
26652
  buttonChoice("quiet-arrow"),
26653
+ buttonChoice("two-tone-pill"),
26793
26654
  buttonChoice("flat-ink"),
26794
26655
  buttonChoice("editorial-link")
26795
26656
  ],
@@ -26997,6 +26858,21 @@ function toSiteChromeBackgroundColorTokens(tokenNames) {
26997
26858
  return token ? [token] : [];
26998
26859
  });
26999
26860
  }
26861
+ /**
26862
+ * Applies the user's nav font-role/size overrides on top of a style-resolved
26863
+ * nav link style. This is where the precedence contract lands:
26864
+ *
26865
+ * - The nav typography TREATMENT (case/tracking identity: plain / heading /
26866
+ * quiet-caps / brand-caps) is ALWAYS owned by the active header style and is
26867
+ * baked into `style` before this call (see `applyNavTypography` in
26868
+ * headerLooks.ts).
26869
+ * - Each treatment resolves through a DEFAULT font role: `heading` resolves
26870
+ * through the heading role; `plain` / `quiet-caps` / `brand-caps` resolve
26871
+ * through the body role.
26872
+ * - The user's `navFontRole` (surfaced here as `preferences.typography`) only
26873
+ * overrides which font ROLE the treatment resolves through. It never changes
26874
+ * the treatment. `'inherit'` keeps the treatment's default role.
26875
+ */
27000
26876
  function mergeHeaderNavTypographyPreference(style, preferences) {
27001
26877
  return preferences.typography === "inherit" && preferences.fontSize === "inherit" ? style : {
27002
26878
  ...style,
@@ -28116,6 +27992,7 @@ function devValidate(node) {
28116
27992
  }
28117
27993
  //#endregion
28118
27994
  //#region ../blocks/src/system/node/fragments/backgroundLayer.ts
27995
+ const BACKGROUND_FRAME_BASE_CLASS = "rb-background-frame rb-absolute rb-inset-0 rb-z-neg-10 rb-h-full rb-w-full rb-isolate rb-pointer-events-none";
28119
27996
  /**
28120
27997
  * Creates background layer nodes for rendering backgrounds from field data.
28121
27998
  *
@@ -28181,6 +28058,34 @@ function backgroundLayer(path, options = {}) {
28181
28058
  ];
28182
28059
  }
28183
28060
  /**
28061
+ * Wrap decorative background layers in their own clipping frame.
28062
+ *
28063
+ * Foreground content remains outside this frame, so editor outlines, focus
28064
+ * rings, and floating controls are never clipped by a visual background.
28065
+ * Backgrounds that explicitly opt into overflow keep that behavior within
28066
+ * the decorative layer rather than changing the content root.
28067
+ */
28068
+ function backgroundFrame(path, options = {}) {
28069
+ const { leadingNodes = [], ...layerOptions } = options;
28070
+ const framedLayerOptions = {
28071
+ ...layerOptions,
28072
+ styleClassName: layerOptions.styleClassName ?? "background-style rb-absolute rb-inset-0 rb-z-0 rb-h-full rb-w-full rb-pointer-events-none",
28073
+ imageClassName: layerOptions.imageClassName ?? "rb-absolute rb-z-0",
28074
+ overlayClassName: layerOptions.overlayClassName ?? "background-overlay rb-absolute rb-inset-0 rb-z-0 rb-h-full rb-w-full rb-pointer-events-none"
28075
+ };
28076
+ return el("div", {
28077
+ className: { $bind: {
28078
+ from: path,
28079
+ transforms: [{
28080
+ id: "background.resolveFrameClassName",
28081
+ options: { baseClass: BACKGROUND_FRAME_BASE_CLASS }
28082
+ }],
28083
+ fallback: `${BACKGROUND_FRAME_BASE_CLASS} rb-overflow-hidden`
28084
+ } },
28085
+ style: { borderRadius: "inherit" }
28086
+ }, [...leadingNodes, ...backgroundLayer(path, framedLayerOptions)]);
28087
+ }
28088
+ /**
28184
28089
  * Creates a media node for rendering background image/video media with conditional rendering.
28185
28090
  *
28186
28091
  * This helper creates a media element that:
@@ -28342,8 +28247,8 @@ function sectionContainer(children, opts) {
28342
28247
  * - content
28343
28248
  */
28344
28249
  function styledContainer(config) {
28345
- const { children, rootType = "div", rootProps, bindFrom = "_containerStyles", baseClassName = "rb-relative rb-isolate rb-overflow-hidden", imageClassName = "rb-absolute rb-z-neg-10", constrainWidth = true } = config;
28346
- const backgroundNodes = backgroundLayer(`${bindFrom}.background`, { imageClassName });
28250
+ const { children, rootType = "div", rootProps, bindFrom = "_containerStyles", baseClassName = "rb-relative rb-isolate rb-overflow-visible", imageClassName = "rb-absolute rb-z-0", constrainWidth = true } = config;
28251
+ const backgroundNode = backgroundFrame(`${bindFrom}.background`, { imageClassName });
28347
28252
  const childrenArray = Array.isArray(children) ? children : [children];
28348
28253
  const { className: _ignoredClassName, style: _ignoredStyle, ...safeRootProps } = rootProps ?? {};
28349
28254
  return el(rootType, {
@@ -28366,7 +28271,7 @@ function styledContainer(config) {
28366
28271
  }],
28367
28272
  fallback: constrainWidth ? `${baseClassName} rb-container` : baseClassName
28368
28273
  } }
28369
- }, [...backgroundNodes, ...childrenArray]);
28274
+ }, [backgroundNode, ...childrenArray]);
28370
28275
  }
28371
28276
  //#endregion
28372
28277
  //#region ../blocks/src/system/spacing.ts
@@ -28499,7 +28404,7 @@ const DEFAULT_SECTION_SPACING = "medium";
28499
28404
  * - Creating a section wrapper with background theme
28500
28405
  * - Adding background color/gradient/image layers
28501
28406
  * - Binding className to section styles with transform
28502
- * - Binding allowOverflow for background positioning
28407
+ * - Keeping foreground overflow visible while decorative backgrounds clip independently
28503
28408
  * - Wrapping content children
28504
28409
  *
28505
28410
  * Use this helper to eliminate 25+ lines of boilerplate section setup code.
@@ -28535,8 +28440,8 @@ const DEFAULT_SECTION_SPACING = "medium";
28535
28440
  * });
28536
28441
  */
28537
28442
  function styledSection(config) {
28538
- const { children, baseClass = "rb-px-6", spacing = DEFAULT_SECTION_SPACING, background = "background", bindFrom = "_sectionStyles", imageClassName = "rb-absolute rb-z-neg-10", renderBackgroundImage = true, backgroundImageLoading, backgroundImageFetchPriority, allowOverflow = false, fullWidthPath } = config;
28539
- const renderedBackgroundNodes = backgroundLayer(`${bindFrom}.background`, {
28443
+ const { children, baseClass = "rb-px-6", spacing = DEFAULT_SECTION_SPACING, background = "background", bindFrom = "_sectionStyles", imageClassName = "rb-absolute rb-z-0", renderBackgroundImage = true, backgroundImageLoading, backgroundImageFetchPriority, fullWidthPath } = config;
28444
+ const renderedBackgroundNode = backgroundFrame(`${bindFrom}.background`, {
28540
28445
  imageClassName,
28541
28446
  fallbackToken: background,
28542
28447
  omitImageLayer: !renderBackgroundImage,
@@ -28559,13 +28464,8 @@ function styledSection(config) {
28559
28464
  fullWidthPath
28560
28465
  }
28561
28466
  }]
28562
- } },
28563
- allowOverflow: allowOverflow ? true : { $bind: {
28564
- from: `${bindFrom}.background`,
28565
- transforms: [{ id: "background.resolveAllowOverflow" }],
28566
- fallback: false
28567
28467
  } }
28568
- }, [...renderedBackgroundNodes, ...childrenArray]);
28468
+ }, [renderedBackgroundNode, ...childrenArray]);
28569
28469
  }
28570
28470
  //#endregion
28571
28471
  //#region ../blocks/src/system/node/fragments/ctaButton.ts
@@ -29426,9 +29326,12 @@ function responsiveTwoColumn({ image, text, ratioFrom, imagePositionFrom, gapCla
29426
29326
  //#endregion
29427
29327
  //#region ../blocks/src/system/node/fragments/styledCard.ts
29428
29328
  function styledCard(children, opts, ...mods) {
29429
- const baseClassName = opts.baseClassName ?? "rb-relative rb-isolate rb-overflow-hidden rb-border";
29430
- const defaultBackgroundLayer = el("div", { className: "rb-absolute rb-inset-0 rb-z-neg-10 rb-h-full rb-w-full rb-pointer-events-none rb-bg-surface" });
29431
- const backgroundNodes = backgroundLayer(opts.backgroundFrom);
29329
+ const baseClassName = opts.baseClassName ?? "rb-relative rb-isolate rb-overflow-visible rb-border";
29330
+ const defaultBackgroundLayer = el("div", {
29331
+ className: "rb-absolute rb-inset-0 rb-z-neg-10 rb-h-full rb-w-full rb-pointer-events-none rb-bg-surface",
29332
+ style: { borderRadius: "inherit" }
29333
+ });
29334
+ const backgroundNode = backgroundFrame(opts.backgroundFrom);
29432
29335
  const style = {
29433
29336
  ...opts.style ?? {},
29434
29337
  borderColor: { $bind: {
@@ -29455,7 +29358,7 @@ function styledCard(children, opts, ...mods) {
29455
29358
  ...style ? { style } : {}
29456
29359
  }, [
29457
29360
  defaultBackgroundLayer,
29458
- ...backgroundNodes,
29361
+ backgroundNode,
29459
29362
  ...children
29460
29363
  ], ...mods);
29461
29364
  }
@@ -30328,7 +30231,7 @@ function buildTestimonialCard(...mods) {
30328
30231
  }, props({ value: "“" })), richText({ className: "rb-prose rb-max-w-none" }, bind("testimonial.content.body"), when("testimonial.content.body"))]), el("div", { className: "rb-testimonial-attribution" }, buildAttributionNodes())])], {
30329
30232
  stylesFrom: "content._cardStyles",
30330
30233
  backgroundFrom: "content._cardStyles.background",
30331
- baseClassName: "rb-testimonial-card rb-relative rb-isolate rb-flex rb-h-full rb-flex-col rb-overflow-hidden rb-p-8"
30234
+ baseClassName: "rb-testimonial-card rb-relative rb-isolate rb-flex rb-h-full rb-flex-col rb-overflow-visible rb-p-8"
30332
30235
  }, ...mods);
30333
30236
  }
30334
30237
  /**
@@ -31056,7 +30959,7 @@ function createFaqAccordionLayout(options = {}) {
31056
30959
  options: {
31057
30960
  axis: "all",
31058
30961
  includeSpacing: false,
31059
- baseClass: "rb-faq-item rb-relative rb-isolate rb-overflow-hidden"
30962
+ baseClass: "rb-faq-item rb-relative rb-isolate rb-overflow-visible"
31060
30963
  }
31061
30964
  }]
31062
30965
  },
@@ -32581,7 +32484,6 @@ function splitLayoutWith(children) {
32581
32484
  }
32582
32485
  }),
32583
32486
  renderBackgroundImage: false,
32584
- allowOverflow: true,
32585
32487
  baseClass: ""
32586
32488
  });
32587
32489
  }
@@ -33209,7 +33111,7 @@ function postCard(children, ...mods) {
33209
33111
  return styledCard(children, {
33210
33112
  stylesFrom: "content._cardStyles",
33211
33113
  backgroundFrom: "content._cardStyles.background",
33212
- baseClassName: "rb-relative rb-isolate rb-overflow-hidden rb-border rb-flex rb-flex-col rb-h-full"
33114
+ baseClassName: "rb-relative rb-isolate rb-overflow-visible rb-border rb-flex rb-flex-col rb-h-full"
33213
33115
  }, ...mods);
33214
33116
  }
33215
33117
  const gridPostCard = postCard([postImageLink("rb-h-48 rb-w-full rb-object-cover rb-transition-transform rb-hover-scale-105", {
@@ -33245,7 +33147,7 @@ const stackPostCard = styledCard([inline({
33245
33147
  ])])], {
33246
33148
  stylesFrom: "content._cardStyles",
33247
33149
  backgroundFrom: "content._cardStyles.background",
33248
- baseClassName: "rb-relative rb-isolate rb-overflow-hidden rb-border"
33150
+ baseClassName: "rb-relative rb-isolate rb-overflow-visible rb-border"
33249
33151
  }, repeat("data.posts", "post"));
33250
33152
  const emptyState$2 = {
33251
33153
  ...styledCard([text({
@@ -33254,7 +33156,7 @@ const emptyState$2 = {
33254
33156
  }, bind("content.emptyMessage", { fallback: "No posts published yet." }))], {
33255
33157
  stylesFrom: "content._cardStyles",
33256
33158
  backgroundFrom: "content._cardStyles.background",
33257
- baseClassName: "rb-relative rb-isolate rb-overflow-hidden rb-border rb-border-dashed rb-p-8 rb-text-center"
33159
+ baseClassName: "rb-relative rb-isolate rb-overflow-visible rb-border rb-border-dashed rb-p-8 rb-text-center"
33258
33160
  }),
33259
33161
  $when: {
33260
33162
  when: { from: "data.posts[0]" },
@@ -33264,7 +33166,7 @@ const emptyState$2 = {
33264
33166
  function blogListingShell(children) {
33265
33167
  return styledSection({
33266
33168
  children: styledContainer({
33267
- baseClassName: "rb-relative rb-isolate rb-overflow-hidden",
33169
+ baseClassName: "rb-relative rb-isolate rb-overflow-visible",
33268
33170
  children
33269
33171
  }),
33270
33172
  baseClass: ""
@@ -33698,7 +33600,7 @@ const copyLayout = fragmentLayoutNode$1(formCopyFragment.layout);
33698
33600
  const formSurface = styledContainer({
33699
33601
  bindFrom: "_containerStyles",
33700
33602
  constrainWidth: false,
33701
- baseClassName: "rb-form-surface rb-relative rb-isolate rb-overflow-hidden",
33603
+ baseClassName: "rb-form-surface rb-relative rb-isolate rb-overflow-visible",
33702
33604
  children: fragmentLayoutNode$1(formEmbedFragment.layout)
33703
33605
  });
33704
33606
  function createFormLayout(variant) {
@@ -34975,6 +34877,7 @@ const headerRootClassTransform = {
34975
34877
  ];
34976
34878
  const variant = header?.variant;
34977
34879
  if (variant && VALID_VARIANTS.includes(variant)) classes.push(`header-variant-${variant}`);
34880
+ if (header?.barFrame === "inset-shell" && variant === "classic") classes.push("header-bar-frame-inset-shell");
34978
34881
  return joinClasses$2(classes);
34979
34882
  }
34980
34883
  };
@@ -35519,7 +35422,7 @@ function markEditableSurfaceForwarding(component) {
35519
35422
  const SITE_CHROME_VISIBLE_HEADER_ATTR = "data-site-chrome-visible-header";
35520
35423
  //#endregion
35521
35424
  //#region ../blocks/src/system/blocks/site-header.ts
35522
- const whenTransformed$1 = (from, transformId, equals = true) => (node) => ({
35425
+ const whenTransformed = (from, transformId, equals = true) => (node) => ({
35523
35426
  ...node,
35524
35427
  $when: {
35525
35428
  when: {
@@ -35547,7 +35450,7 @@ const logoRow = link({
35547
35450
  text({
35548
35451
  as: "strong",
35549
35452
  className: "header-logo-text rb-truncate"
35550
- }, whenTransformed$1("$root.theme.header.logo", "layout.headerLogoTextVisible"), bind("site.title", { fallback: "Your Site" }))
35453
+ }, whenTransformed("$root.theme.header.logo", "layout.headerLogoTextVisible"), bind("site.title", { fallback: "Your Site" }))
35551
35454
  ]);
35552
35455
  const centeredLogoRow = link({
35553
35456
  href: "/",
@@ -35567,7 +35470,7 @@ const centeredLogoRow = link({
35567
35470
  text({
35568
35471
  as: "strong",
35569
35472
  className: "header-logo-text"
35570
- }, whenTransformed$1("$root.theme.header.logo", "layout.headerLogoTextVisible"), bind("site.title", { fallback: "Your Site" }))
35473
+ }, whenTransformed("$root.theme.header.logo", "layout.headerLogoTextVisible"), bind("site.title", { fallback: "Your Site" }))
35571
35474
  ]);
35572
35475
  const createNavRow = (className, align = "end") => navRow({
35573
35476
  className: `${className} header-nav-row`,
@@ -35699,7 +35602,7 @@ const classicLayout = inline({
35699
35602
  logoRow,
35700
35603
  createNavRow(`rb-ml-auto ${desktopOnlyDisplay("flex")} rb-gap-6`),
35701
35604
  headerCta
35702
- ], whenTransformed$1("$root.theme.header", "layout.classicNavMode", "inline"));
35605
+ ], whenTransformed("$root.theme.header", "layout.classicNavMode", "inline"));
35703
35606
  const classicCenteredNavLayout = inline({
35704
35607
  className: bindProp("$root.theme.header.maxWidth", {
35705
35608
  transforms: pipe(tx("layout.maxWidthClass", { base: `rb-header-layout ${desktopOnlyDisplay("flex")} rb-w-full rb-items-center rb-gap-6` })),
@@ -35710,7 +35613,7 @@ const classicCenteredNavLayout = inline({
35710
35613
  logoRow,
35711
35614
  createNavRow(`rb-flex-1 rb-justify-center ${desktopOnlyDisplay("flex")} rb-gap-6`, "center"),
35712
35615
  headerCta
35713
- ], whenTransformed$1("$root.theme.header", "layout.classicNavMode", "centered"));
35616
+ ], whenTransformed("$root.theme.header", "layout.classicNavMode", "centered"));
35714
35617
  const centeredLayout = stack({
35715
35618
  gap: "md",
35716
35619
  align: "center",
@@ -35773,7 +35676,6 @@ const siteHeaderBlockDefinition = { manifest: createBlockManifest({
35773
35676
  transforms: pipe(tx("layout.headerSectionBackground")),
35774
35677
  fallback: "background"
35775
35678
  }),
35776
- allowOverflow: true,
35777
35679
  className: bindProp("$root.theme.header", {
35778
35680
  transforms: pipe(tx("layout.headerRootClass")),
35779
35681
  fallback: "header-root rb-z-40 rb-w-full transition-theme"
@@ -35823,218 +35725,154 @@ const footerNavGroupsLayout = stack({
35823
35725
  linkRequired: true,
35824
35726
  target: { $bind: { from: "entry.target" } },
35825
35727
  rel: { $bind: { from: "entry.rel" } }
35826
- }, [text({ as: "span" }, bind("entry.label"))], repeat("group.children", "entry"))])], repeat("footerMenu.groups", "group"))], when("footerMenu.groups"));
35728
+ }, [text({ as: "span" }, bind("entry.label"))], repeat("group.children", "entry"))])], repeat("footerMenu.groups", "group"))], whenCollectionHasItems("footerMenu.groups"));
35827
35729
  //#endregion
35828
35730
  //#region ../blocks/src/system/blocks/site-footer.ts
35829
- const footerTextLayout = () => materializeFragment({ fragment: footerBottomTextFragment }).layout;
35830
- const whenTransformed = (from, transformId, equals = true) => (node) => ({
35831
- ...node,
35832
- $when: {
35833
- when: {
35834
- from,
35835
- transforms: [{ id: transformId }]
35836
- },
35837
- equals
35838
- }
35839
- });
35840
- const bottomBarTextLayout = () => {
35841
- const bottomTextNode = footerTextLayout()[1];
35842
- return bottomTextNode ? [bottomTextNode] : [];
35843
- };
35844
- const bodyTextLayout = () => {
35845
- const bodyTextNode = footerTextLayout()[0];
35846
- return bodyTextNode ? [bodyTextNode] : [];
35847
- };
35848
- const businessAddressLayout = () => [text({
35849
- as: "p",
35850
- className: "rb-caption rb-opacity-80"
35851
- }, bind("site.businessAddress.displayAddress"), when("content.showBusinessAddress", { equals: true }))];
35852
- const inlineBottomTextLayout = () => {
35853
- const bottomTextNode = footerTextLayout()[1];
35854
- if (!bottomTextNode) return [];
35855
- return [when("$root.theme.footer.bottomBar.enabled", {
35856
- equals: true,
35857
- not: true
35858
- })(bottomTextNode)];
35859
- };
35860
- const simpleFooterLayout = stack({
35861
- gap: "md",
35862
- align: "start",
35863
- className: { $bind: {
35864
- from: "$root.theme.footer",
35865
- transforms: [{ id: "layout.footerSimpleRootClass" }],
35866
- fallback: "rb-container rb-flex rb-w-full rb-flex-col rb-items-start rb-gap-4 rb-py-10 rb-text-left"
35867
- } }
35868
- }, [
35869
- link({
35870
- href: "/",
35871
- className: { $bind: {
35872
- from: "$root.theme.footer.logo",
35873
- transforms: [{
35874
- id: "layout.footerLogoClass",
35875
- options: { requireExplicitShow: true }
35876
- }],
35877
- fallback: "rb-hidden"
35878
- } }
35879
- }, [
35880
- media({ className: { $bind: {
35881
- from: "$root.theme.footer.logo",
35882
- transforms: [{ id: "layout.footerLogoMediaClass" }],
35883
- fallback: "rb-w-auto"
35884
- } } }, when("content.logo"), bind("content.logo")),
35885
- stack({ className: "rb-contents" }, [media({ className: { $bind: {
35886
- from: "$root.theme.footer.logo",
35887
- transforms: [{ id: "layout.footerLogoMediaClass" }],
35888
- fallback: "rb-w-auto"
35889
- } } }, when("site.logo"), bind("site.logo"))], when("content.logo", { not: true })),
35890
- text({
35891
- as: "strong",
35892
- className: "footer-logo-text rb-nav-text"
35893
- }, whenTransformed("$root.theme.footer", "layout.footerLogoTextVisible"), bind("site.title", { fallback: "Your Site" }))
35894
- ]),
35895
- footerNav({
35896
- collectionPath: "footerMenu.items",
35897
- mode: "flatten",
35898
- className: { $bind: {
35899
- from: "$root.theme.footer.navLayout",
35900
- transforms: [{ id: "layout.footerSimpleNavClass" }],
35901
- fallback: "footer-nav rb-flex rb-flex-wrap rb-justify-start rb-gap-x-6 rb-gap-y-3"
35902
- } },
35903
- linkClassName: "footer-nav-link rb-inline-flex rb-items-center rb-px-4 rb-py-2 rb-nav-text transition-theme-standard"
35904
- }),
35905
- ...bodyTextLayout(),
35906
- ...businessAddressLayout(),
35907
- ...inlineBottomTextLayout()
35908
- ], when("$root.theme.footer.variant", { equals: "simple" }));
35909
- const columnsFooterLayout = stack({
35910
- gap: "xl",
35911
- align: "start",
35731
+ const brandLogo = link({
35732
+ href: "/",
35912
35733
  className: { $bind: {
35913
- from: "$root.theme.footer.maxWidth",
35734
+ from: "$root.theme.footer.logo",
35914
35735
  transforms: [{
35915
- id: "layout.maxWidthClass",
35916
- options: { base: "rb-flex rb-w-full rb-flex-col rb-gap-10 rb-py-12" }
35736
+ id: "layout.footerLogoClass",
35737
+ options: { base: "footer-logo rb-inline-flex rb-items-center rb-gap-3 rb-no-underline" }
35917
35738
  }],
35918
- fallback: "rb-container rb-flex rb-w-full rb-flex-col rb-gap-10 rb-py-12"
35739
+ fallback: "footer-logo rb-inline-flex rb-items-center rb-gap-3 rb-no-underline"
35919
35740
  } }
35920
- }, [
35921
- footerNavGroupsLayout,
35922
- inline({ className: "rb-flex rb-w-full rb-flex-wrap rb-items-center rb-justify-between rb-gap-4" }, [text({
35923
- as: "strong",
35924
- className: "rb-block rb-nav-text",
35925
- style: textColorStyle("text")
35926
- }, whenTransformed("$root.theme.footer", "layout.footerLogoTextVisible"), bind("site.title", { fallback: "Your Site" })), footerNav({
35927
- collectionPath: "footerMenu.items",
35928
- mode: "links-only",
35929
- className: "rb-flex rb-flex-wrap rb-justify-end rb-gap-x-6 rb-gap-y-3",
35930
- linkClassName: "footer-nav-link rb-inline-flex rb-items-center rb-px-4 rb-py-2 rb-nav-text transition-theme-standard"
35931
- })]),
35932
- ...bodyTextLayout(),
35933
- ...businessAddressLayout(),
35934
- ...inlineBottomTextLayout()
35935
- ], when("$root.theme.footer.variant", { equals: "columns" }));
35936
- const splitFooterLayout = stack({
35937
- gap: "xl",
35938
- align: "start",
35741
+ }, [media({ className: { $bind: {
35742
+ from: "$root.theme.footer.logo",
35743
+ transforms: [{
35744
+ id: "layout.footerLogoMediaClass",
35745
+ options: { base: "rb-h-10 rb-w-auto" }
35746
+ }],
35747
+ fallback: "rb-h-10 rb-w-auto"
35748
+ } } }, when("module.showLogo", { equals: true }), when("content.logo"), bind("content.logo")), text({
35749
+ as: "strong",
35750
+ className: "footer-logo-text rb-nav-text"
35751
+ }, when("module.showTitle", { equals: true }), bind("site.title", { fallback: "Your Site" }))], when("module.kind", { equals: "brand" }));
35752
+ const navigation = stack({
35753
+ gap: "md",
35754
+ className: "rb-w-full"
35755
+ }, [footerNavGroupsLayout, footerNav({
35756
+ collectionPath: "footerMenu.items",
35757
+ mode: "links-only",
35939
35758
  className: { $bind: {
35940
- from: "$root.theme.footer.maxWidth",
35941
- transforms: [{
35942
- id: "layout.maxWidthClass",
35943
- options: { base: "rb-flex rb-w-full rb-flex-col rb-gap-10 rb-py-12" }
35944
- }],
35945
- fallback: "rb-container rb-flex rb-w-full rb-flex-col rb-gap-10 rb-py-12"
35946
- } }
35759
+ from: "module.navigationClassName",
35760
+ fallback: "footer-nav rb-flex rb-flex-wrap rb-gap-x-6 rb-gap-y-3"
35761
+ } },
35762
+ linkClassName: "footer-nav-link rb-nav-text transition-theme-standard"
35763
+ })], when("module.kind", { equals: "navigation" }));
35764
+ const legalNavigation = footerNav({
35765
+ collectionPath: "legalFooterMenu.items",
35766
+ mode: "links-only",
35767
+ className: "rb-flex rb-flex-wrap rb-gap-x-4 rb-gap-y-2",
35768
+ linkClassName: "footer-nav-link rb-caption transition-theme-standard"
35769
+ });
35770
+ const address = text({
35771
+ as: "address",
35772
+ className: "rb-not-italic rb-opacity-80"
35773
+ }, when("module.kind", { equals: "business-address" }), bind("module.address"));
35774
+ const contact = stack({
35775
+ gap: "sm",
35776
+ className: "rb-items-start"
35777
+ }, [link({
35778
+ href: { $bind: { from: "contactLink.href" } },
35779
+ className: "rb-nav-text rb-break-words transition-theme-standard"
35780
+ }, [text({ as: "span" }, bind("contactLink.label"))], repeat("module.contactLinks", "contactLink"))], when("module.kind", { equals: "contact" }));
35781
+ const hours = stack({
35782
+ gap: "sm",
35783
+ className: "rb-w-full"
35784
+ }, [inline({ className: "rb-flex rb-w-full rb-justify-between rb-gap-4" }, [text({
35785
+ as: "span",
35786
+ className: "rb-label"
35787
+ }, bind("hoursDay.weekday")), text({
35788
+ as: "span",
35789
+ className: "rb-caption rb-opacity-80"
35790
+ }, bind("hoursDay.hours"))], repeat("module.openingHours", "hoursDay")), text({
35791
+ as: "p",
35792
+ className: "rb-caption rb-opacity-70"
35793
+ }, bind("module.timeZone"), when("module.timeZone"))], when("module.kind", { equals: "opening-hours" }));
35794
+ const socials = inline({ className: "rb-flex rb-flex-wrap rb-gap-x-5 rb-gap-y-3" }, [link({
35795
+ href: { $bind: { from: "social.href" } },
35796
+ target: "_blank",
35797
+ rel: "noreferrer noopener",
35798
+ "aria-label": { $bind: { from: "social.label" } },
35799
+ className: "rb-nav-text transition-theme-standard"
35800
+ }, [icon({ className: "rb-h-5 rb-w-5" }, bind("social.icon"), when("social.icon")), text({ as: "span" }, bind("social.label"), when("social.icon", { equals: null }))], repeat("module.socialLinks", "social"))], when("module.kind", { equals: "social-links" }));
35801
+ const authoredCopy = richText({
35802
+ className: "rb-prose rb-prose-sm rb-max-w-none",
35803
+ style: textColorStyle("text/80")
35804
+ }, when("module.content"), bind("module.content", { transforms: [{
35805
+ id: "content.interpolateRichTextTokens",
35806
+ options: { tokens: ["year", "site_name"] }
35807
+ }] }));
35808
+ const footerGroup = stack({
35809
+ gap: "md",
35810
+ align: "stretch",
35811
+ className: "rb-min-w-0",
35812
+ "data-footer-group": { $bind: { from: "group.kind" } }
35813
+ }, [stack({
35814
+ gap: "md",
35815
+ align: "start",
35816
+ "data-preview-footer-module-id": { $bind: { from: "module.id" } }
35947
35817
  }, [
35948
- inline({ className: { $bind: {
35949
- from: "$root.theme.footer.logo",
35950
- transforms: [{ id: "layout.footerSplitMainClass" }],
35951
- fallback: "rb-flex rb-w-full rb-flex-col rb-items-start rb-justify-between rb-gap-8 rb-md-flex-row rb-md-items-end"
35952
- } } }, [stack({}, [footerNav({
35953
- collectionPath: "footerMenu.items",
35954
- mode: "flatten",
35955
- className: { $bind: {
35956
- from: "$root.theme.footer.navLayout",
35957
- transforms: [{ id: "layout.footerSplitNavSingleClass" }],
35958
- fallback: "rb-w-full rb-space-y-3 rb-text-left"
35959
- } },
35960
- linkClassName: "footer-nav-link rb-inline-flex rb-items-center rb-whitespace-nowrap rb-nav-text transition-theme-standard"
35961
- })]), link({
35962
- href: "/",
35963
- className: { $bind: {
35964
- from: "$root.theme.footer.logo",
35965
- transforms: [{ id: "layout.footerLogoClass" }],
35966
- fallback: "footer-logo rb-inline-flex rb-items-center rb-justify-end rb-gap-3 rb-self-end rb-no-underline rb-text-right rb-transition-opacity rb-hover-opacity-80"
35967
- } }
35968
- }, [
35969
- media({ className: { $bind: {
35970
- from: "$root.theme.footer.logo",
35971
- transforms: [{ id: "layout.footerLogoMediaClass" }],
35972
- fallback: "rb-w-auto"
35973
- } } }, when("content.logo"), bind("content.logo")),
35974
- stack({ className: "rb-contents" }, [media({ className: { $bind: {
35975
- from: "$root.theme.footer.logo",
35976
- transforms: [{ id: "layout.footerLogoMediaClass" }],
35977
- fallback: "rb-w-auto"
35978
- } } }, when("site.logo"), bind("site.logo"))], when("content.logo", { not: true })),
35979
- text({
35980
- as: "strong",
35981
- className: "footer-logo-text rb-nav-text"
35982
- }, whenTransformed("$root.theme.footer", "layout.footerLogoTextVisible"), bind("site.title", { fallback: "Your Site" }))
35983
- ])]),
35984
- ...businessAddressLayout(),
35985
- ...inlineBottomTextLayout()
35986
- ], when("$root.theme.footer.variant", { equals: "split" }));
35987
- const footerLayout = section$1({
35988
- background: "background",
35818
+ text({
35819
+ as: "h2",
35820
+ className: "rb-label",
35821
+ style: textColorStyle("text/70")
35822
+ }, bind("module.heading"), when("module.heading")),
35823
+ brandLogo,
35824
+ navigation,
35825
+ stack({
35826
+ gap: "sm",
35827
+ className: "rb-w-full"
35828
+ }, [legalNavigation], when("module.kind", { equals: "legal-navigation" })),
35829
+ address,
35830
+ contact,
35831
+ hours,
35832
+ socials,
35833
+ stack({ className: "rb-w-full" }, [authoredCopy], when("module.kind", { equals: "supporting-text" })),
35834
+ stack({ className: "rb-w-full rb-lg-col-span-3" }, [authoredCopy], when("module.kind", { equals: "legal" }))
35835
+ ], repeat("group.modules", "module"))], repeat("region.groups", "group"));
35836
+ const footerMainRegion = stack({
35837
+ className: { $bind: { from: "region.className" } },
35838
+ "data-footer-region": { $bind: { from: "region.kind" } }
35839
+ }, [footerGroup], when("region.kind", { equals: "main" }), repeat("content.footerRuntime.regions", "region"));
35840
+ const footerBottomRegion = stack({ className: { $bind: {
35841
+ from: "$root.theme.footer",
35842
+ transforms: [{ id: "layout.footerBottomBarContainerClass" }],
35843
+ fallback: "rb-w-full"
35844
+ } } }, [stack({
35989
35845
  className: { $bind: {
35990
35846
  from: "$root.theme.footer",
35991
- transforms: [{ id: "layout.footerRootClass" }],
35992
- fallback: "rb-w-full rb-border-t transition-theme"
35847
+ transforms: [{ id: "layout.footerBottomBarClass" }],
35848
+ fallback: "rb-w-full rb-border-t rb-px-6 rb-py-6 rb-text-center"
35993
35849
  } },
35994
35850
  style: { $bind: {
35995
35851
  from: "$root.theme.footer",
35996
- transforms: [{ id: "layout.footerRootStyle" }],
35997
- fallback: mergeStyles(backgroundColorStyle("surface"), surfaceForegroundStyle({ text: "rgb(var(--tb-text))" }), borderColorStyle("border"))
35998
- } }
35999
- }, [
36000
- simpleFooterLayout,
36001
- columnsFooterLayout,
36002
- splitFooterLayout,
36003
- stack({
36004
- className: { $bind: {
36005
- from: "$root.theme.footer",
36006
- transforms: [{ id: "layout.footerBottomBarClass" }],
36007
- fallback: "rb-w-full rb-border-t rb-py-5"
36008
- } },
36009
- style: { $bind: {
36010
- from: "$root.theme.footer",
36011
- transforms: [{ id: "layout.footerBottomBarStyle" }]
36012
- } }
36013
- }, [stack({ className: { $bind: {
36014
- from: "$root.theme.footer",
36015
- transforms: [{ id: "layout.footerBottomBarContainerClass" }],
36016
- fallback: "rb-container"
36017
- } } }, [...bottomBarTextLayout()])], when("$root.theme.footer.bottomBar.enabled", { equals: true }))
36018
- ]);
35852
+ transforms: [{ id: "layout.footerBottomBarStyle" }]
35853
+ } },
35854
+ "data-footer-region": "bottom"
35855
+ }, [footerGroup])], when("region.kind", { equals: "bottom" }), repeat("content.footerRuntime.regions", "region"));
36019
35856
  const siteFooterBlockDefinition = { manifest: createBlockManifest({
36020
35857
  id: "block.site-footer",
36021
35858
  title: "Site Footer",
36022
35859
  category: "layout",
36023
- fragments: [{
36024
- fragment: footerBottomTextFragment,
36025
- fieldPriority: 0
36026
- }],
36027
35860
  skipSectionStyles: true,
36028
- additionalFields: [{
36029
- id: "showBusinessAddress",
36030
- type: "boolean",
36031
- label: "Add business address to site footer?",
36032
- required: false,
36033
- defaultValue: false,
36034
- ui: { intent: "content" }
36035
- }],
36036
- layout: footerLayout,
36037
- description: "Site-wide footer with navigation links and optional columns.",
35861
+ layout: section$1({
35862
+ background: "background",
35863
+ className: { $bind: {
35864
+ from: "$root.theme.footer",
35865
+ transforms: [{ id: "layout.footerRootClass" }],
35866
+ fallback: "rb-w-full rb-border-t transition-theme"
35867
+ } },
35868
+ style: { $bind: {
35869
+ from: "$root.theme.footer",
35870
+ transforms: [{ id: "layout.footerRootStyle" }],
35871
+ fallback: mergeStyles(backgroundColorStyle("surface"), surfaceForegroundStyle({ text: "rgb(var(--tb-text))" }), borderColorStyle("border"))
35872
+ } },
35873
+ "data-footer-membership": { $bind: { from: "content.footerRuntime.membershipKey" } }
35874
+ }, [footerMainRegion, footerBottomRegion]),
35875
+ description: "Site-wide composed footer with canonical shared details.",
36038
35876
  styleTokens: { spacing: "md" },
36039
35877
  paletteHidden: true
36040
35878
  }) };
@@ -36512,7 +36350,7 @@ const repeatedItemsNode = repeaterFragmentLayout({
36512
36350
  id: "boxStyles.all",
36513
36351
  options: {
36514
36352
  axis: "all",
36515
- baseClass: "rb-collection-item rb-relative rb-isolate rb-overflow-hidden rb-border"
36353
+ baseClass: "rb-collection-item rb-relative rb-isolate rb-overflow-visible rb-border"
36516
36354
  }
36517
36355
  }]
36518
36356
  },
@@ -51475,16 +51313,17 @@ const backgroundTransforms = [
51475
51313
  run: (value, _options, context) => resolveSurfaceForegroundStyles(value, context)
51476
51314
  },
51477
51315
  {
51478
- id: "background.resolveAllowOverflow",
51316
+ id: "background.resolveFrameClassName",
51479
51317
  kind: "formatter",
51480
- summary: "Resolve allowOverflow from background config (explicit overflow or scaled image)",
51481
- run: (value) => {
51482
- if (!value || typeof value !== "object") return false;
51318
+ summary: "Resolve clipping on a decorative background frame without clipping foreground content",
51319
+ run: (value, options) => {
51320
+ const baseClass = options?.baseClass?.trim() ?? "";
51321
+ if (!value || typeof value !== "object") return `${baseClass} rb-overflow-hidden`.trim();
51483
51322
  const input = value;
51484
- if (input.overflow === true) return true;
51323
+ if (input.overflow === true) return `${baseClass} rb-overflow-visible`.trim();
51485
51324
  const objectFit = isString$1(input.objectFit) ? input.objectFit.trim() : null;
51486
51325
  const scale = isString$1(input.scale) ? input.scale.trim() : isNumber$1(input.scale) ? String(input.scale) : null;
51487
- return Boolean((objectFit === "custom" || objectFit === "original") && scale && scale.trim().length > 0);
51326
+ return `${baseClass} ${Boolean((objectFit === "custom" || objectFit === "original") && scale && scale.trim().length > 0) ? "rb-overflow-visible" : "rb-overflow-hidden"}`.trim();
51488
51327
  }
51489
51328
  },
51490
51329
  {
@@ -52029,10 +51868,10 @@ function isRecord$17(value) {
52029
51868
  }
52030
51869
  //#endregion
52031
51870
  //#region ../blocks/src/primitives/layout/Section.tsx
52032
- const Section = forwardRef(function Section({ as: Comp = "section", children, background, className = "", allowOverflow = false, style, "data-slot": dataSlot }, ref) {
51871
+ const Section = forwardRef(function Section({ as: Comp = "section", children, background, className = "", style, "data-slot": dataSlot }, ref) {
52033
51872
  return /* @__PURE__ */ jsx(Comp, {
52034
51873
  ref,
52035
- className: clsx("rb-relative rb-isolate", allowOverflow ? "rb-overflow-visible" : "rb-overflow-hidden", className),
51874
+ className: clsx("rb-relative rb-isolate rb-overflow-visible", className),
52036
51875
  style: mergeStyles(typeof background === "string" && background.trim().length > 0 ? backgroundColorStyle(background.trim()) : void 0, style),
52037
51876
  "data-slot": dataSlot ?? "section",
52038
51877
  children
@@ -52153,16 +51992,83 @@ function Grid({ as: Comp = "div", cols = {
52153
51992
  }
52154
51993
  //#endregion
52155
51994
  //#region ../blocks/src/system/runtime/nodes/layout.tsx
52156
- const SectionNode = ({ blockId: _blockId, blockKind: _blockKind, blockContent: _blockContent, fragmentRegistry: _fragmentRegistry, previewAuthoring: _previewAuthoring, pathBase: _pathBase, allowOverflow, ...props }) => /* @__PURE__ */ jsx(Section, {
52157
- ...props,
52158
- allowOverflow
52159
- });
51995
+ const SectionNode = ({ blockId: _blockId, blockKind: _blockKind, blockContent: _blockContent, fragmentRegistry: _fragmentRegistry, previewAuthoring: _previewAuthoring, pathBase: _pathBase, ...props }) => /* @__PURE__ */ jsx(Section, { ...props });
52160
51996
  const StackNode = ({ blockId: _blockId, blockKind: _blockKind, blockContent: _blockContent, fragmentRegistry: _fragmentRegistry, previewAuthoring: _previewAuthoring, pathBase: _pathBase, ...props }) => /* @__PURE__ */ jsx(Stack, { ...props });
52161
51997
  const InlineNode = ({ blockId: _blockId, blockKind: _blockKind, blockContent: _blockContent, fragmentRegistry: _fragmentRegistry, previewAuthoring: _previewAuthoring, pathBase: _pathBase, ...props }) => /* @__PURE__ */ jsx(Inline, { ...props });
52162
51998
  const GridNode = ({ blockId: _blockId, blockKind: _blockKind, blockContent: _blockContent, fragmentRegistry: _fragmentRegistry, previewAuthoring: _previewAuthoring, pathBase: _pathBase, ...props }) => /* @__PURE__ */ jsx(Grid, { ...props });
52163
51999
  const DivNode = ({ blockId: _blockId, blockKind: _blockKind, blockContent: _blockContent, fragmentRegistry: _fragmentRegistry, previewAuthoring: _previewAuthoring, pathBase: _pathBase, ...props }) => /* @__PURE__ */ jsx("div", { ...props });
52164
52000
  const FigureNode = ({ blockId: _blockId, blockKind: _blockKind, blockContent: _blockContent, fragmentRegistry: _fragmentRegistry, previewAuthoring: _previewAuthoring, pathBase: _pathBase, ...props }) => /* @__PURE__ */ jsx("figure", { ...props });
52165
52001
  //#endregion
52002
+ //#region ../path-utils/src/index.ts
52003
+ const PATH_SEPARATOR_REGEX$1 = /\./g;
52004
+ const BRACKET_ACCESS_REGEX$1 = /\[([^\]]+)\]/g;
52005
+ /**
52006
+ * Segments that would traverse or mutate the prototype chain.
52007
+ *
52008
+ * `setAtPath` creates nested objects along the path, so allowing these
52009
+ * segments is a prototype-pollution vector. They are rejected everywhere a
52010
+ * path is parsed (string or pre-parsed array form) — fail closed.
52011
+ */
52012
+ const UNSAFE_PATH_SEGMENTS = /* @__PURE__ */ new Set([
52013
+ "__proto__",
52014
+ "constructor",
52015
+ "prototype"
52016
+ ]);
52017
+ var UnsafePathSegmentError = class extends Error {
52018
+ constructor(segment) {
52019
+ super(`Unsafe path segment: "${segment}"`);
52020
+ this.name = "UnsafePathSegmentError";
52021
+ this.segment = segment;
52022
+ }
52023
+ };
52024
+ function assertSafePathSegments(segments) {
52025
+ for (const segment of segments) if (typeof segment === "string" && UNSAFE_PATH_SEGMENTS.has(segment)) throw new UnsafePathSegmentError(segment);
52026
+ }
52027
+ function isRecord$16(value) {
52028
+ return typeof value === "object" && value !== null && !Array.isArray(value);
52029
+ }
52030
+ function isPathContainer(value) {
52031
+ return Array.isArray(value) || isRecord$16(value);
52032
+ }
52033
+ function getContainerValue(container, segment) {
52034
+ if (typeof segment === "number") return Array.isArray(container) ? container[segment] : void 0;
52035
+ if (segment in container) return Reflect.get(container, segment);
52036
+ }
52037
+ function parsePath(path) {
52038
+ if (Array.isArray(path)) {
52039
+ assertSafePathSegments(path);
52040
+ return path;
52041
+ }
52042
+ const segments = [];
52043
+ const parts = path.split(PATH_SEPARATOR_REGEX$1);
52044
+ for (const raw of parts) {
52045
+ if (!raw) continue;
52046
+ const baseMatch = raw.match(/^[^\[]+/);
52047
+ if (baseMatch !== null) {
52048
+ const base = baseMatch[1] ?? baseMatch[0];
52049
+ if (/^\d+$/.test(base)) segments.push(Number(base));
52050
+ else segments.push(base);
52051
+ }
52052
+ const bracketMatches = raw.matchAll(BRACKET_ACCESS_REGEX$1);
52053
+ for (const match of bracketMatches) {
52054
+ const token = match[1] ?? "";
52055
+ if (token.startsWith("\"") || token.startsWith("'")) segments.push(token.slice(1, -1));
52056
+ else if (/^\d+$/.test(token)) segments.push(Number(token));
52057
+ else segments.push(token);
52058
+ }
52059
+ if (baseMatch === null && !raw.includes("[")) segments.push(raw);
52060
+ }
52061
+ assertSafePathSegments(segments);
52062
+ return segments;
52063
+ }
52064
+ function getAtPath(source, path) {
52065
+ return parsePath(path).reduce((current, segment) => {
52066
+ if (current === void 0 || current === null) return void 0;
52067
+ if (!isPathContainer(current)) return void 0;
52068
+ return getContainerValue(current, segment);
52069
+ }, source);
52070
+ }
52071
+ //#endregion
52166
52072
  //#region ../blocks/src/primitives/content/utils/sanitizeHref.ts
52167
52073
  const SAFE_PROTOCOLS = /* @__PURE__ */ new Set([
52168
52074
  "http:",
@@ -52394,6 +52300,58 @@ function getCtaIconComponent(name) {
52394
52300
  return CTA_ICON_COMPONENTS[name] ?? null;
52395
52301
  }
52396
52302
  //#endregion
52303
+ //#region ../blocks/src/system/icons/social.tsx
52304
+ const SOCIAL_ICON_NAMES = [
52305
+ "SocialFacebook",
52306
+ "SocialInstagram",
52307
+ "SocialLinkedIn",
52308
+ "SocialTikTok",
52309
+ "SocialX",
52310
+ "SocialYouTube"
52311
+ ];
52312
+ const socialIcons = {
52313
+ SocialFacebook: createIcon("SocialFacebookIcon", /* @__PURE__ */ jsx("path", { d: "M14 8h3V4h-3c-3 0-5 2-5 5v3H6v4h3v6h4v-6h3l1-4h-4V9c0-.7.3-1 1-1Z" })),
52314
+ SocialInstagram: createIcon("SocialInstagramIcon", /* @__PURE__ */ jsxs(Fragment, { children: [
52315
+ /* @__PURE__ */ jsx("rect", {
52316
+ x: "3",
52317
+ y: "3",
52318
+ width: "18",
52319
+ height: "18",
52320
+ rx: "5"
52321
+ }),
52322
+ /* @__PURE__ */ jsx("circle", {
52323
+ cx: "12",
52324
+ cy: "12",
52325
+ r: "4"
52326
+ }),
52327
+ /* @__PURE__ */ jsx("circle", {
52328
+ cx: "17.5",
52329
+ cy: "6.5",
52330
+ r: ".75",
52331
+ fill: "currentColor",
52332
+ stroke: "none"
52333
+ })
52334
+ ] })),
52335
+ SocialLinkedIn: createIcon("SocialLinkedInIcon", /* @__PURE__ */ jsxs(Fragment, { children: [
52336
+ /* @__PURE__ */ jsx("path", { d: "M6 9v10" }),
52337
+ /* @__PURE__ */ jsx("path", {
52338
+ d: "M6 5.5v.01",
52339
+ strokeWidth: "3"
52340
+ }),
52341
+ /* @__PURE__ */ jsx("path", { d: "M10.5 19v-6a4 4 0 0 1 8 0v6" }),
52342
+ /* @__PURE__ */ jsx("path", { d: "M10.5 9v10" })
52343
+ ] })),
52344
+ SocialTikTok: createIcon("SocialTikTokIcon", /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("path", { d: "M14 4v11.5a4.5 4.5 0 1 1-4-4.47" }), /* @__PURE__ */ jsx("path", { d: "M14 4c.7 3 2.4 4.5 5 4.5" })] })),
52345
+ SocialX: createIcon("SocialXIcon", /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("path", { d: "m5 4 14 16" }), /* @__PURE__ */ jsx("path", { d: "M19 4 5 20" })] })),
52346
+ SocialYouTube: createIcon("SocialYouTubeIcon", /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("path", { d: "M21 12c0 3.5-.5 5.5-1.3 6.3S16.5 19.5 12 19.5s-6.9-.4-7.7-1.2S3 15.5 3 12s.5-5.5 1.3-6.3S7.5 4.5 12 4.5s6.9.4 7.7 1.2S21 8.5 21 12Z" }), /* @__PURE__ */ jsx("path", { d: "m10 9 5 3-5 3Z" })] }))
52347
+ };
52348
+ function isSocialIconName(value) {
52349
+ return typeof value === "string" && SOCIAL_ICON_NAMES.includes(value);
52350
+ }
52351
+ function getSocialIconComponent(value) {
52352
+ return isSocialIconName(value) ? socialIcons[value] : null;
52353
+ }
52354
+ //#endregion
52397
52355
  //#region ../blocks/src/system/icons/registry.ts
52398
52356
  function buildSearchText(parts) {
52399
52357
  return parts.map((part) => part.trim()).filter(Boolean).join(" ");
@@ -52423,7 +52381,7 @@ function semanticOptionsForPreset(preset) {
52423
52381
  }
52424
52382
  semanticOptionsForPreset("feature");
52425
52383
  function getIconComponent(name) {
52426
- return getCtaIconComponent(name) ?? getSemanticIconComponent(name);
52384
+ return getCtaIconComponent(name) ?? getSemanticIconComponent(name) ?? getSocialIconComponent(name);
52427
52385
  }
52428
52386
  //#endregion
52429
52387
  //#region ../blocks/src/system/runtime/nodes/buttonAffordance.ts
@@ -53215,7 +53173,6 @@ const HeaderSectionNode = ({ blockId, children, className, "data-preview-site-ch
53215
53173
  const asProp = rest.as;
53216
53174
  const styleProp = rest.style;
53217
53175
  const backgroundProp = typeof rest.background === "string" ? rest.background : void 0;
53218
- const allowOverflowProp = typeof rest.allowOverflow === "boolean" ? rest.allowOverflow : void 0;
53219
53176
  const dataSlotProp = typeof rest["data-slot"] === "string" ? rest["data-slot"] : void 0;
53220
53177
  return /* @__PURE__ */ jsxs("nav", {
53221
53178
  ...getIslandRootProps("headerSection", blockId),
@@ -53230,7 +53187,6 @@ const HeaderSectionNode = ({ blockId, children, className, "data-preview-site-ch
53230
53187
  as: asProp,
53231
53188
  style: styleProp,
53232
53189
  background: backgroundProp ?? "background",
53233
- allowOverflow: allowOverflowProp,
53234
53190
  "data-slot": dataSlotProp,
53235
53191
  className: sectionClasses || void 0,
53236
53192
  children
@@ -53385,7 +53341,7 @@ const SvgNode = ({ blockId: _blockId, blockKind: _blockKind, blockContent: _bloc
53385
53341
  children: (Array.isArray(shapes) ? shapes : []).map((shape, index) => renderShape(shape, index))
53386
53342
  });
53387
53343
  };
53388
- function isRecord$15(value) {
53344
+ function isRecord$14(value) {
53389
53345
  return typeof value === "object" && value !== null && !Array.isArray(value);
53390
53346
  }
53391
53347
  function deepEqualJsonValue(left, right) {
@@ -53395,8 +53351,8 @@ function deepEqualJsonValue(left, right) {
53395
53351
  if (left.length !== right.length) return false;
53396
53352
  return left.every((item, index) => deepEqualJsonValue(item, right[index]));
53397
53353
  }
53398
- if (isRecord$15(left) || isRecord$15(right)) {
53399
- if (!isRecord$15(left) || !isRecord$15(right)) return false;
53354
+ if (isRecord$14(left) || isRecord$14(right)) {
53355
+ if (!isRecord$14(left) || !isRecord$14(right)) return false;
53400
53356
  const leftKeys = Object.keys(left).sort();
53401
53357
  if (!deepEqualJsonValue(leftKeys, Object.keys(right).sort())) return false;
53402
53358
  return leftKeys.every((key) => deepEqualJsonValue(left[key], right[key]));
@@ -53410,12 +53366,12 @@ function toTrimmedString(value) {
53410
53366
  return trimmed ? trimmed : void 0;
53411
53367
  }
53412
53368
  function normalizeBookingFormConfig(form) {
53413
- if (!isRecord$14(form)) return null;
53369
+ if (!isRecord$13(form)) return null;
53414
53370
  const id = readNonEmptyString(form.id);
53415
53371
  const name = readNonEmptyString(form.name);
53416
53372
  if (!id || !name) return null;
53417
- const schemaSource = isRecord$14(form.schema) ? form.schema : isRecord$14(form.schemaJson) ? form.schemaJson : null;
53418
- const settingsSource = isRecord$14(form.settings) ? form.settings : isRecord$14(form.settingsJson) ? form.settingsJson : null;
53373
+ const schemaSource = isRecord$13(form.schema) ? form.schema : isRecord$13(form.schemaJson) ? form.schemaJson : null;
53374
+ const settingsSource = isRecord$13(form.settings) ? form.settings : isRecord$13(form.settingsJson) ? form.settingsJson : null;
53419
53375
  return {
53420
53376
  id,
53421
53377
  name,
@@ -53435,8 +53391,8 @@ function normalizeBookingServices(services) {
53435
53391
  };
53436
53392
  if (!services) return [];
53437
53393
  if (Array.isArray(services)) return services.filter(isBookingFormService).map(normalizeService);
53438
- if (isRecord$14(services) && "services" in services) return Array.isArray(services.services) ? services.services.filter(isBookingFormService).map(normalizeService) : [];
53439
- return isRecord$14(services) ? Object.values(services).filter(isBookingFormService).map(normalizeService) : [];
53394
+ if (isRecord$13(services) && "services" in services) return Array.isArray(services.services) ? services.services.filter(isBookingFormService).map(normalizeService) : [];
53395
+ return isRecord$13(services) ? Object.values(services).filter(isBookingFormService).map(normalizeService) : [];
53440
53396
  }
53441
53397
  function normalizeBookingSchema(value) {
53442
53398
  if (!value) return void 0;
@@ -53447,7 +53403,7 @@ function normalizeBookingSchema(value) {
53447
53403
  };
53448
53404
  }
53449
53405
  function readBookingFormField(value) {
53450
- if (!isRecord$14(value)) return null;
53406
+ if (!isRecord$13(value)) return null;
53451
53407
  const id = readNonEmptyString(value.id);
53452
53408
  const label = readNonEmptyString(value.label);
53453
53409
  const type = readBookingFieldType(value.type);
@@ -53491,7 +53447,7 @@ function readBookingFieldOptions(value) {
53491
53447
  return options.length > 0 ? options : void 0;
53492
53448
  }
53493
53449
  function readBookingFieldOption(value) {
53494
- if (!isRecord$14(value)) return null;
53450
+ if (!isRecord$13(value)) return null;
53495
53451
  const optionValue = readNonEmptyString(value.value);
53496
53452
  const label = readNonEmptyString(value.label);
53497
53453
  return optionValue && label ? {
@@ -53511,7 +53467,7 @@ function normalizeBookingSettings(value) {
53511
53467
  };
53512
53468
  }
53513
53469
  function isBookingFormService(value) {
53514
- return isRecord$14(value) && typeof value.id === "string" && typeof value.siteId === "string" && typeof value.title === "string";
53470
+ return isRecord$13(value) && typeof value.id === "string" && typeof value.siteId === "string" && typeof value.title === "string";
53515
53471
  }
53516
53472
  function readNonEmptyString(value) {
53517
53473
  if (typeof value !== "string") return null;
@@ -53529,7 +53485,7 @@ function readStringArray(value) {
53529
53485
  const strings = value.filter((item) => typeof item === "string");
53530
53486
  return strings.length > 0 ? strings : void 0;
53531
53487
  }
53532
- function isRecord$14(value) {
53488
+ function isRecord$13(value) {
53533
53489
  return typeof value === "object" && value !== null;
53534
53490
  }
53535
53491
  //#endregion
@@ -57950,7 +57906,7 @@ function resolveGroupFrame(cardStyles) {
57950
57906
  contentClassName: "offerings-preview-card-content rb-flex rb-h-full rb-min-h-full rb-flex-col rb-gap-5"
57951
57907
  };
57952
57908
  return {
57953
- containerClassName: ["offerings-preview-card offerings-preview-card--framed rb-relative rb-isolate rb-h-full rb-min-h-full rb-overflow-hidden rb-bg-surface rb-border rb-border-border", resolveGroupFrameClasses(cardStyles)].filter(Boolean).join(" "),
57909
+ containerClassName: ["offerings-preview-card offerings-preview-card--framed rb-relative rb-isolate rb-h-full rb-min-h-full rb-overflow-visible rb-bg-surface rb-border rb-border-border", resolveGroupFrameClasses(cardStyles)].filter(Boolean).join(" "),
57954
57910
  containerStyle: resolveGroupFrameStyle(cardStyles),
57955
57911
  contentClassName: "card-content offerings-preview-card-content rb-flex rb-h-full rb-min-h-full rb-flex-col rb-gap-5"
57956
57912
  };
@@ -60226,14 +60182,14 @@ function isDecoratedHeadingBlockKind(blockKind) {
60226
60182
  return blockKind === "block.intro" || blockKind === "block.feature-cards" || blockKind === "block.testimonials" || blockKind === "block.faq";
60227
60183
  }
60228
60184
  function readVariant(blockContent) {
60229
- if (!isRecord$13(blockContent)) return void 0;
60185
+ if (!isRecord$12(blockContent)) return void 0;
60230
60186
  const variant = blockContent.variant;
60231
60187
  return typeof variant === "string" ? variant : void 0;
60232
60188
  }
60233
60189
  function isFaqDecoratedVariant(variant) {
60234
60190
  return variant === "default" || variant === "question-columns";
60235
60191
  }
60236
- function isRecord$13(value) {
60192
+ function isRecord$12(value) {
60237
60193
  return typeof value === "object" && value !== null && !Array.isArray(value);
60238
60194
  }
60239
60195
  function buildHeadingDecorationWrapperClassName(className) {
@@ -60983,9 +60939,9 @@ function isReactNode(value) {
60983
60939
  * Handles conditionals ($when), scopes ($scopes), repeaters ($repeat), bindings ($bind), and children.
60984
60940
  */
60985
60941
  function resolveNode(node, context, indexFallback) {
60986
- if (!shouldRenderNode(node, context)) return null;
60987
60942
  const scopeContext = applyScopes(node, context);
60988
60943
  if (node.$repeat) return resolveRepeater(node, scopeContext);
60944
+ if (!shouldRenderNode(node, scopeContext)) return null;
60989
60945
  const registry = scopeContext.registry ?? serverComponentRegistry;
60990
60946
  const normalizedType = node.type.toLowerCase();
60991
60947
  const component = registry[node.type] ?? registry[normalizedType] ?? (normalizedType === "section" ? SectionNode : void 0);
@@ -61303,7 +61259,7 @@ function applyStyleOverride(target, key, defaults) {
61303
61259
  //#endregion
61304
61260
  //#region ../blocks/src/system/runtime/blockComposition.ts
61305
61261
  function readBlockComposition(value) {
61306
- if (!isRecord$12(value) || typeof value.kind !== "string") return null;
61262
+ if (!isRecord$11(value) || typeof value.kind !== "string") return null;
61307
61263
  switch (value.kind) {
61308
61264
  case "intro": return value.treatment === "editorial-statement" || value.treatment === "portrait-bio" ? {
61309
61265
  kind: "intro",
@@ -61316,7 +61272,7 @@ function readBlockComposition(value) {
61316
61272
  default: return null;
61317
61273
  }
61318
61274
  }
61319
- function isRecord$12(value) {
61275
+ function isRecord$11(value) {
61320
61276
  return typeof value === "object" && value !== null && !Array.isArray(value);
61321
61277
  }
61322
61278
  //#endregion
@@ -61483,11 +61439,11 @@ function assertThemeConfigCanGenerateAccordionSystem(themeConfig) {
61483
61439
  }
61484
61440
  //#endregion
61485
61441
  //#region ../blocks/src/system/media/constrainedVideoMedia.ts
61486
- function isRecord$11(value) {
61442
+ function isRecord$10(value) {
61487
61443
  return typeof value === "object" && value !== null && !Array.isArray(value);
61488
61444
  }
61489
61445
  function valueAtField(current, fieldId) {
61490
- return isRecord$11(current) ? current[fieldId] : void 0;
61446
+ return isRecord$10(current) ? current[fieldId] : void 0;
61491
61447
  }
61492
61448
  function collectConstrainedVideoMediaValues(options) {
61493
61449
  const { blockKind, fields, currentValue, parentPath = [] } = options;
@@ -61498,7 +61454,7 @@ function collectConstrainedVideoMediaValues(options) {
61498
61454
  const fieldValue = valueAtField(currentValue, field.id);
61499
61455
  switch (field.type) {
61500
61456
  case "media": {
61501
- if (!isRecord$11(fieldValue) || fieldValue.type !== "video") break;
61457
+ if (!isRecord$10(fieldValue) || fieldValue.type !== "video") break;
61502
61458
  const policy = deriveVideoSlotPolicy(resolveVideoSelectionIntentForMediaField({
61503
61459
  fieldPath,
61504
61460
  mediaKinds: field.mediaKinds
@@ -62404,6 +62360,19 @@ const NAV_DROPDOWN_CONTAINER_RAIL_CSS_RULES = [
62404
62360
  //#region ../theme-core/src/header/generateHeaderCss.ts
62405
62361
  const HEADER_BLUR = "blur(12px)";
62406
62362
  const FLOATING_BLUR = "blur(16px)";
62363
+ const INSET_SHELL_MARKER_CLASS = "header-bar-frame-inset-shell";
62364
+ const INSET_SHELL_EDGE = "1rem";
62365
+ const INSET_SHELL_INSET_BLOCK = "0.875rem";
62366
+ const INSET_SHELL_RADIUS = "9999px";
62367
+ const INSET_SHELL_CONTAINER_MAX = "80rem";
62368
+ const INSET_SHELL_INTERIOR_PADDING_X = "1.75rem";
62369
+ /**
62370
+ * Whether the classic header should render as an inset "brand capsule" shell.
62371
+ * The facet is only meaningful for the classic layout; other variants ignore it.
62372
+ */
62373
+ function usesInsetShell(header) {
62374
+ return header.barFrame === "inset-shell" && header.variant === "classic";
62375
+ }
62407
62376
  /**
62408
62377
  * Generate complete CSS for header system from theme config
62409
62378
  *
@@ -62503,7 +62472,36 @@ function generateHeaderRootStyles(header, themeId, tokens, _theme) {
62503
62472
  const baseBlock = `\n${selector} {\n ${rules.join("\n ")}\n}\n`;
62504
62473
  const overlayFix = `\n${`${selector}:has([data-nav-mobile-overlay][aria-hidden="false"])`} {\n backdrop-filter: none !important;\n -webkit-backdrop-filter: none !important;\n}\n`;
62505
62474
  if (isContainedNav || backgroundRules.length === 0) return `${baseBlock}\n${overlayFix}`;
62506
- return `${baseBlock}\n${`\n${backgroundSelector} {\n content: \"\";\n position: absolute;\n inset: 0;\n pointer-events: none;\n border-radius: inherit;\n z-index: -1;\n ${backgroundRules.join("\n ")}\n}\n`}\n${overlayFix}`;
62475
+ return `${baseBlock}\n${`\n${backgroundSelector} {\n content: \"\";\n position: absolute;\n inset: 0;\n pointer-events: none;\n border-radius: inherit;\n z-index: -1;\n ${backgroundRules.join("\n ")}\n}\n`}\n${overlayFix}${usesInsetShell(header) ? generateInsetShellStyles(header, themeId) : ""}`;
62476
+ }
62477
+ /**
62478
+ * Reshapes the full-bleed header paint layer into a contained brand capsule at
62479
+ * the desktop breakpoint. The capsule is centred, capped to the page container
62480
+ * width, inset from the top, fully rounded, and carries the header depth so it
62481
+ * reads as a floating pill. Root border/shadow are neutralised on desktop so a
62482
+ * bordered style does not leave a full-width hairline around the capsule. Sticky
62483
+ * positioning is unaffected — the root stays full width and sticky while the
62484
+ * ::before paint provides the capsule.
62485
+ */
62486
+ function generateInsetShellStyles(header, themeId) {
62487
+ const scope = `:where([data-theme-scope="${themeId}"])`;
62488
+ const shellRootSelector = `${scope} .header-root.${INSET_SHELL_MARKER_CLASS}`;
62489
+ const shellBeforeSelector = `${scope} .header-root.${INSET_SHELL_MARKER_CLASS}::before`;
62490
+ const layoutSelector = `${scope} .header-root.${INSET_SHELL_MARKER_CLASS} .rb-header-layout`;
62491
+ const widthValue = header.maxWidth === "full" ? `calc(100% - (${INSET_SHELL_EDGE} * 2))` : `min(${INSET_SHELL_CONTAINER_MAX}, calc(100% - (${INSET_SHELL_EDGE} * 2)))`;
62492
+ const shadowVar = getComponentShadowVar(header.shadow?.elevation ?? "none");
62493
+ const rootRules = ["border: none;", "box-shadow: none;"];
62494
+ const beforeRules = [
62495
+ `inset: ${INSET_SHELL_INSET_BLOCK} auto;`,
62496
+ "left: 50%;",
62497
+ "right: auto;",
62498
+ "transform: translateX(-50%);",
62499
+ `width: ${widthValue};`,
62500
+ `border-radius: ${INSET_SHELL_RADIUS};`,
62501
+ ...shadowVar ? [`box-shadow: ${shadowVar};`] : []
62502
+ ];
62503
+ const layoutRules = [`padding-inline: ${INSET_SHELL_INTERIOR_PADDING_X};`];
62504
+ return `\n@media ${MQ_MD_UP} {\n${shellRootSelector} {\n ${rootRules.join("\n ")}\n}\n${shellBeforeSelector} {\n ${beforeRules.join("\n ")}\n}\n${layoutSelector} {\n ${layoutRules.join("\n ")}\n}\n}\n`;
62507
62505
  }
62508
62506
  /**
62509
62507
  * Generate logo typography styles
@@ -62581,7 +62579,7 @@ function generateLogoTextBehaviorStyles(logoText, themeId) {
62581
62579
  */
62582
62580
  function generateNavLinkStyles(header, themeId, tokens, theme, contrastTreatment, navTextSize) {
62583
62581
  const navPreferences = {
62584
- typography: header.navTypography ?? "inherit",
62582
+ typography: header.navFontRole ?? header.navTypography ?? "inherit",
62585
62583
  fontSize: readHeaderNavFontSizePreference(header.navTextSize)
62586
62584
  };
62587
62585
  if (header.navLinkStyle) return generateNavLinkCSS({
@@ -66912,6 +66910,12 @@ const containerResponsiveThemeCss = `/*
66912
66910
  .rb-lg-hidden {
66913
66911
  display: none;
66914
66912
  }
66913
+ .rb-lg-flex-row {
66914
+ flex-direction: row;
66915
+ }
66916
+ .rb-lg-items-center {
66917
+ align-items: center;
66918
+ }
66915
66919
  }
66916
66920
 
66917
66921
  }
@@ -78348,7 +78352,7 @@ const containerResponsiveThemeCss = `/*
78348
78352
  [data-block="feature-cards"][data-block-composition="asymmetric-emphasis"]
78349
78353
  .rb-feature-card {
78350
78354
  height: auto;
78351
- overflow: hidden;
78355
+ overflow: visible;
78352
78356
  border: 0;
78353
78357
  border-radius: 0;
78354
78358
  background: transparent;
@@ -79797,108 +79801,6 @@ function getCmsApiUrl() {
79797
79801
  function resolveApiBaseUrl() {
79798
79802
  return getCmsApiUrl();
79799
79803
  }
79800
- const API_ERROR_CODE_SET = /* @__PURE__ */ new Set([
79801
- "auth:unauthenticated",
79802
- "auth:token_expired",
79803
- "auth:token_invalid",
79804
- "auth:forbidden",
79805
- "auth:mfa_required",
79806
- "auth:sudo_required",
79807
- "auth:insufficient_permissions",
79808
- "auth:impersonation_restricted",
79809
- "validation:invalid_input",
79810
- "validation:missing_field",
79811
- "validation:invalid_format",
79812
- "validation:payload_too_large",
79813
- "resource:not_found",
79814
- "resource:already_exists",
79815
- "resource:conflict",
79816
- "resource:gone",
79817
- "rate_limit:exceeded",
79818
- "billing:payment_required",
79819
- "billing:plan_limit_exceeded",
79820
- "billing:pass_redemption_failed",
79821
- "server:internal_error",
79822
- "server:unavailable",
79823
- "external:service_error",
79824
- "external:registrar_orphaned_contact_profile",
79825
- "network:connection_error",
79826
- "network:timeout",
79827
- "network:dns_error"
79828
- ]);
79829
- function isApiErrorCode(value) {
79830
- return typeof value === "string" && API_ERROR_CODE_SET.has(value);
79831
- }
79832
- function isApiError(result) {
79833
- return result.success === false;
79834
- }
79835
- function isApiSuccess(result) {
79836
- return result.success === true;
79837
- }
79838
- function isRecord$9(value) {
79839
- return typeof value === "object" && value !== null && !Array.isArray(value);
79840
- }
79841
- function isFieldError(value) {
79842
- return isRecord$9(value) && typeof value.field === "string" && typeof value.code === "string" && typeof value.message === "string";
79843
- }
79844
- function fieldErrorsFromUnknown(value) {
79845
- if (!Array.isArray(value)) return null;
79846
- return value.every(isFieldError) ? value : null;
79847
- }
79848
- function extractEnvelopeErrorObject(body) {
79849
- if (!isRecord$9(body)) return null;
79850
- const error = body.error;
79851
- if (!isRecord$9(error)) return null;
79852
- if ("success" in body && body.success !== false) return null;
79853
- return error;
79854
- }
79855
- function extractApiEnvelopeErrorDetails(body) {
79856
- const error = extractEnvelopeErrorObject(body);
79857
- if (!error) return {
79858
- rawCode: null,
79859
- code: null,
79860
- message: null,
79861
- status: null,
79862
- fieldErrors: null
79863
- };
79864
- const rawCode = typeof error.code === "string" ? error.code : null;
79865
- const message = typeof error.message === "string" && error.message.trim().length > 0 ? error.message : null;
79866
- return {
79867
- rawCode,
79868
- code: isApiErrorCode(rawCode) ? rawCode : null,
79869
- message,
79870
- status: typeof error.status === "number" && Number.isFinite(error.status) ? error.status : null,
79871
- fieldErrors: fieldErrorsFromUnknown(error.fieldErrors)
79872
- };
79873
- }
79874
- /**
79875
- * Error class for API failures that can be thrown from unwrapResponse.
79876
- * Preserves all error metadata from the envelope.
79877
- */
79878
- var ApiEnvelopeError = class extends Error {
79879
- constructor(error) {
79880
- super(error.message);
79881
- this.name = "ApiEnvelopeError";
79882
- this.code = error.code;
79883
- this.requestId = error.requestId;
79884
- this.timestamp = error.timestamp;
79885
- this.status = error.status;
79886
- this.fieldErrors = error.fieldErrors;
79887
- }
79888
- };
79889
- /**
79890
- * Unwrap a successful API response or throw on error.
79891
- *
79892
- * @example
79893
- * ```typescript
79894
- * const response = await apiClient({ endpoint: 'getUser', params: { id } });
79895
- * const user = unwrapResponse(response); // Throws if not success
79896
- * ```
79897
- */
79898
- function unwrapResponse(result) {
79899
- if (isApiSuccess(result)) return result.data;
79900
- throw new ApiEnvelopeError(result.error);
79901
- }
79902
79804
  //#endregion
79903
79805
  //#region ../api/src/request.ts
79904
79806
  let revalidateTag = null;
@@ -81021,6 +80923,486 @@ z$1.object({
81021
80923
  toolCallsUsed: z$1.number()
81022
80924
  });
81023
80925
  //#endregion
80926
+ //#region src/portal/constants.ts
80927
+ /**
80928
+ * Portal Authentication Constants
80929
+ */
80930
+ /** Cookie name for storing the portal session token */
80931
+ const PORTAL_TOKEN_COOKIE = "portal_token";
80932
+ //#endregion
80933
+ //#region src/portal/token.ts
80934
+ /**
80935
+ * Portal Token Utilities
80936
+ *
80937
+ * Provides functions for reading the portal token from cookies
80938
+ * in server components.
80939
+ *
80940
+ * Usage:
80941
+ * ```ts
80942
+ * import { getPortalToken } from '@riverbankcms/sdk/portal';
80943
+ * import { cookies } from 'next/headers';
80944
+ *
80945
+ * export default async function PortalPage() {
80946
+ * const cookieStore = await cookies();
80947
+ * const token = getPortalToken(cookieStore);
80948
+ *
80949
+ * if (!token) {
80950
+ * return <LoginForm />;
80951
+ * }
80952
+ *
80953
+ * return <CustomerPortal token={token} />;
80954
+ * }
80955
+ * ```
80956
+ */
80957
+ /**
80958
+ * Get the portal token from the cookie store.
80959
+ *
80960
+ * @param cookieStore - The cookie store from `await cookies()`
80961
+ * @returns The portal token, or null if not present
80962
+ */
80963
+ function getPortalToken(cookieStore) {
80964
+ return cookieStore.get(PORTAL_TOKEN_COOKIE)?.value ?? null;
80965
+ }
80966
+ //#endregion
80967
+ //#region src/data/defineOwnDataProperty.ts
80968
+ /** Define a string key as ordinary data without invoking legacy prototype setters. */
80969
+ function defineOwnDataProperty(target, key, value) {
80970
+ Object.defineProperty(target, key, {
80971
+ value,
80972
+ enumerable: true,
80973
+ configurable: true,
80974
+ writable: true
80975
+ });
80976
+ }
80977
+ //#endregion
80978
+ //#region src/data/dataLoaderContext.ts
80979
+ function assertNever$4(value) {
80980
+ throw new Error(`Unhandled data loader render target: ${String(value)}`);
80981
+ }
80982
+ function getDataLoaderOwnerPageId(target) {
80983
+ switch (target.kind) {
80984
+ case "page": return target.pageId;
80985
+ case "entry-template":
80986
+ case "page-surface-template": return target.templateId;
80987
+ default: return assertNever$4(target);
80988
+ }
80989
+ }
80990
+ function normalizeDataLoaderSearchParams(input) {
80991
+ if (!input) return Object.freeze({});
80992
+ const normalized = {};
80993
+ for (const [key, value] of Object.entries(input)) defineOwnDataProperty(normalized, key, value === void 0 || typeof value === "string" ? value : Object.freeze([...value]));
80994
+ return Object.freeze(normalized);
80995
+ }
80996
+ function resolveDataLoaderBlockContent(block, previewStage) {
80997
+ if (previewStage === "preview" && block.draftContent) return block.draftContent;
80998
+ return block.content ?? {};
80999
+ }
81000
+ function createDataLoaderContext(input) {
81001
+ return {
81002
+ siteId: input.siteId,
81003
+ pageId: getDataLoaderOwnerPageId(input.renderTarget),
81004
+ blockId: input.blockId,
81005
+ blockKind: input.blockKind,
81006
+ content: input.content,
81007
+ previewStage: input.previewStage,
81008
+ searchParams: input.searchParams,
81009
+ renderTarget: input.renderTarget
81010
+ };
81011
+ }
81012
+ //#endregion
81013
+ //#region src/types/block-kinds.ts
81014
+ /**
81015
+ * System block kind identifiers.
81016
+ *
81017
+ * SDK-owned copy of the system block kind list.
81018
+ *
81019
+ * Rationale: SDK consumers must be able to typecheck without installing
81020
+ * `@riverbankcms/blocks` (which is not a public dependency). This list is a
81021
+ * stable public contract; keep it in sync with the internal blocks runtime.
81022
+ */
81023
+ const SYSTEM_BLOCK_KINDS = [
81024
+ "block.hero",
81025
+ "block.intro",
81026
+ "block.columns",
81027
+ "block.collection",
81028
+ "block.feature-cards",
81029
+ "block.media-text",
81030
+ "block.cta-full",
81031
+ "block.single-button",
81032
+ "block.body-text",
81033
+ "block.location-map",
81034
+ "block.faq",
81035
+ "block.testimonials",
81036
+ "block.team-members",
81037
+ "block.embed",
81038
+ "block.blog-post",
81039
+ "block.blog-listing",
81040
+ "block.site-header",
81041
+ "block.site-footer",
81042
+ "block.form",
81043
+ "block.contact-newsletter",
81044
+ "block.appointment-booking",
81045
+ "block.weekly-slot-availability",
81046
+ "block.event-registration",
81047
+ "block.event-details",
81048
+ "block.course-registration",
81049
+ "block.course-details",
81050
+ "block.event-spotlight",
81051
+ "block.event-listing",
81052
+ "block.event-calendar",
81053
+ "block.recurring-schedule",
81054
+ "block.offerings-preview",
81055
+ "block.shop",
81056
+ "block.product-list",
81057
+ "block.product-detail",
81058
+ "block.cart",
81059
+ "block.checkout",
81060
+ "block.gifting",
81061
+ "block.newsletter-signup",
81062
+ "block.image-gallery",
81063
+ "block.video-grid",
81064
+ "block.audio-player",
81065
+ "block.file-download"
81066
+ ];
81067
+ //#endregion
81068
+ //#region src/data/dataLoaderValue.ts
81069
+ const MAX_DATA_LOADER_VALUE_NODES = 1e4;
81070
+ const MAX_DATA_LOADER_VALUE_DEPTH = 100;
81071
+ function failure(issue) {
81072
+ return {
81073
+ ok: false,
81074
+ issue
81075
+ };
81076
+ }
81077
+ function inspectArray(value) {
81078
+ try {
81079
+ if (Object.getPrototypeOf(value) !== Array.prototype) return {
81080
+ ok: false,
81081
+ issue: { kind: "non-plain-object" }
81082
+ };
81083
+ const descriptors = Object.getOwnPropertyDescriptors(value);
81084
+ const ownKeys = Reflect.ownKeys(descriptors);
81085
+ if (ownKeys.some((key) => typeof key === "symbol")) return {
81086
+ ok: false,
81087
+ issue: { kind: "symbol-key" }
81088
+ };
81089
+ const lengthDescriptor = descriptors.length;
81090
+ if (!lengthDescriptor || !("value" in lengthDescriptor) || typeof lengthDescriptor.value !== "number") return {
81091
+ ok: false,
81092
+ issue: { kind: "invalid-array" }
81093
+ };
81094
+ const length = lengthDescriptor.value;
81095
+ if (!Number.isSafeInteger(length) || length < 0 || length > MAX_DATA_LOADER_VALUE_NODES) return {
81096
+ ok: false,
81097
+ issue: { kind: "complexity-limit-exceeded" }
81098
+ };
81099
+ const children = [];
81100
+ for (const key of ownKeys) {
81101
+ if (key === "length") continue;
81102
+ if (typeof key !== "string" || !/^(0|[1-9]\d*)$/.test(key)) return {
81103
+ ok: false,
81104
+ issue: { kind: "invalid-array" }
81105
+ };
81106
+ const index = Number(key);
81107
+ if (!Number.isSafeInteger(index) || index < 0 || index >= length) return {
81108
+ ok: false,
81109
+ issue: { kind: "invalid-array" }
81110
+ };
81111
+ const descriptor = descriptors[key];
81112
+ if (!descriptor || !descriptor.enumerable || !("value" in descriptor)) return {
81113
+ ok: false,
81114
+ issue: { kind: "accessor-property" }
81115
+ };
81116
+ }
81117
+ for (let index = 0; index < length; index += 1) {
81118
+ const descriptor = descriptors[String(index)];
81119
+ if (!descriptor || !descriptor.enumerable || !("value" in descriptor)) return {
81120
+ ok: false,
81121
+ issue: { kind: "invalid-array" }
81122
+ };
81123
+ children.push({
81124
+ key: String(index),
81125
+ value: descriptor.value
81126
+ });
81127
+ }
81128
+ return {
81129
+ ok: true,
81130
+ containerKind: "array",
81131
+ length,
81132
+ children
81133
+ };
81134
+ } catch {
81135
+ return {
81136
+ ok: false,
81137
+ issue: { kind: "inspection-failed" }
81138
+ };
81139
+ }
81140
+ }
81141
+ function inspectPlainObject(value) {
81142
+ try {
81143
+ if (Object.getPrototypeOf(value) !== Object.prototype) return {
81144
+ ok: false,
81145
+ issue: { kind: "non-plain-object" }
81146
+ };
81147
+ const descriptors = Object.getOwnPropertyDescriptors(value);
81148
+ const ownKeys = Reflect.ownKeys(descriptors);
81149
+ if (ownKeys.length > MAX_DATA_LOADER_VALUE_NODES) return {
81150
+ ok: false,
81151
+ issue: { kind: "complexity-limit-exceeded" }
81152
+ };
81153
+ if (ownKeys.some((key) => typeof key === "symbol")) return {
81154
+ ok: false,
81155
+ issue: { kind: "symbol-key" }
81156
+ };
81157
+ const children = [];
81158
+ for (const key of ownKeys) {
81159
+ if (typeof key !== "string") return {
81160
+ ok: false,
81161
+ issue: { kind: "symbol-key" }
81162
+ };
81163
+ const descriptor = descriptors[key];
81164
+ if (!descriptor || !descriptor.enumerable || !("value" in descriptor)) return {
81165
+ ok: false,
81166
+ issue: { kind: "accessor-property" }
81167
+ };
81168
+ children.push({
81169
+ key,
81170
+ value: descriptor.value
81171
+ });
81172
+ }
81173
+ return {
81174
+ ok: true,
81175
+ containerKind: "object",
81176
+ children
81177
+ };
81178
+ } catch {
81179
+ return {
81180
+ ok: false,
81181
+ issue: { kind: "inspection-failed" }
81182
+ };
81183
+ }
81184
+ }
81185
+ /**
81186
+ * Validates and snapshots arbitrary loader output without invoking getters,
81187
+ * setters, or conversion hooks. Reflection failures are returned as data,
81188
+ * never thrown, and accepted containers are detached and frozen.
81189
+ */
81190
+ function validateDataLoaderValue(input) {
81191
+ const pending = [{
81192
+ kind: "visit",
81193
+ value: input,
81194
+ depth: 0,
81195
+ target: { kind: "root" }
81196
+ }];
81197
+ const activeAncestors = /* @__PURE__ */ new WeakSet();
81198
+ let validatedRoot = null;
81199
+ let visitedNodes = 0;
81200
+ const assignOutput = (target, value) => {
81201
+ switch (target.kind) {
81202
+ case "root":
81203
+ validatedRoot = value;
81204
+ return;
81205
+ case "object-property":
81206
+ defineOwnDataProperty(target.parent, target.key, value);
81207
+ return;
81208
+ case "array-index":
81209
+ target.parent[target.index] = value;
81210
+ return;
81211
+ }
81212
+ };
81213
+ while (pending.length > 0) {
81214
+ const next = pending.pop();
81215
+ if (!next) continue;
81216
+ if (next.kind === "leave") {
81217
+ activeAncestors.delete(next.source);
81218
+ Object.freeze(next.output);
81219
+ continue;
81220
+ }
81221
+ visitedNodes += 1;
81222
+ if (visitedNodes > MAX_DATA_LOADER_VALUE_NODES || next.depth > MAX_DATA_LOADER_VALUE_DEPTH) return failure({ kind: "complexity-limit-exceeded" });
81223
+ let objectValue;
81224
+ switch (typeof next.value) {
81225
+ case "undefined": return failure({
81226
+ kind: "unsupported-type",
81227
+ valueType: "undefined"
81228
+ });
81229
+ case "bigint": return failure({
81230
+ kind: "unsupported-type",
81231
+ valueType: "bigint"
81232
+ });
81233
+ case "symbol": return failure({
81234
+ kind: "unsupported-type",
81235
+ valueType: "symbol"
81236
+ });
81237
+ case "function": return failure({
81238
+ kind: "unsupported-type",
81239
+ valueType: "function"
81240
+ });
81241
+ case "string":
81242
+ case "boolean":
81243
+ assignOutput(next.target, next.value);
81244
+ continue;
81245
+ case "number":
81246
+ if (!Number.isFinite(next.value)) return failure({ kind: "non-finite-number" });
81247
+ assignOutput(next.target, next.value);
81248
+ continue;
81249
+ case "object":
81250
+ if (next.value === null) {
81251
+ assignOutput(next.target, null);
81252
+ continue;
81253
+ }
81254
+ objectValue = next.value;
81255
+ break;
81256
+ }
81257
+ if (activeAncestors.has(objectValue)) return failure({ kind: "cycle" });
81258
+ activeAncestors.add(objectValue);
81259
+ let isArray;
81260
+ try {
81261
+ isArray = Array.isArray(objectValue);
81262
+ } catch {
81263
+ return failure({ kind: "inspection-failed" });
81264
+ }
81265
+ const inspection = isArray ? inspectArray(objectValue) : inspectPlainObject(objectValue);
81266
+ if (!inspection.ok) return failure(inspection.issue);
81267
+ if (inspection.containerKind === "array") {
81268
+ const output = new Array(inspection.length);
81269
+ assignOutput(next.target, output);
81270
+ pending.push({
81271
+ kind: "leave",
81272
+ source: objectValue,
81273
+ output
81274
+ });
81275
+ for (const child of inspection.children) pending.push({
81276
+ kind: "visit",
81277
+ value: child.value,
81278
+ depth: next.depth + 1,
81279
+ target: {
81280
+ kind: "array-index",
81281
+ parent: output,
81282
+ index: Number(child.key)
81283
+ }
81284
+ });
81285
+ continue;
81286
+ }
81287
+ const output = {};
81288
+ assignOutput(next.target, output);
81289
+ pending.push({
81290
+ kind: "leave",
81291
+ source: objectValue,
81292
+ output
81293
+ });
81294
+ for (const child of inspection.children) pending.push({
81295
+ kind: "visit",
81296
+ value: child.value,
81297
+ depth: next.depth + 1,
81298
+ target: {
81299
+ kind: "object-property",
81300
+ parent: output,
81301
+ key: child.key
81302
+ }
81303
+ });
81304
+ }
81305
+ return {
81306
+ ok: true,
81307
+ value: validatedRoot
81308
+ };
81309
+ }
81310
+ //#endregion
81311
+ //#region src/data/executeCodeLoaders.ts
81312
+ const systemBlockKindSet = new Set(SYSTEM_BLOCK_KINDS);
81313
+ function isBlockKind(value) {
81314
+ return value.startsWith("custom.") || systemBlockKindSet.has(value);
81315
+ }
81316
+ function toFailureBase(context, loaderKey) {
81317
+ return {
81318
+ siteId: context.siteId,
81319
+ pageId: context.pageId,
81320
+ blockId: context.blockId,
81321
+ blockKind: context.blockKind,
81322
+ loaderKey,
81323
+ previewStage: context.previewStage,
81324
+ renderTargetKind: context.renderTarget.kind
81325
+ };
81326
+ }
81327
+ /**
81328
+ * Runs all matching host loaders concurrently. The function returns closed
81329
+ * outcomes and never logs; warning ownership belongs to the shared resolver.
81330
+ */
81331
+ async function executeCodeLoaders(page, context, overrides) {
81332
+ const tasks = [];
81333
+ for (const block of page.blocks) {
81334
+ const blockId = block.id;
81335
+ if (!blockId || !isBlockKind(block.kind)) continue;
81336
+ const blockLoaders = overrides[block.kind];
81337
+ if (!blockLoaders) continue;
81338
+ for (const [loaderKey, loader] of Object.entries(blockLoaders)) {
81339
+ const loaderContext = createDataLoaderContext({
81340
+ siteId: context.siteId,
81341
+ renderTarget: context.renderTarget,
81342
+ blockId,
81343
+ blockKind: block.kind,
81344
+ content: resolveDataLoaderBlockContent(block, context.previewStage),
81345
+ previewStage: context.previewStage,
81346
+ searchParams: context.searchParams
81347
+ });
81348
+ tasks.push((async () => {
81349
+ let output;
81350
+ try {
81351
+ output = await loader(loaderContext);
81352
+ } catch {
81353
+ return {
81354
+ ok: false,
81355
+ failure: {
81356
+ kind: "execution-failed",
81357
+ ...toFailureBase(loaderContext, loaderKey)
81358
+ }
81359
+ };
81360
+ }
81361
+ const validation = validateDataLoaderValue(output);
81362
+ if (!validation.ok) return {
81363
+ ok: false,
81364
+ failure: {
81365
+ kind: "invalid-result",
81366
+ ...toFailureBase(loaderContext, loaderKey),
81367
+ validationIssueKind: validation.issue.kind
81368
+ }
81369
+ };
81370
+ return {
81371
+ ok: true,
81372
+ blockId,
81373
+ loaderKey,
81374
+ value: validation.value
81375
+ };
81376
+ })());
81377
+ }
81378
+ }
81379
+ const outcomes = await Promise.all(tasks);
81380
+ const data = {};
81381
+ const failures = [];
81382
+ for (const outcome of outcomes) {
81383
+ if (!outcome.ok) {
81384
+ failures.push(outcome.failure);
81385
+ continue;
81386
+ }
81387
+ const blockData = { ...data[outcome.blockId] };
81388
+ defineOwnDataProperty(blockData, outcome.loaderKey, outcome.value);
81389
+ defineOwnDataProperty(data, outcome.blockId, blockData);
81390
+ }
81391
+ return {
81392
+ data,
81393
+ failures
81394
+ };
81395
+ }
81396
+ /** Successful host values take precedence on per-block loader-key collisions. */
81397
+ function mergeLoaderResults(configResults, codeResults) {
81398
+ const merged = { ...configResults };
81399
+ for (const [blockId, loaderData] of Object.entries(codeResults)) defineOwnDataProperty(merged, blockId, {
81400
+ ...merged[blockId],
81401
+ ...loaderData
81402
+ });
81403
+ return merged;
81404
+ }
81405
+ //#endregion
81024
81406
  //#region src/data/prefetchBlockData.ts
81025
81407
  function isSupportedLoaderEndpoint(endpoint) {
81026
81408
  return SUPPORTED_LOADER_ENDPOINTS.includes(endpoint);
@@ -85802,7 +86184,7 @@ var CircuitOpenError = class extends Error {
85802
86184
  * 1. This constant
85803
86185
  * 2. The "version" field in package.json
85804
86186
  */
85805
- const SDK_VERSION = "0.107.0";
86187
+ const SDK_VERSION = "0.108.0";
85806
86188
  //#endregion
85807
86189
  //#region src/next/content-load-failure.ts
85808
86190
  const SdkContentLoadError = RiverbankContentLoadError;
@@ -86052,7 +86434,11 @@ function createCatchAllPage(options) {
86052
86434
  const enablePortal = enablePortalOption ?? config.enablePortal ?? false;
86053
86435
  const preview = previewOption ?? detectPreviewFromClient(getClient);
86054
86436
  const contentTypes = (config.content?.contentTypes ?? []).map(toRoutingInfo);
86055
- function resolveContentContract(path) {
86437
+ function resolveContentContract(path, purpose) {
86438
+ if (preview) {
86439
+ const requestedContract = parsePreviewContentContract(purpose.searchParams[PREVIEW_CONTENT_CONTRACT_PARAM]);
86440
+ if (requestedContract === "native") return requestedContract;
86441
+ }
86056
86442
  return typeof contentContractOption === "function" ? contentContractOption({
86057
86443
  path,
86058
86444
  preview
@@ -86101,7 +86487,7 @@ function createCatchAllPage(options) {
86101
86487
  siteId: config.siteId,
86102
86488
  path: contentPath,
86103
86489
  preview,
86104
- contentContract: resolveContentContract(contentPath),
86490
+ contentContract: resolveContentContract(contentPath, purpose),
86105
86491
  ...purpose.kind === "render" ? {
86106
86492
  dataLoaderOverrides: purpose.dataLoaderOverrides,
86107
86493
  searchParams: purpose.searchParams
@@ -86306,7 +86692,10 @@ function createCatchAllPage(options) {
86306
86692
  const resolution = await resolveContentForPath({
86307
86693
  path,
86308
86694
  client: getClient(),
86309
- purpose: { kind: "metadata" }
86695
+ purpose: {
86696
+ kind: "metadata",
86697
+ searchParams
86698
+ }
86310
86699
  });
86311
86700
  if (!resolution.found) {
86312
86701
  if (resolution.reason === "load-failed") throwUpstreamContentError(path, resolution);