@probat/react 0.1.1 → 0.1.2
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 +44 -10
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +44 -10
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
- package/src/utils/api.ts +24 -3
- package/src/utils/documentClickTracker.ts +61 -46
package/dist/index.js
CHANGED
|
@@ -62,7 +62,7 @@ async function sendMetric(baseUrl, proposalId, metricName, variantLabel = "contr
|
|
|
62
62
|
captured_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
63
63
|
};
|
|
64
64
|
try {
|
|
65
|
-
await fetch(url, {
|
|
65
|
+
const response = await fetch(url, {
|
|
66
66
|
method: "POST",
|
|
67
67
|
headers: {
|
|
68
68
|
Accept: "application/json",
|
|
@@ -72,7 +72,26 @@ async function sendMetric(baseUrl, proposalId, metricName, variantLabel = "contr
|
|
|
72
72
|
// CRITICAL: Include cookies to distinguish different users
|
|
73
73
|
body: JSON.stringify(body)
|
|
74
74
|
});
|
|
75
|
-
|
|
75
|
+
if (!response.ok) {
|
|
76
|
+
console.warn("[PROBAT] Metric send failed:", {
|
|
77
|
+
status: response.status,
|
|
78
|
+
statusText: response.statusText,
|
|
79
|
+
url,
|
|
80
|
+
body
|
|
81
|
+
});
|
|
82
|
+
} else {
|
|
83
|
+
console.log("[PROBAT] Metric sent successfully:", {
|
|
84
|
+
metricName,
|
|
85
|
+
proposalId,
|
|
86
|
+
variantLabel
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
} catch (error) {
|
|
90
|
+
console.error("[PROBAT] Error sending metric:", {
|
|
91
|
+
error: error instanceof Error ? error.message : String(error),
|
|
92
|
+
url,
|
|
93
|
+
body
|
|
94
|
+
});
|
|
76
95
|
}
|
|
77
96
|
}
|
|
78
97
|
function extractClickMeta(event) {
|
|
@@ -209,7 +228,9 @@ function handleDocumentClick(event) {
|
|
|
209
228
|
const target = event.target;
|
|
210
229
|
if (!target) return;
|
|
211
230
|
const metadata = getProposalMetadata(target);
|
|
212
|
-
if (!metadata)
|
|
231
|
+
if (!metadata) {
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
213
234
|
const now2 = Date.now();
|
|
214
235
|
const lastClick = lastClickTime.get(metadata.proposalId) || 0;
|
|
215
236
|
if (now2 - lastClick < DEBOUNCE_MS) {
|
|
@@ -217,19 +238,32 @@ function handleDocumentClick(event) {
|
|
|
217
238
|
}
|
|
218
239
|
lastClickTime.set(metadata.proposalId, now2);
|
|
219
240
|
const clickMeta = extractClickMeta(event);
|
|
220
|
-
|
|
221
|
-
const
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
241
|
+
target.hasAttribute("data-probat-track") || target.closest("[data-probat-track]") !== null;
|
|
242
|
+
const finalMeta = clickMeta || {
|
|
243
|
+
target_tag: target.tagName,
|
|
244
|
+
target_class: target.className || "",
|
|
245
|
+
target_id: target.id || "",
|
|
246
|
+
clicked_inside_probat: true
|
|
247
|
+
// Flag to indicate this was tracked via document-level listener
|
|
248
|
+
};
|
|
249
|
+
const experimentId = metadata.variantLabel === "control" ? void 0 : metadata.experimentId && !metadata.experimentId.startsWith("exp_") ? metadata.experimentId : void 0;
|
|
225
250
|
void sendMetric(
|
|
226
251
|
metadata.apiBaseUrl,
|
|
227
252
|
metadata.proposalId,
|
|
228
253
|
"click",
|
|
229
254
|
metadata.variantLabel,
|
|
230
|
-
|
|
231
|
-
|
|
255
|
+
experimentId,
|
|
256
|
+
finalMeta
|
|
232
257
|
);
|
|
258
|
+
console.log("[PROBAT] Click tracked:", {
|
|
259
|
+
proposalId: metadata.proposalId,
|
|
260
|
+
variantLabel: metadata.variantLabel,
|
|
261
|
+
target: target.tagName,
|
|
262
|
+
targetId: target.id || "none",
|
|
263
|
+
targetClass: target.className || "none",
|
|
264
|
+
meta: finalMeta
|
|
265
|
+
});
|
|
266
|
+
console.log("[PROBAT] Sending metric to:", `${metadata.apiBaseUrl}/send_metrics/${metadata.proposalId}`);
|
|
233
267
|
}
|
|
234
268
|
function initDocumentClickTracking() {
|
|
235
269
|
if (isListenerAttached) {
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/utils/environment.ts","../src/utils/api.ts","../src/utils/documentClickTracker.ts","../src/context/ProbatContext.tsx","../src/components/ProbatProviderClient.tsx","../src/hooks/useProbatMetrics.ts","../src/utils/storage.ts","../src/hooks/useExperiment.ts","../src/hoc/withExperiment.tsx"],"names":["React","now","createContext","useMemo","useEffect","useContext","useCallback","useState","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","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 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): 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 // Fetch the variant code (server compiles TSX/JSX to JS)\n const variantUrl = `${baseUrl.replace(/\\/$/, \"\")}/variants/${filePath}`;\n\n const res = await fetch(variantUrl, {\n method: \"GET\",\n headers: { Accept: \"text/javascript\" },\n credentials: \"include\",\n });\n\n if (!res.ok) {\n throw new Error(`HTTP ${res.status}`);\n }\n\n const code = await res.text();\n\n // The server returns an IIFE that assigns to __probatVariant\n // Execute the code to get the component\n // First, ensure React is available globally\n if (typeof window !== \"undefined\") {\n (window as any).React = (window as any).React || React;\n }\n\n // Execute the IIFE code\n const evalFunc = new Function(`\n var __probatVariant;\n ${code}\n return __probatVariant;\n `);\n\n const result = evalFunc();\n\n // The result is { default: Component } from esbuild's IIFE output\n const VariantComponent = result?.default || result;\n\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","/**\n * Document-level click tracking for Probat experiments\n * \n * This module implements event delegation at the document level to track clicks\n * even when components don't have onClick handlers or when stopPropagation() is called.\n */\n\nimport { sendMetric } from './api';\nimport { extractClickMeta } from './api';\n\n// Cache for proposal metadata to avoid repeated DOM queries\nconst proposalCache = new Map<string, {\n proposalId: string;\n experimentId: string | null;\n variantLabel: string;\n apiBaseUrl: string;\n}>();\n\n// Track if listener is already attached\nlet isListenerAttached = false;\n\n// Rate limiting: prevent duplicate rapid clicks\nconst lastClickTime = new Map<string, number>();\nconst DEBOUNCE_MS = 100; // Ignore clicks within 100ms of each other\n\n/**\n * Get proposal metadata from DOM element\n * Looks for the nearest [data-probat-proposal] wrapper\n */\nfunction getProposalMetadata(element: HTMLElement): {\n proposalId: string;\n experimentId: string | null;\n variantLabel: string;\n apiBaseUrl: string;\n} | null {\n // Find the nearest probat wrapper\n const probatWrapper = element.closest('[data-probat-proposal]') as HTMLElement | null;\n \n if (!probatWrapper) return null;\n \n const proposalId = probatWrapper.getAttribute('data-probat-proposal');\n if (!proposalId) return null;\n \n // Check cache first\n const cacheKey = `${proposalId}`;\n const cached = proposalCache.get(cacheKey);\n if (cached) return cached;\n \n // Extract metadata from data attributes\n const experimentId = probatWrapper.getAttribute('data-probat-experiment-id');\n const variantLabel = probatWrapper.getAttribute('data-probat-variant-label') || 'control';\n const apiBaseUrl = probatWrapper.getAttribute('data-probat-api-base-url') || \n (typeof window !== 'undefined' && (window as any).__PROBAT_API) ||\n 'https://gushi.onrender.com';\n \n const metadata = {\n proposalId,\n experimentId: experimentId || null,\n variantLabel,\n apiBaseUrl,\n };\n \n // Cache it\n proposalCache.set(cacheKey, metadata);\n return metadata;\n}\n\n/**\n * Handle click event at document level\n * Uses capture phase to catch events before stopPropagation()\n */\nfunction handleDocumentClick(event: MouseEvent): void {\n const target = event.target as HTMLElement | null;\n if (!target) return;\n \n // Get proposal metadata\n const metadata = getProposalMetadata(target);\n if (!metadata) return;\n \n // Rate limiting: prevent duplicate rapid clicks\n const now = Date.now();\n const lastClick = lastClickTime.get(metadata.proposalId) || 0;\n if (now - lastClick < DEBOUNCE_MS) {\n return; // Ignore rapid duplicate clicks\n }\n lastClickTime.set(metadata.proposalId, now);\n \n // Extract click metadata (your existing function)\n const clickMeta = extractClickMeta(event);\n \n // Determine if we should track this click\n // Track if:\n // 1. It's an actionable element (button, link, etc.) - clickMeta exists\n // 2. Element has data-probat-track attribute\n // 3. Parent has data-probat-track attribute\n const hasTrackAttribute = target.hasAttribute('data-probat-track') || \n target.closest('[data-probat-track]') !== null;\n \n const shouldTrack = clickMeta !== undefined || hasTrackAttribute;\n \n if (!shouldTrack) {\n // Optional: Track \"dead clicks\" for UX insights\n // Uncomment the code below if you want to track clicks on non-interactive elements\n /*\n const deadClickMeta = {\n dead_click: true,\n target_tag: target.tagName,\n target_class: target.className || '',\n target_id: target.id || '',\n };\n \n void sendMetric(\n metadata.apiBaseUrl,\n metadata.proposalId,\n 'dead_click',\n metadata.variantLabel,\n metadata.experimentId,\n deadClickMeta\n );\n */\n return;\n }\n \n // Send click metric\n void sendMetric(\n metadata.apiBaseUrl,\n metadata.proposalId,\n 'click',\n metadata.variantLabel,\n metadata.experimentId || undefined,\n clickMeta\n );\n}\n\n/**\n * Initialize document-level click tracking\n * Call this once when your app initializes (typically in ProbatProvider)\n */\nexport function initDocumentClickTracking(): void {\n if (isListenerAttached) {\n console.warn('[PROBAT] Document click listener already attached');\n return;\n }\n \n if (typeof document === 'undefined') {\n // Server-side rendering - skip\n return;\n }\n \n // Use capture phase (true) to catch events before they bubble\n // This ensures we catch clicks even if stopPropagation() is called\n document.addEventListener('click', handleDocumentClick, true);\n \n isListenerAttached = true;\n console.log('[PROBAT] Document-level click tracking initialized');\n}\n\n/**\n * Clean up the listener (useful for testing or cleanup)\n */\nexport function cleanupDocumentClickTracking(): void {\n if (!isListenerAttached) return;\n \n if (typeof document !== 'undefined') {\n document.removeEventListener('click', handleDocumentClick, true);\n }\n \n isListenerAttached = false;\n proposalCache.clear();\n lastClickTime.clear();\n}\n\n/**\n * Update proposal metadata cache (call this when proposal data changes)\n * This is useful if you want to update the cache without waiting for DOM queries\n */\nexport function updateProposalMetadata(\n proposalId: string,\n metadata: {\n experimentId?: string | null;\n variantLabel?: string;\n apiBaseUrl?: string;\n }\n): void {\n const existing = proposalCache.get(proposalId);\n if (existing) {\n proposalCache.set(proposalId, {\n ...existing,\n ...metadata,\n });\n }\n}\n\n/**\n * Clear the proposal cache (useful for testing)\n */\nexport function clearProposalCache(): void {\n proposalCache.clear();\n}\n\n","\"use client\";\n\nimport React, { createContext, useContext, useMemo, useEffect } from \"react\";\nimport { detectEnvironment } from \"../utils/environment\";\nimport { initDocumentClickTracking, cleanupDocumentClickTracking } from \"../utils/documentClickTracker\";\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 // Initialize document-level click tracking when provider mounts\n useEffect(() => {\n initDocumentClickTracking();\n \n // Cleanup on unmount (optional, but good practice)\n return () => {\n cleanupDocumentClickTracking();\n };\n }, []);\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","\"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 );\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\n onClick={(event) => {\n // Keep existing onClick for backward compatibility\n // Document-level listener will also catch it (in capture phase)\n trackClick(event);\n }}\n data-probat-proposal={proposalId}\n data-probat-experiment-id={choice?.experiment_id || ''}\n data-probat-variant-label={label}\n data-probat-api-base-url={apiBaseUrl}\n >\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/utils/api.ts","../src/utils/documentClickTracker.ts","../src/context/ProbatContext.tsx","../src/components/ProbatProviderClient.tsx","../src/hooks/useProbatMetrics.ts","../src/utils/storage.ts","../src/hooks/useExperiment.ts","../src/hoc/withExperiment.tsx"],"names":["React","now","createContext","useMemo","useEffect","useContext","useCallback","useState","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","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 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 const response = 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 \n // Log in development for debugging\n if (!response.ok) {\n console.warn('[PROBAT] Metric send failed:', {\n status: response.status,\n statusText: response.statusText,\n url,\n body,\n });\n } else {\n console.log('[PROBAT] Metric sent successfully:', {\n metricName,\n proposalId,\n variantLabel,\n });\n }\n } catch (error) {\n // Log error in development, but don't break the app\n console.error('[PROBAT] Error sending metric:', {\n error: error instanceof Error ? error.message : String(error),\n url,\n body,\n });\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): 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 // Fetch the variant code (server compiles TSX/JSX to JS)\n const variantUrl = `${baseUrl.replace(/\\/$/, \"\")}/variants/${filePath}`;\n\n const res = await fetch(variantUrl, {\n method: \"GET\",\n headers: { Accept: \"text/javascript\" },\n credentials: \"include\",\n });\n\n if (!res.ok) {\n throw new Error(`HTTP ${res.status}`);\n }\n\n const code = await res.text();\n\n // The server returns an IIFE that assigns to __probatVariant\n // Execute the code to get the component\n // First, ensure React is available globally\n if (typeof window !== \"undefined\") {\n (window as any).React = (window as any).React || React;\n }\n\n // Execute the IIFE code\n const evalFunc = new Function(`\n var __probatVariant;\n ${code}\n return __probatVariant;\n `);\n\n const result = evalFunc();\n\n // The result is { default: Component } from esbuild's IIFE output\n const VariantComponent = result?.default || result;\n\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","/**\n * Document-level click tracking for Probat experiments\n * \n * This module implements event delegation at the document level to track clicks\n * even when components don't have onClick handlers or when stopPropagation() is called.\n */\n\nimport { sendMetric } from './api';\nimport { extractClickMeta } from './api';\n\n// Cache for proposal metadata to avoid repeated DOM queries\nconst proposalCache = new Map<string, {\n proposalId: string;\n experimentId: string | null;\n variantLabel: string;\n apiBaseUrl: string;\n}>();\n\n// Track if listener is already attached\nlet isListenerAttached = false;\n\n// Rate limiting: prevent duplicate rapid clicks\nconst lastClickTime = new Map<string, number>();\nconst DEBOUNCE_MS = 100; // Ignore clicks within 100ms of each other\n\n/**\n * Get proposal metadata from DOM element\n * Looks for the nearest [data-probat-proposal] wrapper\n */\nfunction getProposalMetadata(element: HTMLElement): {\n proposalId: string;\n experimentId: string | null;\n variantLabel: string;\n apiBaseUrl: string;\n} | null {\n // Find the nearest probat wrapper\n const probatWrapper = element.closest('[data-probat-proposal]') as HTMLElement | null;\n\n if (!probatWrapper) return null;\n\n const proposalId = probatWrapper.getAttribute('data-probat-proposal');\n if (!proposalId) return null;\n\n // Check cache first\n const cacheKey = `${proposalId}`;\n const cached = proposalCache.get(cacheKey);\n if (cached) return cached;\n\n // Extract metadata from data attributes\n const experimentId = probatWrapper.getAttribute('data-probat-experiment-id');\n const variantLabel = probatWrapper.getAttribute('data-probat-variant-label') || 'control';\n const apiBaseUrl = probatWrapper.getAttribute('data-probat-api-base-url') ||\n (typeof window !== 'undefined' && (window as any).__PROBAT_API) ||\n 'https://gushi.onrender.com';\n\n const metadata = {\n proposalId,\n experimentId: experimentId || null,\n variantLabel,\n apiBaseUrl,\n };\n\n // Cache it\n proposalCache.set(cacheKey, metadata);\n return metadata;\n}\n\n/**\n * Handle click event at document level\n * Uses capture phase to catch events before stopPropagation()\n */\nfunction handleDocumentClick(event: MouseEvent): void {\n const target = event.target as HTMLElement | null;\n if (!target) return;\n\n // Get proposal metadata\n const metadata = getProposalMetadata(target);\n if (!metadata) {\n return; // Click outside probat component\n }\n\n // Rate limiting: prevent duplicate rapid clicks\n const now = Date.now();\n const lastClick = lastClickTime.get(metadata.proposalId) || 0;\n if (now - lastClick < DEBOUNCE_MS) {\n return; // Ignore rapid duplicate clicks\n }\n lastClickTime.set(metadata.proposalId, now);\n\n // Extract click metadata (your existing function)\n const clickMeta = extractClickMeta(event);\n\n // Determine if we should track this click\n // Track if:\n // 1. It's an actionable element (button, link, etc.) - clickMeta exists\n // 2. Element has data-probat-track attribute\n // 3. Parent has data-probat-track attribute\n // 4. ANY click within a probat component (more permissive - track all clicks)\n const hasTrackAttribute = target.hasAttribute('data-probat-track') ||\n target.closest('[data-probat-track]') !== null;\n\n // More permissive: Track ALL clicks within probat components\n // This ensures we capture clicks even if elements don't have explicit tracking attributes\n const shouldTrack = clickMeta !== undefined || hasTrackAttribute || true; // Track all clicks in probat components\n\n if (!shouldTrack) {\n return;\n }\n\n // Build metadata - use clickMeta if available, otherwise create basic metadata\n const finalMeta = clickMeta || {\n target_tag: target.tagName,\n target_class: target.className || '',\n target_id: target.id || '',\n clicked_inside_probat: true, // Flag to indicate this was tracked via document-level listener\n };\n\n // Send click metric\n // For control variant, don't send experiment_id (control might be synthetic)\n // For other variants, send experiment_id if it exists and is valid (not synthetic \"exp_\" prefix)\n const experimentId = metadata.variantLabel === 'control'\n ? undefined\n : (metadata.experimentId && !metadata.experimentId.startsWith('exp_')\n ? metadata.experimentId\n : undefined);\n\n void sendMetric(\n metadata.apiBaseUrl,\n metadata.proposalId,\n 'click',\n metadata.variantLabel,\n experimentId,\n finalMeta\n );\n\n // Debug logging (always log for now to help diagnose)\n console.log('[PROBAT] Click tracked:', {\n proposalId: metadata.proposalId,\n variantLabel: metadata.variantLabel,\n target: target.tagName,\n targetId: target.id || 'none',\n targetClass: target.className || 'none',\n meta: finalMeta,\n });\n\n // Also log to help debug if API call fails\n console.log('[PROBAT] Sending metric to:', `${metadata.apiBaseUrl}/send_metrics/${metadata.proposalId}`);\n}\n\n/**\n * Initialize document-level click tracking\n * Call this once when your app initializes (typically in ProbatProvider)\n */\nexport function initDocumentClickTracking(): void {\n if (isListenerAttached) {\n console.warn('[PROBAT] Document click listener already attached');\n return;\n }\n\n if (typeof document === 'undefined') {\n // Server-side rendering - skip\n return;\n }\n\n // Use capture phase (true) to catch events before they bubble\n // This ensures we catch clicks even if stopPropagation() is called\n document.addEventListener('click', handleDocumentClick, true);\n\n isListenerAttached = true;\n console.log('[PROBAT] Document-level click tracking initialized');\n}\n\n/**\n * Clean up the listener (useful for testing or cleanup)\n */\nexport function cleanupDocumentClickTracking(): void {\n if (!isListenerAttached) return;\n\n if (typeof document !== 'undefined') {\n document.removeEventListener('click', handleDocumentClick, true);\n }\n\n isListenerAttached = false;\n proposalCache.clear();\n lastClickTime.clear();\n}\n\n/**\n * Update proposal metadata cache (call this when proposal data changes)\n * This is useful if you want to update the cache without waiting for DOM queries\n */\nexport function updateProposalMetadata(\n proposalId: string,\n metadata: {\n experimentId?: string | null;\n variantLabel?: string;\n apiBaseUrl?: string;\n }\n): void {\n const existing = proposalCache.get(proposalId);\n if (existing) {\n proposalCache.set(proposalId, {\n ...existing,\n ...metadata,\n });\n }\n}\n\n/**\n * Clear the proposal cache (useful for testing)\n */\nexport function clearProposalCache(): void {\n proposalCache.clear();\n}\n\n","\"use client\";\n\nimport React, { createContext, useContext, useMemo, useEffect } from \"react\";\nimport { detectEnvironment } from \"../utils/environment\";\nimport { initDocumentClickTracking, cleanupDocumentClickTracking } from \"../utils/documentClickTracker\";\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 // Initialize document-level click tracking when provider mounts\n useEffect(() => {\n initDocumentClickTracking();\n \n // Cleanup on unmount (optional, but good practice)\n return () => {\n cleanupDocumentClickTracking();\n };\n }, []);\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","\"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 );\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\n onClick={(event) => {\n // Keep existing onClick for backward compatibility\n // Document-level listener will also catch it (in capture phase)\n trackClick(event);\n }}\n data-probat-proposal={proposalId}\n data-probat-experiment-id={choice?.experiment_id || ''}\n data-probat-variant-label={label}\n data-probat-api-base-url={apiBaseUrl}\n >\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"]}
|
package/dist/index.mjs
CHANGED
|
@@ -55,7 +55,7 @@ async function sendMetric(baseUrl, proposalId, metricName, variantLabel = "contr
|
|
|
55
55
|
captured_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
56
56
|
};
|
|
57
57
|
try {
|
|
58
|
-
await fetch(url, {
|
|
58
|
+
const response = await fetch(url, {
|
|
59
59
|
method: "POST",
|
|
60
60
|
headers: {
|
|
61
61
|
Accept: "application/json",
|
|
@@ -65,7 +65,26 @@ async function sendMetric(baseUrl, proposalId, metricName, variantLabel = "contr
|
|
|
65
65
|
// CRITICAL: Include cookies to distinguish different users
|
|
66
66
|
body: JSON.stringify(body)
|
|
67
67
|
});
|
|
68
|
-
|
|
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
|
+
});
|
|
69
88
|
}
|
|
70
89
|
}
|
|
71
90
|
function extractClickMeta(event) {
|
|
@@ -202,7 +221,9 @@ function handleDocumentClick(event) {
|
|
|
202
221
|
const target = event.target;
|
|
203
222
|
if (!target) return;
|
|
204
223
|
const metadata = getProposalMetadata(target);
|
|
205
|
-
if (!metadata)
|
|
224
|
+
if (!metadata) {
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
206
227
|
const now2 = Date.now();
|
|
207
228
|
const lastClick = lastClickTime.get(metadata.proposalId) || 0;
|
|
208
229
|
if (now2 - lastClick < DEBOUNCE_MS) {
|
|
@@ -210,19 +231,32 @@ function handleDocumentClick(event) {
|
|
|
210
231
|
}
|
|
211
232
|
lastClickTime.set(metadata.proposalId, now2);
|
|
212
233
|
const clickMeta = extractClickMeta(event);
|
|
213
|
-
|
|
214
|
-
const
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
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;
|
|
218
243
|
void sendMetric(
|
|
219
244
|
metadata.apiBaseUrl,
|
|
220
245
|
metadata.proposalId,
|
|
221
246
|
"click",
|
|
222
247
|
metadata.variantLabel,
|
|
223
|
-
|
|
224
|
-
|
|
248
|
+
experimentId,
|
|
249
|
+
finalMeta
|
|
225
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}`);
|
|
226
260
|
}
|
|
227
261
|
function initDocumentClickTracking() {
|
|
228
262
|
if (isListenerAttached) {
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/utils/environment.ts","../src/utils/api.ts","../src/utils/documentClickTracker.ts","../src/context/ProbatContext.tsx","../src/components/ProbatProviderClient.tsx","../src/hooks/useProbatMetrics.ts","../src/utils/storage.ts","../src/hooks/useExperiment.ts","../src/hoc/withExperiment.tsx"],"names":["React","now","useEffect","useCallback","meta","useState","label"],"mappings":"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","file":"index.mjs","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","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 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): 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 // Fetch the variant code (server compiles TSX/JSX to JS)\n const variantUrl = `${baseUrl.replace(/\\/$/, \"\")}/variants/${filePath}`;\n\n const res = await fetch(variantUrl, {\n method: \"GET\",\n headers: { Accept: \"text/javascript\" },\n credentials: \"include\",\n });\n\n if (!res.ok) {\n throw new Error(`HTTP ${res.status}`);\n }\n\n const code = await res.text();\n\n // The server returns an IIFE that assigns to __probatVariant\n // Execute the code to get the component\n // First, ensure React is available globally\n if (typeof window !== \"undefined\") {\n (window as any).React = (window as any).React || React;\n }\n\n // Execute the IIFE code\n const evalFunc = new Function(`\n var __probatVariant;\n ${code}\n return __probatVariant;\n `);\n\n const result = evalFunc();\n\n // The result is { default: Component } from esbuild's IIFE output\n const VariantComponent = result?.default || result;\n\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","/**\n * Document-level click tracking for Probat experiments\n * \n * This module implements event delegation at the document level to track clicks\n * even when components don't have onClick handlers or when stopPropagation() is called.\n */\n\nimport { sendMetric } from './api';\nimport { extractClickMeta } from './api';\n\n// Cache for proposal metadata to avoid repeated DOM queries\nconst proposalCache = new Map<string, {\n proposalId: string;\n experimentId: string | null;\n variantLabel: string;\n apiBaseUrl: string;\n}>();\n\n// Track if listener is already attached\nlet isListenerAttached = false;\n\n// Rate limiting: prevent duplicate rapid clicks\nconst lastClickTime = new Map<string, number>();\nconst DEBOUNCE_MS = 100; // Ignore clicks within 100ms of each other\n\n/**\n * Get proposal metadata from DOM element\n * Looks for the nearest [data-probat-proposal] wrapper\n */\nfunction getProposalMetadata(element: HTMLElement): {\n proposalId: string;\n experimentId: string | null;\n variantLabel: string;\n apiBaseUrl: string;\n} | null {\n // Find the nearest probat wrapper\n const probatWrapper = element.closest('[data-probat-proposal]') as HTMLElement | null;\n \n if (!probatWrapper) return null;\n \n const proposalId = probatWrapper.getAttribute('data-probat-proposal');\n if (!proposalId) return null;\n \n // Check cache first\n const cacheKey = `${proposalId}`;\n const cached = proposalCache.get(cacheKey);\n if (cached) return cached;\n \n // Extract metadata from data attributes\n const experimentId = probatWrapper.getAttribute('data-probat-experiment-id');\n const variantLabel = probatWrapper.getAttribute('data-probat-variant-label') || 'control';\n const apiBaseUrl = probatWrapper.getAttribute('data-probat-api-base-url') || \n (typeof window !== 'undefined' && (window as any).__PROBAT_API) ||\n 'https://gushi.onrender.com';\n \n const metadata = {\n proposalId,\n experimentId: experimentId || null,\n variantLabel,\n apiBaseUrl,\n };\n \n // Cache it\n proposalCache.set(cacheKey, metadata);\n return metadata;\n}\n\n/**\n * Handle click event at document level\n * Uses capture phase to catch events before stopPropagation()\n */\nfunction handleDocumentClick(event: MouseEvent): void {\n const target = event.target as HTMLElement | null;\n if (!target) return;\n \n // Get proposal metadata\n const metadata = getProposalMetadata(target);\n if (!metadata) return;\n \n // Rate limiting: prevent duplicate rapid clicks\n const now = Date.now();\n const lastClick = lastClickTime.get(metadata.proposalId) || 0;\n if (now - lastClick < DEBOUNCE_MS) {\n return; // Ignore rapid duplicate clicks\n }\n lastClickTime.set(metadata.proposalId, now);\n \n // Extract click metadata (your existing function)\n const clickMeta = extractClickMeta(event);\n \n // Determine if we should track this click\n // Track if:\n // 1. It's an actionable element (button, link, etc.) - clickMeta exists\n // 2. Element has data-probat-track attribute\n // 3. Parent has data-probat-track attribute\n const hasTrackAttribute = target.hasAttribute('data-probat-track') || \n target.closest('[data-probat-track]') !== null;\n \n const shouldTrack = clickMeta !== undefined || hasTrackAttribute;\n \n if (!shouldTrack) {\n // Optional: Track \"dead clicks\" for UX insights\n // Uncomment the code below if you want to track clicks on non-interactive elements\n /*\n const deadClickMeta = {\n dead_click: true,\n target_tag: target.tagName,\n target_class: target.className || '',\n target_id: target.id || '',\n };\n \n void sendMetric(\n metadata.apiBaseUrl,\n metadata.proposalId,\n 'dead_click',\n metadata.variantLabel,\n metadata.experimentId,\n deadClickMeta\n );\n */\n return;\n }\n \n // Send click metric\n void sendMetric(\n metadata.apiBaseUrl,\n metadata.proposalId,\n 'click',\n metadata.variantLabel,\n metadata.experimentId || undefined,\n clickMeta\n );\n}\n\n/**\n * Initialize document-level click tracking\n * Call this once when your app initializes (typically in ProbatProvider)\n */\nexport function initDocumentClickTracking(): void {\n if (isListenerAttached) {\n console.warn('[PROBAT] Document click listener already attached');\n return;\n }\n \n if (typeof document === 'undefined') {\n // Server-side rendering - skip\n return;\n }\n \n // Use capture phase (true) to catch events before they bubble\n // This ensures we catch clicks even if stopPropagation() is called\n document.addEventListener('click', handleDocumentClick, true);\n \n isListenerAttached = true;\n console.log('[PROBAT] Document-level click tracking initialized');\n}\n\n/**\n * Clean up the listener (useful for testing or cleanup)\n */\nexport function cleanupDocumentClickTracking(): void {\n if (!isListenerAttached) return;\n \n if (typeof document !== 'undefined') {\n document.removeEventListener('click', handleDocumentClick, true);\n }\n \n isListenerAttached = false;\n proposalCache.clear();\n lastClickTime.clear();\n}\n\n/**\n * Update proposal metadata cache (call this when proposal data changes)\n * This is useful if you want to update the cache without waiting for DOM queries\n */\nexport function updateProposalMetadata(\n proposalId: string,\n metadata: {\n experimentId?: string | null;\n variantLabel?: string;\n apiBaseUrl?: string;\n }\n): void {\n const existing = proposalCache.get(proposalId);\n if (existing) {\n proposalCache.set(proposalId, {\n ...existing,\n ...metadata,\n });\n }\n}\n\n/**\n * Clear the proposal cache (useful for testing)\n */\nexport function clearProposalCache(): void {\n proposalCache.clear();\n}\n\n","\"use client\";\n\nimport React, { createContext, useContext, useMemo, useEffect } from \"react\";\nimport { detectEnvironment } from \"../utils/environment\";\nimport { initDocumentClickTracking, cleanupDocumentClickTracking } from \"../utils/documentClickTracker\";\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 // Initialize document-level click tracking when provider mounts\n useEffect(() => {\n initDocumentClickTracking();\n \n // Cleanup on unmount (optional, but good practice)\n return () => {\n cleanupDocumentClickTracking();\n };\n }, []);\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","\"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 );\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\n onClick={(event) => {\n // Keep existing onClick for backward compatibility\n // Document-level listener will also catch it (in capture phase)\n trackClick(event);\n }}\n data-probat-proposal={proposalId}\n data-probat-experiment-id={choice?.experiment_id || ''}\n data-probat-variant-label={label}\n data-probat-api-base-url={apiBaseUrl}\n >\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/utils/api.ts","../src/utils/documentClickTracker.ts","../src/context/ProbatContext.tsx","../src/components/ProbatProviderClient.tsx","../src/hooks/useProbatMetrics.ts","../src/utils/storage.ts","../src/hooks/useExperiment.ts","../src/hoc/withExperiment.tsx"],"names":["React","now","useEffect","useCallback","meta","useState","label"],"mappings":"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","file":"index.mjs","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","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 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 const response = 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 \n // Log in development for debugging\n if (!response.ok) {\n console.warn('[PROBAT] Metric send failed:', {\n status: response.status,\n statusText: response.statusText,\n url,\n body,\n });\n } else {\n console.log('[PROBAT] Metric sent successfully:', {\n metricName,\n proposalId,\n variantLabel,\n });\n }\n } catch (error) {\n // Log error in development, but don't break the app\n console.error('[PROBAT] Error sending metric:', {\n error: error instanceof Error ? error.message : String(error),\n url,\n body,\n });\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): 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 // Fetch the variant code (server compiles TSX/JSX to JS)\n const variantUrl = `${baseUrl.replace(/\\/$/, \"\")}/variants/${filePath}`;\n\n const res = await fetch(variantUrl, {\n method: \"GET\",\n headers: { Accept: \"text/javascript\" },\n credentials: \"include\",\n });\n\n if (!res.ok) {\n throw new Error(`HTTP ${res.status}`);\n }\n\n const code = await res.text();\n\n // The server returns an IIFE that assigns to __probatVariant\n // Execute the code to get the component\n // First, ensure React is available globally\n if (typeof window !== \"undefined\") {\n (window as any).React = (window as any).React || React;\n }\n\n // Execute the IIFE code\n const evalFunc = new Function(`\n var __probatVariant;\n ${code}\n return __probatVariant;\n `);\n\n const result = evalFunc();\n\n // The result is { default: Component } from esbuild's IIFE output\n const VariantComponent = result?.default || result;\n\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","/**\n * Document-level click tracking for Probat experiments\n * \n * This module implements event delegation at the document level to track clicks\n * even when components don't have onClick handlers or when stopPropagation() is called.\n */\n\nimport { sendMetric } from './api';\nimport { extractClickMeta } from './api';\n\n// Cache for proposal metadata to avoid repeated DOM queries\nconst proposalCache = new Map<string, {\n proposalId: string;\n experimentId: string | null;\n variantLabel: string;\n apiBaseUrl: string;\n}>();\n\n// Track if listener is already attached\nlet isListenerAttached = false;\n\n// Rate limiting: prevent duplicate rapid clicks\nconst lastClickTime = new Map<string, number>();\nconst DEBOUNCE_MS = 100; // Ignore clicks within 100ms of each other\n\n/**\n * Get proposal metadata from DOM element\n * Looks for the nearest [data-probat-proposal] wrapper\n */\nfunction getProposalMetadata(element: HTMLElement): {\n proposalId: string;\n experimentId: string | null;\n variantLabel: string;\n apiBaseUrl: string;\n} | null {\n // Find the nearest probat wrapper\n const probatWrapper = element.closest('[data-probat-proposal]') as HTMLElement | null;\n\n if (!probatWrapper) return null;\n\n const proposalId = probatWrapper.getAttribute('data-probat-proposal');\n if (!proposalId) return null;\n\n // Check cache first\n const cacheKey = `${proposalId}`;\n const cached = proposalCache.get(cacheKey);\n if (cached) return cached;\n\n // Extract metadata from data attributes\n const experimentId = probatWrapper.getAttribute('data-probat-experiment-id');\n const variantLabel = probatWrapper.getAttribute('data-probat-variant-label') || 'control';\n const apiBaseUrl = probatWrapper.getAttribute('data-probat-api-base-url') ||\n (typeof window !== 'undefined' && (window as any).__PROBAT_API) ||\n 'https://gushi.onrender.com';\n\n const metadata = {\n proposalId,\n experimentId: experimentId || null,\n variantLabel,\n apiBaseUrl,\n };\n\n // Cache it\n proposalCache.set(cacheKey, metadata);\n return metadata;\n}\n\n/**\n * Handle click event at document level\n * Uses capture phase to catch events before stopPropagation()\n */\nfunction handleDocumentClick(event: MouseEvent): void {\n const target = event.target as HTMLElement | null;\n if (!target) return;\n\n // Get proposal metadata\n const metadata = getProposalMetadata(target);\n if (!metadata) {\n return; // Click outside probat component\n }\n\n // Rate limiting: prevent duplicate rapid clicks\n const now = Date.now();\n const lastClick = lastClickTime.get(metadata.proposalId) || 0;\n if (now - lastClick < DEBOUNCE_MS) {\n return; // Ignore rapid duplicate clicks\n }\n lastClickTime.set(metadata.proposalId, now);\n\n // Extract click metadata (your existing function)\n const clickMeta = extractClickMeta(event);\n\n // Determine if we should track this click\n // Track if:\n // 1. It's an actionable element (button, link, etc.) - clickMeta exists\n // 2. Element has data-probat-track attribute\n // 3. Parent has data-probat-track attribute\n // 4. ANY click within a probat component (more permissive - track all clicks)\n const hasTrackAttribute = target.hasAttribute('data-probat-track') ||\n target.closest('[data-probat-track]') !== null;\n\n // More permissive: Track ALL clicks within probat components\n // This ensures we capture clicks even if elements don't have explicit tracking attributes\n const shouldTrack = clickMeta !== undefined || hasTrackAttribute || true; // Track all clicks in probat components\n\n if (!shouldTrack) {\n return;\n }\n\n // Build metadata - use clickMeta if available, otherwise create basic metadata\n const finalMeta = clickMeta || {\n target_tag: target.tagName,\n target_class: target.className || '',\n target_id: target.id || '',\n clicked_inside_probat: true, // Flag to indicate this was tracked via document-level listener\n };\n\n // Send click metric\n // For control variant, don't send experiment_id (control might be synthetic)\n // For other variants, send experiment_id if it exists and is valid (not synthetic \"exp_\" prefix)\n const experimentId = metadata.variantLabel === 'control'\n ? undefined\n : (metadata.experimentId && !metadata.experimentId.startsWith('exp_')\n ? metadata.experimentId\n : undefined);\n\n void sendMetric(\n metadata.apiBaseUrl,\n metadata.proposalId,\n 'click',\n metadata.variantLabel,\n experimentId,\n finalMeta\n );\n\n // Debug logging (always log for now to help diagnose)\n console.log('[PROBAT] Click tracked:', {\n proposalId: metadata.proposalId,\n variantLabel: metadata.variantLabel,\n target: target.tagName,\n targetId: target.id || 'none',\n targetClass: target.className || 'none',\n meta: finalMeta,\n });\n\n // Also log to help debug if API call fails\n console.log('[PROBAT] Sending metric to:', `${metadata.apiBaseUrl}/send_metrics/${metadata.proposalId}`);\n}\n\n/**\n * Initialize document-level click tracking\n * Call this once when your app initializes (typically in ProbatProvider)\n */\nexport function initDocumentClickTracking(): void {\n if (isListenerAttached) {\n console.warn('[PROBAT] Document click listener already attached');\n return;\n }\n\n if (typeof document === 'undefined') {\n // Server-side rendering - skip\n return;\n }\n\n // Use capture phase (true) to catch events before they bubble\n // This ensures we catch clicks even if stopPropagation() is called\n document.addEventListener('click', handleDocumentClick, true);\n\n isListenerAttached = true;\n console.log('[PROBAT] Document-level click tracking initialized');\n}\n\n/**\n * Clean up the listener (useful for testing or cleanup)\n */\nexport function cleanupDocumentClickTracking(): void {\n if (!isListenerAttached) return;\n\n if (typeof document !== 'undefined') {\n document.removeEventListener('click', handleDocumentClick, true);\n }\n\n isListenerAttached = false;\n proposalCache.clear();\n lastClickTime.clear();\n}\n\n/**\n * Update proposal metadata cache (call this when proposal data changes)\n * This is useful if you want to update the cache without waiting for DOM queries\n */\nexport function updateProposalMetadata(\n proposalId: string,\n metadata: {\n experimentId?: string | null;\n variantLabel?: string;\n apiBaseUrl?: string;\n }\n): void {\n const existing = proposalCache.get(proposalId);\n if (existing) {\n proposalCache.set(proposalId, {\n ...existing,\n ...metadata,\n });\n }\n}\n\n/**\n * Clear the proposal cache (useful for testing)\n */\nexport function clearProposalCache(): void {\n proposalCache.clear();\n}\n\n","\"use client\";\n\nimport React, { createContext, useContext, useMemo, useEffect } from \"react\";\nimport { detectEnvironment } from \"../utils/environment\";\nimport { initDocumentClickTracking, cleanupDocumentClickTracking } from \"../utils/documentClickTracker\";\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 // Initialize document-level click tracking when provider mounts\n useEffect(() => {\n initDocumentClickTracking();\n \n // Cleanup on unmount (optional, but good practice)\n return () => {\n cleanupDocumentClickTracking();\n };\n }, []);\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","\"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 );\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\n onClick={(event) => {\n // Keep existing onClick for backward compatibility\n // Document-level listener will also catch it (in capture phase)\n trackClick(event);\n }}\n data-probat-proposal={proposalId}\n data-probat-experiment-id={choice?.experiment_id || ''}\n data-probat-variant-label={label}\n data-probat-api-base-url={apiBaseUrl}\n >\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"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@probat/react",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "React library for Probat A/B testing and experimentation",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.mjs",
|
|
@@ -42,4 +42,4 @@
|
|
|
42
42
|
"tsup": "^8.0.0",
|
|
43
43
|
"typescript": "^5.0.0"
|
|
44
44
|
}
|
|
45
|
-
}
|
|
45
|
+
}
|
package/src/utils/api.ts
CHANGED
|
@@ -82,7 +82,7 @@ export async function sendMetric(
|
|
|
82
82
|
captured_at: new Date().toISOString(),
|
|
83
83
|
};
|
|
84
84
|
try {
|
|
85
|
-
await fetch(url, {
|
|
85
|
+
const response = await fetch(url, {
|
|
86
86
|
method: "POST",
|
|
87
87
|
headers: {
|
|
88
88
|
Accept: "application/json",
|
|
@@ -91,8 +91,29 @@ export async function sendMetric(
|
|
|
91
91
|
credentials: "include", // CRITICAL: Include cookies to distinguish different users
|
|
92
92
|
body: JSON.stringify(body),
|
|
93
93
|
});
|
|
94
|
-
|
|
95
|
-
//
|
|
94
|
+
|
|
95
|
+
// Log in development for debugging
|
|
96
|
+
if (!response.ok) {
|
|
97
|
+
console.warn('[PROBAT] Metric send failed:', {
|
|
98
|
+
status: response.status,
|
|
99
|
+
statusText: response.statusText,
|
|
100
|
+
url,
|
|
101
|
+
body,
|
|
102
|
+
});
|
|
103
|
+
} else {
|
|
104
|
+
console.log('[PROBAT] Metric sent successfully:', {
|
|
105
|
+
metricName,
|
|
106
|
+
proposalId,
|
|
107
|
+
variantLabel,
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
} catch (error) {
|
|
111
|
+
// Log error in development, but don't break the app
|
|
112
|
+
console.error('[PROBAT] Error sending metric:', {
|
|
113
|
+
error: error instanceof Error ? error.message : String(error),
|
|
114
|
+
url,
|
|
115
|
+
body,
|
|
116
|
+
});
|
|
96
117
|
}
|
|
97
118
|
}
|
|
98
119
|
|
|
@@ -35,31 +35,31 @@ function getProposalMetadata(element: HTMLElement): {
|
|
|
35
35
|
} | null {
|
|
36
36
|
// Find the nearest probat wrapper
|
|
37
37
|
const probatWrapper = element.closest('[data-probat-proposal]') as HTMLElement | null;
|
|
38
|
-
|
|
38
|
+
|
|
39
39
|
if (!probatWrapper) return null;
|
|
40
|
-
|
|
40
|
+
|
|
41
41
|
const proposalId = probatWrapper.getAttribute('data-probat-proposal');
|
|
42
42
|
if (!proposalId) return null;
|
|
43
|
-
|
|
43
|
+
|
|
44
44
|
// Check cache first
|
|
45
45
|
const cacheKey = `${proposalId}`;
|
|
46
46
|
const cached = proposalCache.get(cacheKey);
|
|
47
47
|
if (cached) return cached;
|
|
48
|
-
|
|
48
|
+
|
|
49
49
|
// Extract metadata from data attributes
|
|
50
50
|
const experimentId = probatWrapper.getAttribute('data-probat-experiment-id');
|
|
51
51
|
const variantLabel = probatWrapper.getAttribute('data-probat-variant-label') || 'control';
|
|
52
|
-
const apiBaseUrl = probatWrapper.getAttribute('data-probat-api-base-url') ||
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
52
|
+
const apiBaseUrl = probatWrapper.getAttribute('data-probat-api-base-url') ||
|
|
53
|
+
(typeof window !== 'undefined' && (window as any).__PROBAT_API) ||
|
|
54
|
+
'https://gushi.onrender.com';
|
|
55
|
+
|
|
56
56
|
const metadata = {
|
|
57
57
|
proposalId,
|
|
58
58
|
experimentId: experimentId || null,
|
|
59
59
|
variantLabel,
|
|
60
60
|
apiBaseUrl,
|
|
61
61
|
};
|
|
62
|
-
|
|
62
|
+
|
|
63
63
|
// Cache it
|
|
64
64
|
proposalCache.set(cacheKey, metadata);
|
|
65
65
|
return metadata;
|
|
@@ -72,11 +72,13 @@ function getProposalMetadata(element: HTMLElement): {
|
|
|
72
72
|
function handleDocumentClick(event: MouseEvent): void {
|
|
73
73
|
const target = event.target as HTMLElement | null;
|
|
74
74
|
if (!target) return;
|
|
75
|
-
|
|
75
|
+
|
|
76
76
|
// Get proposal metadata
|
|
77
77
|
const metadata = getProposalMetadata(target);
|
|
78
|
-
if (!metadata)
|
|
79
|
-
|
|
78
|
+
if (!metadata) {
|
|
79
|
+
return; // Click outside probat component
|
|
80
|
+
}
|
|
81
|
+
|
|
80
82
|
// Rate limiting: prevent duplicate rapid clicks
|
|
81
83
|
const now = Date.now();
|
|
82
84
|
const lastClick = lastClickTime.get(metadata.proposalId) || 0;
|
|
@@ -84,52 +86,65 @@ function handleDocumentClick(event: MouseEvent): void {
|
|
|
84
86
|
return; // Ignore rapid duplicate clicks
|
|
85
87
|
}
|
|
86
88
|
lastClickTime.set(metadata.proposalId, now);
|
|
87
|
-
|
|
89
|
+
|
|
88
90
|
// Extract click metadata (your existing function)
|
|
89
91
|
const clickMeta = extractClickMeta(event);
|
|
90
|
-
|
|
92
|
+
|
|
91
93
|
// Determine if we should track this click
|
|
92
94
|
// Track if:
|
|
93
95
|
// 1. It's an actionable element (button, link, etc.) - clickMeta exists
|
|
94
96
|
// 2. Element has data-probat-track attribute
|
|
95
97
|
// 3. Parent has data-probat-track attribute
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
98
|
+
// 4. ANY click within a probat component (more permissive - track all clicks)
|
|
99
|
+
const hasTrackAttribute = target.hasAttribute('data-probat-track') ||
|
|
100
|
+
target.closest('[data-probat-track]') !== null;
|
|
101
|
+
|
|
102
|
+
// More permissive: Track ALL clicks within probat components
|
|
103
|
+
// This ensures we capture clicks even if elements don't have explicit tracking attributes
|
|
104
|
+
const shouldTrack = clickMeta !== undefined || hasTrackAttribute || true; // Track all clicks in probat components
|
|
105
|
+
|
|
101
106
|
if (!shouldTrack) {
|
|
102
|
-
// Optional: Track "dead clicks" for UX insights
|
|
103
|
-
// Uncomment the code below if you want to track clicks on non-interactive elements
|
|
104
|
-
/*
|
|
105
|
-
const deadClickMeta = {
|
|
106
|
-
dead_click: true,
|
|
107
|
-
target_tag: target.tagName,
|
|
108
|
-
target_class: target.className || '',
|
|
109
|
-
target_id: target.id || '',
|
|
110
|
-
};
|
|
111
|
-
|
|
112
|
-
void sendMetric(
|
|
113
|
-
metadata.apiBaseUrl,
|
|
114
|
-
metadata.proposalId,
|
|
115
|
-
'dead_click',
|
|
116
|
-
metadata.variantLabel,
|
|
117
|
-
metadata.experimentId,
|
|
118
|
-
deadClickMeta
|
|
119
|
-
);
|
|
120
|
-
*/
|
|
121
107
|
return;
|
|
122
108
|
}
|
|
123
|
-
|
|
109
|
+
|
|
110
|
+
// Build metadata - use clickMeta if available, otherwise create basic metadata
|
|
111
|
+
const finalMeta = clickMeta || {
|
|
112
|
+
target_tag: target.tagName,
|
|
113
|
+
target_class: target.className || '',
|
|
114
|
+
target_id: target.id || '',
|
|
115
|
+
clicked_inside_probat: true, // Flag to indicate this was tracked via document-level listener
|
|
116
|
+
};
|
|
117
|
+
|
|
124
118
|
// Send click metric
|
|
119
|
+
// For control variant, don't send experiment_id (control might be synthetic)
|
|
120
|
+
// For other variants, send experiment_id if it exists and is valid (not synthetic "exp_" prefix)
|
|
121
|
+
const experimentId = metadata.variantLabel === 'control'
|
|
122
|
+
? undefined
|
|
123
|
+
: (metadata.experimentId && !metadata.experimentId.startsWith('exp_')
|
|
124
|
+
? metadata.experimentId
|
|
125
|
+
: undefined);
|
|
126
|
+
|
|
125
127
|
void sendMetric(
|
|
126
128
|
metadata.apiBaseUrl,
|
|
127
129
|
metadata.proposalId,
|
|
128
130
|
'click',
|
|
129
131
|
metadata.variantLabel,
|
|
130
|
-
|
|
131
|
-
|
|
132
|
+
experimentId,
|
|
133
|
+
finalMeta
|
|
132
134
|
);
|
|
135
|
+
|
|
136
|
+
// Debug logging (always log for now to help diagnose)
|
|
137
|
+
console.log('[PROBAT] Click tracked:', {
|
|
138
|
+
proposalId: metadata.proposalId,
|
|
139
|
+
variantLabel: metadata.variantLabel,
|
|
140
|
+
target: target.tagName,
|
|
141
|
+
targetId: target.id || 'none',
|
|
142
|
+
targetClass: target.className || 'none',
|
|
143
|
+
meta: finalMeta,
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
// Also log to help debug if API call fails
|
|
147
|
+
console.log('[PROBAT] Sending metric to:', `${metadata.apiBaseUrl}/send_metrics/${metadata.proposalId}`);
|
|
133
148
|
}
|
|
134
149
|
|
|
135
150
|
/**
|
|
@@ -141,16 +156,16 @@ export function initDocumentClickTracking(): void {
|
|
|
141
156
|
console.warn('[PROBAT] Document click listener already attached');
|
|
142
157
|
return;
|
|
143
158
|
}
|
|
144
|
-
|
|
159
|
+
|
|
145
160
|
if (typeof document === 'undefined') {
|
|
146
161
|
// Server-side rendering - skip
|
|
147
162
|
return;
|
|
148
163
|
}
|
|
149
|
-
|
|
164
|
+
|
|
150
165
|
// Use capture phase (true) to catch events before they bubble
|
|
151
166
|
// This ensures we catch clicks even if stopPropagation() is called
|
|
152
167
|
document.addEventListener('click', handleDocumentClick, true);
|
|
153
|
-
|
|
168
|
+
|
|
154
169
|
isListenerAttached = true;
|
|
155
170
|
console.log('[PROBAT] Document-level click tracking initialized');
|
|
156
171
|
}
|
|
@@ -160,11 +175,11 @@ export function initDocumentClickTracking(): void {
|
|
|
160
175
|
*/
|
|
161
176
|
export function cleanupDocumentClickTracking(): void {
|
|
162
177
|
if (!isListenerAttached) return;
|
|
163
|
-
|
|
178
|
+
|
|
164
179
|
if (typeof document !== 'undefined') {
|
|
165
180
|
document.removeEventListener('click', handleDocumentClick, true);
|
|
166
181
|
}
|
|
167
|
-
|
|
182
|
+
|
|
168
183
|
isListenerAttached = false;
|
|
169
184
|
proposalCache.clear();
|
|
170
185
|
lastClickTime.clear();
|