@probat/react 0.1.3 → 0.1.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.
package/dist/index.js CHANGED
@@ -164,10 +164,108 @@ async function fetchComponentExperimentConfig(baseUrl, repoFullName, componentPa
164
164
  return fetchPromise;
165
165
  }
166
166
  var variantComponentCache = /* @__PURE__ */ new Map();
167
+ var moduleCache = /* @__PURE__ */ new Map();
167
168
  if (typeof window !== "undefined") {
168
169
  window.__probatReact = React4__default.default;
169
170
  window.React = window.React || React4__default.default;
170
171
  }
172
+ function resolveRelativePath(relativePath, basePath) {
173
+ const baseDir = basePath.substring(0, basePath.lastIndexOf("/"));
174
+ const parts = baseDir.split("/").filter(Boolean);
175
+ const relativeParts = relativePath.split("/").filter(Boolean);
176
+ for (const part of relativeParts) {
177
+ if (part === "..") {
178
+ parts.pop();
179
+ } else if (part !== ".") {
180
+ parts.push(part);
181
+ }
182
+ }
183
+ return "/" + parts.join("/");
184
+ }
185
+ async function loadRelativeModule(absolutePath, baseFilePath, repoFullName, baseRef) {
186
+ const cacheKey = `${baseFilePath}:${absolutePath}`;
187
+ if (moduleCache.has(cacheKey)) {
188
+ return moduleCache.get(cacheKey);
189
+ }
190
+ const extensions = [".jsx", ".tsx", ".js", ".ts"];
191
+ let moduleCode = null;
192
+ let modulePath = null;
193
+ for (const ext of extensions) {
194
+ const testPath = absolutePath + (absolutePath.includes(".") ? "" : ext);
195
+ try {
196
+ const localRes = await fetch(testPath, {
197
+ method: "GET",
198
+ headers: { Accept: "text/plain" }
199
+ });
200
+ if (localRes.ok) {
201
+ moduleCode = await localRes.text();
202
+ modulePath = testPath;
203
+ break;
204
+ }
205
+ } catch {
206
+ }
207
+ if (!moduleCode && repoFullName) {
208
+ try {
209
+ const githubPath = testPath.startsWith("/") ? testPath.substring(1) : testPath;
210
+ const githubUrl = `https://raw.githubusercontent.com/${repoFullName}/${baseRef || "main"}/${githubPath}`;
211
+ const res = await fetch(githubUrl, { method: "GET", headers: { Accept: "text/plain" } });
212
+ if (res.ok) {
213
+ moduleCode = await res.text();
214
+ modulePath = testPath;
215
+ break;
216
+ }
217
+ } catch {
218
+ }
219
+ }
220
+ }
221
+ if (!moduleCode || !modulePath) {
222
+ throw new Error(`Could not resolve module: ${absolutePath} from ${baseFilePath}`);
223
+ }
224
+ let Babel;
225
+ if (typeof window !== "undefined" && window.Babel) {
226
+ Babel = window.Babel;
227
+ } else {
228
+ try {
229
+ const babelModule = await import('@babel/standalone');
230
+ Babel = babelModule.default || babelModule;
231
+ } catch {
232
+ throw new Error("Babel not available for compiling relative import");
233
+ }
234
+ }
235
+ let processedCode = moduleCode;
236
+ processedCode = processedCode.replace(/^import\s+['"].*\.css['"];?\s*$/gm, "");
237
+ processedCode = processedCode.replace(/^import\s+React\s+from\s+['"]react['"];?\s*$/m, "const React = window.React || globalThis.React;");
238
+ processedCode = processedCode.replace(/import\.meta\.env\.[\w$]+/g, "undefined");
239
+ processedCode = processedCode.replace(/\bimport\.meta\b/g, "({})");
240
+ const isTSX = modulePath.endsWith(".tsx");
241
+ const compiled = Babel.transform(processedCode, {
242
+ presets: [
243
+ ["react", { runtime: "classic" }],
244
+ ["typescript", { allExtensions: true, isTSX }]
245
+ ],
246
+ plugins: [["transform-modules-commonjs", { allowTopLevelThis: true }]],
247
+ sourceType: "module",
248
+ filename: modulePath
249
+ }).code;
250
+ const moduleCodeWrapper = `
251
+ var require = function(name) {
252
+ if (name === "react" || name === "react/jsx-runtime") {
253
+ return window.React || globalThis.React;
254
+ }
255
+ if (name.startsWith("/@vite") || name.includes("@vite/client")) {
256
+ return {};
257
+ }
258
+ throw new Error("Unsupported module in relative import: " + name);
259
+ };
260
+ var module = { exports: {} };
261
+ var exports = module.exports;
262
+ ${compiled}
263
+ return module.exports;
264
+ `;
265
+ const moduleExports = new Function(moduleCodeWrapper)();
266
+ moduleCache.set(cacheKey, moduleExports);
267
+ return moduleExports;
268
+ }
171
269
  async function loadVariantComponent(baseUrl, proposalId, experimentId, filePath, repoFullName, baseRef) {
172
270
  if (!filePath) {
173
271
  return null;
@@ -179,21 +277,27 @@ async function loadVariantComponent(baseUrl, proposalId, experimentId, filePath,
179
277
  }
180
278
  const loadPromise = (async () => {
181
279
  try {
182
- try {
183
- const variantUrl = `/probat/${filePath}`;
184
- const mod = await import(
185
- /* @vite-ignore */
186
- variantUrl
187
- );
188
- const VariantComponent2 = mod?.default || mod;
189
- if (VariantComponent2 && typeof VariantComponent2 === "function") {
190
- return VariantComponent2;
191
- }
192
- } catch {
193
- }
194
280
  let code = "";
195
281
  let rawCode = "";
196
282
  let rawCodeFetched = false;
283
+ const isBrowser = typeof window !== "undefined";
284
+ const isNextJSServer = typeof window === "undefined" || typeof globalThis.process !== "undefined" && globalThis.process.env?.NEXT_RUNTIME === "nodejs";
285
+ if (isBrowser && !isNextJSServer) {
286
+ try {
287
+ const variantUrl = `/probat/${filePath}`;
288
+ const mod = await import(
289
+ /* @vite-ignore */
290
+ variantUrl
291
+ );
292
+ const VariantComponent2 = mod?.default || mod;
293
+ if (VariantComponent2 && typeof VariantComponent2 === "function") {
294
+ console.log(`[PROBAT] \u2705 Loaded variant via dynamic import (CSR): ${variantUrl}`);
295
+ return VariantComponent2;
296
+ }
297
+ } catch (dynamicImportError) {
298
+ console.debug(`[PROBAT] Dynamic import failed, using fetch+babel:`, dynamicImportError);
299
+ }
300
+ }
197
301
  const localUrl = `/probat/${filePath}`;
198
302
  try {
199
303
  const localRes = await fetch(localUrl, {
@@ -278,6 +382,17 @@ async function loadVariantComponent(baseUrl, proposalId, experimentId, filePath,
278
382
  rawCode = rawCode.replace(/\bimport\.meta\b/g, "({})");
279
383
  rawCode = rawCode.replace(/^import\s+.*\/@vite\/client.*$/gm, "");
280
384
  rawCode = rawCode.replace(/import\.meta\.hot(?:\.[\w$]+)*/g, "undefined");
385
+ const relativeImportMap = /* @__PURE__ */ new Map();
386
+ rawCode = rawCode.replace(
387
+ /^import\s+(\w+)\s+from\s+['"](\.\.?\/[^'"]+)['"];?\s*$/gm,
388
+ (match, importName, relativePath) => {
389
+ const baseDir = filePath.substring(0, filePath.lastIndexOf("/"));
390
+ const resolvedPath = resolveRelativePath(relativePath, baseDir);
391
+ const absolutePath = resolvedPath.startsWith("/") ? resolvedPath : "/" + resolvedPath;
392
+ relativeImportMap.set(importName, absolutePath);
393
+ return `import ${importName} from "${absolutePath}";`;
394
+ }
395
+ );
281
396
  const compiled = Babel.transform(rawCode, {
282
397
  presets: [
283
398
  ["react", { runtime: "classic" }],
@@ -287,8 +402,22 @@ async function loadVariantComponent(baseUrl, proposalId, experimentId, filePath,
287
402
  sourceType: "module",
288
403
  filename: filePath
289
404
  }).code;
405
+ const relativeModules = {};
406
+ if (relativeImportMap.size > 0) {
407
+ for (const [importName, absolutePath] of relativeImportMap.entries()) {
408
+ try {
409
+ const moduleExports = await loadRelativeModule(absolutePath, filePath, repoFullName, baseRef);
410
+ relativeModules[absolutePath] = moduleExports.default || moduleExports;
411
+ } catch (err) {
412
+ console.warn(`[PROBAT] Failed to load relative import ${absolutePath}:`, err);
413
+ relativeModules[absolutePath] = null;
414
+ }
415
+ }
416
+ }
417
+ const relativeModulesJson = JSON.stringify(relativeModules);
290
418
  code = `
291
419
  var __probatVariant = (function() {
420
+ var relativeModules = ${relativeModulesJson};
292
421
  var require = function(name) {
293
422
  if (name === "react" || name === "react/jsx-runtime") {
294
423
  return window.React || globalThis.React;
@@ -299,6 +428,14 @@ async function loadVariantComponent(baseUrl, proposalId, experimentId, filePath,
299
428
  if (name === "react/jsx-runtime.js") {
300
429
  return window.React || globalThis.React;
301
430
  }
431
+ // Handle relative imports (now converted to absolute paths)
432
+ if (name.startsWith("/") && relativeModules.hasOwnProperty(name)) {
433
+ var mod = relativeModules[name];
434
+ if (mod === null) {
435
+ throw new Error("Failed to load module: " + name);
436
+ }
437
+ return mod;
438
+ }
302
439
  throw new Error("Unsupported module: " + name);
303
440
  };
304
441
  var module = { exports: {} };
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/utils/environment.ts","../src/context/ProbatContext.tsx","../src/components/ProbatProviderClient.tsx","../src/utils/api.ts","../src/hooks/useProbatMetrics.ts","../src/utils/storage.ts","../src/hooks/useExperiment.ts","../src/hoc/withExperiment.tsx"],"names":["createContext","useMemo","useContext","React","VariantComponent","useCallback","useState","useEffect","meta","label"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Detect if the code is running on localhost (development environment).\n * Returns \"dev\" for localhost, \"prod\" for production.\n */\nexport function detectEnvironment(): \"dev\" | \"prod\" {\n if (typeof window === \"undefined\") {\n return \"prod\"; // Server-side, default to prod\n }\n\n const hostname = window.location.hostname;\n\n // Check for localhost, 127.0.0.1, or local IP addresses\n if (\n hostname === \"localhost\" ||\n hostname === \"127.0.0.1\" ||\n hostname === \"0.0.0.0\" ||\n hostname.startsWith(\"192.168.\") ||\n hostname.startsWith(\"10.\") ||\n hostname.startsWith(\"172.16.\") ||\n hostname.startsWith(\"172.17.\") ||\n hostname.startsWith(\"172.18.\") ||\n hostname.startsWith(\"172.19.\") ||\n hostname.startsWith(\"172.20.\") ||\n hostname.startsWith(\"172.21.\") ||\n hostname.startsWith(\"172.22.\") ||\n hostname.startsWith(\"172.23.\") ||\n hostname.startsWith(\"172.24.\") ||\n hostname.startsWith(\"172.25.\") ||\n hostname.startsWith(\"172.26.\") ||\n hostname.startsWith(\"172.27.\") ||\n hostname.startsWith(\"172.28.\") ||\n hostname.startsWith(\"172.29.\") ||\n hostname.startsWith(\"172.30.\") ||\n hostname.startsWith(\"172.31.\")\n ) {\n return \"dev\";\n }\n\n return \"prod\";\n}\n\n","\"use client\";\n\nimport React, { createContext, useContext, useMemo } from \"react\";\nimport { detectEnvironment } from \"../utils/environment\";\n\ndeclare global {\n interface Window {\n __PROBAT_API?: string;\n }\n}\n\nexport interface ProbatContextValue {\n apiBaseUrl: string;\n environment: \"dev\" | \"prod\";\n clientKey?: string;\n repoFullName?: string; // Repository full name (e.g., \"owner/repo\") for component-based experiments\n}\n\nconst ProbatContext = createContext<ProbatContextValue | null>(null);\n\nexport interface ProbatProviderProps {\n /**\n * The base URL for the Probat API.\n * If not provided, will try to read from:\n * - VITE_PROBAT_API (Vite)\n * - NEXT_PUBLIC_PROBAT_API (Next.js)\n * - window.__PROBAT_API\n * - Default: \"https://gushi.onrender.com\"\n */\n apiBaseUrl?: string;\n /**\n * Client key for identification (optional)\n */\n clientKey?: string;\n /**\n * Explicitly set environment. If not provided, will auto-detect based on hostname.\n * \"dev\" for localhost, \"prod\" for production.\n */\n environment?: \"dev\" | \"prod\";\n /**\n * Repository full name (e.g., \"owner/repo\") for component-based experiments.\n * If not provided, will try to read from:\n * - NEXT_PUBLIC_PROBAT_REPO (Next.js)\n * - VITE_PROBAT_REPO (Vite)\n * - window.__PROBAT_REPO\n */\n repoFullName?: string;\n children: React.ReactNode;\n}\n\nexport function ProbatProvider({\n apiBaseUrl,\n clientKey,\n environment: explicitEnvironment,\n repoFullName: explicitRepoFullName,\n children,\n}: ProbatProviderProps) {\n const contextValue = useMemo<ProbatContextValue>(() => {\n // Determine API base URL\n const resolvedApiBaseUrl =\n apiBaseUrl ||\n (typeof import.meta !== \"undefined\" &&\n (import.meta as any).env?.VITE_PROBAT_API) ||\n (typeof globalThis !== \"undefined\" &&\n (globalThis as any).process?.env?.NEXT_PUBLIC_PROBAT_API) ||\n (typeof window !== \"undefined\" && window.__PROBAT_API) ||\n \"https://gushi.onrender.com\";\n\n // Determine environment\n const environment = explicitEnvironment || detectEnvironment();\n\n // Determine repo full name\n const resolvedRepoFullName =\n explicitRepoFullName ||\n (typeof globalThis !== \"undefined\" &&\n (globalThis as any).process?.env?.NEXT_PUBLIC_PROBAT_REPO) ||\n (typeof import.meta !== \"undefined\" &&\n (import.meta as any).env?.VITE_PROBAT_REPO) ||\n (typeof window !== \"undefined\" && (window as any).__PROBAT_REPO) ||\n undefined;\n\n return {\n apiBaseUrl: resolvedApiBaseUrl,\n environment,\n clientKey,\n repoFullName: resolvedRepoFullName,\n };\n }, [apiBaseUrl, clientKey, explicitEnvironment, explicitRepoFullName]);\n\n return (\n <ProbatContext.Provider value={contextValue}>\n {children}\n </ProbatContext.Provider>\n );\n}\n\nexport function useProbatContext(): ProbatContextValue {\n const context = useContext(ProbatContext);\n if (!context) {\n throw new Error(\n \"useProbatContext must be used within a ProbatProvider. Please wrap your app with <ProbatProvider>.\"\n );\n }\n return context;\n}\n\n","\"use client\";\n\nimport React from \"react\";\nimport { ProbatProvider as BaseProbatProvider } from \"../context/ProbatContext\";\nimport type { ProbatProviderProps } from \"../context/ProbatContext\";\n\n/**\n * ProbatProviderClient - Can be imported directly in Next.js Server Components\n * This is a re-export with \"use client\" directive to ensure it works in Server Components\n */\nexport function ProbatProviderClient(props: ProbatProviderProps) {\n return React.createElement(BaseProbatProvider, props);\n}\n\n// Also export as ProbatProvider for convenience\nexport { ProbatProviderClient as ProbatProvider };\nexport type { ProbatProviderProps };\n\n","import React from \"react\";\nimport { detectEnvironment } from \"./environment\";\n\nexport type RetrieveResponse = {\n proposal_id: string;\n experiment_id: string | null;\n label: string | null;\n};\n\nexport type ComponentVariantInfo = {\n experiment_id: string;\n label: string;\n file_path: string | null;\n};\n\nexport type ComponentExperimentConfig = {\n proposal_id: string;\n repo_full_name: string;\n base_ref?: string; // Git branch/ref (default: \"main\")\n variants: Record<string, ComponentVariantInfo>;\n};\n\n// Shared promise cache to prevent multiple simultaneous API calls for the same proposal\nconst pendingFetches = new Map<\n string,\n Promise<{ experiment_id: string; label: string }>\n>();\n\nexport async function fetchDecision(\n baseUrl: string,\n proposalId: string\n): Promise<{ experiment_id: string; label: string }> {\n // Check if there's already a pending fetch for this proposal\n const existingFetch = pendingFetches.get(proposalId);\n if (existingFetch) {\n return existingFetch;\n }\n\n // Create new fetch promise\n const fetchPromise = (async () => {\n try {\n const url = `${baseUrl.replace(/\\/$/, \"\")}/retrieve_react_experiment/${encodeURIComponent(proposalId)}`;\n const res = await fetch(url, {\n method: \"POST\",\n headers: { Accept: \"application/json\" },\n credentials: \"include\", // Include cookies for user identification\n });\n if (!res.ok) throw new Error(`HTTP ${res.status}`);\n const data = (await res.json()) as RetrieveResponse;\n\n const experiment_id = (data.experiment_id || `exp_${proposalId}`).toString();\n const label = data.label && data.label.trim() ? data.label : \"control\";\n\n return { experiment_id, label };\n } finally {\n // Remove from pending cache after completion\n pendingFetches.delete(proposalId);\n }\n })();\n\n // Store the promise so other components can wait for the same call\n pendingFetches.set(proposalId, fetchPromise);\n return fetchPromise;\n}\n\nexport async function sendMetric(\n baseUrl: string,\n proposalId: string,\n metricName: \"visit\" | \"click\" | string,\n variantLabel: string = \"control\",\n experimentId?: string,\n dimensions: Record<string, any> = {}\n) {\n const url = `${baseUrl.replace(/\\/$/, \"\")}/send_metrics/${encodeURIComponent(proposalId)}`;\n const body = {\n experiment_id: experimentId ?? null,\n variant_label: variantLabel,\n metric_name: metricName,\n metric_value: 1,\n metric_unit: \"count\",\n source: \"react\",\n environment: detectEnvironment(), // Include environment (dev or prod)\n dimensions,\n captured_at: new Date().toISOString(),\n };\n try {\n await fetch(url, {\n method: \"POST\",\n headers: {\n Accept: \"application/json\",\n \"Content-Type\": \"application/json\",\n },\n credentials: \"include\", // CRITICAL: Include cookies to distinguish different users\n body: JSON.stringify(body),\n });\n } catch {\n // Silently fail - metrics should not break the app\n }\n}\n\nexport function extractClickMeta(\n event?: { target?: EventTarget | null } | null\n): Record<string, any> | undefined {\n if (!event || !event.target) return undefined;\n const rawTarget = event.target as HTMLElement | null;\n if (!rawTarget) return undefined;\n const actionable = rawTarget.closest(\n \"[data-probat-conversion='true'], button, a, [role='button']\"\n );\n if (!actionable) return undefined;\n const meta: Record<string, any> = {\n target_tag: actionable.tagName,\n };\n if (actionable.id) meta.target_id = actionable.id;\n const attr = actionable.getAttribute(\"data-probat-conversion\");\n if (attr) meta.conversion_attr = attr;\n const text = actionable.textContent?.trim();\n if (text) meta.target_text = text.slice(0, 120);\n return meta;\n}\n\n// Cache for component config fetches\nconst componentConfigCache = new Map<\n string,\n Promise<ComponentExperimentConfig | null>\n>();\n\nexport async function fetchComponentExperimentConfig(\n baseUrl: string,\n repoFullName: string,\n componentPath: string\n): Promise<ComponentExperimentConfig | null> {\n const cacheKey = `${repoFullName}:${componentPath}`;\n\n // Check cache\n const existingFetch = componentConfigCache.get(cacheKey);\n if (existingFetch) {\n return existingFetch;\n }\n\n // Create new fetch promise\n const fetchPromise = (async () => {\n try {\n const url = new URL(`${baseUrl.replace(/\\/$/, \"\")}/get_component_experiment_config`);\n url.searchParams.set(\"repo_full_name\", repoFullName);\n url.searchParams.set(\"component_path\", componentPath);\n\n const res = await fetch(url.toString(), {\n method: \"GET\",\n headers: { Accept: \"application/json\" },\n credentials: \"include\",\n });\n\n if (res.status === 404) {\n // No experiments for this component - return null\n return null;\n }\n\n if (!res.ok) {\n throw new Error(`HTTP ${res.status}`);\n }\n\n const data = (await res.json()) as ComponentExperimentConfig;\n return data;\n } catch (e) {\n console.warn(`[PROBAT] Failed to fetch component config: ${e}`);\n return null;\n } finally {\n // Remove from cache after completion\n componentConfigCache.delete(cacheKey);\n }\n })();\n\n // Store the promise\n componentConfigCache.set(cacheKey, fetchPromise);\n return fetchPromise;\n}\n\n// Cache for variant component loads\nconst variantComponentCache = new Map<string, Promise<React.ComponentType<any> | null>>();\n\n// Make React available globally for variant components\nif (typeof window !== \"undefined\") {\n (window as any).__probatReact = React;\n (window as any).React = (window as any).React || React;\n}\n\nexport async function loadVariantComponent(\n baseUrl: string,\n proposalId: string,\n experimentId: string,\n filePath: string | null,\n repoFullName?: string,\n baseRef?: string\n): Promise<React.ComponentType<any> | null> {\n if (!filePath) {\n return null;\n }\n\n const cacheKey = `${proposalId}:${experimentId}`;\n\n // Check cache\n const existingLoad = variantComponentCache.get(cacheKey);\n if (existingLoad) {\n return existingLoad;\n }\n\n // Create new load promise\n const loadPromise = (async () => {\n try {\n // ============================================\n // Preferred path: dynamic ESM import (Vite/Next can resolve deps)\n // ============================================\n try {\n const variantUrl = `/probat/${filePath}`;\n const mod = await import(/* @vite-ignore */ variantUrl);\n const VariantComponent = (mod as any)?.default || mod;\n if (VariantComponent && typeof VariantComponent === \"function\") {\n return VariantComponent as React.ComponentType<any>;\n }\n } catch {\n // Fall through to legacy path\n }\n\n // Legacy path (fetch + babel + eval) retained for non-Vite envs\n let code: string = \"\";\n let rawCode: string = \"\";\n let rawCodeFetched = false;\n\n const localUrl = `/probat/${filePath}`;\n try {\n const localRes = await fetch(localUrl, {\n method: \"GET\",\n headers: { Accept: \"text/plain\" },\n });\n if (localRes.ok) {\n rawCode = await localRes.text();\n rawCodeFetched = true;\n console.log(`[PROBAT] ✅ Loaded variant from local (user's repo): ${localUrl}`);\n }\n } catch {\n console.debug(`[PROBAT] Local file not available (${localUrl}), trying GitHub...`);\n }\n\n if (!rawCodeFetched && repoFullName) {\n const githubPath = `probat/${filePath}`;\n const gitRef = baseRef || \"main\";\n const githubUrl = `https://raw.githubusercontent.com/${repoFullName}/${gitRef}/${githubPath}`;\n const res = await fetch(githubUrl, { method: \"GET\", headers: { Accept: \"text/plain\" } });\n if (res.ok) {\n rawCode = await res.text();\n rawCodeFetched = true;\n console.log(`[PROBAT] ⚠️ Loaded variant from GitHub (fallback): ${githubUrl}`);\n } else {\n console.warn(`[PROBAT] ⚠️ GitHub fetch failed (${res.status}), falling back to server compilation`);\n }\n }\n\n if (rawCodeFetched && rawCode) {\n let Babel: any;\n if (typeof window !== \"undefined\" && (window as any).Babel) {\n Babel = (window as any).Babel;\n } else {\n try {\n // @ts-ignore\n const babelModule = await import(\"@babel/standalone\");\n Babel = babelModule.default || babelModule;\n } catch (importError) {\n try {\n await new Promise<void>((resolve, reject) => {\n if (typeof document === \"undefined\") {\n reject(new Error(\"Document not available\"));\n return;\n }\n if ((window as any).Babel) {\n Babel = (window as any).Babel;\n resolve();\n return;\n }\n const script = document.createElement(\"script\");\n script.src = \"https://unpkg.com/@babel/standalone/babel.min.js\";\n script.async = true;\n script.onload = () => {\n Babel = (window as any).Babel;\n if (!Babel) reject(new Error(\"Babel not found after script load\"));\n else resolve();\n };\n script.onerror = () => reject(new Error(\"Failed to load Babel from CDN\"));\n document.head.appendChild(script);\n });\n } catch (babelError) {\n console.error(\"[PROBAT] Failed to load Babel, falling back to server compilation\", babelError);\n rawCodeFetched = false;\n }\n }\n }\n\n if (rawCodeFetched && rawCode && Babel) {\n const isTSX = filePath.endsWith(\".tsx\");\n rawCode = rawCode.replace(/^import\\s+['\"].*\\.css['\"];?\\s*$/gm, \"\");\n rawCode = rawCode.replace(/^import\\s+.*from\\s+['\"].*\\.css['\"];?\\s*$/gm, \"\");\n rawCode = rawCode.replace(\n /^import\\s+React(?:\\s*,\\s*\\{[^}]*\\})?\\s+from\\s+['\"]react['\"];?\\s*$/m,\n \"const React = window.React || globalThis.React;\"\n );\n rawCode = rawCode.replace(\n /^import\\s+\\*\\s+as\\s+React\\s+from\\s+['\"]react['\"];?\\s*$/m,\n \"const React = window.React || globalThis.React;\"\n );\n rawCode = rawCode.replace(\n /^import\\s+\\{([^}]+)\\}\\s+from\\s+['\"]react['\"];?\\s*$/m,\n (match, imports) => `const {${imports}} = window.React || globalThis.React;`\n );\n rawCode = rawCode.replace(/import\\.meta\\.env\\.[\\w$]+/g, \"undefined\");\n rawCode = rawCode.replace(/\\bimport\\.meta\\b/g, \"({})\");\n rawCode = rawCode.replace(/^import\\s+.*\\/@vite\\/client.*$/gm, \"\");\n rawCode = rawCode.replace(/import\\.meta\\.hot(?:\\.[\\w$]+)*/g, \"undefined\");\n\n const compiled = Babel.transform(rawCode, {\n presets: [\n [\"react\", { runtime: \"classic\" }],\n [\"typescript\", { allExtensions: true, isTSX }],\n ],\n plugins: [[\"transform-modules-commonjs\", { allowTopLevelThis: true }]],\n sourceType: \"module\",\n filename: filePath,\n }).code;\n\n code = `\n var __probatVariant = (function() {\n var require = function(name) {\n if (name === \"react\" || name === \"react/jsx-runtime\") {\n return window.React || globalThis.React;\n }\n if (name.startsWith(\"/@vite\") || name.includes(\"@vite/client\") || name.includes(\".vite/deps\")) {\n return {};\n }\n if (name === \"react/jsx-runtime.js\") {\n return window.React || globalThis.React;\n }\n throw new Error(\"Unsupported module: \" + name);\n };\n var module = { exports: {} };\n var exports = module.exports;\n ${compiled}\n return module.exports.default || module.exports;\n })();\n `;\n } else {\n rawCodeFetched = false;\n code = \"\";\n }\n }\n\n if (!rawCodeFetched || code === \"\") {\n const variantUrl = `${baseUrl.replace(/\\/$/, \"\")}/variants/${filePath}`;\n const serverRes = await fetch(variantUrl, {\n method: \"GET\",\n headers: { Accept: \"text/javascript\" },\n credentials: \"include\",\n });\n if (!serverRes.ok) {\n throw new Error(`HTTP ${serverRes.status}`);\n }\n code = await serverRes.text();\n }\n\n if (typeof window !== \"undefined\") {\n (window as any).React = (window as any).React || React;\n }\n\n const evalFunc = new Function(`\n var __probatVariant;\n ${code}\n return __probatVariant;\n `);\n\n const result = evalFunc();\n const VariantComponent = result?.default || result;\n if (typeof VariantComponent === \"function\") {\n return VariantComponent as React.ComponentType<any>;\n }\n\n console.warn(\"[PROBAT] Variant component is not a function\", result);\n return null;\n } catch (e) {\n console.warn(`[PROBAT] Failed to load variant component: ${e}`);\n return null;\n } finally {\n // Remove from cache after completion\n variantComponentCache.delete(cacheKey);\n }\n })();\n\n // Store the promise\n variantComponentCache.set(cacheKey, loadPromise);\n return loadPromise;\n}\n\n","\"use client\";\n\nimport { useCallback } from \"react\";\nimport type { MouseEvent } from \"react\";\nimport { useProbatContext } from \"../context/ProbatContext\";\nimport { sendMetric, extractClickMeta } from \"../utils/api\";\n\nexport interface UseProbatMetricsReturn {\n /**\n * Track a click event\n * @param event - Optional React mouse event (will extract metadata automatically)\n * @param options - Optional configuration\n * @param options.force - Force tracking even if no actionable element is found\n * @param options.proposalId - Override the proposal ID (usually not needed)\n * @param options.variantLabel - Override the variant label (usually not needed)\n * @param options.dimensions - Additional dimensions to include\n */\n trackClick: (\n event?: MouseEvent | null,\n options?: {\n force?: boolean;\n proposalId?: string;\n variantLabel?: string;\n dimensions?: Record<string, any>;\n }\n ) => boolean;\n /**\n * Track a custom metric\n * @param metricName - Name of the metric\n * @param proposalId - Proposal ID\n * @param variantLabel - Variant label (defaults to \"control\")\n * @param dimensions - Additional dimensions\n */\n trackMetric: (\n metricName: string,\n proposalId: string,\n variantLabel?: string,\n dimensions?: Record<string, any>\n ) => void;\n /**\n * Track an impression/view\n * @param proposalId - Proposal ID\n * @param variantLabel - Variant label (defaults to \"control\")\n * @param experimentId - Optional experiment ID\n */\n trackImpression: (\n proposalId: string,\n variantLabel?: string,\n experimentId?: string\n ) => void;\n}\n\n/**\n * Hook for tracking Probat metrics (clicks, impressions, custom metrics)\n *\n * @example\n * ```tsx\n * const { trackClick, trackImpression } = useProbatMetrics();\n *\n * // Track click on button\n * <button onClick={(e) => trackClick(e)}>Click me</button>\n *\n * // Track impression\n * useEffect(() => {\n * trackImpression(proposalId, variantLabel, experimentId);\n * }, [proposalId, variantLabel, experimentId]);\n * ```\n */\nexport function useProbatMetrics(): UseProbatMetricsReturn {\n const { apiBaseUrl } = useProbatContext();\n\n const trackClick = useCallback(\n (\n event?: MouseEvent | null,\n options?: {\n force?: boolean;\n proposalId?: string;\n variantLabel?: string;\n dimensions?: Record<string, any>;\n }\n ) => {\n const meta = extractClickMeta(event ?? undefined);\n if (!options?.force && event && !meta) {\n return false;\n }\n\n const proposalId = options?.proposalId;\n const variantLabel = options?.variantLabel || \"control\";\n\n if (!proposalId) {\n console.warn(\n \"[Probat] trackClick called without proposalId. Provide it in options or use useExperiment hook.\"\n );\n return false;\n }\n\n void sendMetric(\n apiBaseUrl,\n proposalId,\n \"click\",\n variantLabel,\n undefined,\n { ...meta, ...options?.dimensions }\n );\n return true;\n },\n [apiBaseUrl]\n );\n\n const trackMetric = useCallback(\n (\n metricName: string,\n proposalId: string,\n variantLabel: string = \"control\",\n dimensions: Record<string, any> = {}\n ) => {\n void sendMetric(\n apiBaseUrl,\n proposalId,\n metricName,\n variantLabel,\n undefined,\n dimensions\n );\n },\n [apiBaseUrl]\n );\n\n const trackImpression = useCallback(\n (\n proposalId: string,\n variantLabel: string = \"control\",\n experimentId?: string\n ) => {\n void sendMetric(\n apiBaseUrl,\n proposalId,\n \"visit\",\n variantLabel,\n experimentId\n );\n },\n [apiBaseUrl]\n );\n\n return {\n trackClick,\n trackMetric,\n trackImpression,\n };\n}\n\n","const TTL_MS = 6 * 60 * 60 * 1000; // 6 hours\n\nexport type Choice = {\n experiment_id: string;\n label: string;\n ts: number;\n};\n\nexport function safeGet(k: string): any | null {\n try {\n const raw = localStorage.getItem(k);\n return raw ? JSON.parse(raw) : null;\n } catch {\n return null;\n }\n}\n\nexport function safeSet(k: string, v: any) {\n try {\n localStorage.setItem(k, JSON.stringify(v));\n } catch { }\n}\n\nexport function now() {\n return Date.now();\n}\n\nexport function fresh(ts: number) {\n return now() - ts <= TTL_MS;\n}\n\nexport const KEY = (proposalId: string) => `probat_choice_v3:${proposalId}`;\nexport const VISIT_KEY = (proposalId: string, label: string) =>\n `probat_visit_v1:${proposalId}:${label}`;\n\nexport function readChoice(proposalId: string): Choice | null {\n const c = safeGet(KEY(proposalId)) as Choice | null;\n return c && fresh(c.ts) ? c : null;\n}\n\nexport function writeChoice(\n proposalId: string,\n experiment_id: string,\n label: string\n) {\n safeSet(KEY(proposalId), { experiment_id, label, ts: now() } as Choice);\n}\n\nconst visitMemo = new Set<string>();\n\nexport function hasTrackedVisit(proposalId: string, label: string): boolean {\n const key = VISIT_KEY(proposalId, label);\n if (visitMemo.has(key)) return true;\n try {\n const raw = localStorage.getItem(key);\n if (!raw) return false;\n const ts = Number(raw);\n if (!Number.isFinite(ts) || ts <= 0) return false;\n if (now() - ts > TTL_MS) {\n localStorage.removeItem(key);\n return false;\n }\n visitMemo.add(key);\n return true;\n } catch {\n return false;\n }\n}\n\nexport function markTrackedVisit(proposalId: string, label: string) {\n const key = VISIT_KEY(proposalId, label);\n visitMemo.add(key);\n try {\n localStorage.setItem(key, now().toString());\n } catch { }\n}\n\n","\"use client\";\n\nimport { useState, useEffect, useCallback } from \"react\";\nimport type { MouseEvent } from \"react\";\nimport { useProbatContext } from \"../context/ProbatContext\";\nimport { fetchDecision } from \"../utils/api\";\nimport {\n readChoice,\n writeChoice,\n hasTrackedVisit,\n markTrackedVisit,\n} from \"../utils/storage\";\nimport { sendMetric } from \"../utils/api\";\n\nexport interface UseExperimentReturn {\n /**\n * The current variant label (e.g., \"control\", \"variant-a\")\n */\n variantLabel: string;\n /**\n * The experiment ID\n */\n experimentId: string | null;\n /**\n * Whether the experiment decision is still loading\n */\n isLoading: boolean;\n /**\n * Any error that occurred while fetching the experiment\n */\n error: Error | null;\n /**\n * Manually track a click for this experiment\n */\n trackClick: (event?: MouseEvent | null) => void;\n}\n\n/**\n * Hook for fetching and applying experiment variants\n *\n * @param proposalId - The proposal ID for the experiment\n * @param options - Optional configuration\n * @param options.autoTrackImpression - Automatically track impression when variant is loaded (default: true)\n *\n * @example\n * ```tsx\n * const { variantLabel, isLoading, trackClick } = useExperiment(\"proposal-id\");\n *\n * if (isLoading) return <div>Loading...</div>;\n *\n * return (\n * <div onClick={trackClick}>\n * {variantLabel === \"control\" ? <ControlComponent /> : <VariantComponent />}\n * </div>\n * );\n * ```\n */\nexport function useExperiment(\n proposalId: string,\n options?: { autoTrackImpression?: boolean }\n): UseExperimentReturn {\n const { apiBaseUrl } = useProbatContext();\n const [choice, setChoice] = useState<{\n experiment_id: string;\n label: string;\n } | null>(null);\n const [isLoading, setIsLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n\n const autoTrackImpression = options?.autoTrackImpression !== false;\n\n // Fetch experiment decision\n useEffect(() => {\n let alive = true;\n\n const cached = readChoice(proposalId);\n if (cached) {\n setChoice({ experiment_id: cached.experiment_id, label: cached.label });\n setIsLoading(false);\n } else {\n setIsLoading(true);\n (async () => {\n try {\n const { experiment_id, label } = await fetchDecision(\n apiBaseUrl,\n proposalId\n );\n if (!alive) return;\n writeChoice(proposalId, experiment_id, label);\n setChoice({ experiment_id, label });\n setError(null);\n } catch (e) {\n if (!alive) return;\n const err = e instanceof Error ? e : new Error(String(e));\n setError(err);\n setChoice({\n experiment_id: `exp_${proposalId}`,\n label: \"control\",\n });\n } finally {\n if (alive) {\n setIsLoading(false);\n }\n }\n })();\n }\n\n return () => {\n alive = false;\n };\n }, [proposalId, apiBaseUrl]);\n\n // Track impression when variant is determined\n useEffect(() => {\n if (!autoTrackImpression || !choice) return;\n\n const exp = choice.experiment_id;\n const lbl = choice.label ?? \"control\";\n if (!lbl) return;\n\n // Only track if we haven't already tracked this visit\n if (hasTrackedVisit(proposalId, lbl)) return;\n markTrackedVisit(proposalId, lbl);\n void sendMetric(apiBaseUrl, proposalId, \"visit\", lbl, exp);\n }, [proposalId, choice?.experiment_id, choice?.label, apiBaseUrl, autoTrackImpression]);\n\n const trackClick = useCallback(\n (event?: MouseEvent | null) => {\n const exp = choice?.experiment_id;\n const lbl = choice?.label ?? \"control\";\n const meta = event\n ? (() => {\n const rawTarget = event.target as HTMLElement | null;\n if (!rawTarget) return undefined;\n const actionable = rawTarget.closest(\n \"[data-probat-conversion='true'], button, a, [role='button']\"\n );\n if (!actionable) return undefined;\n const meta: Record<string, any> = {\n target_tag: actionable.tagName,\n };\n if (actionable.id) meta.target_id = actionable.id;\n const attr = actionable.getAttribute(\"data-probat-conversion\");\n if (attr) meta.conversion_attr = attr;\n const text = actionable.textContent?.trim();\n if (text) meta.target_text = text.slice(0, 120);\n return meta;\n })()\n : undefined;\n\n void sendMetric(apiBaseUrl, proposalId, \"click\", lbl, undefined, meta);\n },\n [proposalId, choice?.experiment_id, choice?.label, apiBaseUrl]\n );\n\n return {\n variantLabel: choice?.label ?? \"control\",\n experimentId: choice?.experiment_id ?? null,\n isLoading,\n error,\n trackClick,\n };\n}\n\n","\"use client\";\n\nimport React, { useState, useEffect, useCallback } from \"react\";\nimport type { MouseEvent } from \"react\";\nimport { useProbatContext } from \"../context/ProbatContext\";\nimport {\n fetchDecision,\n fetchComponentExperimentConfig,\n loadVariantComponent,\n sendMetric,\n extractClickMeta,\n} from \"../utils/api\";\nimport {\n readChoice,\n writeChoice,\n hasTrackedVisit,\n markTrackedVisit,\n} from \"../utils/storage\";\n\n// Support both old and new API for backward compatibility\nexport interface WithExperimentOptions {\n // New API: component-based\n componentPath?: string;\n repoFullName?: string;\n\n // Old API: direct proposal/registry (for backward compatibility)\n proposalId?: string;\n registry?: Record<string, React.ComponentType<any>>;\n}\n\n/**\n * Higher-Order Component for wrapping components with experiment variants\n */\nexport function withExperiment<P = any>(\n Control: React.ComponentType<P>,\n options: WithExperimentOptions\n): React.ComponentType<P & { probat?: { trackClick: () => void } }> {\n // Validate inputs at HOC level (not in component)\n if (!Control) {\n console.error(\"[PROBAT] withExperiment: Control component is required\");\n return ((props: P) => null) as any;\n }\n\n if (!options || typeof options !== 'object') {\n console.error(\"[PROBAT] withExperiment: options is required\");\n return Control as any;\n }\n\n const useNewAPI = !!options.componentPath;\n const useOldAPI = !!(options.proposalId && options.registry);\n\n if (!useNewAPI && !useOldAPI) {\n console.warn(\"[PROBAT] withExperiment: Invalid config, returning Control\");\n return Control as any;\n }\n\n const ControlComponent = Control;\n\n function Wrapped(props: P) {\n // ============================================================\n // ALL HOOKS MUST BE AT THE TOP - BEFORE ANY CONDITIONAL RETURNS\n // ============================================================\n\n // 1. Context hook - always called first\n const context = useProbatContext();\n const apiBaseUrl = context?.apiBaseUrl || \"https://gushi.onrender.com\";\n const contextRepoFullName = context?.repoFullName;\n\n // 2. State hooks - always called in same order\n const [config, setConfig] = useState<{\n proposalId: string;\n variants: Record<string, React.ComponentType<any>>;\n } | null>(null);\n const [configLoading, setConfigLoading] = useState(useNewAPI);\n const [choice, setChoice] = useState<{\n experiment_id: string;\n label: string;\n } | null>(null);\n\n // Derived values\n const repoFullName = options.repoFullName || contextRepoFullName;\n const proposalId = useNewAPI ? config?.proposalId : options.proposalId;\n\n // 3. Effect hooks - always called\n // Load component config (new API)\n useEffect(() => {\n if (!useNewAPI) return;\n if (!repoFullName) {\n console.warn(\"[PROBAT] componentPath provided but repoFullName not found\");\n setConfigLoading(false);\n return;\n }\n\n let alive = true;\n setConfigLoading(true);\n\n (async () => {\n try {\n const componentConfig = await fetchComponentExperimentConfig(\n apiBaseUrl,\n repoFullName,\n options.componentPath!\n );\n\n if (!alive) return;\n\n if (!componentConfig) {\n setConfig(null);\n setConfigLoading(false);\n return;\n }\n\n const variantComponents: Record<string, React.ComponentType<any>> = {\n control: ControlComponent,\n };\n\n for (const [label, variantInfo] of Object.entries(componentConfig.variants)) {\n if (label === \"control\") continue;\n if (variantInfo?.file_path) {\n try {\n const VariantComp = await loadVariantComponent(\n apiBaseUrl,\n componentConfig.proposal_id,\n variantInfo.experiment_id,\n variantInfo.file_path,\n componentConfig.repo_full_name,\n componentConfig.base_ref\n );\n if (VariantComp && typeof VariantComp === 'function' && alive) {\n variantComponents[label] = VariantComp;\n }\n } catch (e) {\n console.warn(`[PROBAT] Failed to load variant ${label}:`, e);\n }\n }\n }\n\n if (alive) {\n setConfig({\n proposalId: componentConfig.proposal_id,\n variants: variantComponents,\n });\n setConfigLoading(false);\n }\n } catch (e) {\n console.warn(\"[PROBAT] Failed to load component config:\", e);\n if (alive) {\n setConfig(null);\n setConfigLoading(false);\n }\n }\n })();\n\n return () => { alive = false; };\n }, [useNewAPI, options.componentPath, repoFullName, apiBaseUrl]);\n\n // Fetch experiment decision\n useEffect(() => {\n if (!proposalId) return;\n if (useNewAPI && configLoading) return;\n\n let alive = true;\n const cached = readChoice(proposalId);\n\n if (cached) {\n setChoice({\n experiment_id: cached.experiment_id,\n label: cached.label,\n });\n } else {\n (async () => {\n try {\n const { experiment_id, label } = await fetchDecision(apiBaseUrl, proposalId);\n if (!alive) return;\n writeChoice(proposalId, experiment_id, label);\n setChoice({ experiment_id, label });\n } catch (e) {\n if (!alive) return;\n setChoice({\n experiment_id: `exp_${proposalId}`,\n label: \"control\",\n });\n }\n })();\n }\n\n return () => { alive = false; };\n }, [proposalId, apiBaseUrl, useNewAPI, configLoading]);\n\n // Track visit\n useEffect(() => {\n if (!proposalId) return;\n const lbl = choice?.label ?? \"control\";\n if (!lbl || hasTrackedVisit(proposalId, lbl)) return;\n markTrackedVisit(proposalId, lbl);\n void sendMetric(apiBaseUrl, proposalId, \"visit\", lbl, choice?.experiment_id);\n }, [proposalId, choice?.experiment_id, choice?.label, apiBaseUrl]);\n\n // 4. Callback hooks - always called\n const trackClick = useCallback(\n (event?: MouseEvent | null, opts?: { force?: boolean }) => {\n if (!proposalId) return false;\n const lbl = choice?.label ?? \"control\";\n const meta = extractClickMeta(event ?? undefined);\n if (!opts?.force && event && !meta) return false;\n void sendMetric(apiBaseUrl, proposalId, \"click\", lbl, undefined, meta);\n return true;\n },\n [proposalId, choice?.experiment_id, choice?.label, apiBaseUrl]\n );\n\n // ============================================================\n // NOW WE CAN DO CONDITIONAL RETURNS - AFTER ALL HOOKS\n // ============================================================\n\n // Loading state - return control\n if (useNewAPI && (configLoading || !config || !proposalId)) {\n return React.createElement(ControlComponent as any, props as any);\n }\n\n // No proposalId - return control\n if (!proposalId) {\n return React.createElement(ControlComponent as any, props as any);\n }\n\n // Build registry - always has control\n const registry: Record<string, React.ComponentType<any>> = { control: ControlComponent };\n\n if (useNewAPI && config?.variants) {\n for (const [key, value] of Object.entries(config.variants)) {\n if (key !== 'control' && value && typeof value === 'function') {\n registry[key] = value;\n }\n }\n } else if (!useNewAPI && options.registry) {\n for (const [key, value] of Object.entries(options.registry)) {\n if (key !== 'control' && value && typeof value === 'function') {\n registry[key] = value;\n }\n }\n }\n\n // Select variant\n const label = choice?.label ?? \"control\";\n const Variant = registry[label] || registry.control || ControlComponent;\n\n return (\n <div onClick={(event) => trackClick(event)} data-probat-proposal={proposalId}>\n {React.createElement(Variant, {\n key: `${proposalId}:${label}`,\n ...(props as any),\n probat: { trackClick: () => trackClick(null, { force: true }) },\n })}\n </div>\n );\n }\n\n Wrapped.displayName = `withExperiment(${Control.displayName || Control.name || \"Component\"})`;\n return Wrapped as any;\n}\n"]}
1
+ {"version":3,"sources":["../src/utils/environment.ts","../src/context/ProbatContext.tsx","../src/components/ProbatProviderClient.tsx","../src/utils/api.ts","../src/hooks/useProbatMetrics.ts","../src/utils/storage.ts","../src/hooks/useExperiment.ts","../src/hoc/withExperiment.tsx"],"names":["createContext","useMemo","useContext","React","VariantComponent","useCallback","useState","useEffect","meta","label"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Detect if the code is running on localhost (development environment).\n * Returns \"dev\" for localhost, \"prod\" for production.\n */\nexport function detectEnvironment(): \"dev\" | \"prod\" {\n if (typeof window === \"undefined\") {\n return \"prod\"; // Server-side, default to prod\n }\n\n const hostname = window.location.hostname;\n\n // Check for localhost, 127.0.0.1, or local IP addresses\n if (\n hostname === \"localhost\" ||\n hostname === \"127.0.0.1\" ||\n hostname === \"0.0.0.0\" ||\n hostname.startsWith(\"192.168.\") ||\n hostname.startsWith(\"10.\") ||\n hostname.startsWith(\"172.16.\") ||\n hostname.startsWith(\"172.17.\") ||\n hostname.startsWith(\"172.18.\") ||\n hostname.startsWith(\"172.19.\") ||\n hostname.startsWith(\"172.20.\") ||\n hostname.startsWith(\"172.21.\") ||\n hostname.startsWith(\"172.22.\") ||\n hostname.startsWith(\"172.23.\") ||\n hostname.startsWith(\"172.24.\") ||\n hostname.startsWith(\"172.25.\") ||\n hostname.startsWith(\"172.26.\") ||\n hostname.startsWith(\"172.27.\") ||\n hostname.startsWith(\"172.28.\") ||\n hostname.startsWith(\"172.29.\") ||\n hostname.startsWith(\"172.30.\") ||\n hostname.startsWith(\"172.31.\")\n ) {\n return \"dev\";\n }\n\n return \"prod\";\n}\n\n","\"use client\";\n\nimport React, { createContext, useContext, useMemo } from \"react\";\nimport { detectEnvironment } from \"../utils/environment\";\n\ndeclare global {\n interface Window {\n __PROBAT_API?: string;\n }\n}\n\nexport interface ProbatContextValue {\n apiBaseUrl: string;\n environment: \"dev\" | \"prod\";\n clientKey?: string;\n repoFullName?: string; // Repository full name (e.g., \"owner/repo\") for component-based experiments\n}\n\nconst ProbatContext = createContext<ProbatContextValue | null>(null);\n\nexport interface ProbatProviderProps {\n /**\n * The base URL for the Probat API.\n * If not provided, will try to read from:\n * - VITE_PROBAT_API (Vite)\n * - NEXT_PUBLIC_PROBAT_API (Next.js)\n * - window.__PROBAT_API\n * - Default: \"https://gushi.onrender.com\"\n */\n apiBaseUrl?: string;\n /**\n * Client key for identification (optional)\n */\n clientKey?: string;\n /**\n * Explicitly set environment. If not provided, will auto-detect based on hostname.\n * \"dev\" for localhost, \"prod\" for production.\n */\n environment?: \"dev\" | \"prod\";\n /**\n * Repository full name (e.g., \"owner/repo\") for component-based experiments.\n * If not provided, will try to read from:\n * - NEXT_PUBLIC_PROBAT_REPO (Next.js)\n * - VITE_PROBAT_REPO (Vite)\n * - window.__PROBAT_REPO\n */\n repoFullName?: string;\n children: React.ReactNode;\n}\n\nexport function ProbatProvider({\n apiBaseUrl,\n clientKey,\n environment: explicitEnvironment,\n repoFullName: explicitRepoFullName,\n children,\n}: ProbatProviderProps) {\n const contextValue = useMemo<ProbatContextValue>(() => {\n // Determine API base URL\n const resolvedApiBaseUrl =\n apiBaseUrl ||\n (typeof import.meta !== \"undefined\" &&\n (import.meta as any).env?.VITE_PROBAT_API) ||\n (typeof globalThis !== \"undefined\" &&\n (globalThis as any).process?.env?.NEXT_PUBLIC_PROBAT_API) ||\n (typeof window !== \"undefined\" && window.__PROBAT_API) ||\n \"https://gushi.onrender.com\";\n\n // Determine environment\n const environment = explicitEnvironment || detectEnvironment();\n\n // Determine repo full name\n const resolvedRepoFullName =\n explicitRepoFullName ||\n (typeof globalThis !== \"undefined\" &&\n (globalThis as any).process?.env?.NEXT_PUBLIC_PROBAT_REPO) ||\n (typeof import.meta !== \"undefined\" &&\n (import.meta as any).env?.VITE_PROBAT_REPO) ||\n (typeof window !== \"undefined\" && (window as any).__PROBAT_REPO) ||\n undefined;\n\n return {\n apiBaseUrl: resolvedApiBaseUrl,\n environment,\n clientKey,\n repoFullName: resolvedRepoFullName,\n };\n }, [apiBaseUrl, clientKey, explicitEnvironment, explicitRepoFullName]);\n\n return (\n <ProbatContext.Provider value={contextValue}>\n {children}\n </ProbatContext.Provider>\n );\n}\n\nexport function useProbatContext(): ProbatContextValue {\n const context = useContext(ProbatContext);\n if (!context) {\n throw new Error(\n \"useProbatContext must be used within a ProbatProvider. Please wrap your app with <ProbatProvider>.\"\n );\n }\n return context;\n}\n\n","\"use client\";\n\nimport React from \"react\";\nimport { ProbatProvider as BaseProbatProvider } from \"../context/ProbatContext\";\nimport type { ProbatProviderProps } from \"../context/ProbatContext\";\n\n/**\n * ProbatProviderClient - Can be imported directly in Next.js Server Components\n * This is a re-export with \"use client\" directive to ensure it works in Server Components\n */\nexport function ProbatProviderClient(props: ProbatProviderProps) {\n return React.createElement(BaseProbatProvider, props);\n}\n\n// Also export as ProbatProvider for convenience\nexport { ProbatProviderClient as ProbatProvider };\nexport type { ProbatProviderProps };\n\n","import React from \"react\";\nimport { detectEnvironment } from \"./environment\";\n\nexport type RetrieveResponse = {\n proposal_id: string;\n experiment_id: string | null;\n label: string | null;\n};\n\nexport type ComponentVariantInfo = {\n experiment_id: string;\n label: string;\n file_path: string | null;\n};\n\nexport type ComponentExperimentConfig = {\n proposal_id: string;\n repo_full_name: string;\n base_ref?: string; // Git branch/ref (default: \"main\")\n variants: Record<string, ComponentVariantInfo>;\n};\n\n// Shared promise cache to prevent multiple simultaneous API calls for the same proposal\nconst pendingFetches = new Map<\n string,\n Promise<{ experiment_id: string; label: string }>\n>();\n\nexport async function fetchDecision(\n baseUrl: string,\n proposalId: string\n): Promise<{ experiment_id: string; label: string }> {\n // Check if there's already a pending fetch for this proposal\n const existingFetch = pendingFetches.get(proposalId);\n if (existingFetch) {\n return existingFetch;\n }\n\n // Create new fetch promise\n const fetchPromise = (async () => {\n try {\n const url = `${baseUrl.replace(/\\/$/, \"\")}/retrieve_react_experiment/${encodeURIComponent(proposalId)}`;\n const res = await fetch(url, {\n method: \"POST\",\n headers: { Accept: \"application/json\" },\n credentials: \"include\", // Include cookies for user identification\n });\n if (!res.ok) throw new Error(`HTTP ${res.status}`);\n const data = (await res.json()) as RetrieveResponse;\n\n const experiment_id = (data.experiment_id || `exp_${proposalId}`).toString();\n const label = data.label && data.label.trim() ? data.label : \"control\";\n\n return { experiment_id, label };\n } finally {\n // Remove from pending cache after completion\n pendingFetches.delete(proposalId);\n }\n })();\n\n // Store the promise so other components can wait for the same call\n pendingFetches.set(proposalId, fetchPromise);\n return fetchPromise;\n}\n\nexport async function sendMetric(\n baseUrl: string,\n proposalId: string,\n metricName: \"visit\" | \"click\" | string,\n variantLabel: string = \"control\",\n experimentId?: string,\n dimensions: Record<string, any> = {}\n) {\n const url = `${baseUrl.replace(/\\/$/, \"\")}/send_metrics/${encodeURIComponent(proposalId)}`;\n const body = {\n experiment_id: experimentId ?? null,\n variant_label: variantLabel,\n metric_name: metricName,\n metric_value: 1,\n metric_unit: \"count\",\n source: \"react\",\n environment: detectEnvironment(), // Include environment (dev or prod)\n dimensions,\n captured_at: new Date().toISOString(),\n };\n try {\n await fetch(url, {\n method: \"POST\",\n headers: {\n Accept: \"application/json\",\n \"Content-Type\": \"application/json\",\n },\n credentials: \"include\", // CRITICAL: Include cookies to distinguish different users\n body: JSON.stringify(body),\n });\n } catch {\n // Silently fail - metrics should not break the app\n }\n}\n\nexport function extractClickMeta(\n event?: { target?: EventTarget | null } | null\n): Record<string, any> | undefined {\n if (!event || !event.target) return undefined;\n const rawTarget = event.target as HTMLElement | null;\n if (!rawTarget) return undefined;\n const actionable = rawTarget.closest(\n \"[data-probat-conversion='true'], button, a, [role='button']\"\n );\n if (!actionable) return undefined;\n const meta: Record<string, any> = {\n target_tag: actionable.tagName,\n };\n if (actionable.id) meta.target_id = actionable.id;\n const attr = actionable.getAttribute(\"data-probat-conversion\");\n if (attr) meta.conversion_attr = attr;\n const text = actionable.textContent?.trim();\n if (text) meta.target_text = text.slice(0, 120);\n return meta;\n}\n\n// Cache for component config fetches\nconst componentConfigCache = new Map<\n string,\n Promise<ComponentExperimentConfig | null>\n>();\n\nexport async function fetchComponentExperimentConfig(\n baseUrl: string,\n repoFullName: string,\n componentPath: string\n): Promise<ComponentExperimentConfig | null> {\n const cacheKey = `${repoFullName}:${componentPath}`;\n\n // Check cache\n const existingFetch = componentConfigCache.get(cacheKey);\n if (existingFetch) {\n return existingFetch;\n }\n\n // Create new fetch promise\n const fetchPromise = (async () => {\n try {\n const url = new URL(`${baseUrl.replace(/\\/$/, \"\")}/get_component_experiment_config`);\n url.searchParams.set(\"repo_full_name\", repoFullName);\n url.searchParams.set(\"component_path\", componentPath);\n\n const res = await fetch(url.toString(), {\n method: \"GET\",\n headers: { Accept: \"application/json\" },\n credentials: \"include\",\n });\n\n if (res.status === 404) {\n // No experiments for this component - return null\n return null;\n }\n\n if (!res.ok) {\n throw new Error(`HTTP ${res.status}`);\n }\n\n const data = (await res.json()) as ComponentExperimentConfig;\n return data;\n } catch (e) {\n console.warn(`[PROBAT] Failed to fetch component config: ${e}`);\n return null;\n } finally {\n // Remove from cache after completion\n componentConfigCache.delete(cacheKey);\n }\n })();\n\n // Store the promise\n componentConfigCache.set(cacheKey, fetchPromise);\n return fetchPromise;\n}\n\n// Cache for variant component loads\nconst variantComponentCache = new Map<string, Promise<React.ComponentType<any> | null>>();\nconst moduleCache = new Map<string, any>(); // Cache for loaded modules (relative imports)\n\n// Make React available globally for variant components\nif (typeof window !== \"undefined\") {\n (window as any).__probatReact = React;\n (window as any).React = (window as any).React || React;\n}\n\n/**\n * Resolve relative import path to absolute path\n */\nfunction resolveRelativePath(relativePath: string, basePath: string): string {\n // Remove file extension if present\n const baseDir = basePath.substring(0, basePath.lastIndexOf('/'));\n const parts = baseDir.split('/').filter(Boolean);\n const relativeParts = relativePath.split('/').filter(Boolean);\n\n for (const part of relativeParts) {\n if (part === '..') {\n parts.pop();\n } else if (part !== '.') {\n parts.push(part);\n }\n }\n\n return '/' + parts.join('/');\n}\n\n/**\n * Fetch and compile a module from absolute path\n */\nasync function loadRelativeModule(\n absolutePath: string,\n baseFilePath: string,\n repoFullName?: string,\n baseRef?: string\n): Promise<any> {\n const cacheKey = `${baseFilePath}:${absolutePath}`;\n if (moduleCache.has(cacheKey)) {\n return moduleCache.get(cacheKey);\n }\n\n // Try to determine file extension\n const extensions = ['.jsx', '.tsx', '.js', '.ts'];\n let moduleCode: string | null = null;\n let modulePath: string | null = null;\n\n // Try each extension\n for (const ext of extensions) {\n const testPath = absolutePath + (absolutePath.includes('.') ? '' : ext);\n\n // Try local first\n try {\n const localRes = await fetch(testPath, {\n method: \"GET\",\n headers: { Accept: \"text/plain\" },\n });\n if (localRes.ok) {\n moduleCode = await localRes.text();\n modulePath = testPath;\n break;\n }\n } catch {\n // Continue to next extension or GitHub\n }\n\n // Try GitHub if local failed\n if (!moduleCode && repoFullName) {\n try {\n const githubPath = testPath.startsWith('/') ? testPath.substring(1) : testPath;\n const githubUrl = `https://raw.githubusercontent.com/${repoFullName}/${baseRef || 'main'}/${githubPath}`;\n const res = await fetch(githubUrl, { method: \"GET\", headers: { Accept: \"text/plain\" } });\n if (res.ok) {\n moduleCode = await res.text();\n modulePath = testPath;\n break;\n }\n } catch {\n // Continue\n }\n }\n }\n\n if (!moduleCode || !modulePath) {\n throw new Error(`Could not resolve module: ${absolutePath} from ${baseFilePath}`);\n }\n\n // Compile the module\n let Babel: any;\n if (typeof window !== \"undefined\" && (window as any).Babel) {\n Babel = (window as any).Babel;\n } else {\n try {\n // @ts-ignore\n const babelModule = await import(\"@babel/standalone\");\n Babel = babelModule.default || babelModule;\n } catch {\n throw new Error(\"Babel not available for compiling relative import\");\n }\n }\n\n // Preprocess module code\n let processedCode = moduleCode;\n processedCode = processedCode.replace(/^import\\s+['\"].*\\.css['\"];?\\s*$/gm, \"\");\n processedCode = processedCode.replace(/^import\\s+React\\s+from\\s+['\"]react['\"];?\\s*$/m, \"const React = window.React || globalThis.React;\");\n processedCode = processedCode.replace(/import\\.meta\\.env\\.[\\w$]+/g, \"undefined\");\n processedCode = processedCode.replace(/\\bimport\\.meta\\b/g, \"({})\");\n\n const isTSX = modulePath.endsWith(\".tsx\");\n const compiled = Babel.transform(processedCode, {\n presets: [\n [\"react\", { runtime: \"classic\" }],\n [\"typescript\", { allExtensions: true, isTSX }],\n ],\n plugins: [[\"transform-modules-commonjs\", { allowTopLevelThis: true }]],\n sourceType: \"module\",\n filename: modulePath,\n }).code;\n\n // Execute compiled module\n const moduleCodeWrapper = `\n var require = function(name) {\n if (name === \"react\" || name === \"react/jsx-runtime\") {\n return window.React || globalThis.React;\n }\n if (name.startsWith(\"/@vite\") || name.includes(\"@vite/client\")) {\n return {};\n }\n throw new Error(\"Unsupported module in relative import: \" + name);\n };\n var module = { exports: {} };\n var exports = module.exports;\n ${compiled}\n return module.exports;\n `;\n\n const moduleExports = new Function(moduleCodeWrapper)();\n moduleCache.set(cacheKey, moduleExports);\n return moduleExports;\n}\n\nexport async function loadVariantComponent(\n baseUrl: string,\n proposalId: string,\n experimentId: string,\n filePath: string | null,\n repoFullName?: string,\n baseRef?: string\n): Promise<React.ComponentType<any> | null> {\n if (!filePath) {\n return null;\n }\n\n const cacheKey = `${proposalId}:${experimentId}`;\n\n // Check cache\n const existingLoad = variantComponentCache.get(cacheKey);\n if (existingLoad) {\n return existingLoad;\n }\n\n // Create new load promise\n const loadPromise = (async () => {\n try {\n // ============================================\n // Hybrid approach: Dynamic import for CSR (Vite), fetch+babel for SSR (Next.js)\n // ============================================\n let code: string = \"\";\n let rawCode: string = \"\";\n let rawCodeFetched = false;\n\n // Try dynamic import first (works great for Vite/CSR, resolves relative imports automatically)\n // Only attempt in browser and not during Next.js server-side compilation\n const isBrowser = typeof window !== \"undefined\";\n const isNextJSServer = typeof window === \"undefined\" ||\n (typeof (globalThis as any).process !== \"undefined\" && (globalThis as any).process.env?.NEXT_RUNTIME === \"nodejs\");\n\n if (isBrowser && !isNextJSServer) {\n try {\n const variantUrl = `/probat/${filePath}`;\n // Use dynamic import - Vite can resolve relative imports automatically\n const mod = await import(/* @vite-ignore */ variantUrl);\n const VariantComponent = (mod as any)?.default || mod;\n if (VariantComponent && typeof VariantComponent === \"function\") {\n console.log(`[PROBAT] ✅ Loaded variant via dynamic import (CSR): ${variantUrl}`);\n return VariantComponent as React.ComponentType<any>;\n }\n } catch (dynamicImportError) {\n // Dynamic import failed (might be Next.js or other issue), fall through to fetch+babel\n console.debug(`[PROBAT] Dynamic import failed, using fetch+babel:`, dynamicImportError);\n }\n }\n\n // Fallback: fetch + babel compilation (works for Next.js SSR and when dynamic import fails)\n const localUrl = `/probat/${filePath}`;\n try {\n const localRes = await fetch(localUrl, {\n method: \"GET\",\n headers: { Accept: \"text/plain\" },\n });\n if (localRes.ok) {\n rawCode = await localRes.text();\n rawCodeFetched = true;\n console.log(`[PROBAT] ✅ Loaded variant from local (user's repo): ${localUrl}`);\n }\n } catch {\n console.debug(`[PROBAT] Local file not available (${localUrl}), trying GitHub...`);\n }\n\n if (!rawCodeFetched && repoFullName) {\n const githubPath = `probat/${filePath}`;\n const gitRef = baseRef || \"main\";\n const githubUrl = `https://raw.githubusercontent.com/${repoFullName}/${gitRef}/${githubPath}`;\n const res = await fetch(githubUrl, { method: \"GET\", headers: { Accept: \"text/plain\" } });\n if (res.ok) {\n rawCode = await res.text();\n rawCodeFetched = true;\n console.log(`[PROBAT] ⚠️ Loaded variant from GitHub (fallback): ${githubUrl}`);\n } else {\n console.warn(`[PROBAT] ⚠️ GitHub fetch failed (${res.status}), falling back to server compilation`);\n }\n }\n\n if (rawCodeFetched && rawCode) {\n let Babel: any;\n if (typeof window !== \"undefined\" && (window as any).Babel) {\n Babel = (window as any).Babel;\n } else {\n try {\n // @ts-ignore\n const babelModule = await import(\"@babel/standalone\");\n Babel = babelModule.default || babelModule;\n } catch (importError) {\n try {\n await new Promise<void>((resolve, reject) => {\n if (typeof document === \"undefined\") {\n reject(new Error(\"Document not available\"));\n return;\n }\n if ((window as any).Babel) {\n Babel = (window as any).Babel;\n resolve();\n return;\n }\n const script = document.createElement(\"script\");\n script.src = \"https://unpkg.com/@babel/standalone/babel.min.js\";\n script.async = true;\n script.onload = () => {\n Babel = (window as any).Babel;\n if (!Babel) reject(new Error(\"Babel not found after script load\"));\n else resolve();\n };\n script.onerror = () => reject(new Error(\"Failed to load Babel from CDN\"));\n document.head.appendChild(script);\n });\n } catch (babelError) {\n console.error(\"[PROBAT] Failed to load Babel, falling back to server compilation\", babelError);\n rawCodeFetched = false;\n }\n }\n }\n\n if (rawCodeFetched && rawCode && Babel) {\n const isTSX = filePath.endsWith(\".tsx\");\n rawCode = rawCode.replace(/^import\\s+['\"].*\\.css['\"];?\\s*$/gm, \"\");\n rawCode = rawCode.replace(/^import\\s+.*from\\s+['\"].*\\.css['\"];?\\s*$/gm, \"\");\n rawCode = rawCode.replace(\n /^import\\s+React(?:\\s*,\\s*\\{[^}]*\\})?\\s+from\\s+['\"]react['\"];?\\s*$/m,\n \"const React = window.React || globalThis.React;\"\n );\n rawCode = rawCode.replace(\n /^import\\s+\\*\\s+as\\s+React\\s+from\\s+['\"]react['\"];?\\s*$/m,\n \"const React = window.React || globalThis.React;\"\n );\n rawCode = rawCode.replace(\n /^import\\s+\\{([^}]+)\\}\\s+from\\s+['\"]react['\"];?\\s*$/m,\n (match, imports) => `const {${imports}} = window.React || globalThis.React;`\n );\n rawCode = rawCode.replace(/import\\.meta\\.env\\.[\\w$]+/g, \"undefined\");\n rawCode = rawCode.replace(/\\bimport\\.meta\\b/g, \"({})\");\n rawCode = rawCode.replace(/^import\\s+.*\\/@vite\\/client.*$/gm, \"\");\n rawCode = rawCode.replace(/import\\.meta\\.hot(?:\\.[\\w$]+)*/g, \"undefined\");\n\n // Preprocess relative imports: convert to absolute paths that can be fetched\n // This allows the require shim to fetch them later\n const relativeImportMap = new Map<string, string>();\n rawCode = rawCode.replace(\n /^import\\s+(\\w+)\\s+from\\s+['\"](\\.\\.?\\/[^'\"]+)['\"];?\\s*$/gm,\n (match, importName, relativePath) => {\n // Resolve relative path to absolute\n const baseDir = filePath.substring(0, filePath.lastIndexOf('/'));\n const resolvedPath = resolveRelativePath(relativePath, baseDir);\n // Try to find the file with extension\n const absolutePath = resolvedPath.startsWith('/') ? resolvedPath : '/' + resolvedPath;\n relativeImportMap.set(importName, absolutePath);\n // Replace with absolute path import - Babel will compile this to require()\n return `import ${importName} from \"${absolutePath}\";`;\n }\n );\n\n const compiled = Babel.transform(rawCode, {\n presets: [\n [\"react\", { runtime: \"classic\" }],\n [\"typescript\", { allExtensions: true, isTSX }],\n ],\n plugins: [[\"transform-modules-commonjs\", { allowTopLevelThis: true }]],\n sourceType: \"module\",\n filename: filePath,\n }).code;\n\n // Pre-load relative imports if any\n const relativeModules: Record<string, any> = {};\n if (relativeImportMap.size > 0) {\n for (const [importName, absolutePath] of relativeImportMap.entries()) {\n try {\n const moduleExports = await loadRelativeModule(absolutePath, filePath, repoFullName, baseRef);\n relativeModules[absolutePath] = moduleExports.default || moduleExports;\n } catch (err) {\n console.warn(`[PROBAT] Failed to load relative import ${absolutePath}:`, err);\n relativeModules[absolutePath] = null;\n }\n }\n }\n\n // Build require shim that can resolve relative imports\n const relativeModulesJson = JSON.stringify(relativeModules);\n code = `\n var __probatVariant = (function() {\n var relativeModules = ${relativeModulesJson};\n var require = function(name) {\n if (name === \"react\" || name === \"react/jsx-runtime\") {\n return window.React || globalThis.React;\n }\n if (name.startsWith(\"/@vite\") || name.includes(\"@vite/client\") || name.includes(\".vite/deps\")) {\n return {};\n }\n if (name === \"react/jsx-runtime.js\") {\n return window.React || globalThis.React;\n }\n // Handle relative imports (now converted to absolute paths)\n if (name.startsWith(\"/\") && relativeModules.hasOwnProperty(name)) {\n var mod = relativeModules[name];\n if (mod === null) {\n throw new Error(\"Failed to load module: \" + name);\n }\n return mod;\n }\n throw new Error(\"Unsupported module: \" + name);\n };\n var module = { exports: {} };\n var exports = module.exports;\n ${compiled}\n return module.exports.default || module.exports;\n })();\n `;\n } else {\n rawCodeFetched = false;\n code = \"\";\n }\n }\n\n if (!rawCodeFetched || code === \"\") {\n const variantUrl = `${baseUrl.replace(/\\/$/, \"\")}/variants/${filePath}`;\n const serverRes = await fetch(variantUrl, {\n method: \"GET\",\n headers: { Accept: \"text/javascript\" },\n credentials: \"include\",\n });\n if (!serverRes.ok) {\n throw new Error(`HTTP ${serverRes.status}`);\n }\n code = await serverRes.text();\n }\n\n if (typeof window !== \"undefined\") {\n (window as any).React = (window as any).React || React;\n }\n\n const evalFunc = new Function(`\n var __probatVariant;\n ${code}\n return __probatVariant;\n `);\n\n const result = evalFunc();\n const VariantComponent = result?.default || result;\n if (typeof VariantComponent === \"function\") {\n return VariantComponent as React.ComponentType<any>;\n }\n\n console.warn(\"[PROBAT] Variant component is not a function\", result);\n return null;\n } catch (e) {\n console.warn(`[PROBAT] Failed to load variant component: ${e}`);\n return null;\n } finally {\n // Remove from cache after completion\n variantComponentCache.delete(cacheKey);\n }\n })();\n\n // Store the promise\n variantComponentCache.set(cacheKey, loadPromise);\n return loadPromise;\n}\n\n","\"use client\";\n\nimport { useCallback } from \"react\";\nimport type { MouseEvent } from \"react\";\nimport { useProbatContext } from \"../context/ProbatContext\";\nimport { sendMetric, extractClickMeta } from \"../utils/api\";\n\nexport interface UseProbatMetricsReturn {\n /**\n * Track a click event\n * @param event - Optional React mouse event (will extract metadata automatically)\n * @param options - Optional configuration\n * @param options.force - Force tracking even if no actionable element is found\n * @param options.proposalId - Override the proposal ID (usually not needed)\n * @param options.variantLabel - Override the variant label (usually not needed)\n * @param options.dimensions - Additional dimensions to include\n */\n trackClick: (\n event?: MouseEvent | null,\n options?: {\n force?: boolean;\n proposalId?: string;\n variantLabel?: string;\n dimensions?: Record<string, any>;\n }\n ) => boolean;\n /**\n * Track a custom metric\n * @param metricName - Name of the metric\n * @param proposalId - Proposal ID\n * @param variantLabel - Variant label (defaults to \"control\")\n * @param dimensions - Additional dimensions\n */\n trackMetric: (\n metricName: string,\n proposalId: string,\n variantLabel?: string,\n dimensions?: Record<string, any>\n ) => void;\n /**\n * Track an impression/view\n * @param proposalId - Proposal ID\n * @param variantLabel - Variant label (defaults to \"control\")\n * @param experimentId - Optional experiment ID\n */\n trackImpression: (\n proposalId: string,\n variantLabel?: string,\n experimentId?: string\n ) => void;\n}\n\n/**\n * Hook for tracking Probat metrics (clicks, impressions, custom metrics)\n *\n * @example\n * ```tsx\n * const { trackClick, trackImpression } = useProbatMetrics();\n *\n * // Track click on button\n * <button onClick={(e) => trackClick(e)}>Click me</button>\n *\n * // Track impression\n * useEffect(() => {\n * trackImpression(proposalId, variantLabel, experimentId);\n * }, [proposalId, variantLabel, experimentId]);\n * ```\n */\nexport function useProbatMetrics(): UseProbatMetricsReturn {\n const { apiBaseUrl } = useProbatContext();\n\n const trackClick = useCallback(\n (\n event?: MouseEvent | null,\n options?: {\n force?: boolean;\n proposalId?: string;\n variantLabel?: string;\n dimensions?: Record<string, any>;\n }\n ) => {\n const meta = extractClickMeta(event ?? undefined);\n if (!options?.force && event && !meta) {\n return false;\n }\n\n const proposalId = options?.proposalId;\n const variantLabel = options?.variantLabel || \"control\";\n\n if (!proposalId) {\n console.warn(\n \"[Probat] trackClick called without proposalId. Provide it in options or use useExperiment hook.\"\n );\n return false;\n }\n\n void sendMetric(\n apiBaseUrl,\n proposalId,\n \"click\",\n variantLabel,\n undefined,\n { ...meta, ...options?.dimensions }\n );\n return true;\n },\n [apiBaseUrl]\n );\n\n const trackMetric = useCallback(\n (\n metricName: string,\n proposalId: string,\n variantLabel: string = \"control\",\n dimensions: Record<string, any> = {}\n ) => {\n void sendMetric(\n apiBaseUrl,\n proposalId,\n metricName,\n variantLabel,\n undefined,\n dimensions\n );\n },\n [apiBaseUrl]\n );\n\n const trackImpression = useCallback(\n (\n proposalId: string,\n variantLabel: string = \"control\",\n experimentId?: string\n ) => {\n void sendMetric(\n apiBaseUrl,\n proposalId,\n \"visit\",\n variantLabel,\n experimentId\n );\n },\n [apiBaseUrl]\n );\n\n return {\n trackClick,\n trackMetric,\n trackImpression,\n };\n}\n\n","const TTL_MS = 6 * 60 * 60 * 1000; // 6 hours\n\nexport type Choice = {\n experiment_id: string;\n label: string;\n ts: number;\n};\n\nexport function safeGet(k: string): any | null {\n try {\n const raw = localStorage.getItem(k);\n return raw ? JSON.parse(raw) : null;\n } catch {\n return null;\n }\n}\n\nexport function safeSet(k: string, v: any) {\n try {\n localStorage.setItem(k, JSON.stringify(v));\n } catch { }\n}\n\nexport function now() {\n return Date.now();\n}\n\nexport function fresh(ts: number) {\n return now() - ts <= TTL_MS;\n}\n\nexport const KEY = (proposalId: string) => `probat_choice_v3:${proposalId}`;\nexport const VISIT_KEY = (proposalId: string, label: string) =>\n `probat_visit_v1:${proposalId}:${label}`;\n\nexport function readChoice(proposalId: string): Choice | null {\n const c = safeGet(KEY(proposalId)) as Choice | null;\n return c && fresh(c.ts) ? c : null;\n}\n\nexport function writeChoice(\n proposalId: string,\n experiment_id: string,\n label: string\n) {\n safeSet(KEY(proposalId), { experiment_id, label, ts: now() } as Choice);\n}\n\nconst visitMemo = new Set<string>();\n\nexport function hasTrackedVisit(proposalId: string, label: string): boolean {\n const key = VISIT_KEY(proposalId, label);\n if (visitMemo.has(key)) return true;\n try {\n const raw = localStorage.getItem(key);\n if (!raw) return false;\n const ts = Number(raw);\n if (!Number.isFinite(ts) || ts <= 0) return false;\n if (now() - ts > TTL_MS) {\n localStorage.removeItem(key);\n return false;\n }\n visitMemo.add(key);\n return true;\n } catch {\n return false;\n }\n}\n\nexport function markTrackedVisit(proposalId: string, label: string) {\n const key = VISIT_KEY(proposalId, label);\n visitMemo.add(key);\n try {\n localStorage.setItem(key, now().toString());\n } catch { }\n}\n\n","\"use client\";\n\nimport { useState, useEffect, useCallback } from \"react\";\nimport type { MouseEvent } from \"react\";\nimport { useProbatContext } from \"../context/ProbatContext\";\nimport { fetchDecision } from \"../utils/api\";\nimport {\n readChoice,\n writeChoice,\n hasTrackedVisit,\n markTrackedVisit,\n} from \"../utils/storage\";\nimport { sendMetric } from \"../utils/api\";\n\nexport interface UseExperimentReturn {\n /**\n * The current variant label (e.g., \"control\", \"variant-a\")\n */\n variantLabel: string;\n /**\n * The experiment ID\n */\n experimentId: string | null;\n /**\n * Whether the experiment decision is still loading\n */\n isLoading: boolean;\n /**\n * Any error that occurred while fetching the experiment\n */\n error: Error | null;\n /**\n * Manually track a click for this experiment\n */\n trackClick: (event?: MouseEvent | null) => void;\n}\n\n/**\n * Hook for fetching and applying experiment variants\n *\n * @param proposalId - The proposal ID for the experiment\n * @param options - Optional configuration\n * @param options.autoTrackImpression - Automatically track impression when variant is loaded (default: true)\n *\n * @example\n * ```tsx\n * const { variantLabel, isLoading, trackClick } = useExperiment(\"proposal-id\");\n *\n * if (isLoading) return <div>Loading...</div>;\n *\n * return (\n * <div onClick={trackClick}>\n * {variantLabel === \"control\" ? <ControlComponent /> : <VariantComponent />}\n * </div>\n * );\n * ```\n */\nexport function useExperiment(\n proposalId: string,\n options?: { autoTrackImpression?: boolean }\n): UseExperimentReturn {\n const { apiBaseUrl } = useProbatContext();\n const [choice, setChoice] = useState<{\n experiment_id: string;\n label: string;\n } | null>(null);\n const [isLoading, setIsLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n\n const autoTrackImpression = options?.autoTrackImpression !== false;\n\n // Fetch experiment decision\n useEffect(() => {\n let alive = true;\n\n const cached = readChoice(proposalId);\n if (cached) {\n setChoice({ experiment_id: cached.experiment_id, label: cached.label });\n setIsLoading(false);\n } else {\n setIsLoading(true);\n (async () => {\n try {\n const { experiment_id, label } = await fetchDecision(\n apiBaseUrl,\n proposalId\n );\n if (!alive) return;\n writeChoice(proposalId, experiment_id, label);\n setChoice({ experiment_id, label });\n setError(null);\n } catch (e) {\n if (!alive) return;\n const err = e instanceof Error ? e : new Error(String(e));\n setError(err);\n setChoice({\n experiment_id: `exp_${proposalId}`,\n label: \"control\",\n });\n } finally {\n if (alive) {\n setIsLoading(false);\n }\n }\n })();\n }\n\n return () => {\n alive = false;\n };\n }, [proposalId, apiBaseUrl]);\n\n // Track impression when variant is determined\n useEffect(() => {\n if (!autoTrackImpression || !choice) return;\n\n const exp = choice.experiment_id;\n const lbl = choice.label ?? \"control\";\n if (!lbl) return;\n\n // Only track if we haven't already tracked this visit\n if (hasTrackedVisit(proposalId, lbl)) return;\n markTrackedVisit(proposalId, lbl);\n void sendMetric(apiBaseUrl, proposalId, \"visit\", lbl, exp);\n }, [proposalId, choice?.experiment_id, choice?.label, apiBaseUrl, autoTrackImpression]);\n\n const trackClick = useCallback(\n (event?: MouseEvent | null) => {\n const exp = choice?.experiment_id;\n const lbl = choice?.label ?? \"control\";\n const meta = event\n ? (() => {\n const rawTarget = event.target as HTMLElement | null;\n if (!rawTarget) return undefined;\n const actionable = rawTarget.closest(\n \"[data-probat-conversion='true'], button, a, [role='button']\"\n );\n if (!actionable) return undefined;\n const meta: Record<string, any> = {\n target_tag: actionable.tagName,\n };\n if (actionable.id) meta.target_id = actionable.id;\n const attr = actionable.getAttribute(\"data-probat-conversion\");\n if (attr) meta.conversion_attr = attr;\n const text = actionable.textContent?.trim();\n if (text) meta.target_text = text.slice(0, 120);\n return meta;\n })()\n : undefined;\n\n void sendMetric(apiBaseUrl, proposalId, \"click\", lbl, undefined, meta);\n },\n [proposalId, choice?.experiment_id, choice?.label, apiBaseUrl]\n );\n\n return {\n variantLabel: choice?.label ?? \"control\",\n experimentId: choice?.experiment_id ?? null,\n isLoading,\n error,\n trackClick,\n };\n}\n\n","\"use client\";\n\nimport React, { useState, useEffect, useCallback } from \"react\";\nimport type { MouseEvent } from \"react\";\nimport { useProbatContext } from \"../context/ProbatContext\";\nimport {\n fetchDecision,\n fetchComponentExperimentConfig,\n loadVariantComponent,\n sendMetric,\n extractClickMeta,\n} from \"../utils/api\";\nimport {\n readChoice,\n writeChoice,\n hasTrackedVisit,\n markTrackedVisit,\n} from \"../utils/storage\";\n\n// Support both old and new API for backward compatibility\nexport interface WithExperimentOptions {\n // New API: component-based\n componentPath?: string;\n repoFullName?: string;\n\n // Old API: direct proposal/registry (for backward compatibility)\n proposalId?: string;\n registry?: Record<string, React.ComponentType<any>>;\n}\n\n/**\n * Higher-Order Component for wrapping components with experiment variants\n */\nexport function withExperiment<P = any>(\n Control: React.ComponentType<P>,\n options: WithExperimentOptions\n): React.ComponentType<P & { probat?: { trackClick: () => void } }> {\n // Validate inputs at HOC level (not in component)\n if (!Control) {\n console.error(\"[PROBAT] withExperiment: Control component is required\");\n return ((props: P) => null) as any;\n }\n\n if (!options || typeof options !== 'object') {\n console.error(\"[PROBAT] withExperiment: options is required\");\n return Control as any;\n }\n\n const useNewAPI = !!options.componentPath;\n const useOldAPI = !!(options.proposalId && options.registry);\n\n if (!useNewAPI && !useOldAPI) {\n console.warn(\"[PROBAT] withExperiment: Invalid config, returning Control\");\n return Control as any;\n }\n\n const ControlComponent = Control;\n\n function Wrapped(props: P) {\n // ============================================================\n // ALL HOOKS MUST BE AT THE TOP - BEFORE ANY CONDITIONAL RETURNS\n // ============================================================\n\n // 1. Context hook - always called first\n const context = useProbatContext();\n const apiBaseUrl = context?.apiBaseUrl || \"https://gushi.onrender.com\";\n const contextRepoFullName = context?.repoFullName;\n\n // 2. State hooks - always called in same order\n const [config, setConfig] = useState<{\n proposalId: string;\n variants: Record<string, React.ComponentType<any>>;\n } | null>(null);\n const [configLoading, setConfigLoading] = useState(useNewAPI);\n const [choice, setChoice] = useState<{\n experiment_id: string;\n label: string;\n } | null>(null);\n\n // Derived values\n const repoFullName = options.repoFullName || contextRepoFullName;\n const proposalId = useNewAPI ? config?.proposalId : options.proposalId;\n\n // 3. Effect hooks - always called\n // Load component config (new API)\n useEffect(() => {\n if (!useNewAPI) return;\n if (!repoFullName) {\n console.warn(\"[PROBAT] componentPath provided but repoFullName not found\");\n setConfigLoading(false);\n return;\n }\n\n let alive = true;\n setConfigLoading(true);\n\n (async () => {\n try {\n const componentConfig = await fetchComponentExperimentConfig(\n apiBaseUrl,\n repoFullName,\n options.componentPath!\n );\n\n if (!alive) return;\n\n if (!componentConfig) {\n setConfig(null);\n setConfigLoading(false);\n return;\n }\n\n const variantComponents: Record<string, React.ComponentType<any>> = {\n control: ControlComponent,\n };\n\n for (const [label, variantInfo] of Object.entries(componentConfig.variants)) {\n if (label === \"control\") continue;\n if (variantInfo?.file_path) {\n try {\n const VariantComp = await loadVariantComponent(\n apiBaseUrl,\n componentConfig.proposal_id,\n variantInfo.experiment_id,\n variantInfo.file_path,\n componentConfig.repo_full_name,\n componentConfig.base_ref\n );\n if (VariantComp && typeof VariantComp === 'function' && alive) {\n variantComponents[label] = VariantComp;\n }\n } catch (e) {\n console.warn(`[PROBAT] Failed to load variant ${label}:`, e);\n }\n }\n }\n\n if (alive) {\n setConfig({\n proposalId: componentConfig.proposal_id,\n variants: variantComponents,\n });\n setConfigLoading(false);\n }\n } catch (e) {\n console.warn(\"[PROBAT] Failed to load component config:\", e);\n if (alive) {\n setConfig(null);\n setConfigLoading(false);\n }\n }\n })();\n\n return () => { alive = false; };\n }, [useNewAPI, options.componentPath, repoFullName, apiBaseUrl]);\n\n // Fetch experiment decision\n useEffect(() => {\n if (!proposalId) return;\n if (useNewAPI && configLoading) return;\n\n let alive = true;\n const cached = readChoice(proposalId);\n\n if (cached) {\n setChoice({\n experiment_id: cached.experiment_id,\n label: cached.label,\n });\n } else {\n (async () => {\n try {\n const { experiment_id, label } = await fetchDecision(apiBaseUrl, proposalId);\n if (!alive) return;\n writeChoice(proposalId, experiment_id, label);\n setChoice({ experiment_id, label });\n } catch (e) {\n if (!alive) return;\n setChoice({\n experiment_id: `exp_${proposalId}`,\n label: \"control\",\n });\n }\n })();\n }\n\n return () => { alive = false; };\n }, [proposalId, apiBaseUrl, useNewAPI, configLoading]);\n\n // Track visit\n useEffect(() => {\n if (!proposalId) return;\n const lbl = choice?.label ?? \"control\";\n if (!lbl || hasTrackedVisit(proposalId, lbl)) return;\n markTrackedVisit(proposalId, lbl);\n void sendMetric(apiBaseUrl, proposalId, \"visit\", lbl, choice?.experiment_id);\n }, [proposalId, choice?.experiment_id, choice?.label, apiBaseUrl]);\n\n // 4. Callback hooks - always called\n const trackClick = useCallback(\n (event?: MouseEvent | null, opts?: { force?: boolean }) => {\n if (!proposalId) return false;\n const lbl = choice?.label ?? \"control\";\n const meta = extractClickMeta(event ?? undefined);\n if (!opts?.force && event && !meta) return false;\n void sendMetric(apiBaseUrl, proposalId, \"click\", lbl, undefined, meta);\n return true;\n },\n [proposalId, choice?.experiment_id, choice?.label, apiBaseUrl]\n );\n\n // ============================================================\n // NOW WE CAN DO CONDITIONAL RETURNS - AFTER ALL HOOKS\n // ============================================================\n\n // Loading state - return control\n if (useNewAPI && (configLoading || !config || !proposalId)) {\n return React.createElement(ControlComponent as any, props as any);\n }\n\n // No proposalId - return control\n if (!proposalId) {\n return React.createElement(ControlComponent as any, props as any);\n }\n\n // Build registry - always has control\n const registry: Record<string, React.ComponentType<any>> = { control: ControlComponent };\n\n if (useNewAPI && config?.variants) {\n for (const [key, value] of Object.entries(config.variants)) {\n if (key !== 'control' && value && typeof value === 'function') {\n registry[key] = value;\n }\n }\n } else if (!useNewAPI && options.registry) {\n for (const [key, value] of Object.entries(options.registry)) {\n if (key !== 'control' && value && typeof value === 'function') {\n registry[key] = value;\n }\n }\n }\n\n // Select variant\n const label = choice?.label ?? \"control\";\n const Variant = registry[label] || registry.control || ControlComponent;\n\n return (\n <div onClick={(event) => trackClick(event)} data-probat-proposal={proposalId}>\n {React.createElement(Variant, {\n key: `${proposalId}:${label}`,\n ...(props as any),\n probat: { trackClick: () => trackClick(null, { force: true }) },\n })}\n </div>\n );\n }\n\n Wrapped.displayName = `withExperiment(${Control.displayName || Control.name || \"Component\"})`;\n return Wrapped as any;\n}\n"]}