@probat/react 0.1.2 → 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.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  "use client";
2
2
  "use client";
3
- import React4, { createContext, useMemo, useEffect, useContext, useCallback, useState } from 'react';
3
+ import React4, { createContext, useMemo, useContext, useCallback, useState, useEffect } from 'react';
4
4
 
5
5
  // src/utils/environment.ts
6
6
  function detectEnvironment() {
@@ -13,6 +13,41 @@ function detectEnvironment() {
13
13
  }
14
14
  return "prod";
15
15
  }
16
+
17
+ // src/context/ProbatContext.tsx
18
+ var ProbatContext = createContext(null);
19
+ function ProbatProvider({
20
+ apiBaseUrl,
21
+ clientKey,
22
+ environment: explicitEnvironment,
23
+ repoFullName: explicitRepoFullName,
24
+ children
25
+ }) {
26
+ const contextValue = useMemo(() => {
27
+ const resolvedApiBaseUrl = apiBaseUrl || typeof import.meta !== "undefined" && import.meta.env?.VITE_PROBAT_API || typeof globalThis !== "undefined" && globalThis.process?.env?.NEXT_PUBLIC_PROBAT_API || typeof window !== "undefined" && window.__PROBAT_API || "https://gushi.onrender.com";
28
+ const environment = explicitEnvironment || detectEnvironment();
29
+ const resolvedRepoFullName = explicitRepoFullName || typeof globalThis !== "undefined" && globalThis.process?.env?.NEXT_PUBLIC_PROBAT_REPO || typeof import.meta !== "undefined" && import.meta.env?.VITE_PROBAT_REPO || typeof window !== "undefined" && window.__PROBAT_REPO || void 0;
30
+ return {
31
+ apiBaseUrl: resolvedApiBaseUrl,
32
+ environment,
33
+ clientKey,
34
+ repoFullName: resolvedRepoFullName
35
+ };
36
+ }, [apiBaseUrl, clientKey, explicitEnvironment, explicitRepoFullName]);
37
+ return /* @__PURE__ */ React4.createElement(ProbatContext.Provider, { value: contextValue }, children);
38
+ }
39
+ function useProbatContext() {
40
+ const context = useContext(ProbatContext);
41
+ if (!context) {
42
+ throw new Error(
43
+ "useProbatContext must be used within a ProbatProvider. Please wrap your app with <ProbatProvider>."
44
+ );
45
+ }
46
+ return context;
47
+ }
48
+ function ProbatProviderClient(props) {
49
+ return React4.createElement(ProbatProvider, props);
50
+ }
16
51
  var pendingFetches = /* @__PURE__ */ new Map();
17
52
  async function fetchDecision(baseUrl, proposalId) {
18
53
  const existingFetch = pendingFetches.get(proposalId);
@@ -55,7 +90,7 @@ async function sendMetric(baseUrl, proposalId, metricName, variantLabel = "contr
55
90
  captured_at: (/* @__PURE__ */ new Date()).toISOString()
56
91
  };
57
92
  try {
58
- const response = await fetch(url, {
93
+ await fetch(url, {
59
94
  method: "POST",
60
95
  headers: {
61
96
  Accept: "application/json",
@@ -65,26 +100,7 @@ async function sendMetric(baseUrl, proposalId, metricName, variantLabel = "contr
65
100
  // CRITICAL: Include cookies to distinguish different users
66
101
  body: JSON.stringify(body)
67
102
  });
68
- if (!response.ok) {
69
- console.warn("[PROBAT] Metric send failed:", {
70
- status: response.status,
71
- statusText: response.statusText,
72
- url,
73
- body
74
- });
75
- } else {
76
- console.log("[PROBAT] Metric sent successfully:", {
77
- metricName,
78
- proposalId,
79
- variantLabel
80
- });
81
- }
82
- } catch (error) {
83
- console.error("[PROBAT] Error sending metric:", {
84
- error: error instanceof Error ? error.message : String(error),
85
- url,
86
- body
87
- });
103
+ } catch {
88
104
  }
89
105
  }
90
106
  function extractClickMeta(event) {
@@ -141,11 +157,109 @@ async function fetchComponentExperimentConfig(baseUrl, repoFullName, componentPa
141
157
  return fetchPromise;
142
158
  }
143
159
  var variantComponentCache = /* @__PURE__ */ new Map();
160
+ var moduleCache = /* @__PURE__ */ new Map();
144
161
  if (typeof window !== "undefined") {
145
162
  window.__probatReact = React4;
146
163
  window.React = window.React || React4;
147
164
  }
148
- async function loadVariantComponent(baseUrl, proposalId, experimentId, filePath) {
165
+ function resolveRelativePath(relativePath, basePath) {
166
+ const baseDir = basePath.substring(0, basePath.lastIndexOf("/"));
167
+ const parts = baseDir.split("/").filter(Boolean);
168
+ const relativeParts = relativePath.split("/").filter(Boolean);
169
+ for (const part of relativeParts) {
170
+ if (part === "..") {
171
+ parts.pop();
172
+ } else if (part !== ".") {
173
+ parts.push(part);
174
+ }
175
+ }
176
+ return "/" + parts.join("/");
177
+ }
178
+ async function loadRelativeModule(absolutePath, baseFilePath, repoFullName, baseRef) {
179
+ const cacheKey = `${baseFilePath}:${absolutePath}`;
180
+ if (moduleCache.has(cacheKey)) {
181
+ return moduleCache.get(cacheKey);
182
+ }
183
+ const extensions = [".jsx", ".tsx", ".js", ".ts"];
184
+ let moduleCode = null;
185
+ let modulePath = null;
186
+ for (const ext of extensions) {
187
+ const testPath = absolutePath + (absolutePath.includes(".") ? "" : ext);
188
+ try {
189
+ const localRes = await fetch(testPath, {
190
+ method: "GET",
191
+ headers: { Accept: "text/plain" }
192
+ });
193
+ if (localRes.ok) {
194
+ moduleCode = await localRes.text();
195
+ modulePath = testPath;
196
+ break;
197
+ }
198
+ } catch {
199
+ }
200
+ if (!moduleCode && repoFullName) {
201
+ try {
202
+ const githubPath = testPath.startsWith("/") ? testPath.substring(1) : testPath;
203
+ const githubUrl = `https://raw.githubusercontent.com/${repoFullName}/${baseRef || "main"}/${githubPath}`;
204
+ const res = await fetch(githubUrl, { method: "GET", headers: { Accept: "text/plain" } });
205
+ if (res.ok) {
206
+ moduleCode = await res.text();
207
+ modulePath = testPath;
208
+ break;
209
+ }
210
+ } catch {
211
+ }
212
+ }
213
+ }
214
+ if (!moduleCode || !modulePath) {
215
+ throw new Error(`Could not resolve module: ${absolutePath} from ${baseFilePath}`);
216
+ }
217
+ let Babel;
218
+ if (typeof window !== "undefined" && window.Babel) {
219
+ Babel = window.Babel;
220
+ } else {
221
+ try {
222
+ const babelModule = await import('@babel/standalone');
223
+ Babel = babelModule.default || babelModule;
224
+ } catch {
225
+ throw new Error("Babel not available for compiling relative import");
226
+ }
227
+ }
228
+ let processedCode = moduleCode;
229
+ processedCode = processedCode.replace(/^import\s+['"].*\.css['"];?\s*$/gm, "");
230
+ processedCode = processedCode.replace(/^import\s+React\s+from\s+['"]react['"];?\s*$/m, "const React = window.React || globalThis.React;");
231
+ processedCode = processedCode.replace(/import\.meta\.env\.[\w$]+/g, "undefined");
232
+ processedCode = processedCode.replace(/\bimport\.meta\b/g, "({})");
233
+ const isTSX = modulePath.endsWith(".tsx");
234
+ const compiled = Babel.transform(processedCode, {
235
+ presets: [
236
+ ["react", { runtime: "classic" }],
237
+ ["typescript", { allExtensions: true, isTSX }]
238
+ ],
239
+ plugins: [["transform-modules-commonjs", { allowTopLevelThis: true }]],
240
+ sourceType: "module",
241
+ filename: modulePath
242
+ }).code;
243
+ const moduleCodeWrapper = `
244
+ var require = function(name) {
245
+ if (name === "react" || name === "react/jsx-runtime") {
246
+ return window.React || globalThis.React;
247
+ }
248
+ if (name.startsWith("/@vite") || name.includes("@vite/client")) {
249
+ return {};
250
+ }
251
+ throw new Error("Unsupported module in relative import: " + name);
252
+ };
253
+ var module = { exports: {} };
254
+ var exports = module.exports;
255
+ ${compiled}
256
+ return module.exports;
257
+ `;
258
+ const moduleExports = new Function(moduleCodeWrapper)();
259
+ moduleCache.set(cacheKey, moduleExports);
260
+ return moduleExports;
261
+ }
262
+ async function loadVariantComponent(baseUrl, proposalId, experimentId, filePath, repoFullName, baseRef) {
149
263
  if (!filePath) {
150
264
  return null;
151
265
  }
@@ -156,16 +270,190 @@ async function loadVariantComponent(baseUrl, proposalId, experimentId, filePath)
156
270
  }
157
271
  const loadPromise = (async () => {
158
272
  try {
159
- const variantUrl = `${baseUrl.replace(/\/$/, "")}/variants/${filePath}`;
160
- const res = await fetch(variantUrl, {
161
- method: "GET",
162
- headers: { Accept: "text/javascript" },
163
- credentials: "include"
164
- });
165
- if (!res.ok) {
166
- throw new Error(`HTTP ${res.status}`);
273
+ let code = "";
274
+ let rawCode = "";
275
+ let rawCodeFetched = false;
276
+ const isBrowser = typeof window !== "undefined";
277
+ const isNextJSServer = typeof window === "undefined" || typeof globalThis.process !== "undefined" && globalThis.process.env?.NEXT_RUNTIME === "nodejs";
278
+ if (isBrowser && !isNextJSServer) {
279
+ try {
280
+ const variantUrl = `/probat/${filePath}`;
281
+ const mod = await import(
282
+ /* @vite-ignore */
283
+ variantUrl
284
+ );
285
+ const VariantComponent2 = mod?.default || mod;
286
+ if (VariantComponent2 && typeof VariantComponent2 === "function") {
287
+ console.log(`[PROBAT] \u2705 Loaded variant via dynamic import (CSR): ${variantUrl}`);
288
+ return VariantComponent2;
289
+ }
290
+ } catch (dynamicImportError) {
291
+ console.debug(`[PROBAT] Dynamic import failed, using fetch+babel:`, dynamicImportError);
292
+ }
293
+ }
294
+ const localUrl = `/probat/${filePath}`;
295
+ try {
296
+ const localRes = await fetch(localUrl, {
297
+ method: "GET",
298
+ headers: { Accept: "text/plain" }
299
+ });
300
+ if (localRes.ok) {
301
+ rawCode = await localRes.text();
302
+ rawCodeFetched = true;
303
+ console.log(`[PROBAT] \u2705 Loaded variant from local (user's repo): ${localUrl}`);
304
+ }
305
+ } catch {
306
+ console.debug(`[PROBAT] Local file not available (${localUrl}), trying GitHub...`);
307
+ }
308
+ if (!rawCodeFetched && repoFullName) {
309
+ const githubPath = `probat/${filePath}`;
310
+ const gitRef = baseRef || "main";
311
+ const githubUrl = `https://raw.githubusercontent.com/${repoFullName}/${gitRef}/${githubPath}`;
312
+ const res = await fetch(githubUrl, { method: "GET", headers: { Accept: "text/plain" } });
313
+ if (res.ok) {
314
+ rawCode = await res.text();
315
+ rawCodeFetched = true;
316
+ console.log(`[PROBAT] \u26A0\uFE0F Loaded variant from GitHub (fallback): ${githubUrl}`);
317
+ } else {
318
+ console.warn(`[PROBAT] \u26A0\uFE0F GitHub fetch failed (${res.status}), falling back to server compilation`);
319
+ }
320
+ }
321
+ if (rawCodeFetched && rawCode) {
322
+ let Babel;
323
+ if (typeof window !== "undefined" && window.Babel) {
324
+ Babel = window.Babel;
325
+ } else {
326
+ try {
327
+ const babelModule = await import('@babel/standalone');
328
+ Babel = babelModule.default || babelModule;
329
+ } catch (importError) {
330
+ try {
331
+ await new Promise((resolve, reject) => {
332
+ if (typeof document === "undefined") {
333
+ reject(new Error("Document not available"));
334
+ return;
335
+ }
336
+ if (window.Babel) {
337
+ Babel = window.Babel;
338
+ resolve();
339
+ return;
340
+ }
341
+ const script = document.createElement("script");
342
+ script.src = "https://unpkg.com/@babel/standalone/babel.min.js";
343
+ script.async = true;
344
+ script.onload = () => {
345
+ Babel = window.Babel;
346
+ if (!Babel) reject(new Error("Babel not found after script load"));
347
+ else resolve();
348
+ };
349
+ script.onerror = () => reject(new Error("Failed to load Babel from CDN"));
350
+ document.head.appendChild(script);
351
+ });
352
+ } catch (babelError) {
353
+ console.error("[PROBAT] Failed to load Babel, falling back to server compilation", babelError);
354
+ rawCodeFetched = false;
355
+ }
356
+ }
357
+ }
358
+ if (rawCodeFetched && rawCode && Babel) {
359
+ const isTSX = filePath.endsWith(".tsx");
360
+ rawCode = rawCode.replace(/^import\s+['"].*\.css['"];?\s*$/gm, "");
361
+ rawCode = rawCode.replace(/^import\s+.*from\s+['"].*\.css['"];?\s*$/gm, "");
362
+ rawCode = rawCode.replace(
363
+ /^import\s+React(?:\s*,\s*\{[^}]*\})?\s+from\s+['"]react['"];?\s*$/m,
364
+ "const React = window.React || globalThis.React;"
365
+ );
366
+ rawCode = rawCode.replace(
367
+ /^import\s+\*\s+as\s+React\s+from\s+['"]react['"];?\s*$/m,
368
+ "const React = window.React || globalThis.React;"
369
+ );
370
+ rawCode = rawCode.replace(
371
+ /^import\s+\{([^}]+)\}\s+from\s+['"]react['"];?\s*$/m,
372
+ (match, imports) => `const {${imports}} = window.React || globalThis.React;`
373
+ );
374
+ rawCode = rawCode.replace(/import\.meta\.env\.[\w$]+/g, "undefined");
375
+ rawCode = rawCode.replace(/\bimport\.meta\b/g, "({})");
376
+ rawCode = rawCode.replace(/^import\s+.*\/@vite\/client.*$/gm, "");
377
+ rawCode = rawCode.replace(/import\.meta\.hot(?:\.[\w$]+)*/g, "undefined");
378
+ const relativeImportMap = /* @__PURE__ */ new Map();
379
+ rawCode = rawCode.replace(
380
+ /^import\s+(\w+)\s+from\s+['"](\.\.?\/[^'"]+)['"];?\s*$/gm,
381
+ (match, importName, relativePath) => {
382
+ const baseDir = filePath.substring(0, filePath.lastIndexOf("/"));
383
+ const resolvedPath = resolveRelativePath(relativePath, baseDir);
384
+ const absolutePath = resolvedPath.startsWith("/") ? resolvedPath : "/" + resolvedPath;
385
+ relativeImportMap.set(importName, absolutePath);
386
+ return `import ${importName} from "${absolutePath}";`;
387
+ }
388
+ );
389
+ const compiled = Babel.transform(rawCode, {
390
+ presets: [
391
+ ["react", { runtime: "classic" }],
392
+ ["typescript", { allExtensions: true, isTSX }]
393
+ ],
394
+ plugins: [["transform-modules-commonjs", { allowTopLevelThis: true }]],
395
+ sourceType: "module",
396
+ filename: filePath
397
+ }).code;
398
+ const relativeModules = {};
399
+ if (relativeImportMap.size > 0) {
400
+ for (const [importName, absolutePath] of relativeImportMap.entries()) {
401
+ try {
402
+ const moduleExports = await loadRelativeModule(absolutePath, filePath, repoFullName, baseRef);
403
+ relativeModules[absolutePath] = moduleExports.default || moduleExports;
404
+ } catch (err) {
405
+ console.warn(`[PROBAT] Failed to load relative import ${absolutePath}:`, err);
406
+ relativeModules[absolutePath] = null;
407
+ }
408
+ }
409
+ }
410
+ const relativeModulesJson = JSON.stringify(relativeModules);
411
+ code = `
412
+ var __probatVariant = (function() {
413
+ var relativeModules = ${relativeModulesJson};
414
+ var require = function(name) {
415
+ if (name === "react" || name === "react/jsx-runtime") {
416
+ return window.React || globalThis.React;
417
+ }
418
+ if (name.startsWith("/@vite") || name.includes("@vite/client") || name.includes(".vite/deps")) {
419
+ return {};
420
+ }
421
+ if (name === "react/jsx-runtime.js") {
422
+ return window.React || globalThis.React;
423
+ }
424
+ // Handle relative imports (now converted to absolute paths)
425
+ if (name.startsWith("/") && relativeModules.hasOwnProperty(name)) {
426
+ var mod = relativeModules[name];
427
+ if (mod === null) {
428
+ throw new Error("Failed to load module: " + name);
429
+ }
430
+ return mod;
431
+ }
432
+ throw new Error("Unsupported module: " + name);
433
+ };
434
+ var module = { exports: {} };
435
+ var exports = module.exports;
436
+ ${compiled}
437
+ return module.exports.default || module.exports;
438
+ })();
439
+ `;
440
+ } else {
441
+ rawCodeFetched = false;
442
+ code = "";
443
+ }
444
+ }
445
+ if (!rawCodeFetched || code === "") {
446
+ const variantUrl = `${baseUrl.replace(/\/$/, "")}/variants/${filePath}`;
447
+ const serverRes = await fetch(variantUrl, {
448
+ method: "GET",
449
+ headers: { Accept: "text/javascript" },
450
+ credentials: "include"
451
+ });
452
+ if (!serverRes.ok) {
453
+ throw new Error(`HTTP ${serverRes.status}`);
454
+ }
455
+ code = await serverRes.text();
167
456
  }
168
- const code = await res.text();
169
457
  if (typeof window !== "undefined") {
170
458
  window.React = window.React || React4;
171
459
  }
@@ -192,146 +480,7 @@ async function loadVariantComponent(baseUrl, proposalId, experimentId, filePath)
192
480
  return loadPromise;
193
481
  }
194
482
 
195
- // src/utils/documentClickTracker.ts
196
- var proposalCache = /* @__PURE__ */ new Map();
197
- var isListenerAttached = false;
198
- var lastClickTime = /* @__PURE__ */ new Map();
199
- var DEBOUNCE_MS = 100;
200
- function getProposalMetadata(element) {
201
- const probatWrapper = element.closest("[data-probat-proposal]");
202
- if (!probatWrapper) return null;
203
- const proposalId = probatWrapper.getAttribute("data-probat-proposal");
204
- if (!proposalId) return null;
205
- const cacheKey = `${proposalId}`;
206
- const cached = proposalCache.get(cacheKey);
207
- if (cached) return cached;
208
- const experimentId = probatWrapper.getAttribute("data-probat-experiment-id");
209
- const variantLabel = probatWrapper.getAttribute("data-probat-variant-label") || "control";
210
- const apiBaseUrl = probatWrapper.getAttribute("data-probat-api-base-url") || typeof window !== "undefined" && window.__PROBAT_API || "https://gushi.onrender.com";
211
- const metadata = {
212
- proposalId,
213
- experimentId: experimentId || null,
214
- variantLabel,
215
- apiBaseUrl
216
- };
217
- proposalCache.set(cacheKey, metadata);
218
- return metadata;
219
- }
220
- function handleDocumentClick(event) {
221
- const target = event.target;
222
- if (!target) return;
223
- const metadata = getProposalMetadata(target);
224
- if (!metadata) {
225
- return;
226
- }
227
- const now2 = Date.now();
228
- const lastClick = lastClickTime.get(metadata.proposalId) || 0;
229
- if (now2 - lastClick < DEBOUNCE_MS) {
230
- return;
231
- }
232
- lastClickTime.set(metadata.proposalId, now2);
233
- const clickMeta = extractClickMeta(event);
234
- target.hasAttribute("data-probat-track") || target.closest("[data-probat-track]") !== null;
235
- const finalMeta = clickMeta || {
236
- target_tag: target.tagName,
237
- target_class: target.className || "",
238
- target_id: target.id || "",
239
- clicked_inside_probat: true
240
- // Flag to indicate this was tracked via document-level listener
241
- };
242
- const experimentId = metadata.variantLabel === "control" ? void 0 : metadata.experimentId && !metadata.experimentId.startsWith("exp_") ? metadata.experimentId : void 0;
243
- void sendMetric(
244
- metadata.apiBaseUrl,
245
- metadata.proposalId,
246
- "click",
247
- metadata.variantLabel,
248
- experimentId,
249
- finalMeta
250
- );
251
- console.log("[PROBAT] Click tracked:", {
252
- proposalId: metadata.proposalId,
253
- variantLabel: metadata.variantLabel,
254
- target: target.tagName,
255
- targetId: target.id || "none",
256
- targetClass: target.className || "none",
257
- meta: finalMeta
258
- });
259
- console.log("[PROBAT] Sending metric to:", `${metadata.apiBaseUrl}/send_metrics/${metadata.proposalId}`);
260
- }
261
- function initDocumentClickTracking() {
262
- if (isListenerAttached) {
263
- console.warn("[PROBAT] Document click listener already attached");
264
- return;
265
- }
266
- if (typeof document === "undefined") {
267
- return;
268
- }
269
- document.addEventListener("click", handleDocumentClick, true);
270
- isListenerAttached = true;
271
- console.log("[PROBAT] Document-level click tracking initialized");
272
- }
273
- function cleanupDocumentClickTracking() {
274
- if (!isListenerAttached) return;
275
- if (typeof document !== "undefined") {
276
- document.removeEventListener("click", handleDocumentClick, true);
277
- }
278
- isListenerAttached = false;
279
- proposalCache.clear();
280
- lastClickTime.clear();
281
- }
282
- function updateProposalMetadata(proposalId, metadata) {
283
- const existing = proposalCache.get(proposalId);
284
- if (existing) {
285
- proposalCache.set(proposalId, {
286
- ...existing,
287
- ...metadata
288
- });
289
- }
290
- }
291
- function clearProposalCache() {
292
- proposalCache.clear();
293
- }
294
-
295
- // src/context/ProbatContext.tsx
296
- var ProbatContext = createContext(null);
297
- function ProbatProvider({
298
- apiBaseUrl,
299
- clientKey,
300
- environment: explicitEnvironment,
301
- repoFullName: explicitRepoFullName,
302
- children
303
- }) {
304
- const contextValue = useMemo(() => {
305
- const resolvedApiBaseUrl = apiBaseUrl || typeof import.meta !== "undefined" && import.meta.env?.VITE_PROBAT_API || typeof globalThis !== "undefined" && globalThis.process?.env?.NEXT_PUBLIC_PROBAT_API || typeof window !== "undefined" && window.__PROBAT_API || "https://gushi.onrender.com";
306
- const environment = explicitEnvironment || detectEnvironment();
307
- const resolvedRepoFullName = explicitRepoFullName || typeof globalThis !== "undefined" && globalThis.process?.env?.NEXT_PUBLIC_PROBAT_REPO || typeof import.meta !== "undefined" && import.meta.env?.VITE_PROBAT_REPO || typeof window !== "undefined" && window.__PROBAT_REPO || void 0;
308
- return {
309
- apiBaseUrl: resolvedApiBaseUrl,
310
- environment,
311
- clientKey,
312
- repoFullName: resolvedRepoFullName
313
- };
314
- }, [apiBaseUrl, clientKey, explicitEnvironment, explicitRepoFullName]);
315
- useEffect(() => {
316
- initDocumentClickTracking();
317
- return () => {
318
- cleanupDocumentClickTracking();
319
- };
320
- }, []);
321
- return /* @__PURE__ */ React4.createElement(ProbatContext.Provider, { value: contextValue }, children);
322
- }
323
- function useProbatContext() {
324
- const context = useContext(ProbatContext);
325
- if (!context) {
326
- throw new Error(
327
- "useProbatContext must be used within a ProbatProvider. Please wrap your app with <ProbatProvider>."
328
- );
329
- }
330
- return context;
331
- }
332
- function ProbatProviderClient(props) {
333
- return React4.createElement(ProbatProvider, props);
334
- }
483
+ // src/hooks/useProbatMetrics.ts
335
484
  function useProbatMetrics() {
336
485
  const { apiBaseUrl } = useProbatContext();
337
486
  const trackClick = useCallback(
@@ -595,7 +744,9 @@ function withExperiment(Control, options) {
595
744
  apiBaseUrl,
596
745
  componentConfig.proposal_id,
597
746
  variantInfo.experiment_id,
598
- variantInfo.file_path
747
+ variantInfo.file_path,
748
+ componentConfig.repo_full_name,
749
+ componentConfig.base_ref
599
750
  );
600
751
  if (VariantComp && typeof VariantComp === "function" && alive) {
601
752
  variantComponents[label2] = VariantComp;
@@ -694,28 +845,16 @@ function withExperiment(Control, options) {
694
845
  }
695
846
  const label = choice?.label ?? "control";
696
847
  const Variant = registry[label] || registry.control || ControlComponent;
697
- return /* @__PURE__ */ React4.createElement(
698
- "div",
699
- {
700
- onClick: (event) => {
701
- trackClick(event);
702
- },
703
- "data-probat-proposal": proposalId,
704
- "data-probat-experiment-id": choice?.experiment_id || "",
705
- "data-probat-variant-label": label,
706
- "data-probat-api-base-url": apiBaseUrl
707
- },
708
- React4.createElement(Variant, {
709
- key: `${proposalId}:${label}`,
710
- ...props,
711
- probat: { trackClick: () => trackClick(null, { force: true }) }
712
- })
713
- );
848
+ return /* @__PURE__ */ React4.createElement("div", { onClick: (event) => trackClick(event), "data-probat-proposal": proposalId }, React4.createElement(Variant, {
849
+ key: `${proposalId}:${label}`,
850
+ ...props,
851
+ probat: { trackClick: () => trackClick(null, { force: true }) }
852
+ }));
714
853
  }
715
854
  Wrapped.displayName = `withExperiment(${Control.displayName || Control.name || "Component"})`;
716
855
  return Wrapped;
717
856
  }
718
857
 
719
- export { ProbatProvider, ProbatProviderClient, cleanupDocumentClickTracking, clearProposalCache, detectEnvironment, extractClickMeta, fetchDecision, hasTrackedVisit, initDocumentClickTracking, markTrackedVisit, readChoice, sendMetric, updateProposalMetadata, useExperiment, useProbatContext, useProbatMetrics, withExperiment, writeChoice };
858
+ export { ProbatProvider, ProbatProviderClient, detectEnvironment, extractClickMeta, fetchDecision, hasTrackedVisit, markTrackedVisit, readChoice, sendMetric, useExperiment, useProbatContext, useProbatMetrics, withExperiment, writeChoice };
720
859
  //# sourceMappingURL=index.mjs.map
721
860
  //# sourceMappingURL=index.mjs.map