@riverbankcms/sdk 0.72.0 → 0.75.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 (146) hide show
  1. package/README.md +1 -1
  2. package/dist/{PreviewEditorSidebar-44T64SAR.mjs → PreviewEditorSidebar-U2IHCBYN.mjs} +3 -3
  3. package/dist/{PreviewEditorUI-4WKHZTXW.mjs → PreviewEditorUI-ZGH2RQNP.mjs} +3 -3
  4. package/dist/SdkPreviewModeRuntime-MTUGBTLQ.mjs +8 -0
  5. package/dist/_dts/ai/src/contracts/proposals.d.ts +10 -10
  6. package/dist/_dts/api/src/cache-tags.d.ts +22 -0
  7. package/dist/_dts/api/src/contentRuntime.d.ts +1 -0
  8. package/dist/_dts/api/src/endpoints.d.ts +24 -24
  9. package/dist/_dts/api/src/publicExperienceEndpoints.d.ts +2 -1
  10. package/dist/_dts/block-form/src/blockDraftSaveability.d.ts +4 -1
  11. package/dist/_dts/blocks/src/client/booking-form.d.ts +2 -0
  12. package/dist/_dts/blocks/src/client/carousel.d.ts +1 -0
  13. package/dist/_dts/blocks/src/client/course-registration.d.ts +2 -0
  14. package/dist/_dts/blocks/src/client/events.d.ts +4 -0
  15. package/dist/_dts/blocks/src/client/form.d.ts +2 -0
  16. package/dist/_dts/blocks/src/client/header.d.ts +1 -0
  17. package/dist/_dts/blocks/src/client/location-map.d.ts +1 -0
  18. package/dist/_dts/blocks/src/client/newsletter-form.d.ts +2 -0
  19. package/dist/_dts/blocks/src/client/shop.d.ts +6 -0
  20. package/dist/_dts/blocks/src/lib/video.d.ts +2 -0
  21. package/dist/_dts/blocks/src/system/manifest/fieldValidation/index.d.ts +21 -1
  22. package/dist/_dts/blocks/src/system/manifest/schema.d.ts +6 -6
  23. package/dist/_dts/blocks/src/system/node/fragments/backgroundLayer.d.ts +15 -1
  24. package/dist/_dts/blocks/src/system/node/fragments/styledSection.d.ts +11 -0
  25. package/dist/_dts/blocks/src/system/runtime/components/registry.client.d.ts +1 -0
  26. package/dist/_dts/blocks/src/system/runtime/header/enhanceHeaderSection.d.ts +13 -0
  27. package/dist/_dts/blocks/src/system/runtime/nodes/booking-form.headless.state.d.ts +3 -2
  28. package/dist/_dts/blocks/src/system/runtime/nodes/events/index.d.ts +3 -0
  29. package/dist/_dts/blocks/src/system/runtime/nodes/header-section.client.d.ts +1 -0
  30. package/dist/_dts/blocks/src/system/runtime/nodes/header-section.server.d.ts +1 -0
  31. package/dist/_dts/blocks/src/system/runtime/nodes/media.d.ts +6 -0
  32. package/dist/_dts/content-editor/src/hooks/validateBlocksForPublish.d.ts +5 -0
  33. package/dist/_dts/preview-next/src/client/preview/SiteChromeEditableSurface.d.ts +12 -2
  34. package/dist/_dts/sdk/src/public-api/contracts.d.ts +1 -0
  35. package/dist/_dts/sdk/src/rendering/components/Layout.d.ts +2 -2
  36. package/dist/_dts/sdk/src/rendering/islands/deferredVideoEmbeds.d.ts +2 -0
  37. package/dist/_dts/sdk/src/rendering/islands/enhancers/accordion.d.ts +1 -0
  38. package/dist/_dts/sdk/src/rendering/islands/enhancers/bookingForm.d.ts +1 -0
  39. package/dist/_dts/sdk/src/rendering/islands/enhancers/carousel.d.ts +1 -0
  40. package/dist/_dts/sdk/src/rendering/islands/enhancers/cart.d.ts +1 -0
  41. package/dist/_dts/sdk/src/rendering/islands/enhancers/checkout.d.ts +1 -0
  42. package/dist/_dts/sdk/src/rendering/islands/enhancers/courseRegistration.d.ts +1 -0
  43. package/dist/_dts/sdk/src/rendering/islands/enhancers/eventCalendar.d.ts +1 -0
  44. package/dist/_dts/sdk/src/rendering/islands/enhancers/eventCombined.d.ts +1 -0
  45. package/dist/_dts/sdk/src/rendering/islands/enhancers/eventDetails.d.ts +1 -0
  46. package/dist/_dts/sdk/src/rendering/islands/enhancers/eventListing.d.ts +1 -0
  47. package/dist/_dts/sdk/src/rendering/islands/enhancers/eventRegistration.d.ts +1 -0
  48. package/dist/_dts/sdk/src/rendering/islands/enhancers/form.d.ts +1 -0
  49. package/dist/_dts/sdk/src/rendering/islands/enhancers/headerSection.d.ts +1 -0
  50. package/dist/_dts/sdk/src/rendering/islands/enhancers/locationMap.d.ts +1 -0
  51. package/dist/_dts/sdk/src/rendering/islands/enhancers/newsletterForm.d.ts +1 -0
  52. package/dist/_dts/sdk/src/rendering/islands/enhancers/productDetail.d.ts +1 -0
  53. package/dist/_dts/sdk/src/rendering/islands/enhancers/productList.d.ts +1 -0
  54. package/dist/_dts/sdk/src/rendering/islands/enhancers/shop.d.ts +1 -0
  55. package/dist/_dts/sdk/src/rendering/islands/hydrateBlocksIslands.d.ts +2 -2
  56. package/dist/_dts/sdk/src/rendering/islands/propsDecoder.d.ts +7 -0
  57. package/dist/_dts/sdk/src/rendering/islands/types.d.ts +9 -0
  58. package/dist/_dts/sdk/src/rendering/server.d.ts +3 -0
  59. package/dist/_dts/sdk/src/version.d.ts +1 -1
  60. package/dist/_dts/theme-core/src/accordions/types.d.ts +3 -3
  61. package/dist/_dts/theme-core/src/buttons/personalities/types.d.ts +7 -7
  62. package/dist/_dts/theme-core/src/buttons/types.d.ts +20 -20
  63. package/dist/_dts/theme-core/src/cards/types.d.ts +2 -2
  64. package/dist/_dts/theme-core/src/generated/containerResponsiveThemeCss.d.ts +1 -1
  65. package/dist/_dts/theme-core/src/header/navDropdownSizing.d.ts +7 -0
  66. package/dist/_dts/theme-core/src/inputs/types.d.ts +3 -3
  67. package/dist/_dts/theme-core/src/interactive/baseSchema.d.ts +1 -1
  68. package/dist/_dts/theme-core/src/mock-themes/all.d.ts +156 -156
  69. package/dist/_dts/theme-core/src/navigation/types.d.ts +1 -1
  70. package/dist/_dts/theme-core/src/palette/variants/types.d.ts +4 -4
  71. package/dist/_dts/theme-core/src/schema.d.ts +178 -178
  72. package/dist/_dts/theme-core/src/shared/componentStyles.d.ts +2 -2
  73. package/dist/_dts/theme-core/src/site-styles/designState.d.ts +8 -8
  74. package/dist/_dts/theme-core/src/site-styles/generatedSchemas.d.ts +5 -5
  75. package/dist/_dts/theme-core/src/tokens/themeColorTokens.d.ts +2 -2
  76. package/dist/{chunk-G4NLITC2.mjs → chunk-BGMNDF6T.mjs} +7 -7
  77. package/dist/{chunk-3YNCQG5N.mjs → chunk-GFE74WRD.mjs} +457 -98
  78. package/dist/{chunk-HV745JYE.mjs → chunk-RWXQBRQZ.mjs} +1 -1
  79. package/dist/{chunk-7RX72SK2.mjs → chunk-VX7B5VAC.mjs} +36 -25
  80. package/dist/{chunk-YRJKZEQ3.mjs → chunk-Z7JLNTJR.mjs} +1 -1
  81. package/dist/{chunk-KWQPAJYS.mjs → chunk-ZSHFGFUG.mjs} +2 -2
  82. package/dist/cli/index.mjs +3498 -3826
  83. package/dist/client/accordion-T2UD2ZTH.mjs +120 -0
  84. package/dist/client/altcha-LIGLPZS5.mjs +2755 -0
  85. package/dist/client/bookingForm-GUP75FKN.mjs +3022 -0
  86. package/dist/client/bookings.mjs +32 -10
  87. package/dist/client/carousel-2NQA6V57.mjs +47 -0
  88. package/dist/client/cart-5TFIAFDS.mjs +18 -0
  89. package/dist/client/checkout-TP4WAHZE.mjs +18 -0
  90. package/dist/client/chunk-2PHQZ666.mjs +383 -0
  91. package/dist/client/chunk-3DCJ45Z2.mjs +36 -0
  92. package/dist/client/chunk-3PEDD5KJ.mjs +146 -0
  93. package/dist/client/chunk-CY2ZTSE5.mjs +204 -0
  94. package/dist/client/chunk-F7LHOKEH.mjs +146 -0
  95. package/dist/client/chunk-FU2QRZMX.mjs +7617 -0
  96. package/dist/client/chunk-I2MMZO53.mjs +6 -0
  97. package/dist/client/chunk-II7O4XN3.mjs +2206 -0
  98. package/dist/client/chunk-M3L3KYYR.mjs +1181 -0
  99. package/dist/client/chunk-N7PBWBWQ.mjs +26 -0
  100. package/dist/client/chunk-NWOUL6JY.mjs +1378 -0
  101. package/dist/client/chunk-OJPZEZU2.mjs +31 -0
  102. package/dist/client/chunk-PMAIXMAB.mjs +1960 -0
  103. package/dist/client/chunk-RTZ3JKKX.mjs +178 -0
  104. package/dist/client/chunk-TQ5MSPDX.mjs +74 -0
  105. package/dist/client/chunk-VUAOE3AG.mjs +5592 -0
  106. package/dist/client/chunk-WJXXNDSE.mjs +245 -0
  107. package/dist/client/chunk-YLMKMCSJ.mjs +86 -0
  108. package/dist/client/chunk-ZLMS67RR.mjs +106 -0
  109. package/dist/client/client.mjs +51865 -52071
  110. package/dist/client/courseRegistration-5DPU6PDY.mjs +1737 -0
  111. package/dist/client/eventCalendar-F3GZGTEF.mjs +40 -0
  112. package/dist/client/eventCombined-BQOB6QMY.mjs +37 -0
  113. package/dist/client/eventDetails-PEM2EJWE.mjs +25 -0
  114. package/dist/client/eventListing-YMIQPVME.mjs +40 -0
  115. package/dist/client/eventRegistration-4I6ZNDUF.mjs +40 -0
  116. package/dist/client/form-ZJVAYZ6G.mjs +300 -0
  117. package/dist/client/headerSection-TOT5MGTF.mjs +729 -0
  118. package/dist/client/hooks.mjs +91 -42
  119. package/dist/client/locationMap-J66NZREU.mjs +227 -0
  120. package/dist/client/newsletterForm-ET2XUMRO.mjs +208 -0
  121. package/dist/client/productDetail-C2XIH7C5.mjs +18 -0
  122. package/dist/client/productList-T2AZLFTP.mjs +18 -0
  123. package/dist/client/rendering/client.mjs +12796 -18295
  124. package/dist/client/rendering/islands.mjs +108 -44022
  125. package/dist/client/rendering.mjs +45141 -45346
  126. package/dist/client/shop-UZ6IUZXD.mjs +20 -0
  127. package/dist/preview-next/before-render.mjs +37 -25
  128. package/dist/preview-next/client/runtime.mjs +5 -5
  129. package/dist/preview-next/middleware.mjs +37 -25
  130. package/dist/{sdk-runtime-NGDWSWOS.mjs → sdk-runtime-JCUQM63Y.mjs} +6 -6
  131. package/dist/server/components.mjs +472 -276
  132. package/dist/server/config-validation.mjs +91 -42
  133. package/dist/server/config.mjs +91 -42
  134. package/dist/server/data.mjs +91 -42
  135. package/dist/server/index.mjs +45 -33
  136. package/dist/server/next.mjs +468 -272
  137. package/dist/server/page-converter.mjs +41 -17
  138. package/dist/server/prebuild.mjs +1 -1
  139. package/dist/server/rendering/server.mjs +556 -275
  140. package/dist/server/rendering.mjs +474 -278
  141. package/dist/server/routing.mjs +99 -43
  142. package/dist/server/server.mjs +92 -43
  143. package/dist/server/theme-bridge.mjs +29 -0
  144. package/dist/styles/index.css +16 -0
  145. package/package.json +2 -1
  146. package/dist/SdkPreviewModeRuntime-FO6V7YVY.mjs +0 -8
@@ -0,0 +1,1960 @@
1
+ import { jsx } from 'react/jsx-runtime';
2
+
3
+ // ../../node_modules/.pnpm/clsx@2.1.1/node_modules/clsx/dist/clsx.mjs
4
+ function r(e) {
5
+ var t, f, n = "";
6
+ if ("string" == typeof e || "number" == typeof e) n += e;
7
+ else if ("object" == typeof e) if (Array.isArray(e)) {
8
+ var o = e.length;
9
+ for (t = 0; t < o; t++) e[t] && (f = r(e[t])) && (n && (n += " "), n += f);
10
+ } else for (f in e) e[f] && (n && (n += " "), n += f);
11
+ return n;
12
+ }
13
+ function clsx() {
14
+ for (var e, t, f = 0, n = "", o = arguments.length; f < o; f++) (e = arguments[f]) && (t = r(e)) && (n && (n += " "), n += t);
15
+ return n;
16
+ }
17
+ var clsx_default = clsx;
18
+
19
+ // ../core/src/branded.ts
20
+ var asMediaAssetId = (id) => id;
21
+ var asFormId = (id) => id;
22
+ var asPassId = (id) => id;
23
+ var asCustomerPassId = (id) => id;
24
+ var asAppointmentServiceId = (id) => id;
25
+ var asAppointmentResourceId = (id) => id;
26
+
27
+ // ../core/src/date-math.ts
28
+ function addDaysToDate(date, dayCount) {
29
+ const next = new Date(date);
30
+ next.setUTCDate(next.getUTCDate() + dayCount);
31
+ return next;
32
+ }
33
+ function addDaysToIso(isoString, dayCount) {
34
+ const date = new Date(isoString);
35
+ if (!Number.isFinite(date.getTime())) {
36
+ return isoString;
37
+ }
38
+ return addDaysToDate(date, dayCount).toISOString();
39
+ }
40
+ function subtractDaysFromIso(isoString, dayCount) {
41
+ return addDaysToIso(isoString, -dayCount);
42
+ }
43
+
44
+ // ../core/src/booking-flexible-balance.ts
45
+ function clampFlexibleBalanceConfiguredAmount(amountCents, totalAmountCents) {
46
+ return Math.max(0, Math.min(amountCents, totalAmountCents));
47
+ }
48
+ function resolveFlexibleBalanceInitialPaymentCents(input) {
49
+ return clampFlexibleBalanceConfiguredAmount(
50
+ input.config.upfrontAmountCents,
51
+ input.totalAmountCents
52
+ );
53
+ }
54
+ function resolveFlexibleBalanceDueAt(input) {
55
+ switch (input.dueDateRule.kind) {
56
+ case "relative_to_start_date":
57
+ return subtractDaysFromIso(
58
+ input.bookingStartAt,
59
+ input.dueDateRule.daysBeforeStart
60
+ );
61
+ case "fixed_calendar_date":
62
+ return input.dueDateRule.dueAt;
63
+ default:
64
+ return assertNever(input.dueDateRule);
65
+ }
66
+ }
67
+ function assertNever(value) {
68
+ throw new Error(`Unexpected value: ${String(value)}`);
69
+ }
70
+
71
+ // ../core/src/booking-instalments.ts
72
+ function isDepositBearingBookingInstalmentPlan(plan) {
73
+ switch (plan.kind) {
74
+ case "deposit_plus_one_remainder":
75
+ case "deposit_plus_scheduled_instalments":
76
+ return true;
77
+ case "equal_scheduled_instalments":
78
+ return false;
79
+ default:
80
+ return assertNever2(plan);
81
+ }
82
+ }
83
+ function getBookingInstalmentDepositRefundability(plan) {
84
+ return isDepositBearingBookingInstalmentPlan(plan) ? plan.depositRefundability : null;
85
+ }
86
+ function clampConfiguredAmount(amountCents, totalAmountCents) {
87
+ return Math.max(0, Math.min(amountCents, totalAmountCents));
88
+ }
89
+ function splitAmountWithRemainderInFirst(totalAmountCents, partCount) {
90
+ if (partCount <= 0) {
91
+ return [];
92
+ }
93
+ const baseAmountCents = Math.floor(totalAmountCents / partCount);
94
+ const remainderCents = totalAmountCents - baseAmountCents * partCount;
95
+ return Array.from({ length: partCount }, (_, index) => index === 0 ? baseAmountCents + remainderCents : baseAmountCents);
96
+ }
97
+ function addIntervalPreservingMonthAnchor(isoString, intervalCount, intervalUnit) {
98
+ const date = new Date(isoString);
99
+ if (!Number.isFinite(date.getTime())) {
100
+ return isoString;
101
+ }
102
+ switch (intervalUnit) {
103
+ case "day":
104
+ date.setUTCDate(date.getUTCDate() + intervalCount);
105
+ return date.toISOString();
106
+ case "week":
107
+ date.setUTCDate(date.getUTCDate() + intervalCount * 7);
108
+ return date.toISOString();
109
+ case "month":
110
+ return addMonthsPreservingAnchorDay(date, intervalCount).toISOString();
111
+ default:
112
+ return assertNever2(intervalUnit);
113
+ }
114
+ }
115
+ function getBookingInstalmentPlanIntervalCount(plan) {
116
+ switch (plan.kind) {
117
+ case "deposit_plus_one_remainder":
118
+ return plan.remainderDueCount;
119
+ case "deposit_plus_scheduled_instalments":
120
+ case "equal_scheduled_instalments":
121
+ return plan.intervalCount;
122
+ default:
123
+ return assertNever2(plan);
124
+ }
125
+ }
126
+ function omitZeroAmountFutureRows(rows) {
127
+ if (rows.length <= 1) {
128
+ return rows;
129
+ }
130
+ const [firstRow, ...futureRows] = rows;
131
+ if (!firstRow) {
132
+ return [];
133
+ }
134
+ return [
135
+ firstRow,
136
+ ...futureRows.filter((row) => row.amountCents > 0)
137
+ ];
138
+ }
139
+ function addMonthsPreservingAnchorDay(date, intervalCount) {
140
+ const anchorDay = date.getUTCDate();
141
+ const nextMonth = new Date(Date.UTC(
142
+ date.getUTCFullYear(),
143
+ date.getUTCMonth() + intervalCount,
144
+ 1,
145
+ date.getUTCHours(),
146
+ date.getUTCMinutes(),
147
+ date.getUTCSeconds(),
148
+ date.getUTCMilliseconds()
149
+ ));
150
+ const lastDayOfTargetMonth = new Date(Date.UTC(
151
+ nextMonth.getUTCFullYear(),
152
+ nextMonth.getUTCMonth() + 1,
153
+ 0
154
+ )).getUTCDate();
155
+ nextMonth.setUTCDate(Math.min(anchorDay, lastDayOfTargetMonth));
156
+ return nextMonth;
157
+ }
158
+ function assertNever2(value) {
159
+ throw new Error(`Unexpected value: ${String(value)}`);
160
+ }
161
+
162
+ // ../core/src/result.ts
163
+ function ok(value) {
164
+ return { ok: true, value };
165
+ }
166
+ function err(error) {
167
+ return { ok: false, error };
168
+ }
169
+
170
+ // ../core/src/booking-date-time.ts
171
+ var DEFAULT_LOCALE = "en-US";
172
+ var FALLBACK_TIMEZONE = "UTC";
173
+ var LOCAL_DATE_PATTERN = /^(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})$/u;
174
+ function isValidTimeZone(timeZone) {
175
+ try {
176
+ new Intl.DateTimeFormat(DEFAULT_LOCALE, { timeZone }).format(/* @__PURE__ */ new Date());
177
+ return true;
178
+ } catch {
179
+ return false;
180
+ }
181
+ }
182
+ function getSafeTimeZone(timeZone) {
183
+ const normalized = typeof timeZone === "string" ? timeZone.trim() : "";
184
+ return normalized && isValidTimeZone(normalized) ? normalized : FALLBACK_TIMEZONE;
185
+ }
186
+ function parseStrictBookingTimeZone(timeZone) {
187
+ const normalized = timeZone.trim();
188
+ if (!normalized || !isValidTimeZone(normalized)) {
189
+ return null;
190
+ }
191
+ return normalized;
192
+ }
193
+ function formatParseError(error) {
194
+ switch (error.reason) {
195
+ case "invalid_starts_at":
196
+ return `Expected a valid UTC/offset-aware ISO datetime in startsAt, received "${error.value}"`;
197
+ case "invalid_ends_at":
198
+ return `Expected a valid UTC/offset-aware ISO datetime in endsAt, received "${error.value ?? ""}"`;
199
+ case "invalid_time_zone":
200
+ return `Expected a valid IANA timezone in timeZone, received "${error.value}"`;
201
+ }
202
+ }
203
+ function formatToPartsLookup(date, locale, timeZone, format) {
204
+ return new Map(
205
+ new Intl.DateTimeFormat(locale, {
206
+ ...format,
207
+ timeZone
208
+ }).formatToParts(date).map((part) => [part.type, part.value])
209
+ );
210
+ }
211
+ function getZonedDateTimeParts(date, timeZone) {
212
+ const parts = formatToPartsLookup(date, "en-GB", timeZone, {
213
+ year: "numeric",
214
+ month: "2-digit",
215
+ day: "2-digit",
216
+ hour: "2-digit",
217
+ minute: "2-digit",
218
+ second: "2-digit",
219
+ hour12: false
220
+ });
221
+ const read = (type) => Number(parts.get(type) ?? "");
222
+ return {
223
+ year: read("year"),
224
+ month: read("month"),
225
+ day: read("day"),
226
+ hour: read("hour"),
227
+ minute: read("minute"),
228
+ second: read("second")
229
+ };
230
+ }
231
+ function formatDateKey(date) {
232
+ const year = String(date.year).padStart(4, "0");
233
+ const month = String(date.month).padStart(2, "0");
234
+ const day = String(date.day).padStart(2, "0");
235
+ return `${year}-${month}-${day}`;
236
+ }
237
+ function toBookingTimeZone(timeZone) {
238
+ return getSafeTimeZone(timeZone);
239
+ }
240
+ var DEFAULT_BOOKING_TIME_ZONE = FALLBACK_TIMEZONE;
241
+ function resolveBookingTimeZoneId(...candidates) {
242
+ for (const candidate of candidates) {
243
+ const normalized = typeof candidate === "string" ? candidate.trim() : "";
244
+ if (normalized && isValidTimeZone(normalized)) {
245
+ return normalized;
246
+ }
247
+ }
248
+ return FALLBACK_TIMEZONE;
249
+ }
250
+ function parseUtcIsoDateTimeString(value) {
251
+ const normalized = value.trim();
252
+ const hasUtcSuffix = normalized.endsWith("Z");
253
+ const hasExplicitOffset = /[+-]\d{2}:\d{2}$/u.test(normalized);
254
+ if (!hasUtcSuffix && !hasExplicitOffset) {
255
+ return err("missing-timezone-offset");
256
+ }
257
+ const date = new Date(normalized);
258
+ if (Number.isNaN(date.getTime())) {
259
+ return err("invalid-date-time");
260
+ }
261
+ return ok(date.toISOString());
262
+ }
263
+ function toUtcIsoDateTimeString(value) {
264
+ const parsed = parseUtcIsoDateTimeString(value);
265
+ if (!parsed.ok) {
266
+ const message = parsed.error === "missing-timezone-offset" ? `Expected an offset-aware ISO datetime, received "${value}"` : `Expected a valid ISO datetime, received "${value}"`;
267
+ throw new Error(message);
268
+ }
269
+ return parsed.value;
270
+ }
271
+ function parseScheduledBookingDateTime(input) {
272
+ try {
273
+ const startsAt = toUtcIsoDateTimeString(input.startsAt);
274
+ const timeZone = parseStrictBookingTimeZone(input.timeZone);
275
+ if (!timeZone) {
276
+ return {
277
+ ok: false,
278
+ field: "timeZone",
279
+ reason: "invalid_time_zone",
280
+ value: input.timeZone
281
+ };
282
+ }
283
+ return {
284
+ ok: true,
285
+ value: {
286
+ startsAt,
287
+ timeZone,
288
+ locale: input.locale
289
+ }
290
+ };
291
+ } catch {
292
+ return {
293
+ ok: false,
294
+ field: "startsAt",
295
+ reason: "invalid_starts_at",
296
+ value: input.startsAt
297
+ };
298
+ }
299
+ }
300
+ function parseScheduledBookingDateRange(input) {
301
+ const start = parseScheduledBookingDateTime(input);
302
+ if (!start.ok) {
303
+ return start;
304
+ }
305
+ if (input.endsAt == null) {
306
+ return {
307
+ ok: true,
308
+ value: start.value
309
+ };
310
+ }
311
+ try {
312
+ return {
313
+ ok: true,
314
+ value: {
315
+ ...start.value,
316
+ endsAt: toUtcIsoDateTimeString(input.endsAt)
317
+ }
318
+ };
319
+ } catch {
320
+ return {
321
+ ok: false,
322
+ field: "endsAt",
323
+ reason: "invalid_ends_at",
324
+ value: input.endsAt
325
+ };
326
+ }
327
+ }
328
+ function toScheduledBookingDateTime(input) {
329
+ const result = parseScheduledBookingDateTime(input);
330
+ if (result.ok) {
331
+ return result.value;
332
+ }
333
+ throw new Error(formatParseError(result));
334
+ }
335
+ function toScheduledBookingDateRange(input) {
336
+ const result = parseScheduledBookingDateRange(input);
337
+ if (result.ok) {
338
+ return result.value;
339
+ }
340
+ throw new Error(formatParseError(result));
341
+ }
342
+ function formatBookingInstant(isoString, options) {
343
+ const date = new Date(isoString);
344
+ if (Number.isNaN(date.getTime())) {
345
+ return isoString;
346
+ }
347
+ return new Intl.DateTimeFormat(options.locale ?? DEFAULT_LOCALE, {
348
+ ...options.format,
349
+ timeZone: getSafeTimeZone(options.timeZone)
350
+ }).format(date);
351
+ }
352
+ function formatBookingDate(input, format = {
353
+ weekday: "long",
354
+ year: "numeric",
355
+ month: "long",
356
+ day: "numeric"
357
+ }) {
358
+ return formatBookingInstant(input.startsAt, {
359
+ locale: input.locale,
360
+ timeZone: input.timeZone,
361
+ format
362
+ });
363
+ }
364
+ function formatBookingTime(input, format = {
365
+ hour: "numeric",
366
+ minute: "2-digit",
367
+ hour12: true
368
+ }) {
369
+ return formatBookingInstant(input.startsAt, {
370
+ locale: input.locale,
371
+ timeZone: input.timeZone,
372
+ format
373
+ });
374
+ }
375
+ function formatBookingDateTime(input, format = {
376
+ weekday: "short",
377
+ month: "short",
378
+ day: "numeric",
379
+ hour: "numeric",
380
+ minute: "2-digit"
381
+ }) {
382
+ return formatBookingInstant(input.startsAt, {
383
+ locale: input.locale,
384
+ timeZone: input.timeZone,
385
+ format
386
+ });
387
+ }
388
+ function formatBookingDateParts(input, options) {
389
+ return {
390
+ date: formatBookingDate(
391
+ input,
392
+ options?.dateFormat ?? {
393
+ weekday: "short",
394
+ month: "short",
395
+ day: "numeric",
396
+ year: "numeric"
397
+ }
398
+ ),
399
+ time: formatBookingTime(
400
+ input,
401
+ options?.timeFormat ?? {
402
+ hour: "numeric",
403
+ minute: "2-digit",
404
+ hour12: true
405
+ }
406
+ )
407
+ };
408
+ }
409
+ function getBookingLocalDateKey(input) {
410
+ return formatDateKey(getLocalScheduleDate(new Date(input.startsAt), input.timeZone));
411
+ }
412
+ function parseBookingLocalDate(value) {
413
+ const match = LOCAL_DATE_PATTERN.exec(value.trim());
414
+ if (!match?.groups) {
415
+ throw new Error(`Invalid booking date format: "${value}" (expected YYYY-MM-DD)`);
416
+ }
417
+ const year = Number(match.groups.year);
418
+ const month = Number(match.groups.month);
419
+ const day = Number(match.groups.day);
420
+ const candidate = new Date(Date.UTC(year, month - 1, day, 12, 0, 0));
421
+ if (Number.isNaN(candidate.getTime()) || candidate.getUTCFullYear() !== year || candidate.getUTCMonth() + 1 !== month || candidate.getUTCDate() !== day) {
422
+ throw new Error(`Invalid booking date format: "${value}" (expected YYYY-MM-DD)`);
423
+ }
424
+ return { year, month, day };
425
+ }
426
+ function getLocalScheduleDate(date, timeZone) {
427
+ const parts = getZonedDateTimeParts(date, getSafeTimeZone(timeZone));
428
+ return { year: parts.year, month: parts.month, day: parts.day };
429
+ }
430
+ function formatLocalScheduleDate(date) {
431
+ return formatDateKey(date);
432
+ }
433
+ function addLocalScheduleDays(date, days) {
434
+ const utcDate = new Date(Date.UTC(date.year, date.month - 1, date.day + days, 12, 0, 0));
435
+ return {
436
+ year: utcDate.getUTCFullYear(),
437
+ month: utcDate.getUTCMonth() + 1,
438
+ day: utcDate.getUTCDate()
439
+ };
440
+ }
441
+
442
+ // ../core/src/location.ts
443
+ function normalizeLocationAddressText(value) {
444
+ if (typeof value !== "string") {
445
+ return null;
446
+ }
447
+ const trimmed = value.trim();
448
+ return trimmed ? trimmed : null;
449
+ }
450
+ function hasLocationCoordinates(value) {
451
+ return typeof value?.lat === "number" && typeof value?.lng === "number";
452
+ }
453
+ function toLocationCoordinates(value) {
454
+ if (!hasLocationCoordinates(value)) {
455
+ return null;
456
+ }
457
+ return {
458
+ lat: value.lat,
459
+ lng: value.lng
460
+ };
461
+ }
462
+
463
+ // ../core/src/planner.ts
464
+ var systemPlanningClock = {
465
+ now: () => Date.now()
466
+ };
467
+ function resolvePlanningNowDate(input = {}) {
468
+ if (input.now !== void 0) {
469
+ return input.now;
470
+ }
471
+ return new Date((input.clock ?? systemPlanningClock).now());
472
+ }
473
+ function resolvePlanningDateInput(input = {}) {
474
+ if (input instanceof Date) {
475
+ return input;
476
+ }
477
+ return resolvePlanningNowDate(input);
478
+ }
479
+
480
+ // ../media-core/src/typeGuards.ts
481
+ function isRecord(value) {
482
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
483
+ }
484
+ function asRecord(value) {
485
+ return isRecord(value) ? value : void 0;
486
+ }
487
+
488
+ // ../media-core/src/url.ts
489
+ var DEFAULT_BASE_PATH = "/api/img";
490
+ var RELATIVE_STORAGE_PATH_PREFIXES = [
491
+ "originals/",
492
+ "variants/",
493
+ "imports/"
494
+ ];
495
+ function isRelativeDirectImageStoragePath(storagePath) {
496
+ return RELATIVE_STORAGE_PATH_PREFIXES.some((prefix) => storagePath.startsWith(prefix));
497
+ }
498
+ function isSiteScopedDirectImageStoragePath(storagePath) {
499
+ return storagePath.startsWith("sites/");
500
+ }
501
+ function encodeStoragePath(storagePath) {
502
+ return storagePath.split("/").map((segment) => encodeURIComponent(segment)).join("/");
503
+ }
504
+ function resolveDirectImagePathTarget(target) {
505
+ switch (target.kind) {
506
+ case "relative":
507
+ return `sites/${target.siteId}/${target.storagePath}`;
508
+ case "site-scoped":
509
+ case "bucket-scoped":
510
+ return target.storagePath;
511
+ }
512
+ }
513
+ function buildDirectImageUrl(supabaseUrl, target, storageBucket = "media", options) {
514
+ const baseUrl = supabaseUrl.replace(/\/$/, "");
515
+ const resolvedPath = resolveDirectImagePathTarget(target);
516
+ const encodedPath = encodeStoragePath(resolvedPath);
517
+ const sourcePath = target.storagePath;
518
+ const isSvg = sourcePath.toLowerCase().endsWith(".svg");
519
+ if (options && !isSvg && (options.width || options.height)) {
520
+ const params = new URLSearchParams();
521
+ if (options.width) params.set("width", String(options.width));
522
+ if (options.height) params.set("height", String(options.height));
523
+ if (options.quality) params.set("quality", String(options.quality));
524
+ if (options.resize) params.set("resize", options.resize);
525
+ return `${baseUrl}/storage/v1/render/image/public/${storageBucket}/${encodedPath}?${params.toString()}`;
526
+ }
527
+ return `${baseUrl}/storage/v1/object/public/${storageBucket}/${encodedPath}`;
528
+ }
529
+ function getDirectImageUrlForRelativePath(supabaseUrl, storagePath, siteId, storageBucket = "media", options) {
530
+ return buildDirectImageUrl(
531
+ supabaseUrl,
532
+ { kind: "relative", storagePath, siteId },
533
+ storageBucket,
534
+ options
535
+ );
536
+ }
537
+ function getDirectImageUrlForSiteScopedPath(supabaseUrl, storagePath, storageBucket = "media", options) {
538
+ return buildDirectImageUrl(
539
+ supabaseUrl,
540
+ { kind: "site-scoped", storagePath },
541
+ storageBucket,
542
+ options
543
+ );
544
+ }
545
+ function getDirectImageUrlForBucketPath(supabaseUrl, storagePath, storageBucket = "media", options) {
546
+ return buildDirectImageUrl(
547
+ supabaseUrl,
548
+ { kind: "bucket-scoped", storagePath },
549
+ storageBucket,
550
+ options
551
+ );
552
+ }
553
+ function getDirectImageUrlForStoragePath(supabaseUrl, storagePath, storageBucket = "media", siteId, options) {
554
+ if (isRelativeDirectImageStoragePath(storagePath) && siteId) {
555
+ return getDirectImageUrlForRelativePath(supabaseUrl, storagePath, siteId, storageBucket, options);
556
+ }
557
+ if (isSiteScopedDirectImageStoragePath(storagePath)) {
558
+ return getDirectImageUrlForSiteScopedPath(supabaseUrl, storagePath, storageBucket, options);
559
+ }
560
+ return getDirectImageUrl(supabaseUrl, storagePath, storageBucket, siteId, options);
561
+ }
562
+ function getDirectImageUrl(supabaseUrl, storagePath, storageBucket = "media", siteId, options) {
563
+ if (isSiteScopedDirectImageStoragePath(storagePath)) {
564
+ if (siteId && true) {
565
+ console.warn(
566
+ `[media-core] storagePath "${storagePath}" already contains site prefix. Using path as-is for backward compatibility. After migration, paths should be relative (e.g., "originals/2024/12/img.jpg").`
567
+ );
568
+ }
569
+ return getDirectImageUrlForSiteScopedPath(supabaseUrl, storagePath, storageBucket, options);
570
+ }
571
+ if (siteId && isRelativeDirectImageStoragePath(storagePath)) {
572
+ return getDirectImageUrlForRelativePath(supabaseUrl, storagePath, siteId, storageBucket, options);
573
+ }
574
+ return getDirectImageUrlForBucketPath(supabaseUrl, storagePath, storageBucket, options);
575
+ }
576
+ var formatNumber = (value) => Number.isInteger(value) ? value.toString() : value.toFixed(6).replace(/0+$/, "").replace(/\.$/, "");
577
+ var ORDER = [
578
+ "w",
579
+ "h",
580
+ "fit",
581
+ "rect",
582
+ "q",
583
+ "autoFormat",
584
+ "or"
585
+ ];
586
+ var getImageUrl = (asset, params = {}, basePath = DEFAULT_BASE_PATH) => {
587
+ const trimmedBase = basePath.endsWith("/") ? basePath.slice(0, Math.max(basePath.length - 1, 0)) : basePath;
588
+ const path = `${trimmedBase}/${encodeURIComponent(asset.id)}`;
589
+ const searchParams = new URLSearchParams();
590
+ if (params.w !== void 0) searchParams.set("w", formatNumber(params.w));
591
+ if (params.h !== void 0) searchParams.set("h", formatNumber(params.h));
592
+ if (params.fit !== void 0) searchParams.set("fit", params.fit);
593
+ if (params.rect) searchParams.set("rect", params.rect.map(formatNumber).join(","));
594
+ if (params.q !== void 0) searchParams.set("q", formatNumber(params.q));
595
+ if (params.autoFormat) searchParams.append("auto", "format");
596
+ if (params.or !== void 0) searchParams.set("or", String(params.or));
597
+ const sorted = new URLSearchParams();
598
+ ORDER.forEach((key) => {
599
+ if (key === "autoFormat") {
600
+ if (params.autoFormat) sorted.append("auto", "format");
601
+ return;
602
+ }
603
+ const value = searchParams.get(key);
604
+ if (value !== null) sorted.set(key, value);
605
+ });
606
+ const query = sorted.toString();
607
+ return query ? `${path}?${query}` : path;
608
+ };
609
+
610
+ // ../media-core/src/transformRect.ts
611
+ function isValidTransformRectStructure(rect) {
612
+ if (!Array.isArray(rect) || rect.length !== 4) return false;
613
+ const [left, top, width, height] = rect;
614
+ return Number.isFinite(left) && Number.isFinite(top) && Number.isFinite(width) && Number.isFinite(height) && left >= 0 && top >= 0 && width > 0 && height > 0;
615
+ }
616
+
617
+ // ../media-core/src/aspectTransforms.ts
618
+ var DEFAULT_RECT_EPSILON = 0.5;
619
+ function parseAspectRatioValue(value) {
620
+ if (typeof value === "number") {
621
+ return Number.isFinite(value) && value > 0 ? value : void 0;
622
+ }
623
+ if (typeof value !== "string") return void 0;
624
+ const normalized = value.trim();
625
+ if (!normalized) return void 0;
626
+ if (normalized === "auto") return void 0;
627
+ if (normalized.includes(":") || normalized.includes("/")) {
628
+ const delimiter = normalized.includes(":") ? ":" : "/";
629
+ const [wRaw, hRaw] = normalized.split(delimiter);
630
+ const width = Number(wRaw?.trim());
631
+ const height = Number(hRaw?.trim());
632
+ if (!Number.isFinite(width) || !Number.isFinite(height) || width <= 0 || height <= 0) {
633
+ return void 0;
634
+ }
635
+ return width / height;
636
+ }
637
+ const numeric = Number(normalized);
638
+ if (!Number.isFinite(numeric) || numeric <= 0) return void 0;
639
+ return numeric;
640
+ }
641
+ var MAX_ASPECT_DISTANCE = 0.25;
642
+ function resolveMediaTransformForAspect(transform, targetAspect) {
643
+ if (!transform) return {};
644
+ const base = {
645
+ rect: transform.rect,
646
+ hotspot: transform.hotspot,
647
+ rotation: transform.rotation
648
+ };
649
+ const target = parseAspectRatioValue(targetAspect);
650
+ const crops = transform.aspectCrops;
651
+ if (!target || !crops || Object.keys(crops).length === 0) {
652
+ return base;
653
+ }
654
+ let best = null;
655
+ let bestDistance = Number.POSITIVE_INFINITY;
656
+ for (const [key, candidate] of Object.entries(crops)) {
657
+ const candidateAspect = parseAspectRatioValue(candidate.aspect ?? key);
658
+ if (!candidateAspect) continue;
659
+ const distance = Math.abs(Math.log(candidateAspect / target));
660
+ if (distance < bestDistance) {
661
+ best = candidate;
662
+ bestDistance = distance;
663
+ }
664
+ }
665
+ if (!best) return base;
666
+ if (bestDistance > MAX_ASPECT_DISTANCE) return base;
667
+ return {
668
+ rect: best.rect ?? base.rect,
669
+ hotspot: best.hotspot ?? base.hotspot,
670
+ rotation: best.rotation ?? base.rotation
671
+ };
672
+ }
673
+ function isValidTransformRect(rect) {
674
+ return isValidTransformRectStructure(rect);
675
+ }
676
+ function isExplicitRectCrop(rect, sourceWidth, sourceHeight, epsilon = DEFAULT_RECT_EPSILON) {
677
+ if (!isValidTransformRect(rect)) return false;
678
+ const hasSourceDimensions = typeof sourceWidth === "number" && Number.isFinite(sourceWidth) && sourceWidth > 0 && typeof sourceHeight === "number" && Number.isFinite(sourceHeight) && sourceHeight > 0;
679
+ if (!hasSourceDimensions) {
680
+ return true;
681
+ }
682
+ const [x, y, width, height] = rect;
683
+ const isFullFrame = Math.abs(x) <= epsilon && Math.abs(y) <= epsilon && Math.abs(width - sourceWidth) <= epsilon && Math.abs(height - sourceHeight) <= epsilon;
684
+ return !isFullFrame;
685
+ }
686
+
687
+ // ../media-core/src/deliveryContracts.ts
688
+ var DEFAULT_MEDIA_WIDTH_CANDIDATES = [
689
+ 320,
690
+ 480,
691
+ 640,
692
+ 768,
693
+ 960,
694
+ 1200,
695
+ 1536,
696
+ 1920,
697
+ 2560
698
+ ];
699
+ function normalizeWidthCandidates(candidates, max = 2560) {
700
+ const source = (candidates ?? DEFAULT_MEDIA_WIDTH_CANDIDATES).filter((value) => Number.isFinite(value) && value > 0);
701
+ const uniqueSorted = [...new Set(source.map((value) => Math.round(value)))].filter((value) => value > 0 && value <= max).sort((a, b) => a - b);
702
+ if (uniqueSorted.length > 0) {
703
+ return uniqueSorted;
704
+ }
705
+ return DEFAULT_MEDIA_WIDTH_CANDIDATES.filter((value) => value <= max);
706
+ }
707
+
708
+ // ../media-core/src/rotation.ts
709
+ function rotateNormalizedPoint(point, rotation) {
710
+ const x = point.x;
711
+ const y = point.y;
712
+ switch (rotation) {
713
+ case 90:
714
+ return { x: 1 - y, y: x };
715
+ case 180:
716
+ return { x: 1 - x, y: 1 - y };
717
+ case 270:
718
+ return { x: y, y: 1 - x };
719
+ default:
720
+ return { x, y };
721
+ }
722
+ }
723
+
724
+ // ../blocks/src/system/media/slotContracts.ts
725
+ var DEFAULT_MIN_SOURCE_WIDTH = 1200;
726
+ var LARGE_MIN_SOURCE_WIDTH = 1400;
727
+ var SECTION_BACKGROUND_MIN_SOURCE_WIDTH = 1920;
728
+ var SECTION_BACKGROUND_MIN_SOURCE_HEIGHT = 900;
729
+ var TEAM_MEMBER_MIN_SOURCE_WIDTH = 1e3;
730
+ var DEFAULT_DELIVERY_MAX_WIDTH = 2560;
731
+ var DEFAULT_MARQUEE_IMAGE_PX = 256;
732
+ function normalizeSlotPath(path) {
733
+ return path.split(".").map((segment) => /^\d+$/.test(segment) ? "[]" : segment).join(".");
734
+ }
735
+ function asString(value) {
736
+ return typeof value === "string" && value.trim().length > 0 ? value.trim() : void 0;
737
+ }
738
+ function asFiniteNumber(value) {
739
+ if (typeof value !== "number" || !Number.isFinite(value)) return void 0;
740
+ return value;
741
+ }
742
+ function asPositiveIntArray(value) {
743
+ if (!Array.isArray(value)) return void 0;
744
+ const numbers = value.map((entry) => asFiniteNumber(entry)).filter((entry) => entry !== void 0 && entry > 0).map((entry) => Math.round(entry));
745
+ return numbers.length > 0 ? numbers : void 0;
746
+ }
747
+ function getValueAtPath(values, path) {
748
+ const segments = path.split(".").filter((segment) => segment.length > 0);
749
+ let current = values;
750
+ for (const segment of segments) {
751
+ if (Array.isArray(current)) {
752
+ const numericIndex = Number.parseInt(segment, 10);
753
+ if (!Number.isFinite(numericIndex)) return void 0;
754
+ const next2 = current[numericIndex];
755
+ if (next2 === void 0) return void 0;
756
+ current = next2;
757
+ continue;
758
+ }
759
+ const record = asRecord(current);
760
+ if (!record) return void 0;
761
+ const next = record[segment];
762
+ if (next === void 0) return void 0;
763
+ current = next;
764
+ }
765
+ return current;
766
+ }
767
+ function resolveSiblingAspectRatio(fieldPath, values) {
768
+ if (!values) return void 0;
769
+ const lastDotIndex = fieldPath.lastIndexOf(".");
770
+ if (lastDotIndex < 0) {
771
+ return asString(values.aspectRatio);
772
+ }
773
+ const parentPath = fieldPath.slice(0, lastDotIndex);
774
+ const parentValue = getValueAtPath(values, parentPath);
775
+ const parentRecord = asRecord(parentValue);
776
+ return asString(parentRecord?.aspectRatio);
777
+ }
778
+ function getMinSourceConstraints(aspectRatio, minSourceWidth) {
779
+ const parsedAspect = parseAspectRatioValue(aspectRatio);
780
+ if (!parsedAspect) {
781
+ return { minSourceWidth };
782
+ }
783
+ return {
784
+ minSourceWidth,
785
+ minSourceHeight: Math.max(1, Math.round(minSourceWidth / parsedAspect))
786
+ };
787
+ }
788
+ function resolveColumnsGridCols(content) {
789
+ const items = Array.isArray(content.columns) ? content.columns : [];
790
+ const count = Math.min(4, Math.max(1, items.length || 1));
791
+ const configuredDesktopColumnsRaw = typeof content.desktopColumns === "string" ? content.desktopColumns : "auto";
792
+ const configuredDesktopColumnsMap = {
793
+ "2": 2,
794
+ "3": 3,
795
+ "4": 4
796
+ };
797
+ const desktopColumns = configuredDesktopColumnsMap[configuredDesktopColumnsRaw] ?? count;
798
+ if (desktopColumns <= 1) {
799
+ return { base: 1 };
800
+ }
801
+ if (desktopColumns === 2) {
802
+ return { base: 1, md: 2 };
803
+ }
804
+ if (desktopColumns === 3) {
805
+ return { base: 1, md: 2, lg: 3 };
806
+ }
807
+ return { base: 1, md: 2, lg: 3, xl: 4 };
808
+ }
809
+ function formatVw(value) {
810
+ const rounded = Math.round(value * 100) / 100;
811
+ return `${Number.isInteger(rounded) ? rounded.toFixed(0) : rounded.toFixed(2)}vw`;
812
+ }
813
+ function fractionToVw(numerator, denominator) {
814
+ if (!Number.isFinite(numerator) || !Number.isFinite(denominator) || denominator <= 0) {
815
+ return "100vw";
816
+ }
817
+ const clampedNumerator = Math.max(1, Math.min(numerator, denominator));
818
+ return formatVw(clampedNumerator / denominator * 100);
819
+ }
820
+ function resolveColumnsDeliveryContract(fieldPath, values) {
821
+ const defaultCandidates = normalizeWidthCandidates(void 0, DEFAULT_DELIVERY_MAX_WIDTH);
822
+ if (!values) {
823
+ return {
824
+ strategy: "columnsAuto",
825
+ sizes: "100vw",
826
+ widthCandidates: defaultCandidates
827
+ };
828
+ }
829
+ const match = fieldPath.match(/^columns\.(\d+)\.media$/);
830
+ const matchIndex = match?.[1];
831
+ const columnIndex = typeof matchIndex === "string" ? Number.parseInt(matchIndex, 10) : void 0;
832
+ const columns = Array.isArray(values.columns) ? values.columns : [];
833
+ const columnValue = columnIndex !== void 0 ? asRecord(columns[columnIndex]) : void 0;
834
+ const rawSpan = asString(columnValue?.desktopSpan);
835
+ const desktopSpan = rawSpan === "2" || rawSpan === "3" || rawSpan === "4" ? Number.parseInt(rawSpan, 10) : 1;
836
+ const cols = resolveColumnsGridCols(values);
837
+ const mobileCols = cols.base;
838
+ const mdCols = cols.md ?? mobileCols;
839
+ const lgCols = cols.lg ?? mdCols;
840
+ const xlCols = cols.xl ?? lgCols;
841
+ const sizes = [
842
+ `(min-width: 1280px) ${fractionToVw(desktopSpan, xlCols)}`,
843
+ `(min-width: 1024px) ${fractionToVw(desktopSpan, lgCols)}`,
844
+ `(min-width: 768px) ${fractionToVw(1, mdCols)}`,
845
+ fractionToVw(1, mobileCols)
846
+ ].join(", ");
847
+ return {
848
+ strategy: "columnsAuto",
849
+ sizes,
850
+ widthCandidates: defaultCandidates
851
+ };
852
+ }
853
+ function parseSlidesToShow(value, fallback) {
854
+ const asText = asString(value);
855
+ if (!asText) return fallback;
856
+ const parsed = Number.parseInt(asText, 10);
857
+ if (!Number.isFinite(parsed) || parsed <= 0) return fallback;
858
+ return parsed;
859
+ }
860
+ function resolveMarqueeImageSizePixels(values) {
861
+ const size = asString(values?.marqueeImageSize) ?? "md";
862
+ if (size === "sm") return 200;
863
+ if (size === "lg") return 320;
864
+ if (size === "xl") return 400;
865
+ return DEFAULT_MARQUEE_IMAGE_PX;
866
+ }
867
+ function resolveMarqueeMinSourceWidth(values) {
868
+ const pixels = resolveMarqueeImageSizePixels(values);
869
+ return Math.max(600, Math.round(pixels * 3));
870
+ }
871
+ function resolveImageGalleryDeliveryContract(values) {
872
+ const variant = asString(values?.variant) ?? "grid";
873
+ const defaultCandidates = normalizeWidthCandidates(void 0, DEFAULT_DELIVERY_MAX_WIDTH);
874
+ if (variant === "carousel") {
875
+ const mobile = parseSlidesToShow(values?.slidesToShow, 1);
876
+ const tablet = parseSlidesToShow(values?.slidesToShowTablet, mobile);
877
+ const desktop = parseSlidesToShow(values?.slidesToShowDesktop, tablet);
878
+ return {
879
+ strategy: "imageGalleryVariant",
880
+ sizes: [
881
+ `(min-width: 1280px) ${fractionToVw(1, desktop)}`,
882
+ `(min-width: 768px) ${fractionToVw(1, tablet)}`,
883
+ fractionToVw(1, mobile)
884
+ ].join(", "),
885
+ widthCandidates: defaultCandidates
886
+ };
887
+ }
888
+ if (variant === "marquee") {
889
+ const marqueePixels = resolveMarqueeImageSizePixels(values);
890
+ return {
891
+ strategy: "imageGalleryVariant",
892
+ sizes: `${marqueePixels}px`,
893
+ widthCandidates: defaultCandidates
894
+ };
895
+ }
896
+ return {
897
+ strategy: "imageGalleryVariant",
898
+ sizes: "(min-width: 1280px) 31vw, (min-width: 768px) 47vw, 96vw",
899
+ widthCandidates: defaultCandidates
900
+ };
901
+ }
902
+ function parseRatioToken(value) {
903
+ const raw = asString(value);
904
+ if (!raw) return null;
905
+ const [numRaw, denomRaw] = raw.split("/").map((part) => part.trim());
906
+ const numerator = Number(numRaw);
907
+ const denominator = Number(denomRaw);
908
+ if (!Number.isFinite(numerator) || !Number.isFinite(denominator)) return null;
909
+ if (numerator <= 0 || denominator <= 0) return null;
910
+ return { numerator, denominator };
911
+ }
912
+ function resolveResponsiveTwoColumnImageSizes(values) {
913
+ const ratio = parseRatioToken(values?.ratio) ?? { numerator: 1, denominator: 2 };
914
+ return fractionToVw(ratio.numerator, ratio.denominator);
915
+ }
916
+ function parseColumnsCount(raw, fallback) {
917
+ const cols = typeof raw === "number" ? raw : typeof raw === "string" ? Number.parseInt(raw, 10) : fallback;
918
+ const safe = Number.isFinite(cols) ? cols : fallback;
919
+ return Math.max(1, Math.min(6, safe));
920
+ }
921
+ function resolveTeamMembersDeliveryContract(values) {
922
+ const defaultCandidates = normalizeWidthCandidates(void 0, DEFAULT_DELIVERY_MAX_WIDTH);
923
+ const variant = asString(values?.variant) ?? "grid";
924
+ if (variant === "stack") {
925
+ const ratio = parseRatioToken(values?.imageColSize) ?? { numerator: 1, denominator: 3 };
926
+ const desktop = fractionToVw(ratio.numerator, ratio.denominator);
927
+ return {
928
+ strategy: "default",
929
+ sizes: `(min-width: 768px) ${desktop}, 100vw`,
930
+ widthCandidates: defaultCandidates
931
+ };
932
+ }
933
+ const clamped = parseColumnsCount(values?.columns, 3);
934
+ return {
935
+ strategy: "default",
936
+ sizes: fractionToVw(1, clamped),
937
+ widthCandidates: defaultCandidates
938
+ };
939
+ }
940
+ function resolveMediaTextDeliveryContract(values) {
941
+ const defaultCandidates = normalizeWidthCandidates(void 0, DEFAULT_DELIVERY_MAX_WIDTH);
942
+ const desktop = resolveResponsiveTwoColumnImageSizes(values);
943
+ return {
944
+ strategy: "default",
945
+ sizes: `(min-width: 768px) ${desktop}, 100vw`,
946
+ widthCandidates: defaultCandidates
947
+ };
948
+ }
949
+ function resolveCollectionDeliveryContract(values) {
950
+ const defaultCandidates = normalizeWidthCandidates(void 0, DEFAULT_DELIVERY_MAX_WIDTH);
951
+ const layout = asString(values?.layout) ?? "grid";
952
+ if (layout !== "grid") {
953
+ return { strategy: "default", sizes: "100vw", widthCandidates: defaultCandidates };
954
+ }
955
+ const clamped = parseColumnsCount(values?.columns, 3);
956
+ return {
957
+ strategy: "default",
958
+ sizes: fractionToVw(1, clamped),
959
+ widthCandidates: defaultCandidates
960
+ };
961
+ }
962
+ function resolveSmallLogoDeliveryContract() {
963
+ const defaultCandidates = normalizeWidthCandidates(void 0, DEFAULT_DELIVERY_MAX_WIDTH);
964
+ return {
965
+ strategy: "default",
966
+ sizes: "256px",
967
+ widthCandidates: defaultCandidates
968
+ };
969
+ }
970
+ function resolveDefaultDeliveryContract(slotPath) {
971
+ const widthCandidates = normalizeWidthCandidates(void 0, DEFAULT_DELIVERY_MAX_WIDTH);
972
+ if (slotPath.endsWith("_sectionStyles.background.image")) {
973
+ return {
974
+ strategy: "default",
975
+ sizes: "100vw",
976
+ widthCandidates,
977
+ maxCssWidth: DEFAULT_DELIVERY_MAX_WIDTH
978
+ };
979
+ }
980
+ return {
981
+ strategy: "default",
982
+ sizes: "100vw",
983
+ widthCandidates
984
+ };
985
+ }
986
+ function parseMediaDeliveryConfig(value) {
987
+ const record = asRecord(value);
988
+ if (!record) return void 0;
989
+ const strategyValue = asString(record.strategy);
990
+ const strategy = strategyValue === "default" || strategyValue === "columnsAuto" || strategyValue === "imageGalleryVariant" ? strategyValue : void 0;
991
+ const strategyOptions = asRecord(record.strategyOptions);
992
+ const parsed = {};
993
+ const sizes = asString(record.sizes);
994
+ if (sizes) parsed.sizes = sizes;
995
+ const widthCandidates = asPositiveIntArray(record.widthCandidates);
996
+ if (widthCandidates) parsed.widthCandidates = widthCandidates;
997
+ const maxCssWidth = asFiniteNumber(record.maxCssWidth);
998
+ if (maxCssWidth !== void 0) parsed.maxCssWidth = maxCssWidth;
999
+ const maxCssHeight = asFiniteNumber(record.maxCssHeight);
1000
+ if (maxCssHeight !== void 0) parsed.maxCssHeight = maxCssHeight;
1001
+ if (strategy) parsed.strategy = strategy;
1002
+ if (strategyOptions) parsed.strategyOptions = strategyOptions;
1003
+ return parsed;
1004
+ }
1005
+ function resolveFieldUiDeliveryConfig(fieldUi, variant) {
1006
+ const ui = asRecord(fieldUi);
1007
+ if (!ui) return void 0;
1008
+ const defaultConfig = parseMediaDeliveryConfig(ui.mediaDelivery);
1009
+ const byVariant = asRecord(ui.mediaDeliveryByVariant);
1010
+ const variantConfig = variant ? parseMediaDeliveryConfig(byVariant?.[variant]) : void 0;
1011
+ if (!defaultConfig && !variantConfig) return void 0;
1012
+ return {
1013
+ ...defaultConfig,
1014
+ ...variantConfig,
1015
+ strategyOptions: {
1016
+ ...defaultConfig?.strategyOptions ?? {},
1017
+ ...variantConfig?.strategyOptions ?? {}
1018
+ }
1019
+ };
1020
+ }
1021
+ function mergeDelivery(base, override) {
1022
+ if (!override) return base;
1023
+ const maxCssWidth = override.maxCssWidth ?? base.maxCssWidth;
1024
+ const cap = maxCssWidth && maxCssWidth > 0 ? Math.round(maxCssWidth) : DEFAULT_DELIVERY_MAX_WIDTH;
1025
+ const widthCandidates = normalizeWidthCandidates(
1026
+ override.widthCandidates ?? base.widthCandidates,
1027
+ cap
1028
+ );
1029
+ return {
1030
+ ...base,
1031
+ ...override,
1032
+ widthCandidates
1033
+ };
1034
+ }
1035
+ function buildContract(edit, delivery) {
1036
+ return {
1037
+ edit,
1038
+ delivery
1039
+ };
1040
+ }
1041
+ function resolveImageGalleryEditContract(slotPath, values) {
1042
+ if (slotPath !== "images.[].image") {
1043
+ return void 0;
1044
+ }
1045
+ const variant = asString(values?.variant) ?? "grid";
1046
+ if (variant === "marquee") {
1047
+ const aspectRatio = "1/1";
1048
+ const minSourceWidth = resolveMarqueeMinSourceWidth(values);
1049
+ return {
1050
+ mode: "fixed-aspect",
1051
+ aspectRatio,
1052
+ ...getMinSourceConstraints(aspectRatio, minSourceWidth)
1053
+ };
1054
+ }
1055
+ if (variant === "masonry") {
1056
+ return {
1057
+ mode: "original-aspect",
1058
+ minSourceWidth: DEFAULT_MIN_SOURCE_WIDTH
1059
+ };
1060
+ }
1061
+ const configuredAspect = asString(values?.aspectRatio);
1062
+ if (!configuredAspect || configuredAspect === "auto") {
1063
+ return {
1064
+ mode: "original-aspect",
1065
+ minSourceWidth: DEFAULT_MIN_SOURCE_WIDTH
1066
+ };
1067
+ }
1068
+ return {
1069
+ mode: "fixed-aspect",
1070
+ aspectRatio: configuredAspect,
1071
+ ...getMinSourceConstraints(configuredAspect, DEFAULT_MIN_SOURCE_WIDTH)
1072
+ };
1073
+ }
1074
+ function resolveEditContract(blockKind, fieldPath, slotPath, values, fieldAspectRatio) {
1075
+ const normalizedFieldAspect = asString(fieldAspectRatio);
1076
+ if (slotPath.endsWith("_sectionStyles.background.image")) {
1077
+ return {
1078
+ mode: "original-aspect",
1079
+ minSourceWidth: SECTION_BACKGROUND_MIN_SOURCE_WIDTH,
1080
+ minSourceHeight: SECTION_BACKGROUND_MIN_SOURCE_HEIGHT
1081
+ };
1082
+ }
1083
+ if (blockKind === "block.image-gallery") {
1084
+ const imageGalleryContract = resolveImageGalleryEditContract(slotPath, values);
1085
+ if (imageGalleryContract) return imageGalleryContract;
1086
+ }
1087
+ if (blockKind === "block.team-members" && slotPath === "members.[].photo") {
1088
+ return {
1089
+ mode: "fixed-aspect",
1090
+ aspectRatio: "1/1",
1091
+ ...getMinSourceConstraints("1/1", TEAM_MEMBER_MIN_SOURCE_WIDTH)
1092
+ };
1093
+ }
1094
+ if (blockKind === "block.media-text" && slotPath === "images.[].image") {
1095
+ const blockAspectRatio = asString(values?.aspectRatio);
1096
+ if (blockAspectRatio && blockAspectRatio !== "auto") {
1097
+ return {
1098
+ mode: "fixed-aspect",
1099
+ aspectRatio: blockAspectRatio,
1100
+ ...getMinSourceConstraints(blockAspectRatio, LARGE_MIN_SOURCE_WIDTH)
1101
+ };
1102
+ }
1103
+ return {
1104
+ mode: "original-aspect",
1105
+ minSourceWidth: LARGE_MIN_SOURCE_WIDTH
1106
+ };
1107
+ }
1108
+ const siblingAspectRatio = resolveSiblingAspectRatio(fieldPath, values);
1109
+ if (siblingAspectRatio && siblingAspectRatio !== "auto") {
1110
+ return {
1111
+ mode: "fixed-aspect",
1112
+ aspectRatio: siblingAspectRatio,
1113
+ ...getMinSourceConstraints(siblingAspectRatio, DEFAULT_MIN_SOURCE_WIDTH)
1114
+ };
1115
+ }
1116
+ if (siblingAspectRatio === "auto") {
1117
+ return {
1118
+ mode: "original-aspect",
1119
+ minSourceWidth: DEFAULT_MIN_SOURCE_WIDTH
1120
+ };
1121
+ }
1122
+ if (!normalizedFieldAspect || normalizedFieldAspect === "auto") {
1123
+ return {
1124
+ mode: "original-aspect",
1125
+ minSourceWidth: DEFAULT_MIN_SOURCE_WIDTH
1126
+ };
1127
+ }
1128
+ return {
1129
+ mode: "fixed-aspect",
1130
+ aspectRatio: normalizedFieldAspect,
1131
+ ...getMinSourceConstraints(normalizedFieldAspect, DEFAULT_MIN_SOURCE_WIDTH)
1132
+ };
1133
+ }
1134
+ function resolveStrategyDelivery(blockKind, fieldPath, slotPath, values) {
1135
+ if (blockKind === "block.columns" && slotPath === "columns.[].media") {
1136
+ return resolveColumnsDeliveryContract(fieldPath, values);
1137
+ }
1138
+ if (blockKind === "block.image-gallery" && slotPath === "images.[].image") {
1139
+ return resolveImageGalleryDeliveryContract(values);
1140
+ }
1141
+ if (blockKind === "block.team-members" && slotPath === "members.[].photo") {
1142
+ return resolveTeamMembersDeliveryContract(values);
1143
+ }
1144
+ if (blockKind === "block.media-text" && slotPath === "images.[].image") {
1145
+ return resolveMediaTextDeliveryContract(values);
1146
+ }
1147
+ if (blockKind === "block.collection" && slotPath.startsWith("items.[].")) {
1148
+ return resolveCollectionDeliveryContract(values);
1149
+ }
1150
+ if (blockKind === "block.site-header" && slotPath === "logo") {
1151
+ return resolveSmallLogoDeliveryContract();
1152
+ }
1153
+ if (blockKind === "block.site-footer" && slotPath === "logo") {
1154
+ return resolveSmallLogoDeliveryContract();
1155
+ }
1156
+ return void 0;
1157
+ }
1158
+ function resolveMediaSlotContract({
1159
+ blockKind,
1160
+ fieldPath,
1161
+ values,
1162
+ fieldAspectRatio,
1163
+ fieldUi
1164
+ }) {
1165
+ const slotPath = normalizeSlotPath(fieldPath);
1166
+ const variant = asString(values?.variant);
1167
+ const edit = resolveEditContract(blockKind, fieldPath, slotPath, values, fieldAspectRatio);
1168
+ const defaultDelivery = resolveDefaultDeliveryContract(slotPath);
1169
+ const fieldDelivery = resolveFieldUiDeliveryConfig(fieldUi, variant);
1170
+ const strategyDelivery = resolveStrategyDelivery(blockKind, fieldPath, slotPath, values);
1171
+ const mergedField = mergeDelivery(defaultDelivery, fieldDelivery);
1172
+ const merged = mergeDelivery(mergedField, strategyDelivery);
1173
+ return buildContract(edit, merged);
1174
+ }
1175
+
1176
+ // ../theme-core/src/tokens/colorTokenParts.ts
1177
+ function parseOpacityPercent(source) {
1178
+ const trimmed = source.trim();
1179
+ if (!trimmed) return null;
1180
+ if (!/^\d{1,3}(?:\.\d+)?$/.test(trimmed)) return null;
1181
+ const value = Number(trimmed);
1182
+ if (!Number.isFinite(value)) return null;
1183
+ if (value < 0 || value > 100) return null;
1184
+ return value;
1185
+ }
1186
+ function parseColorTokenParts(source) {
1187
+ const trimmed = source.trim();
1188
+ if (trimmed.startsWith("raw:")) {
1189
+ return { kind: "raw", value: trimmed.slice(4) };
1190
+ }
1191
+ const [token, opacityRaw, extra] = trimmed.split("/");
1192
+ if (!token || extra !== void 0) {
1193
+ return { kind: "invalid", token: trimmed };
1194
+ }
1195
+ if (opacityRaw === void 0) {
1196
+ return { kind: "token", token, opacityPercent: null };
1197
+ }
1198
+ const opacityPercent = parseOpacityPercent(opacityRaw);
1199
+ if (opacityPercent === null) {
1200
+ return { kind: "invalid", token: trimmed };
1201
+ }
1202
+ return { kind: "token", token, opacityPercent };
1203
+ }
1204
+
1205
+ // ../theme-core/src/utils/colorStyles.ts
1206
+ var COLOR_VAR_PREFIX = "--tb-";
1207
+ function parseToken(source) {
1208
+ const parts = parseColorTokenParts(source);
1209
+ if (parts.kind === "raw") {
1210
+ return { token: source, raw: parts.value };
1211
+ }
1212
+ if (parts.kind === "invalid") {
1213
+ return { token: source };
1214
+ }
1215
+ return {
1216
+ token: parts.token,
1217
+ alpha: parts.opacityPercent === null ? void 0 : parts.opacityPercent / 100
1218
+ };
1219
+ }
1220
+ function rgbColorValue(token) {
1221
+ const { token: baseToken, alpha, raw } = parseToken(token);
1222
+ if (raw) {
1223
+ return raw;
1224
+ }
1225
+ const cssVar = `${COLOR_VAR_PREFIX}${baseToken}`;
1226
+ if (alpha === void 0) {
1227
+ return `rgb(var(${cssVar}))`;
1228
+ }
1229
+ return `rgba(var(${cssVar}), ${alpha})`;
1230
+ }
1231
+ function backgroundColorStyle(token) {
1232
+ return { backgroundColor: rgbColorValue(token) };
1233
+ }
1234
+ function textColorStyle(token) {
1235
+ return { color: rgbColorValue(token) };
1236
+ }
1237
+ function borderColorStyle(token) {
1238
+ return { borderColor: rgbColorValue(token) };
1239
+ }
1240
+ function mergeStyles(...styles) {
1241
+ const merged = {};
1242
+ for (const style of styles) {
1243
+ if (!style) continue;
1244
+ Object.assign(merged, style);
1245
+ }
1246
+ return Object.keys(merged).length ? merged : void 0;
1247
+ }
1248
+ function buildMediaAssetIndex(assets) {
1249
+ if (!assets || assets.length === 0) return void 0;
1250
+ const byId = /* @__PURE__ */ new Map();
1251
+ const byIdentifier = /* @__PURE__ */ new Map();
1252
+ for (const asset of assets) {
1253
+ if (!asset?.id) continue;
1254
+ byId.set(asset.id, asset);
1255
+ const identifier = typeof asset.identifier === "string" ? asset.identifier.trim() : "";
1256
+ if (identifier) byIdentifier.set(identifier, asset);
1257
+ }
1258
+ return { byId, byIdentifier };
1259
+ }
1260
+ var MAX_RENDER_DIMENSION = 4096;
1261
+ var MAX_SRCSET_WIDTH = 2560;
1262
+ var RELATIVE_IMG_PROXY_BASE_PATH = "/api/img";
1263
+ function normalizeSupabaseUrl(value) {
1264
+ return value?.replace(/\/$/, "");
1265
+ }
1266
+ function buildResolveImageUrlContext(input) {
1267
+ return {
1268
+ supabaseUrl: normalizeSupabaseUrl(input?.supabaseUrl),
1269
+ siteId: input?.siteId,
1270
+ mediaAssetIndex: input?.mediaAssetIndex ?? buildMediaAssetIndex(input?.mediaAssets)
1271
+ };
1272
+ }
1273
+ function getValidSourceDimension(value) {
1274
+ return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : void 0;
1275
+ }
1276
+ function isExplicitCropProxyEnabled() {
1277
+ const raw = process.env.NEXT_PUBLIC_MEDIA_EXPLICIT_CROP_PROXY_ENABLED ?? process.env.MEDIA_EXPLICIT_CROP_PROXY_ENABLED;
1278
+ if (!raw) return true;
1279
+ const normalized = raw.trim().toLowerCase();
1280
+ return !(normalized === "0" || normalized === "false" || normalized === "no" || normalized === "off");
1281
+ }
1282
+ function getRequestedDimension(value) {
1283
+ if (typeof value !== "number" || !Number.isFinite(value)) return void 0;
1284
+ return Math.min(MAX_RENDER_DIMENSION, Math.max(1, Math.round(value)));
1285
+ }
1286
+ function getPositiveAspectRatio(value) {
1287
+ if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) return void 0;
1288
+ return value;
1289
+ }
1290
+ function getHeightForAspect(width, aspectRatio) {
1291
+ if (!aspectRatio) return void 0;
1292
+ return Math.max(1, Math.round(width / aspectRatio));
1293
+ }
1294
+ function mapResizeToFit(resize) {
1295
+ if (resize === "contain") return "clip";
1296
+ return "crop";
1297
+ }
1298
+ function shouldUseExplicitRectProxy(value, options, resolvedTransform, sourceWidth, sourceHeight) {
1299
+ if ("original" in options && options.original) return false;
1300
+ if (!isExplicitCropProxyEnabled()) return false;
1301
+ if (!value.assetId) return false;
1302
+ if (typeof resolvedTransform.rotation === "number" && resolvedTransform.rotation !== 0) return true;
1303
+ return isExplicitRectCrop(resolvedTransform.rect, sourceWidth, sourceHeight);
1304
+ }
1305
+ function buildProxyTransformParams(options, resolvedTransform) {
1306
+ const requestedWidth = "width" in options ? getRequestedDimension(options.width) : void 0;
1307
+ const requestedHeight = "height" in options ? getRequestedDimension(options.height) : void 0;
1308
+ const params = {
1309
+ w: requestedWidth,
1310
+ h: requestedHeight,
1311
+ q: "quality" in options ? options.quality : void 0,
1312
+ fit: mapResizeToFit("resize" in options ? options.resize : void 0),
1313
+ autoFormat: true
1314
+ };
1315
+ if (resolvedTransform.rect) {
1316
+ params.rect = resolvedTransform.rect;
1317
+ }
1318
+ if (resolvedTransform.rotation) {
1319
+ params.or = resolvedTransform.rotation;
1320
+ }
1321
+ return params;
1322
+ }
1323
+ function buildDirectTransformOptions(options) {
1324
+ if ("original" in options && options.original) return void 0;
1325
+ const requestedWidth = "width" in options ? getRequestedDimension(options.width) : void 0;
1326
+ const requestedHeight = "height" in options ? getRequestedDimension(options.height) : void 0;
1327
+ return {
1328
+ width: requestedWidth,
1329
+ height: requestedHeight,
1330
+ quality: "quality" in options ? options.quality : void 0,
1331
+ resize: "resize" in options ? options.resize : void 0
1332
+ };
1333
+ }
1334
+ function resolveTransformResolution(value, targetAspectRatio) {
1335
+ return {
1336
+ resolvedTransform: resolveMediaTransformForAspect(value.transform, targetAspectRatio),
1337
+ sourceWidth: getValidSourceDimension(value.width),
1338
+ sourceHeight: getValidSourceDimension(value.height)
1339
+ };
1340
+ }
1341
+ function buildCssRectStylePatch(value, rect) {
1342
+ const sourceWidth = getValidSourceDimension(value.width);
1343
+ const sourceHeight = getValidSourceDimension(value.height);
1344
+ if (sourceWidth === void 0 || sourceHeight === void 0 || rect[2] <= 0 || rect[3] <= 0) {
1345
+ return void 0;
1346
+ }
1347
+ const [x, y, width, height] = rect;
1348
+ const centerX = (x + width / 2) / sourceWidth;
1349
+ const centerY = (y + height / 2) / sourceHeight;
1350
+ const zoomX = sourceWidth / width;
1351
+ const zoomY = sourceHeight / height;
1352
+ const uniformZoom = Math.max(1, Math.min(64, Math.max(zoomX, zoomY)));
1353
+ return {
1354
+ objectPosition: `${centerX * 100}% ${centerY * 100}%`,
1355
+ transform: `scale(${uniformZoom})`,
1356
+ transformOrigin: "center"
1357
+ };
1358
+ }
1359
+ function appendTransform(base, transform) {
1360
+ if (!base || base.length === 0) return transform;
1361
+ return `${base} ${transform}`;
1362
+ }
1363
+ function applyRectTransform(existingStyle, patch) {
1364
+ const next = { ...patch };
1365
+ if (patch.transform) {
1366
+ next.transform = appendTransform(existingStyle?.transform, patch.transform);
1367
+ }
1368
+ return next;
1369
+ }
1370
+ function getProxyImageUrl(value, options, transformAspectRatio, resolved) {
1371
+ if (!value.assetId) return void 0;
1372
+ const targetAspect = transformAspectRatio ?? resolveTargetAspectRatio(options);
1373
+ const { resolvedTransform, sourceWidth, sourceHeight } = resolved ?? resolveTransformResolution(value, targetAspect);
1374
+ if (!shouldUseExplicitRectProxy(value, options, resolvedTransform, sourceWidth, sourceHeight)) return void 0;
1375
+ const params = buildProxyTransformParams(options, resolvedTransform);
1376
+ const proxyBasePath = getImageProxyBasePath();
1377
+ const proxyUrl = getImageUrl({ id: asMediaAssetId(value.assetId) }, params, proxyBasePath);
1378
+ debugMediaNodeLog("resolve:proxy-img", { assetId: value.assetId, params, proxyBasePath, proxyUrl });
1379
+ return proxyUrl;
1380
+ }
1381
+ function resolveMediaStorageUrl(value, context, transformOptions) {
1382
+ const canonical = resolveMediaWithCanonicalAsset(value, context ?? void 0);
1383
+ if (!canonical.storagePath || canonical.storagePath.length === 0) return void 0;
1384
+ const supabaseUrl = context?.supabaseUrl?.replace(/\/$/, "") ?? getSupabaseUrl();
1385
+ const siteId = context?.siteId ?? getSiteId();
1386
+ const bucket = canonical.storageBucket ?? "media";
1387
+ if (isRelativeDirectImageStoragePath(canonical.storagePath) && !siteId) {
1388
+ console.warn(
1389
+ `[blocks] Relative storagePath "${canonical.storagePath}" requires siteId context. Media URL may be incorrect. Ensure siteId is set via runWithMediaContext or setContextSiteId.`
1390
+ );
1391
+ }
1392
+ const directUrl = getDirectImageUrlForStoragePath(
1393
+ supabaseUrl,
1394
+ canonical.storagePath,
1395
+ bucket,
1396
+ siteId,
1397
+ transformOptions
1398
+ );
1399
+ debugMediaNodeLog("resolve:direct-supabase", {
1400
+ storagePath: canonical.storagePath,
1401
+ siteId,
1402
+ bucket,
1403
+ directUrl,
1404
+ transformOptions
1405
+ });
1406
+ return directUrl;
1407
+ }
1408
+ function getDirectImageUrlForValue(value, options, context) {
1409
+ return resolveMediaStorageUrl(value, context, buildDirectTransformOptions(options));
1410
+ }
1411
+ function resolveStorageImageUrl(value, options, context, transformAspectRatio, resolved) {
1412
+ const proxyUrl = getProxyImageUrl(value, options, transformAspectRatio, resolved);
1413
+ if (proxyUrl) return proxyUrl;
1414
+ const directUrl = getDirectImageUrlForValue(value, options, context);
1415
+ if (directUrl) return directUrl;
1416
+ return void 0;
1417
+ }
1418
+ var ImagePresets = {
1419
+ /** Small thumbnails (200px) - for block previews, lists */
1420
+ thumbnail: { width: 200, quality: 80, resize: "contain" },
1421
+ /** Card-sized images (600px) - for cards, grids */
1422
+ card: { width: 600, quality: 80, resize: "contain" },
1423
+ /** Hero images (1200px) - for above-fold content */
1424
+ hero: { width: 1200, quality: 85, resize: "contain" },
1425
+ /** Full-width images (1920px) - for backgrounds, large displays */
1426
+ full: { width: 1920, quality: 85, resize: "contain" }
1427
+ };
1428
+ var _serverStorage = null;
1429
+ var _serverStorageChecked = false;
1430
+ function getServerStorage() {
1431
+ if (typeof window !== "undefined") return null;
1432
+ if (_serverStorageChecked) return _serverStorage;
1433
+ _serverStorageChecked = true;
1434
+ try {
1435
+ const globalWithNonWebpackRequire = globalThis;
1436
+ const nonWebpackRequire = typeof globalWithNonWebpackRequire.__non_webpack_require__ === "function" ? globalWithNonWebpackRequire.__non_webpack_require__ : new Function("id", "return require(id)");
1437
+ const asyncHooks = nonWebpackRequire("async_hooks");
1438
+ const AsyncLocalStorage = asyncHooks.AsyncLocalStorage;
1439
+ if (AsyncLocalStorage) {
1440
+ _serverStorage = new AsyncLocalStorage();
1441
+ return _serverStorage;
1442
+ }
1443
+ return null;
1444
+ } catch {
1445
+ {
1446
+ console.warn("[blocks] AsyncLocalStorage not available - using module-level state");
1447
+ }
1448
+ return null;
1449
+ }
1450
+ }
1451
+ var RB_MEDIA_CONTEXT_KEY = /* @__PURE__ */ Symbol.for("riverbankcms.blocks.mediaContext");
1452
+ function getClientContextStore() {
1453
+ const g = globalThis;
1454
+ const existing = g[RB_MEDIA_CONTEXT_KEY];
1455
+ if (existing && typeof existing === "object") return existing;
1456
+ const next = {};
1457
+ g[RB_MEDIA_CONTEXT_KEY] = next;
1458
+ return next;
1459
+ }
1460
+ function getMediaContext() {
1461
+ const storage = getServerStorage();
1462
+ if (storage) {
1463
+ return storage.getStore() ?? {};
1464
+ }
1465
+ return getClientContextStore();
1466
+ }
1467
+ function setContextSupabaseUrl(url) {
1468
+ const normalizedUrl = normalizeSupabaseUrl(url);
1469
+ const storage = getServerStorage();
1470
+ if (storage) {
1471
+ const current = storage.getStore();
1472
+ if (current) {
1473
+ current.supabaseUrl = normalizedUrl;
1474
+ } else {
1475
+ if (storage.enterWith) {
1476
+ const next = { supabaseUrl: normalizedUrl };
1477
+ storage.enterWith(next);
1478
+ } else {
1479
+ getClientContextStore().supabaseUrl = normalizedUrl;
1480
+ }
1481
+ }
1482
+ } else {
1483
+ getClientContextStore().supabaseUrl = normalizedUrl;
1484
+ }
1485
+ }
1486
+ function setContextSiteId(siteId) {
1487
+ const storage = getServerStorage();
1488
+ if (storage) {
1489
+ const current = storage.getStore();
1490
+ if (current) {
1491
+ current.siteId = siteId;
1492
+ } else {
1493
+ if (storage.enterWith) {
1494
+ const next = { siteId };
1495
+ storage.enterWith(next);
1496
+ } else {
1497
+ getClientContextStore().siteId = siteId;
1498
+ }
1499
+ }
1500
+ } else {
1501
+ getClientContextStore().siteId = siteId;
1502
+ }
1503
+ }
1504
+ function setContextMediaAssetIndex(index) {
1505
+ const storage = getServerStorage();
1506
+ if (storage) {
1507
+ const current = storage.getStore();
1508
+ if (current) {
1509
+ current.mediaAssetIndex = index;
1510
+ } else {
1511
+ if (storage.enterWith) {
1512
+ const next = { mediaAssetIndex: index };
1513
+ storage.enterWith(next);
1514
+ } else {
1515
+ getClientContextStore().mediaAssetIndex = index;
1516
+ }
1517
+ }
1518
+ } else {
1519
+ getClientContextStore().mediaAssetIndex = index;
1520
+ }
1521
+ }
1522
+ function setContextResolveImageUrlContext(context) {
1523
+ setContextSupabaseUrl(context?.supabaseUrl);
1524
+ setContextSiteId(context?.siteId);
1525
+ setContextMediaAssetIndex(context?.mediaAssetIndex);
1526
+ }
1527
+ function getCurrentResolveImageUrlContext() {
1528
+ const context = getMediaContext();
1529
+ if (!context.supabaseUrl && !context.siteId && !context.mediaAssetIndex) {
1530
+ return void 0;
1531
+ }
1532
+ return {
1533
+ supabaseUrl: context.supabaseUrl,
1534
+ siteId: context.siteId,
1535
+ mediaAssetIndex: context.mediaAssetIndex
1536
+ };
1537
+ }
1538
+ function getSupabaseUrl() {
1539
+ const context = getMediaContext();
1540
+ if (context.supabaseUrl) {
1541
+ return context.supabaseUrl;
1542
+ }
1543
+ const url = process.env.NEXT_PUBLIC_SUPABASE_URL;
1544
+ if (!url) {
1545
+ throw new Error(
1546
+ "NEXT_PUBLIC_SUPABASE_URL is not configured. Set it to your Supabase project URL (e.g., https://xxx.supabase.co)"
1547
+ );
1548
+ }
1549
+ return url.replace(/\/$/, "");
1550
+ }
1551
+ function resolveDashboardOrigin(raw) {
1552
+ if (!raw) return void 0;
1553
+ const trimmed = raw.trim();
1554
+ if (!trimmed) return void 0;
1555
+ const withoutTrailingSlash = trimmed.replace(/\/+$/, "");
1556
+ const withoutApiSuffix = withoutTrailingSlash.replace(/\/api\/?$/, "");
1557
+ const hasProtocol = /^https?:\/\//i.test(withoutApiSuffix);
1558
+ const normalized = hasProtocol ? withoutApiSuffix : `http://${withoutApiSuffix.replace(/^\/+/, "")}`;
1559
+ try {
1560
+ return new URL(normalized).origin;
1561
+ } catch {
1562
+ return void 0;
1563
+ }
1564
+ }
1565
+ function getImageProxyBasePath() {
1566
+ const dashboardOrigin = resolveDashboardOrigin(process.env.NEXT_PUBLIC_DASHBOARD_URL);
1567
+ if (!dashboardOrigin) return RELATIVE_IMG_PROXY_BASE_PATH;
1568
+ return `${dashboardOrigin}${RELATIVE_IMG_PROXY_BASE_PATH}`;
1569
+ }
1570
+ function getSiteId() {
1571
+ return getMediaContext().siteId;
1572
+ }
1573
+ function getMediaAssetIndex(context) {
1574
+ return context?.mediaAssetIndex ?? getMediaContext().mediaAssetIndex;
1575
+ }
1576
+ function resolveCanonicalMediaAsset(value, context) {
1577
+ const index = getMediaAssetIndex(context);
1578
+ if (!index) return void 0;
1579
+ if (value.assetId) {
1580
+ const hit = index.byId.get(value.assetId);
1581
+ if (hit) return hit;
1582
+ }
1583
+ const identifier = typeof value.identifier === "string" ? value.identifier.trim() : "";
1584
+ if (identifier) {
1585
+ const hit = index.byIdentifier.get(identifier);
1586
+ if (hit) return hit;
1587
+ }
1588
+ return void 0;
1589
+ }
1590
+ function resolveMediaWithCanonicalAsset(value, context) {
1591
+ const asset = resolveCanonicalMediaAsset(value, context);
1592
+ if (!asset) return value;
1593
+ return {
1594
+ ...value,
1595
+ assetId: asset.id ?? value.assetId,
1596
+ identifier: typeof value.identifier === "string" && value.identifier.trim().length > 0 ? value.identifier : asset.identifier ?? value.identifier,
1597
+ storageBucket: asset.storageBucket ?? value.storageBucket,
1598
+ storagePath: asset.storagePath ?? value.storagePath,
1599
+ width: asset.width ?? value.width,
1600
+ height: asset.height ?? value.height
1601
+ };
1602
+ }
1603
+ function resolveVideoPosterUrl(value, context) {
1604
+ if (value.type !== "video") return void 0;
1605
+ const poster = value.poster;
1606
+ if (!poster) return void 0;
1607
+ switch (poster.tag) {
1608
+ case "external-src":
1609
+ return poster.src;
1610
+ case "storage":
1611
+ return resolveMediaStorageUrl({
1612
+ type: "image",
1613
+ assetId: poster.assetId,
1614
+ storageBucket: poster.storageBucket,
1615
+ storagePath: poster.storagePath
1616
+ }, context);
1617
+ }
1618
+ }
1619
+ var debugMediaNodeLog = (...args) => {
1620
+ if (typeof window === "undefined") return;
1621
+ const debugFlag = Reflect.get(window, "__DEBUG_MEDIA_NODE__");
1622
+ if (debugFlag === true) console.log("[MediaNode]", ...args);
1623
+ };
1624
+ function resolveMediaNodeResponsiveImage(value, size, style, slot, context) {
1625
+ const styleAspectRatio = resolveStyleAspectRatio(style);
1626
+ const transformAspectRatio = styleAspectRatio ?? resolveTargetAspectRatio(size);
1627
+ const slotContract = resolveSlotContract(slot);
1628
+ const targetAspectRatioToken = slotContract?.edit.mode === "fixed-aspect" ? slotContract.edit.aspectRatio : void 0;
1629
+ const targetAspectRatio = parseAspectRatioValue(targetAspectRatioToken);
1630
+ const responsive = slotContract ? resolveImageSourceSetWithContext(
1631
+ value,
1632
+ {
1633
+ widthCandidates: slotContract.delivery.widthCandidates,
1634
+ sizes: slotContract.delivery.sizes,
1635
+ resize: "cover",
1636
+ quality: "quality" in size ? size.quality : 80,
1637
+ targetAspectRatio,
1638
+ defaultWidth: "width" in size && typeof size.width === "number" ? size.width : 640
1639
+ },
1640
+ context
1641
+ ) : void 0;
1642
+ const imageUrl = responsive?.src ?? resolveImageUrlWithContext(value, size, context, transformAspectRatio);
1643
+ const resolvedTransform = resolveMediaTransformForAspect(value.transform, transformAspectRatio);
1644
+ const isProxy = typeof imageUrl === "string" && imageUrl.includes("/api/img/");
1645
+ return { transformAspectRatio, responsive, imageUrl, resolvedTransform, isProxy };
1646
+ }
1647
+ function resolveSlotContract(slot) {
1648
+ if (!slot.fieldPath) return void 0;
1649
+ const values = asRecord(slot.blockContent);
1650
+ if (!values) return void 0;
1651
+ return resolveMediaSlotContract({
1652
+ blockKind: slot.blockKind,
1653
+ fieldPath: slot.fieldPath,
1654
+ values,
1655
+ fieldAspectRatio: void 0,
1656
+ fieldUi: void 0
1657
+ });
1658
+ }
1659
+ function resolveStyleAspectRatio(style) {
1660
+ const raw = style?.aspectRatio;
1661
+ if (typeof raw === "number" && Number.isFinite(raw) && raw > 0) return raw;
1662
+ if (typeof raw === "string" && raw.trim().length > 0) return raw.trim();
1663
+ return void 0;
1664
+ }
1665
+ function renderVideo(value, className, style, context, options = {}) {
1666
+ if (value.type !== "video") return null;
1667
+ const src = resolvePublicMediaUrl(value, context);
1668
+ if (!src) return null;
1669
+ if (options.playback === "background") {
1670
+ const poster2 = resolveVideoPosterUrl(value, context);
1671
+ return /* @__PURE__ */ jsx(
1672
+ "video",
1673
+ {
1674
+ className,
1675
+ style,
1676
+ src,
1677
+ ...poster2 ? { poster: poster2 } : {},
1678
+ autoPlay: true,
1679
+ muted: true,
1680
+ loop: true,
1681
+ playsInline: true,
1682
+ preload: "metadata",
1683
+ "aria-hidden": "true",
1684
+ "data-rb-background-video": "true"
1685
+ }
1686
+ );
1687
+ }
1688
+ const poster = resolveVideoPosterUrl(value, context);
1689
+ return /* @__PURE__ */ jsx(
1690
+ "video",
1691
+ {
1692
+ className,
1693
+ style,
1694
+ src,
1695
+ ...poster ? { poster } : {},
1696
+ controls: true,
1697
+ controlsList: "nodownload",
1698
+ preload: "metadata",
1699
+ ...value.alt ? { "aria-label": value.alt } : {}
1700
+ }
1701
+ );
1702
+ }
1703
+ function resolvePublicMediaUrl(value, context) {
1704
+ return resolveMediaStorageUrl(value, context) ?? value.src;
1705
+ }
1706
+ function renderAudio(value, className, style, context) {
1707
+ if (value.type !== "audio") return null;
1708
+ const src = resolvePublicMediaUrl(value, context);
1709
+ if (!src) return null;
1710
+ return /* @__PURE__ */ jsx(
1711
+ "audio",
1712
+ {
1713
+ className,
1714
+ style,
1715
+ src,
1716
+ controls: true,
1717
+ controlsList: "nodownload",
1718
+ "aria-label": value.alt ?? "Audio"
1719
+ }
1720
+ );
1721
+ }
1722
+ function computeMediaTransformStyle(value, style, targetAspectRatio, options) {
1723
+ const transform = options?.resolvedTransform ?? resolveMediaTransformForAspect(value.transform, targetAspectRatio);
1724
+ const rect = transform.rect;
1725
+ const hotspot = transform.hotspot;
1726
+ const rotation = transform.rotation;
1727
+ if (!rect && !hotspot && !rotation) return style;
1728
+ const stylePatch = {};
1729
+ const heuristicSuppressCss = Boolean(
1730
+ isExplicitCropProxyEnabled() && value.assetId && (typeof rotation === "number" && rotation !== 0 || isExplicitRectCrop(rect, getValidSourceDimension(value.width), getValidSourceDimension(value.height)))
1731
+ );
1732
+ const shouldSuppressCss = options?.isProxy ?? heuristicSuppressCss;
1733
+ if (rect && !shouldSuppressCss) {
1734
+ const rectPatch = buildCssRectStylePatch(value, rect);
1735
+ if (rectPatch) {
1736
+ const mergedRect = applyRectTransform(style, rectPatch);
1737
+ Object.assign(stylePatch, mergedRect);
1738
+ }
1739
+ }
1740
+ if (hotspot) {
1741
+ const effectiveObjectFit = stylePatch.objectFit ?? style?.objectFit;
1742
+ const shouldApplyHotspot = !effectiveObjectFit || effectiveObjectFit === "cover" || effectiveObjectFit === "contain";
1743
+ if (shouldApplyHotspot && stylePatch.objectPosition === void 0) {
1744
+ const resolved = shouldSuppressCss && rotation ? rotateNormalizedPoint({ x: hotspot.x, y: hotspot.y }, rotation) : { x: hotspot.x, y: hotspot.y };
1745
+ stylePatch.objectPosition = `${resolved.x * 100}% ${resolved.y * 100}%`;
1746
+ }
1747
+ }
1748
+ if (rotation && !shouldSuppressCss) {
1749
+ const existingTransform = stylePatch.transform ?? style?.transform;
1750
+ stylePatch.transform = existingTransform ? `${existingTransform} rotate(${rotation}deg)` : `rotate(${rotation}deg)`;
1751
+ if (!stylePatch.transformOrigin) {
1752
+ stylePatch.transformOrigin = "center";
1753
+ }
1754
+ }
1755
+ return mergeStyles(style, stylePatch);
1756
+ }
1757
+ function resolveTargetAspectRatio(size) {
1758
+ if ("original" in size) return void 0;
1759
+ if ("width" in size && "height" in size && typeof size.width === "number" && typeof size.height === "number") {
1760
+ return size.width / size.height;
1761
+ }
1762
+ return void 0;
1763
+ }
1764
+ function MediaPlaceholder({
1765
+ className,
1766
+ style
1767
+ }) {
1768
+ return /* @__PURE__ */ jsx(
1769
+ "div",
1770
+ {
1771
+ className: clsx_default("rb-flex rb-h-48 rb-w-full rb-items-center rb-justify-center", className),
1772
+ style: mergeStyles(backgroundColorStyle("surface"), style),
1773
+ children: /* @__PURE__ */ jsx("span", { className: "rb-caption", style: textColorStyle("mutedText"), children: "Image unavailable" })
1774
+ }
1775
+ );
1776
+ }
1777
+ function resolveImageUrlWithContext(value, options, context, transformAspectRatio) {
1778
+ return resolveImageUrlWithContextInternal(value, options, context ?? void 0, transformAspectRatio);
1779
+ }
1780
+ function resolveImageUrlWithContextInternal(value, options, context, transformAspectRatio, resolved) {
1781
+ if (value.type !== "image") return void 0;
1782
+ const canonical = resolveMediaWithCanonicalAsset(value, context);
1783
+ debugMediaNodeLog("resolveImageUrl input", {
1784
+ assetId: canonical.assetId,
1785
+ storagePath: canonical.storagePath,
1786
+ src: canonical.src,
1787
+ type: canonical.type,
1788
+ options
1789
+ });
1790
+ if (canonical.storagePath && canonical.storagePath.length > 0) {
1791
+ const resolvedStorageUrl = resolveStorageImageUrl(canonical, options, context, transformAspectRatio, resolved);
1792
+ if (resolvedStorageUrl) {
1793
+ return resolvedStorageUrl;
1794
+ }
1795
+ }
1796
+ if (typeof canonical.src === "string" && canonical.src.length > 0) {
1797
+ debugMediaNodeLog("resolve:explicit-src", { src: canonical.src });
1798
+ return canonical.src;
1799
+ }
1800
+ const legacyUrl = typeof canonical === "object" && canonical !== null ? Reflect.get(canonical, "url") : void 0;
1801
+ debugMediaNodeLog("resolve:fallback-url", { fallbackUrl: typeof legacyUrl === "string" ? legacyUrl : null });
1802
+ return typeof legacyUrl === "string" ? legacyUrl : void 0;
1803
+ }
1804
+ function resolveImageSourceSetWithContext(value, options, context) {
1805
+ const normalizedContext = context ?? void 0;
1806
+ if (value.type !== "image") return void 0;
1807
+ const canonical = resolveMediaWithCanonicalAsset(value, normalizedContext);
1808
+ const widthCandidates = normalizeWidthCandidates(options.widthCandidates, MAX_SRCSET_WIDTH);
1809
+ if (widthCandidates.length === 0) return void 0;
1810
+ const targetAspectRatio = getPositiveAspectRatio(options.targetAspectRatio);
1811
+ const quality = options.quality;
1812
+ const resize = options.resize;
1813
+ const resolvedTransform = resolveMediaTransformForAspect(canonical.transform, targetAspectRatio);
1814
+ const sourceWidth = getValidSourceDimension(canonical.width);
1815
+ const sourceHeight = getValidSourceDimension(canonical.height);
1816
+ const hasExplicitRectCrop = isExplicitRectCrop(resolvedTransform.rect, sourceWidth, sourceHeight);
1817
+ const coverFactor = resolveCoverFactor({
1818
+ resize,
1819
+ targetAspectRatio,
1820
+ hasExplicitRectCrop,
1821
+ sourceWidth,
1822
+ sourceHeight
1823
+ });
1824
+ const shouldProxy = Boolean(
1825
+ isExplicitCropProxyEnabled() && canonical.assetId && (hasExplicitRectCrop || typeof resolvedTransform.rotation === "number" && resolvedTransform.rotation !== 0)
1826
+ );
1827
+ const effectiveSizes = coverFactor > 1 && typeof options.sizes === "string" && options.sizes.length > 0 ? scaleSizesAttribute(options.sizes, coverFactor) : options.sizes;
1828
+ const srcSetParts = widthCandidates.map((width) => {
1829
+ const height = shouldProxy && hasExplicitRectCrop ? getHeightForAspect(width, targetAspectRatio) : void 0;
1830
+ const effectiveResize = height ? resize : "contain";
1831
+ const url = resolveImageUrlWithContextInternal(
1832
+ canonical,
1833
+ height ? { width, height, resize: effectiveResize, quality } : { width, resize: effectiveResize, quality },
1834
+ normalizedContext,
1835
+ targetAspectRatio,
1836
+ { resolvedTransform, sourceWidth, sourceHeight }
1837
+ );
1838
+ if (!url) return null;
1839
+ return `${url} ${width}w`;
1840
+ }).filter((entry) => entry !== null);
1841
+ if (srcSetParts.length === 0) return void 0;
1842
+ const fallbackWidth = widthCandidates[Math.min(2, widthCandidates.length - 1)];
1843
+ if (fallbackWidth === void 0) return void 0;
1844
+ const defaultWidth = options.defaultWidth ?? fallbackWidth;
1845
+ const scaledDefaultWidth = coverFactor > 1 ? Math.round(defaultWidth * coverFactor) : defaultWidth;
1846
+ const nearestWidth = widthCandidates.find((candidate) => candidate >= scaledDefaultWidth) ?? widthCandidates[widthCandidates.length - 1];
1847
+ if (nearestWidth === void 0) return void 0;
1848
+ const defaultHeight = shouldProxy && hasExplicitRectCrop ? getHeightForAspect(nearestWidth, targetAspectRatio) : void 0;
1849
+ const effectiveDefaultResize = defaultHeight ? resize : "contain";
1850
+ const src = resolveImageUrlWithContextInternal(
1851
+ canonical,
1852
+ defaultHeight ? { width: nearestWidth, height: defaultHeight, resize: effectiveDefaultResize, quality } : { width: nearestWidth, resize: effectiveDefaultResize, quality },
1853
+ normalizedContext,
1854
+ targetAspectRatio,
1855
+ { resolvedTransform, sourceWidth, sourceHeight }
1856
+ );
1857
+ if (!src) return void 0;
1858
+ const fallbackSrc = shouldProxy ? getDirectImageUrlForValue(
1859
+ canonical,
1860
+ { width: nearestWidth, resize: "contain", quality },
1861
+ normalizedContext
1862
+ ) : void 0;
1863
+ return {
1864
+ src,
1865
+ srcSet: srcSetParts.join(", "),
1866
+ sizes: effectiveSizes,
1867
+ fallbackSrc
1868
+ };
1869
+ }
1870
+ function resolveCoverFactor(input) {
1871
+ if (input.resize !== "cover") return 1;
1872
+ if (!input.targetAspectRatio) return 1;
1873
+ if (input.hasExplicitRectCrop) return 1;
1874
+ if (!input.sourceWidth || !input.sourceHeight) return 1;
1875
+ const sourceAspect = input.sourceWidth / input.sourceHeight;
1876
+ if (!Number.isFinite(sourceAspect) || sourceAspect <= 0) return 1;
1877
+ return sourceAspect > input.targetAspectRatio ? sourceAspect / input.targetAspectRatio : 1;
1878
+ }
1879
+ function scaleSizesAttribute(sizes, factor) {
1880
+ const parts = splitSizesAttributeList(sizes).map((part) => part.trim()).filter(Boolean);
1881
+ if (parts.length === 0) return sizes;
1882
+ return parts.map((part) => {
1883
+ const parsed = parseLeadingMediaCondition(part);
1884
+ if (parsed) {
1885
+ const scaled2 = scaleCssLengthExpression(parsed.length, factor);
1886
+ return scaled2 ? `${parsed.media} ${scaled2}` : part;
1887
+ }
1888
+ const scaled = scaleCssLengthExpression(part, factor);
1889
+ return scaled ?? part;
1890
+ }).join(", ");
1891
+ }
1892
+ function splitSizesAttributeList(sizes) {
1893
+ const out = [];
1894
+ let depth = 0;
1895
+ let start = 0;
1896
+ for (let i = 0; i < sizes.length; i++) {
1897
+ const ch = sizes[i];
1898
+ if (ch === "(") depth++;
1899
+ else if (ch === ")") depth = Math.max(0, depth - 1);
1900
+ else if (ch === "," && depth === 0) {
1901
+ out.push(sizes.slice(start, i));
1902
+ start = i + 1;
1903
+ }
1904
+ }
1905
+ out.push(sizes.slice(start));
1906
+ return out;
1907
+ }
1908
+ function parseLeadingMediaCondition(part) {
1909
+ const trimmed = part.trim();
1910
+ if (!trimmed.startsWith("(")) return null;
1911
+ let depth = 0;
1912
+ for (let i = 0; i < trimmed.length; i++) {
1913
+ const ch = trimmed[i];
1914
+ if (ch === "(") depth++;
1915
+ else if (ch === ")") {
1916
+ depth--;
1917
+ if (depth === 0) {
1918
+ const media = trimmed.slice(0, i + 1).trim();
1919
+ const length = trimmed.slice(i + 1).trim();
1920
+ if (!length) return null;
1921
+ return { media, length };
1922
+ }
1923
+ }
1924
+ }
1925
+ return null;
1926
+ }
1927
+ function scaleCssLengthExpression(token, factor) {
1928
+ const simple = scaleCssLengthToken(token, factor);
1929
+ if (simple) return simple;
1930
+ if (!/\d/.test(token)) return null;
1931
+ let didReplace = false;
1932
+ const scaled = token.replace(/(-?\d+(?:\.\d+)?)([a-z%]+)/gi, (_full, rawNum, unit) => {
1933
+ const raw = Number(rawNum);
1934
+ if (!Number.isFinite(raw)) return _full;
1935
+ didReplace = true;
1936
+ const value = raw * factor;
1937
+ if (!Number.isFinite(value)) return _full;
1938
+ if (unit.toLowerCase() === "px") return `${Math.round(value)}px`;
1939
+ const rounded = Math.round(value * 100) / 100;
1940
+ return `${rounded}${unit}`;
1941
+ });
1942
+ return didReplace ? scaled : null;
1943
+ }
1944
+ function scaleCssLengthToken(token, factor) {
1945
+ const match = token.match(/^(-?\d+(?:\.\d+)?)([a-z%]+)$/i);
1946
+ if (!match) return null;
1947
+ const raw = Number(match[1]);
1948
+ const unit = match[2];
1949
+ if (!unit) return null;
1950
+ if (!Number.isFinite(raw)) return null;
1951
+ const scaled = raw * factor;
1952
+ if (!Number.isFinite(scaled)) return null;
1953
+ if (unit.toLowerCase() === "px") {
1954
+ return `${Math.round(scaled)}px`;
1955
+ }
1956
+ const rounded = Math.round(scaled * 100) / 100;
1957
+ return `${rounded}${unit}`;
1958
+ }
1959
+
1960
+ export { DEFAULT_BOOKING_TIME_ZONE, ImagePresets, MediaPlaceholder, addIntervalPreservingMonthAnchor, addLocalScheduleDays, asAppointmentResourceId, asAppointmentServiceId, asCustomerPassId, asFormId, asPassId, backgroundColorStyle, borderColorStyle, buildResolveImageUrlContext, clampConfiguredAmount, clsx_default, computeMediaTransformStyle, formatBookingDate, formatBookingDateParts, formatBookingDateTime, formatBookingInstant, formatBookingTime, formatLocalScheduleDate, getBookingInstalmentDepositRefundability, getBookingInstalmentPlanIntervalCount, getBookingLocalDateKey, getCurrentResolveImageUrlContext, mergeStyles, normalizeLocationAddressText, omitZeroAmountFutureRows, parseAspectRatioValue, parseBookingLocalDate, parseColorTokenParts, renderAudio, renderVideo, resolveBookingTimeZoneId, resolveFlexibleBalanceDueAt, resolveFlexibleBalanceInitialPaymentCents, resolveImageUrlWithContext, resolveMediaNodeResponsiveImage, resolvePlanningDateInput, rgbColorValue, setContextResolveImageUrlContext, splitAmountWithRemainderInFirst, textColorStyle, toBookingTimeZone, toLocationCoordinates, toScheduledBookingDateRange, toScheduledBookingDateTime };