@uptrademedia/site-kit 1.0.1 → 1.0.4

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/SetupWizard-Cki06kB0.d.mts +12 -0
  2. package/dist/SetupWizard-Cki06kB0.d.ts +12 -0
  3. package/dist/analytics/index.d.mts +87 -0
  4. package/dist/analytics/index.d.ts +87 -0
  5. package/dist/blog/index.d.mts +24 -0
  6. package/dist/blog/index.d.ts +24 -0
  7. package/dist/blog/index.js.map +1 -1
  8. package/dist/blog/index.mjs.map +1 -1
  9. package/dist/chunk-2IHTEKHU.mjs +332 -0
  10. package/dist/chunk-2IHTEKHU.mjs.map +1 -0
  11. package/dist/chunk-5R4R3WDP.js +1451 -0
  12. package/dist/chunk-5R4R3WDP.js.map +1 -0
  13. package/dist/{chunk-RV7H3I6J.js → chunk-ADHVEFWD.js} +68 -2
  14. package/dist/chunk-ADHVEFWD.js.map +1 -0
  15. package/dist/chunk-BGJLOJ7T.mjs +605 -0
  16. package/dist/chunk-BGJLOJ7T.mjs.map +1 -0
  17. package/dist/chunk-BZBJVG5Y.js +88 -0
  18. package/dist/chunk-BZBJVG5Y.js.map +1 -0
  19. package/dist/{chunk-COI6GOX2.mjs → chunk-DOHML47I.mjs} +3 -3
  20. package/dist/chunk-DOHML47I.mjs.map +1 -0
  21. package/dist/chunk-DRFTRTKV.js +809 -0
  22. package/dist/chunk-DRFTRTKV.js.map +1 -0
  23. package/dist/chunk-EL5QTAA3.mjs +805 -0
  24. package/dist/chunk-EL5QTAA3.mjs.map +1 -0
  25. package/dist/chunk-GAJLEDRD.js +334 -0
  26. package/dist/chunk-GAJLEDRD.js.map +1 -0
  27. package/dist/{chunk-3MUOUXHV.js → chunk-K2HWVOEO.js} +3 -3
  28. package/dist/chunk-K2HWVOEO.js.map +1 -0
  29. package/dist/chunk-O2OHHBUD.js +997 -0
  30. package/dist/chunk-O2OHHBUD.js.map +1 -0
  31. package/dist/chunk-QAYJV4KK.js +608 -0
  32. package/dist/chunk-QAYJV4KK.js.map +1 -0
  33. package/dist/{chunk-FEBYQGY4 2.mjs → chunk-SMUFNQLM.mjs} +67 -3
  34. package/dist/chunk-SMUFNQLM.mjs.map +1 -0
  35. package/dist/chunk-VDMZZL2O.mjs +83 -0
  36. package/dist/chunk-VDMZZL2O.mjs.map +1 -0
  37. package/dist/chunk-XFRPT5ZX.mjs +1449 -0
  38. package/dist/chunk-XFRPT5ZX.mjs.map +1 -0
  39. package/dist/chunk-XQJX252G.mjs +981 -0
  40. package/dist/chunk-XQJX252G.mjs.map +1 -0
  41. package/dist/commerce/index.d.mts +168 -0
  42. package/dist/commerce/index.d.ts +168 -0
  43. package/dist/commerce/index.js +38 -38
  44. package/dist/commerce/index.mjs +1 -1
  45. package/dist/commerce/server.d.mts +98 -0
  46. package/dist/commerce/server.d.ts +98 -0
  47. package/dist/engage/index.d.mts +27 -0
  48. package/dist/engage/index.d.ts +27 -0
  49. package/dist/engage/index.js +7 -40
  50. package/dist/engage/index.js.map +1 -1
  51. package/dist/engage/index.mjs +1 -41
  52. package/dist/engage/index.mjs.map +1 -1
  53. package/dist/forms/index.d.mts +437 -0
  54. package/dist/forms/index.d.ts +437 -0
  55. package/dist/forms/index.js +13 -5
  56. package/dist/forms/index.js.map +1 -1
  57. package/dist/forms/index.mjs +2 -2
  58. package/dist/forms/index.mjs.map +1 -1
  59. package/dist/{generators-7Y5ABRYV 2.mjs → generators-TO2FKJR6.mjs} +134 -3
  60. package/dist/generators-TO2FKJR6.mjs.map +1 -0
  61. package/dist/{generators-GWIYCA5M.js → generators-YZWIGHCO.js} +135 -2
  62. package/dist/generators-YZWIGHCO.js.map +1 -0
  63. package/dist/images/index.d.mts +133 -0
  64. package/dist/images/index.d.ts +133 -0
  65. package/dist/images/index.js +41 -0
  66. package/dist/images/index.js.map +1 -0
  67. package/dist/images/index.mjs +8 -0
  68. package/dist/images/index.mjs.map +1 -0
  69. package/dist/index.d.mts +649 -0
  70. package/dist/index.d.ts +649 -0
  71. package/dist/index.js +1355 -104
  72. package/dist/index.js.map +1 -1
  73. package/dist/index.mjs +1242 -76
  74. package/dist/index.mjs.map +1 -1
  75. package/dist/redirects/index.d.mts +72 -0
  76. package/dist/redirects/index.d.ts +72 -0
  77. package/dist/redirects/index.js +25 -0
  78. package/dist/redirects/index.js.map +1 -0
  79. package/dist/redirects/index.mjs +4 -0
  80. package/dist/redirects/index.mjs.map +1 -0
  81. package/dist/routing-BWjUF7lp.d.ts +105 -0
  82. package/dist/routing-CgmRi9tD.d.mts +105 -0
  83. package/dist/{scanner-MF7P3CDE 2.mjs → scanner-AZV5I6US.mjs} +123 -4
  84. package/dist/scanner-AZV5I6US.mjs.map +1 -0
  85. package/dist/{scanner-NT6YG4TD 2.js → scanner-ETJAMIT7.js} +124 -3
  86. package/dist/scanner-ETJAMIT7.js.map +1 -0
  87. package/dist/seo/index.d.mts +273 -0
  88. package/dist/seo/index.d.ts +273 -0
  89. package/dist/seo/server.d.mts +89 -0
  90. package/dist/seo/server.d.ts +89 -0
  91. package/dist/setup/client.d.mts +60 -0
  92. package/dist/setup/client.d.ts +60 -0
  93. package/dist/setup/client.js +30 -0
  94. package/dist/setup/client.js.map +1 -0
  95. package/dist/setup/client.mjs +5 -0
  96. package/dist/setup/client.mjs.map +1 -0
  97. package/dist/setup/index.d.mts +5 -0
  98. package/dist/setup/index.d.ts +5 -0
  99. package/dist/setup/index.js +28 -1043
  100. package/dist/setup/index.js.map +1 -1
  101. package/dist/setup/index.mjs +3 -1043
  102. package/dist/setup/index.mjs.map +1 -1
  103. package/dist/setup/server.d.mts +14 -0
  104. package/dist/setup/server.d.ts +14 -0
  105. package/dist/setup/server.js +13 -0
  106. package/dist/setup/server.js.map +1 -0
  107. package/dist/setup/server.mjs +4 -0
  108. package/dist/setup/server.mjs.map +1 -0
  109. package/dist/sitemap/index.d.mts +78 -0
  110. package/dist/sitemap/index.d.ts +78 -0
  111. package/dist/types-BDojCvvL.d.mts +156 -0
  112. package/dist/types-BDojCvvL.d.ts +156 -0
  113. package/dist/types-BmzutFwy.d.mts +227 -0
  114. package/dist/types-BmzutFwy.d.ts +227 -0
  115. package/dist/types-C0pJGfbH.d.mts +155 -0
  116. package/dist/types-C0pJGfbH.d.ts +155 -0
  117. package/dist/types-DA_Kocle.d.mts +127 -0
  118. package/dist/types-DA_Kocle.d.ts +127 -0
  119. package/dist/types-lFLKKn0G.d.mts +163 -0
  120. package/dist/types-lFLKKn0G.d.ts +163 -0
  121. package/dist/types-nB206tPK.d.mts +309 -0
  122. package/dist/types-nB206tPK.d.ts +309 -0
  123. package/dist/useEventModal-6U1pF3_g.d.mts +209 -0
  124. package/dist/useEventModal-BA8g-1-P.d.ts +209 -0
  125. package/package.json +21 -1
  126. package/dist/chunk-3MUOUXHV.js.map +0 -1
  127. package/dist/chunk-4HVYXYQL 2.mjs +0 -255
  128. package/dist/chunk-4HVYXYQL.mjs +0 -255
  129. package/dist/chunk-4HVYXYQL.mjs.map +0 -1
  130. package/dist/chunk-COI6GOX2.mjs.map +0 -1
  131. package/dist/chunk-EQCVQC35.js 2.map +0 -1
  132. package/dist/chunk-FEBYQGY4.mjs +0 -251
  133. package/dist/chunk-FEBYQGY4.mjs.map +0 -1
  134. package/dist/chunk-NYKRE2FL 2.mjs +0 -31
  135. package/dist/chunk-NYKRE2FL.mjs 2.map +0 -1
  136. package/dist/chunk-RV7H3I6J.js 2.map +0 -1
  137. package/dist/chunk-RV7H3I6J.js.map +0 -1
  138. package/dist/chunk-TUKGA3UK.js +0 -257
  139. package/dist/chunk-TUKGA3UK.js 2.map +0 -1
  140. package/dist/chunk-TUKGA3UK.js.map +0 -1
  141. package/dist/generators-7Y5ABRYV.mjs +0 -161
  142. package/dist/generators-7Y5ABRYV.mjs 2.map +0 -1
  143. package/dist/generators-7Y5ABRYV.mjs.map +0 -1
  144. package/dist/generators-GWIYCA5M.js 2.map +0 -1
  145. package/dist/generators-GWIYCA5M.js.map +0 -1
  146. package/dist/index 2.mjs +0 -74
  147. package/dist/index.js 2.map +0 -1
  148. package/dist/migrator-V6KS75EA 2.mjs +0 -265
  149. package/dist/migrator-V6KS75EA.mjs 2.map +0 -1
  150. package/dist/migrator-XKM7YQCY.js 2.map +0 -1
  151. package/dist/scanner-MF7P3CDE.mjs +0 -14386
  152. package/dist/scanner-MF7P3CDE.mjs 2.map +0 -1
  153. package/dist/scanner-MF7P3CDE.mjs.map +0 -1
  154. package/dist/scanner-NT6YG4TD.js +0 -14397
  155. package/dist/scanner-NT6YG4TD.js 2.map +0 -1
  156. package/dist/scanner-NT6YG4TD.js.map +0 -1
  157. package/dist/web-vitals-BH55V7EJ.js 2.map +0 -1
  158. package/dist/web-vitals-RJYPWAR3 2.mjs +0 -241
  159. package/dist/web-vitals-RJYPWAR3.mjs 2.map +0 -1
@@ -0,0 +1,981 @@
1
+ import { SitemapSync } from './chunk-WPSRS352.mjs';
2
+ import { AnalyticsProvider } from './chunk-FKVJOT2F.mjs';
3
+ import { EngageWidget } from './chunk-BGJLOJ7T.mjs';
4
+ import { configureFormsApi } from './chunk-SMUFNQLM.mjs';
5
+ import { createContext, useContext, useState, useRef, useCallback, useEffect, useMemo, Suspense } from 'react';
6
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
7
+
8
+ var SignalContext = createContext(null);
9
+ function useSignal() {
10
+ const context = useContext(SignalContext);
11
+ if (!context) {
12
+ throw new Error("useSignal must be used within a SignalBridge");
13
+ }
14
+ return context;
15
+ }
16
+ function getApiConfig() {
17
+ const apiUrl = typeof window !== "undefined" ? window.__SITE_KIT_API_URL__ || "https://api.uptrademedia.com" : "https://api.uptrademedia.com";
18
+ const apiKey = typeof window !== "undefined" ? window.__SITE_KIT_API_KEY__ : void 0;
19
+ return { apiUrl, apiKey };
20
+ }
21
+ function getVisitorId() {
22
+ if (typeof window === "undefined") return "";
23
+ const key = "_uptrade_vid";
24
+ let visitorId = localStorage.getItem(key);
25
+ if (!visitorId) {
26
+ visitorId = crypto.randomUUID();
27
+ localStorage.setItem(key, visitorId);
28
+ }
29
+ return visitorId;
30
+ }
31
+ function getSessionId() {
32
+ if (typeof window === "undefined") return "";
33
+ const key = "_uptrade_sid";
34
+ let sessionId = sessionStorage.getItem(key);
35
+ if (!sessionId) {
36
+ sessionId = crypto.randomUUID();
37
+ sessionStorage.setItem(key, sessionId);
38
+ }
39
+ return sessionId;
40
+ }
41
+ function getDeviceType() {
42
+ if (typeof window === "undefined") return "desktop";
43
+ const ua = navigator.userAgent;
44
+ if (/tablet|ipad|playbook|silk/i.test(ua)) return "tablet";
45
+ if (/mobile|iphone|ipod|android|blackberry|opera mini|iemobile/i.test(ua)) return "mobile";
46
+ return "desktop";
47
+ }
48
+ function getBrowser() {
49
+ if (typeof window === "undefined") return "unknown";
50
+ const ua = navigator.userAgent;
51
+ if (ua.includes("Firefox")) return "Firefox";
52
+ if (ua.includes("Edg")) return "Edge";
53
+ if (ua.includes("Chrome")) return "Chrome";
54
+ if (ua.includes("Safari")) return "Safari";
55
+ return "Other";
56
+ }
57
+ function getOS() {
58
+ if (typeof window === "undefined") return "unknown";
59
+ const ua = navigator.userAgent;
60
+ if (ua.includes("Windows")) return "Windows";
61
+ if (ua.includes("Mac")) return "macOS";
62
+ if (ua.includes("iPhone") || ua.includes("iPad")) return "iOS";
63
+ if (ua.includes("Android")) return "Android";
64
+ if (ua.includes("Linux")) return "Linux";
65
+ return "Other";
66
+ }
67
+ function SignalBridge({
68
+ enabled = true,
69
+ realtime = true,
70
+ experiments = true,
71
+ behaviorTracking = true,
72
+ children
73
+ }) {
74
+ const [config, setConfig] = useState(null);
75
+ const [loading, setLoading] = useState(true);
76
+ const [error, setError] = useState(null);
77
+ const eventSourceRef = useRef(null);
78
+ const eventQueueRef = useRef([]);
79
+ const flushTimeoutRef = useRef(null);
80
+ const assignmentsRef = useRef(/* @__PURE__ */ new Map());
81
+ const pageLoadTimeRef = useRef(Date.now());
82
+ const scrollDepthRef = useRef(0);
83
+ const clickCountRef = useRef(0);
84
+ const { apiUrl, apiKey } = getApiConfig();
85
+ const fetchConfig = useCallback(async () => {
86
+ if (!apiKey || !enabled) {
87
+ setLoading(false);
88
+ return;
89
+ }
90
+ try {
91
+ const response = await fetch(`${apiUrl}/api/public/signal/config`, {
92
+ headers: {
93
+ "x-api-key": apiKey,
94
+ "x-visitor-id": getVisitorId()
95
+ }
96
+ });
97
+ if (!response.ok) {
98
+ throw new Error(`Failed to fetch Signal config: ${response.statusText}`);
99
+ }
100
+ const data = await response.json();
101
+ setConfig(data.config);
102
+ setError(null);
103
+ if (experiments && data.config?.experiments) {
104
+ for (const exp of data.config.experiments) {
105
+ if (exp.status === "running") {
106
+ await loadExperimentAssignment(exp.id);
107
+ }
108
+ }
109
+ }
110
+ } catch (err) {
111
+ console.error("[Signal] Config fetch error:", err);
112
+ setError(err);
113
+ } finally {
114
+ setLoading(false);
115
+ }
116
+ }, [apiUrl, apiKey, enabled, experiments]);
117
+ const connectSSE = useCallback(() => {
118
+ if (!apiKey || !enabled || !realtime) return;
119
+ if (eventSourceRef.current) {
120
+ eventSourceRef.current.close();
121
+ }
122
+ const url = `${apiUrl}/api/public/signal/stream?key=${apiKey}`;
123
+ const eventSource = new EventSource(url);
124
+ eventSource.addEventListener("config_update", (e) => {
125
+ try {
126
+ const { config: newConfig, version } = JSON.parse(e.data);
127
+ setConfig((prev) => {
128
+ if (prev?.version !== version) {
129
+ console.log("[Signal] Config updated to version:", version);
130
+ return newConfig;
131
+ }
132
+ return prev;
133
+ });
134
+ } catch (err) {
135
+ console.error("[Signal] SSE parse error:", err);
136
+ }
137
+ });
138
+ eventSource.addEventListener("experiment_update", (e) => {
139
+ try {
140
+ const { experiment_id, action } = JSON.parse(e.data);
141
+ if (action === "started" || action === "updated") {
142
+ loadExperimentAssignment(experiment_id);
143
+ } else if (action === "stopped") {
144
+ assignmentsRef.current.delete(experiment_id);
145
+ }
146
+ } catch (err) {
147
+ console.error("[Signal] Experiment update error:", err);
148
+ }
149
+ });
150
+ eventSource.onerror = () => {
151
+ console.warn("[Signal] SSE connection error, reconnecting...");
152
+ eventSource.close();
153
+ setTimeout(connectSSE, 5e3);
154
+ };
155
+ eventSourceRef.current = eventSource;
156
+ }, [apiUrl, apiKey, enabled, realtime]);
157
+ const loadExperimentAssignment = useCallback(async (experimentId) => {
158
+ const storageKey = `_signal_exp_${experimentId}`;
159
+ const stored = localStorage.getItem(storageKey);
160
+ if (stored) {
161
+ try {
162
+ const assignment = JSON.parse(stored);
163
+ if (assignment.expires > Date.now()) {
164
+ assignmentsRef.current.set(experimentId, assignment);
165
+ return assignment;
166
+ }
167
+ } catch {
168
+ }
169
+ }
170
+ try {
171
+ const response = await fetch(`${apiUrl}/api/public/signal/experiment/${experimentId}`, {
172
+ headers: {
173
+ "x-api-key": apiKey,
174
+ "x-visitor-id": getVisitorId()
175
+ }
176
+ });
177
+ if (!response.ok) return null;
178
+ const assignment = await response.json();
179
+ localStorage.setItem(storageKey, JSON.stringify(assignment));
180
+ assignmentsRef.current.set(experimentId, assignment);
181
+ return assignment;
182
+ } catch (err) {
183
+ console.error("[Signal] Experiment assignment error:", err);
184
+ return null;
185
+ }
186
+ }, [apiUrl, apiKey]);
187
+ const getExperiment = useCallback((experimentId) => {
188
+ return assignmentsRef.current.get(experimentId) || null;
189
+ }, []);
190
+ const flushEvents = useCallback(async () => {
191
+ if (eventQueueRef.current.length === 0) return;
192
+ const events = [...eventQueueRef.current];
193
+ eventQueueRef.current = [];
194
+ try {
195
+ await fetch(`${apiUrl}/api/public/signal/events`, {
196
+ method: "POST",
197
+ headers: {
198
+ "Content-Type": "application/json",
199
+ "x-api-key": apiKey
200
+ },
201
+ body: JSON.stringify({
202
+ visitor_id: getVisitorId(),
203
+ session_id: getSessionId(),
204
+ events
205
+ })
206
+ });
207
+ } catch (err) {
208
+ eventQueueRef.current = [...events, ...eventQueueRef.current];
209
+ console.error("[Signal] Event flush error:", err);
210
+ }
211
+ }, [apiUrl, apiKey]);
212
+ const trackEvent = useCallback((event) => {
213
+ if (!enabled || !apiKey) return;
214
+ const enrichedEvent = {
215
+ ...event,
216
+ page_url: window.location.href,
217
+ page_path: window.location.pathname,
218
+ referrer: document.referrer,
219
+ device_type: getDeviceType(),
220
+ browser: getBrowser(),
221
+ os: getOS(),
222
+ viewport_width: window.innerWidth,
223
+ viewport_height: window.innerHeight,
224
+ time_on_page: Date.now() - pageLoadTimeRef.current,
225
+ scroll_depth: scrollDepthRef.current,
226
+ click_count: clickCountRef.current,
227
+ experiments: Array.from(assignmentsRef.current.values()).map((a) => ({
228
+ experiment_id: a.experiment_id,
229
+ variant_key: a.variant_key
230
+ })),
231
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
232
+ };
233
+ eventQueueRef.current.push(enrichedEvent);
234
+ if (flushTimeoutRef.current) {
235
+ clearTimeout(flushTimeoutRef.current);
236
+ }
237
+ flushTimeoutRef.current = setTimeout(flushEvents, 1e3);
238
+ }, [enabled, apiKey, flushEvents]);
239
+ const trackOutcome = useCallback(async (outcome) => {
240
+ if (!enabled || !apiKey) return;
241
+ try {
242
+ await fetch(`${apiUrl}/api/public/signal/outcome`, {
243
+ method: "POST",
244
+ headers: {
245
+ "Content-Type": "application/json",
246
+ "x-api-key": apiKey
247
+ },
248
+ body: JSON.stringify({
249
+ ...outcome,
250
+ visitor_id: getVisitorId(),
251
+ session_id: getSessionId(),
252
+ experiments: Array.from(assignmentsRef.current.keys()),
253
+ page_url: window.location.href,
254
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
255
+ })
256
+ });
257
+ } catch (err) {
258
+ console.error("[Signal] Outcome tracking error:", err);
259
+ }
260
+ }, [apiUrl, apiKey, enabled]);
261
+ useEffect(() => {
262
+ if (!behaviorTracking || typeof window === "undefined") return;
263
+ const handleScroll = () => {
264
+ const scrollTop = window.scrollY;
265
+ const docHeight = document.documentElement.scrollHeight - window.innerHeight;
266
+ const depth = docHeight > 0 ? Math.round(scrollTop / docHeight * 100) : 0;
267
+ scrollDepthRef.current = Math.max(scrollDepthRef.current, depth);
268
+ };
269
+ const handleClick = () => {
270
+ clickCountRef.current++;
271
+ };
272
+ window.addEventListener("scroll", handleScroll, { passive: true });
273
+ window.addEventListener("click", handleClick);
274
+ const handleVisibilityChange = () => {
275
+ if (document.visibilityState === "hidden") {
276
+ flushEvents();
277
+ }
278
+ };
279
+ document.addEventListener("visibilitychange", handleVisibilityChange);
280
+ window.addEventListener("beforeunload", flushEvents);
281
+ return () => {
282
+ window.removeEventListener("scroll", handleScroll);
283
+ window.removeEventListener("click", handleClick);
284
+ document.removeEventListener("visibilitychange", handleVisibilityChange);
285
+ window.removeEventListener("beforeunload", flushEvents);
286
+ };
287
+ }, [behaviorTracking, flushEvents]);
288
+ useEffect(() => {
289
+ fetchConfig();
290
+ }, [fetchConfig]);
291
+ useEffect(() => {
292
+ if (config && realtime) {
293
+ connectSSE();
294
+ }
295
+ return () => {
296
+ if (eventSourceRef.current) {
297
+ eventSourceRef.current.close();
298
+ }
299
+ };
300
+ }, [config, realtime, connectSSE]);
301
+ const contextValue = useMemo(() => ({
302
+ config,
303
+ loading,
304
+ error,
305
+ trackEvent,
306
+ trackOutcome,
307
+ getExperiment,
308
+ refreshConfig: fetchConfig
309
+ }), [config, loading, error, trackEvent, trackOutcome, getExperiment, fetchConfig]);
310
+ return /* @__PURE__ */ jsx(SignalContext.Provider, { value: contextValue, children });
311
+ }
312
+ function useSignalConfig() {
313
+ const { config } = useSignal();
314
+ return config;
315
+ }
316
+ function useSignalEvent() {
317
+ const { trackEvent } = useSignal();
318
+ return trackEvent;
319
+ }
320
+ function useSignalOutcome() {
321
+ const { trackOutcome } = useSignal();
322
+ return { trackOutcome };
323
+ }
324
+ function useSignalExperiment(experimentId) {
325
+ const { getExperiment, config } = useSignal();
326
+ const assignment = getExperiment(experimentId);
327
+ const experiment = config?.experiments?.find((e) => e.id === experimentId);
328
+ const isRunning = experiment?.status === "running";
329
+ return {
330
+ assignment: isRunning ? assignment : null,
331
+ variant: isRunning && assignment ? assignment.variant_key : null,
332
+ isControl: !assignment || assignment.variant_key === "control"
333
+ };
334
+ }
335
+ var SiteKitContext = createContext(null);
336
+ function useSiteKit() {
337
+ const context = useContext(SiteKitContext);
338
+ if (!context) {
339
+ throw new Error("useSiteKit must be used within a SiteKitProvider");
340
+ }
341
+ return context;
342
+ }
343
+ function SiteKitProvider({
344
+ children,
345
+ apiUrl = "https://api.uptrademedia.com",
346
+ signalUrl = "https://signal.uptrademedia.com",
347
+ apiKey,
348
+ analytics,
349
+ engage,
350
+ forms,
351
+ signal,
352
+ debug = false
353
+ }) {
354
+ useEffect(() => {
355
+ if (typeof window !== "undefined") {
356
+ window.__SITE_KIT_API_URL__ = apiUrl;
357
+ window.__SITE_KIT_SIGNAL_URL__ = signalUrl;
358
+ window.__SITE_KIT_API_KEY__ = apiKey;
359
+ window.__SITE_KIT_DEBUG__ = debug;
360
+ }
361
+ configureFormsApi({
362
+ baseUrl: apiUrl,
363
+ apiKey
364
+ });
365
+ }, [apiUrl, signalUrl, apiKey, debug]);
366
+ const contextValue = useMemo(
367
+ () => ({
368
+ apiUrl,
369
+ signalUrl,
370
+ apiKey,
371
+ analytics,
372
+ engage,
373
+ forms,
374
+ signal,
375
+ debug,
376
+ isReady: true
377
+ }),
378
+ [apiUrl, signalUrl, apiKey, analytics, engage, forms, signal, debug]
379
+ );
380
+ let content = /* @__PURE__ */ jsx(Fragment, { children });
381
+ if (signal?.enabled) {
382
+ content = /* @__PURE__ */ jsx(
383
+ SignalBridge,
384
+ {
385
+ enabled: signal.enabled,
386
+ realtime: signal.realtime !== false,
387
+ experiments: signal.experiments !== false,
388
+ behaviorTracking: signal.behaviorTracking !== false,
389
+ children: content
390
+ }
391
+ );
392
+ }
393
+ if (analytics?.enabled) {
394
+ content = /* @__PURE__ */ jsx(Suspense, { fallback: null, children: /* @__PURE__ */ jsx(
395
+ AnalyticsProvider,
396
+ {
397
+ apiUrl,
398
+ apiKey,
399
+ trackPageViews: analytics.trackPageViews !== false,
400
+ trackWebVitals: analytics.trackWebVitals !== false,
401
+ trackScrollDepth: analytics.trackScrollDepth !== false,
402
+ trackClicks: analytics.trackClicks !== false,
403
+ debug,
404
+ children: content
405
+ }
406
+ ) });
407
+ }
408
+ if (engage?.enabled) {
409
+ content = /* @__PURE__ */ jsxs(Fragment, { children: [
410
+ content,
411
+ /* @__PURE__ */ jsx(
412
+ EngageWidget,
413
+ {
414
+ apiUrl,
415
+ apiKey,
416
+ position: engage.position || "bottom-right",
417
+ chatEnabled: engage.chatEnabled !== false
418
+ }
419
+ )
420
+ ] });
421
+ }
422
+ content = /* @__PURE__ */ jsxs(Fragment, { children: [
423
+ content,
424
+ /* @__PURE__ */ jsx(SitemapSync, { debug })
425
+ ] });
426
+ return /* @__PURE__ */ jsx(SiteKitContext.Provider, { value: contextValue, children: content });
427
+ }
428
+ var isDevMode = () => {
429
+ if (typeof window === "undefined") return false;
430
+ return process.env.NODE_ENV === "development" || window.location.hostname === "localhost" || window.location.hostname === "127.0.0.1" || window.location.search.includes("uptrade_dev=true");
431
+ };
432
+ function ManagedImage({
433
+ slotId,
434
+ pagePath,
435
+ alt,
436
+ className = "",
437
+ width,
438
+ height,
439
+ objectFit = "cover",
440
+ fallback,
441
+ placeholder,
442
+ onLoad,
443
+ onError,
444
+ priority,
445
+ style,
446
+ forceDevMode
447
+ }) {
448
+ const context = useSiteKit();
449
+ const [imageData, setImageData] = useState(null);
450
+ const [loading, setLoading] = useState(true);
451
+ const [error, setError] = useState(null);
452
+ const [showPicker, setShowPicker] = useState(false);
453
+ const [devMode] = useState(() => forceDevMode || isDevMode());
454
+ const currentPath = pagePath ?? (typeof window !== "undefined" ? window.location.pathname : "/");
455
+ const fetchImage = useCallback(async () => {
456
+ if (!context?.apiKey || !context?.apiUrl) {
457
+ setLoading(false);
458
+ return;
459
+ }
460
+ try {
461
+ const params = new URLSearchParams({ page_path: currentPath });
462
+ const res = await fetch(
463
+ `${context.apiUrl}/public/images/slot/${encodeURIComponent(slotId)}?${params}`,
464
+ {
465
+ headers: {
466
+ "Content-Type": "application/json",
467
+ "x-api-key": context.apiKey
468
+ }
469
+ }
470
+ );
471
+ if (!res.ok) {
472
+ throw new Error(`Failed to fetch image: ${res.status}`);
473
+ }
474
+ const data = await res.json();
475
+ setImageData(data.image);
476
+ setError(null);
477
+ } catch (err) {
478
+ console.error("[ManagedImage] Fetch error:", err);
479
+ setError(err instanceof Error ? err : new Error(String(err)));
480
+ onError?.(err instanceof Error ? err : new Error(String(err)));
481
+ } finally {
482
+ setLoading(false);
483
+ }
484
+ }, [context?.apiKey, context?.apiUrl, slotId, currentPath, onError]);
485
+ useEffect(() => {
486
+ fetchImage();
487
+ }, [fetchImage]);
488
+ const objectPosition = imageData ? `${imageData.focal_point_x}% ${imageData.focal_point_y}%` : "50% 50%";
489
+ const imageUrl = imageData?.public_url || imageData?.external_url || fallback;
490
+ const handleClick = (e) => {
491
+ if (devMode) {
492
+ e.preventDefault();
493
+ e.stopPropagation();
494
+ setShowPicker(true);
495
+ }
496
+ };
497
+ if (loading) {
498
+ return /* @__PURE__ */ jsx(
499
+ "div",
500
+ {
501
+ className: `bg-gray-200 animate-pulse ${className}`,
502
+ style: {
503
+ width: width ?? "100%",
504
+ height: height ?? 200,
505
+ ...style
506
+ }
507
+ }
508
+ );
509
+ }
510
+ if (!imageUrl) {
511
+ if (placeholder) {
512
+ return /* @__PURE__ */ jsx(Fragment, { children: placeholder });
513
+ }
514
+ return /* @__PURE__ */ jsxs(
515
+ "div",
516
+ {
517
+ onClick: handleClick,
518
+ className: `
519
+ bg-gray-100 border-2 border-dashed border-gray-300
520
+ flex items-center justify-center text-gray-400
521
+ ${devMode ? "cursor-pointer hover:border-blue-400 hover:text-blue-500 hover:bg-blue-50" : ""}
522
+ ${className}
523
+ `,
524
+ style: {
525
+ width: width ?? "100%",
526
+ height: height ?? 200,
527
+ ...style
528
+ },
529
+ title: devMode ? `Click to add image for slot: ${slotId}` : void 0,
530
+ children: [
531
+ /* @__PURE__ */ jsxs("div", { className: "text-center p-4", children: [
532
+ /* @__PURE__ */ jsx(
533
+ "svg",
534
+ {
535
+ className: "w-12 h-12 mx-auto mb-2",
536
+ fill: "none",
537
+ stroke: "currentColor",
538
+ viewBox: "0 0 24 24",
539
+ children: /* @__PURE__ */ jsx(
540
+ "path",
541
+ {
542
+ strokeLinecap: "round",
543
+ strokeLinejoin: "round",
544
+ strokeWidth: 1.5,
545
+ d: "M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z"
546
+ }
547
+ )
548
+ }
549
+ ),
550
+ devMode && /* @__PURE__ */ jsx("p", { className: "text-sm font-medium", children: "Click to add image" }),
551
+ /* @__PURE__ */ jsx("p", { className: "text-xs mt-1", children: slotId })
552
+ ] }),
553
+ showPicker && /* @__PURE__ */ jsx(
554
+ ImagePickerModal,
555
+ {
556
+ slotId,
557
+ pagePath: currentPath,
558
+ config: context,
559
+ onClose: () => setShowPicker(false),
560
+ onSelect: () => {
561
+ setShowPicker(false);
562
+ fetchImage();
563
+ }
564
+ }
565
+ )
566
+ ]
567
+ }
568
+ );
569
+ }
570
+ return /* @__PURE__ */ jsxs("div", { className: "relative", style: { width, height }, children: [
571
+ /* @__PURE__ */ jsx(
572
+ "img",
573
+ {
574
+ src: imageUrl,
575
+ alt: imageData?.alt_text || alt || "",
576
+ title: imageData?.title || void 0,
577
+ className,
578
+ style: {
579
+ objectFit,
580
+ objectPosition,
581
+ width: width ?? "100%",
582
+ height: height ?? "auto",
583
+ ...style
584
+ },
585
+ onLoad,
586
+ onError: () => onError?.(new Error("Image failed to load")),
587
+ loading: priority ? "eager" : "lazy",
588
+ onClick: handleClick
589
+ }
590
+ ),
591
+ devMode && /* @__PURE__ */ jsx(
592
+ "div",
593
+ {
594
+ className: "absolute inset-0 bg-black/0 hover:bg-black/30 transition-colors cursor-pointer flex items-center justify-center opacity-0 hover:opacity-100",
595
+ onClick: handleClick,
596
+ children: /* @__PURE__ */ jsx("div", { className: "bg-white/90 px-3 py-1.5 rounded-lg shadow-lg text-sm font-medium text-gray-700", children: "Edit Image" })
597
+ }
598
+ ),
599
+ showPicker && /* @__PURE__ */ jsx(
600
+ ImagePickerModal,
601
+ {
602
+ slotId,
603
+ pagePath: currentPath,
604
+ config: context,
605
+ currentImage: imageData,
606
+ onClose: () => setShowPicker(false),
607
+ onSelect: () => {
608
+ setShowPicker(false);
609
+ fetchImage();
610
+ }
611
+ }
612
+ )
613
+ ] });
614
+ }
615
+ function ImagePickerModal({
616
+ slotId,
617
+ pagePath,
618
+ config,
619
+ currentImage,
620
+ onClose,
621
+ onSelect
622
+ }) {
623
+ const [files, setFiles] = useState([]);
624
+ const [folders, setFolders] = useState([]);
625
+ const [currentFolder, setCurrentFolder] = useState("");
626
+ const [search, setSearch] = useState("");
627
+ const [loading, setLoading] = useState(true);
628
+ const [uploading, setUploading] = useState(false);
629
+ const [altText, setAltText] = useState(currentImage?.alt_text || "");
630
+ const fetchFiles = useCallback(async () => {
631
+ if (!config?.apiKey || !config?.apiUrl) return;
632
+ setLoading(true);
633
+ try {
634
+ const params = new URLSearchParams();
635
+ if (currentFolder) params.set("folder", currentFolder);
636
+ if (search) params.set("search", search);
637
+ const res = await fetch(
638
+ `${config.apiUrl}/public/images/files?${params}`,
639
+ {
640
+ headers: {
641
+ "Content-Type": "application/json",
642
+ "x-api-key": config.apiKey
643
+ }
644
+ }
645
+ );
646
+ if (res.ok) {
647
+ const data = await res.json();
648
+ setFiles(data.files || []);
649
+ setFolders(data.folders || []);
650
+ }
651
+ } catch (err) {
652
+ console.error("[ImagePicker] Fetch error:", err);
653
+ } finally {
654
+ setLoading(false);
655
+ }
656
+ }, [config?.apiKey, config?.apiUrl, currentFolder, search]);
657
+ useEffect(() => {
658
+ fetchFiles();
659
+ }, [fetchFiles]);
660
+ const handleSelectFile = async (file) => {
661
+ if (!config?.apiKey || !config?.apiUrl) return;
662
+ try {
663
+ const res = await fetch(
664
+ `${config.apiUrl}/public/images/slot/${encodeURIComponent(slotId)}`,
665
+ {
666
+ method: "POST",
667
+ headers: {
668
+ "Content-Type": "application/json",
669
+ "x-api-key": config.apiKey
670
+ },
671
+ body: JSON.stringify({
672
+ page_path: pagePath,
673
+ file_id: file.id,
674
+ alt_text: altText || file.filename
675
+ })
676
+ }
677
+ );
678
+ if (res.ok) {
679
+ onSelect();
680
+ }
681
+ } catch (err) {
682
+ console.error("[ImagePicker] Select error:", err);
683
+ }
684
+ };
685
+ const handleUpload = async (e) => {
686
+ const file = e.target.files?.[0];
687
+ if (!file || !config?.apiKey || !config?.apiUrl) return;
688
+ setUploading(true);
689
+ try {
690
+ const formData = new FormData();
691
+ formData.append("file", file);
692
+ formData.append("slot_id", slotId);
693
+ formData.append("page_path", pagePath);
694
+ formData.append("folder", currentFolder || "Website/Images");
695
+ if (altText) formData.append("alt_text", altText);
696
+ const res = await fetch(`${config.apiUrl}/public/images/upload`, {
697
+ method: "POST",
698
+ headers: {
699
+ "x-api-key": config.apiKey
700
+ },
701
+ body: formData
702
+ });
703
+ if (res.ok) {
704
+ onSelect();
705
+ }
706
+ } catch (err) {
707
+ console.error("[ImagePicker] Upload error:", err);
708
+ } finally {
709
+ setUploading(false);
710
+ }
711
+ };
712
+ const handleClear = async () => {
713
+ if (!config?.apiKey || !config?.apiUrl) return;
714
+ try {
715
+ const params = new URLSearchParams({ page_path: pagePath });
716
+ await fetch(
717
+ `${config.apiUrl}/public/images/slot/${encodeURIComponent(slotId)}?${params}`,
718
+ {
719
+ method: "DELETE",
720
+ headers: {
721
+ "x-api-key": config.apiKey
722
+ }
723
+ }
724
+ );
725
+ onSelect();
726
+ } catch (err) {
727
+ console.error("[ImagePicker] Clear error:", err);
728
+ }
729
+ };
730
+ return /* @__PURE__ */ jsx(
731
+ "div",
732
+ {
733
+ className: "fixed inset-0 z-[99999] bg-black/50 flex items-center justify-center p-4",
734
+ onClick: onClose,
735
+ children: /* @__PURE__ */ jsxs(
736
+ "div",
737
+ {
738
+ className: "bg-white rounded-xl shadow-2xl max-w-4xl w-full max-h-[90vh] overflow-hidden",
739
+ onClick: (e) => e.stopPropagation(),
740
+ children: [
741
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between p-4 border-b", children: [
742
+ /* @__PURE__ */ jsxs("div", { children: [
743
+ /* @__PURE__ */ jsx("h2", { className: "text-lg font-semibold", children: "Select Image" }),
744
+ /* @__PURE__ */ jsxs("p", { className: "text-sm text-gray-500", children: [
745
+ "Slot: ",
746
+ slotId
747
+ ] })
748
+ ] }),
749
+ /* @__PURE__ */ jsx(
750
+ "button",
751
+ {
752
+ onClick: onClose,
753
+ className: "text-gray-400 hover:text-gray-600 p-2",
754
+ children: /* @__PURE__ */ jsx("svg", { className: "w-5 h-5", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) })
755
+ }
756
+ )
757
+ ] }),
758
+ /* @__PURE__ */ jsxs("div", { className: "p-4 overflow-y-auto", style: { maxHeight: "calc(90vh - 180px)" }, children: [
759
+ /* @__PURE__ */ jsxs("div", { className: "flex gap-4 mb-4", children: [
760
+ /* @__PURE__ */ jsx("div", { className: "flex-1", children: /* @__PURE__ */ jsx(
761
+ "input",
762
+ {
763
+ type: "text",
764
+ placeholder: "Search images...",
765
+ value: search,
766
+ onChange: (e) => setSearch(e.target.value),
767
+ className: "w-full px-3 py-2 border rounded-lg text-sm"
768
+ }
769
+ ) }),
770
+ /* @__PURE__ */ jsxs("label", { className: "px-4 py-2 bg-blue-600 text-white rounded-lg cursor-pointer hover:bg-blue-700 text-sm font-medium flex items-center gap-2", children: [
771
+ uploading ? "Uploading..." : "Upload New",
772
+ /* @__PURE__ */ jsx(
773
+ "input",
774
+ {
775
+ type: "file",
776
+ accept: "image/*",
777
+ onChange: handleUpload,
778
+ disabled: uploading,
779
+ className: "hidden"
780
+ }
781
+ )
782
+ ] }),
783
+ currentImage?.file_id && /* @__PURE__ */ jsx(
784
+ "button",
785
+ {
786
+ onClick: handleClear,
787
+ className: "px-4 py-2 border border-red-200 text-red-600 rounded-lg hover:bg-red-50 text-sm",
788
+ children: "Remove"
789
+ }
790
+ )
791
+ ] }),
792
+ /* @__PURE__ */ jsx("div", { className: "mb-4", children: /* @__PURE__ */ jsx(
793
+ "input",
794
+ {
795
+ type: "text",
796
+ placeholder: "Alt text for image...",
797
+ value: altText,
798
+ onChange: (e) => setAltText(e.target.value),
799
+ className: "w-full px-3 py-2 border rounded-lg text-sm"
800
+ }
801
+ ) }),
802
+ folders.length > 0 && /* @__PURE__ */ jsxs("div", { className: "flex gap-2 mb-4 flex-wrap", children: [
803
+ /* @__PURE__ */ jsx(
804
+ "button",
805
+ {
806
+ onClick: () => setCurrentFolder(""),
807
+ className: `px-3 py-1 text-sm rounded-full ${!currentFolder ? "bg-blue-100 text-blue-700" : "bg-gray-100 hover:bg-gray-200"}`,
808
+ children: "All"
809
+ }
810
+ ),
811
+ folders.map((folder) => /* @__PURE__ */ jsx(
812
+ "button",
813
+ {
814
+ onClick: () => setCurrentFolder(folder),
815
+ className: `px-3 py-1 text-sm rounded-full ${currentFolder === folder ? "bg-blue-100 text-blue-700" : "bg-gray-100 hover:bg-gray-200"}`,
816
+ children: folder
817
+ },
818
+ folder
819
+ ))
820
+ ] }),
821
+ loading ? /* @__PURE__ */ jsx("div", { className: "grid grid-cols-4 gap-4", children: [...Array(8)].map((_, i) => /* @__PURE__ */ jsx("div", { className: "aspect-square bg-gray-200 rounded-lg animate-pulse" }, i)) }) : files.length === 0 ? /* @__PURE__ */ jsxs("div", { className: "text-center py-12 text-gray-500", children: [
822
+ /* @__PURE__ */ jsx("p", { children: "No images found" }),
823
+ /* @__PURE__ */ jsx("p", { className: "text-sm mt-1", children: "Upload a new image to get started" })
824
+ ] }) : /* @__PURE__ */ jsx("div", { className: "grid grid-cols-4 gap-4", children: files.map((file) => /* @__PURE__ */ jsx(
825
+ "button",
826
+ {
827
+ onClick: () => handleSelectFile(file),
828
+ className: `
829
+ aspect-square rounded-lg overflow-hidden border-2 transition-all
830
+ hover:border-blue-400 hover:shadow-lg
831
+ ${currentImage?.file_id === file.id ? "border-blue-500 ring-2 ring-blue-200" : "border-gray-200"}
832
+ `,
833
+ children: /* @__PURE__ */ jsx(
834
+ "img",
835
+ {
836
+ src: file.public_url,
837
+ alt: file.filename,
838
+ className: "w-full h-full object-cover"
839
+ }
840
+ )
841
+ },
842
+ file.id
843
+ )) })
844
+ ] }),
845
+ /* @__PURE__ */ jsx("div", { className: "p-4 border-t bg-gray-50 flex justify-end", children: /* @__PURE__ */ jsx(
846
+ "button",
847
+ {
848
+ onClick: onClose,
849
+ className: "px-4 py-2 text-gray-700 hover:bg-gray-100 rounded-lg text-sm",
850
+ children: "Cancel"
851
+ }
852
+ ) })
853
+ ]
854
+ }
855
+ )
856
+ }
857
+ );
858
+ }
859
+
860
+ // src/images/api.ts
861
+ async function fetchManagedImage(config, slotId, pagePath) {
862
+ const params = new URLSearchParams();
863
+ if (pagePath) params.set("page_path", pagePath);
864
+ const res = await fetch(
865
+ `${config.apiUrl}/public/images/slot/${encodeURIComponent(slotId)}?${params}`,
866
+ {
867
+ headers: {
868
+ "Content-Type": "application/json",
869
+ "x-api-key": config.apiKey
870
+ }
871
+ }
872
+ );
873
+ if (!res.ok) {
874
+ throw new Error(`Failed to fetch image: ${res.status}`);
875
+ }
876
+ return res.json();
877
+ }
878
+ async function fetchManagedImages(config, options) {
879
+ const params = new URLSearchParams();
880
+ if (options?.pagePath) params.set("page_path", options.pagePath);
881
+ if (options?.category) params.set("category", options.category);
882
+ if (options?.includePlaceholders) params.set("include_placeholders", "true");
883
+ const res = await fetch(
884
+ `${config.apiUrl}/public/images?${params}`,
885
+ {
886
+ headers: {
887
+ "Content-Type": "application/json",
888
+ "x-api-key": config.apiKey
889
+ }
890
+ }
891
+ );
892
+ if (!res.ok) {
893
+ throw new Error(`Failed to fetch images: ${res.status}`);
894
+ }
895
+ return res.json();
896
+ }
897
+ async function listImageFiles(config, options) {
898
+ const params = new URLSearchParams();
899
+ if (options?.folder) params.set("folder", options.folder);
900
+ if (options?.search) params.set("search", options.search);
901
+ const res = await fetch(
902
+ `${config.apiUrl}/public/images/files?${params}`,
903
+ {
904
+ headers: {
905
+ "Content-Type": "application/json",
906
+ "x-api-key": config.apiKey
907
+ }
908
+ }
909
+ );
910
+ if (!res.ok) {
911
+ throw new Error(`Failed to list files: ${res.status}`);
912
+ }
913
+ return res.json();
914
+ }
915
+ async function uploadImage(config, file, options) {
916
+ const formData = new FormData();
917
+ formData.append("file", file);
918
+ if (options?.slotId) formData.append("slot_id", options.slotId);
919
+ if (options?.pagePath) formData.append("page_path", options.pagePath);
920
+ if (options?.folder) formData.append("folder", options.folder);
921
+ if (options?.altText) formData.append("alt_text", options.altText);
922
+ const res = await fetch(`${config.apiUrl}/public/images/upload`, {
923
+ method: "POST",
924
+ headers: {
925
+ "x-api-key": config.apiKey
926
+ },
927
+ body: formData
928
+ });
929
+ if (!res.ok) {
930
+ throw new Error(`Failed to upload image: ${res.status}`);
931
+ }
932
+ return res.json();
933
+ }
934
+ async function assignImageToSlot(config, slotId, options) {
935
+ const res = await fetch(
936
+ `${config.apiUrl}/public/images/slot/${encodeURIComponent(slotId)}`,
937
+ {
938
+ method: "POST",
939
+ headers: {
940
+ "Content-Type": "application/json",
941
+ "x-api-key": config.apiKey
942
+ },
943
+ body: JSON.stringify({
944
+ page_path: options.pagePath,
945
+ file_id: options.fileId,
946
+ external_url: options.externalUrl,
947
+ alt_text: options.altText,
948
+ title: options.title,
949
+ caption: options.caption,
950
+ focal_point_x: options.focalPointX,
951
+ focal_point_y: options.focalPointY,
952
+ aspect_ratio: options.aspectRatio
953
+ })
954
+ }
955
+ );
956
+ if (!res.ok) {
957
+ throw new Error(`Failed to assign image: ${res.status}`);
958
+ }
959
+ return res.json();
960
+ }
961
+ async function clearImageSlot(config, slotId, pagePath) {
962
+ const params = new URLSearchParams();
963
+ if (pagePath) params.set("page_path", pagePath);
964
+ const res = await fetch(
965
+ `${config.apiUrl}/public/images/slot/${encodeURIComponent(slotId)}?${params}`,
966
+ {
967
+ method: "DELETE",
968
+ headers: {
969
+ "x-api-key": config.apiKey
970
+ }
971
+ }
972
+ );
973
+ if (!res.ok) {
974
+ throw new Error(`Failed to clear slot: ${res.status}`);
975
+ }
976
+ return res.json();
977
+ }
978
+
979
+ export { ManagedImage, SignalBridge, SiteKitProvider, assignImageToSlot, clearImageSlot, fetchManagedImage, fetchManagedImages, listImageFiles, uploadImage, useSignal, useSignalConfig, useSignalEvent, useSignalExperiment, useSignalOutcome, useSiteKit };
980
+ //# sourceMappingURL=chunk-XQJX252G.mjs.map
981
+ //# sourceMappingURL=chunk-XQJX252G.mjs.map