@probat/react 0.4.0 → 0.4.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.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/context/ProbatContext.tsx","../src/components/ProbatProviderClient.tsx","../src/utils/environment.ts","../src/utils/eventContext.ts","../src/utils/api.ts","../src/utils/dedupeStorage.ts","../src/utils/stableInstanceId.ts","../src/components/Experiment.tsx","../src/hooks/useProbatMetrics.ts"],"names":["createContext","useMemo","React","useContext","useRef","useState","useEffect","useCallback"],"mappings":"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","file":"index.js","sourcesContent":["\"use client\";\n\nimport React, { createContext, useContext, useMemo } from \"react\";\n\nexport interface ProbatContextValue {\n host: string;\n customerId?: string;\n bootstrap: Record<string, string>;\n}\n\nconst ProbatContext = createContext<ProbatContextValue | null>(null);\n\nconst DEFAULT_HOST = \"https://gushi.onrender.com\";\n\nexport interface ProbatProviderProps {\n /** Your end-user's ID. When provided, used as the distinct_id for variant\n * assignment (consistent across devices) and attached to all events. */\n customerId?: string;\n /** Base URL for the Probat API. Defaults to https://gushi.onrender.com */\n host?: string;\n /**\n * Bootstrap assignments to avoid flash on first render.\n * Map of experiment id → variant key.\n * e.g. { \"cta-copy-test\": \"ai_v1\" }\n */\n bootstrap?: Record<string, string>;\n children: React.ReactNode;\n}\n\nexport function ProbatProvider({\n customerId,\n host = DEFAULT_HOST,\n bootstrap,\n children,\n}: ProbatProviderProps) {\n const value = useMemo<ProbatContextValue>(\n () => ({\n host: host.replace(/\\/$/, \"\"),\n customerId,\n bootstrap: bootstrap ?? {},\n }),\n [customerId, host, bootstrap]\n );\n\n return (\n <ProbatContext.Provider value={value}>\n {children}\n </ProbatContext.Provider>\n );\n}\n\nexport function useProbatContext(): ProbatContextValue {\n const ctx = useContext(ProbatContext);\n if (!ctx) {\n throw new Error(\n \"useProbatContext must be used within <ProbatProviderClient>. Wrap your app with <ProbatProviderClient>.\"\n );\n }\n return ctx;\n}\n","\"use client\";\n\nimport React from \"react\";\nimport { ProbatProvider } from \"../context/ProbatContext\";\nimport type { ProbatProviderProps } from \"../context/ProbatContext\";\n\n/**\n * Client-only provider for Next.js App Router.\n * Import this in your layout/providers file.\n *\n * @example\n * ```tsx\n * // app/providers.tsx\n * \"use client\";\n * import { ProbatProviderClient } from \"@probat/react\";\n *\n * export function Providers({ children }) {\n * return (\n * <ProbatProviderClient customerId={user.id}>\n * {children}\n * </ProbatProviderClient>\n * );\n * }\n * ```\n */\nexport function ProbatProviderClient(props: ProbatProviderProps) {\n return React.createElement(ProbatProvider, props);\n}\n\nexport type { ProbatProviderProps };\n","/**\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","/**\n * Event context helpers: distinct_id, session_id, page info.\n * All browser-safe — no-ops when window is unavailable.\n */\n\nconst DISTINCT_ID_KEY = \"probat:distinct_id\";\nconst SESSION_ID_KEY = \"probat:session_id\";\n\nlet cachedDistinctId: string | null = null;\nlet cachedSessionId: string | null = null;\n\nfunction generateId(): string {\n // crypto.randomUUID where available, else fallback\n if (typeof crypto !== \"undefined\" && crypto.randomUUID) {\n return crypto.randomUUID();\n }\n // fallback: random hex\n const bytes = new Uint8Array(16);\n if (typeof crypto !== \"undefined\" && crypto.getRandomValues) {\n crypto.getRandomValues(bytes);\n } else {\n for (let i = 0; i < 16; i++) bytes[i] = Math.floor(Math.random() * 256);\n }\n return Array.from(bytes, (b) => b.toString(16).padStart(2, \"0\")).join(\"\");\n}\n\nexport function getDistinctId(): string {\n if (cachedDistinctId) return cachedDistinctId;\n if (typeof window === \"undefined\") return \"server\";\n try {\n const stored = localStorage.getItem(DISTINCT_ID_KEY);\n if (stored) {\n cachedDistinctId = stored;\n return stored;\n }\n } catch {}\n const id = `anon_${generateId()}`;\n cachedDistinctId = id;\n try {\n localStorage.setItem(DISTINCT_ID_KEY, id);\n } catch {}\n return id;\n}\n\nexport function getSessionId(): string {\n if (cachedSessionId) return cachedSessionId;\n if (typeof window === \"undefined\") return \"server\";\n try {\n const stored = sessionStorage.getItem(SESSION_ID_KEY);\n if (stored) {\n cachedSessionId = stored;\n return stored;\n }\n } catch {}\n const id = `sess_${generateId()}`;\n cachedSessionId = id;\n try {\n sessionStorage.setItem(SESSION_ID_KEY, id);\n } catch {}\n return id;\n}\n\nexport function getPageKey(): string {\n if (typeof window === \"undefined\") return \"\";\n return window.location.pathname + window.location.search;\n}\n\nexport function getPageUrl(): string {\n if (typeof window === \"undefined\") return \"\";\n return window.location.href;\n}\n\nexport function getReferrer(): string {\n if (typeof document === \"undefined\") return \"\";\n return document.referrer;\n}\n\nexport interface EventContext {\n distinct_id: string;\n session_id: string;\n $page_url: string;\n $pathname: string;\n $referrer: string;\n}\n\nexport function buildEventContext(): EventContext {\n return {\n distinct_id: getDistinctId(),\n session_id: getSessionId(),\n $page_url: getPageUrl(),\n $pathname: typeof window !== \"undefined\" ? window.location.pathname : \"\",\n $referrer: getReferrer(),\n };\n}\n","import { detectEnvironment } from \"./environment\";\nimport { buildEventContext } from \"./eventContext\";\n\n// ── Types ──────────────────────────────────────────────────────────────────\n\nexport interface DecisionResponse {\n variant_key: string;\n}\n\nexport interface MetricPayload {\n event: string;\n environment: \"dev\" | \"prod\";\n properties: Record<string, unknown>;\n}\n\n// ── Assignment fetching ────────────────────────────────────────────────────\n\nconst pendingDecisions = new Map<string, Promise<string>>();\n\n/**\n * Fetch the variant assignment for an experiment.\n * Returns the variant key string (e.g. \"control\", \"ai_v1\").\n * Deduplicates concurrent calls for the same experiment.\n */\nexport async function fetchDecision(\n host: string,\n experimentId: string,\n distinctId: string\n): Promise<string> {\n const existing = pendingDecisions.get(experimentId);\n if (existing) return existing;\n\n const promise = (async () => {\n try {\n const url = `${host.replace(/\\/$/, \"\")}/experiment/decide`;\n const res = await fetch(url, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n },\n credentials: \"include\",\n body: JSON.stringify({\n experiment_id: experimentId,\n distinct_id: distinctId,\n }),\n });\n if (!res.ok) throw new Error(`HTTP ${res.status}`);\n const data = (await res.json()) as DecisionResponse;\n return data.variant_key || \"control\";\n } finally {\n pendingDecisions.delete(experimentId);\n }\n })();\n\n pendingDecisions.set(experimentId, promise);\n return promise;\n}\n\n// ── Metric sending ─────────────────────────────────────────────────────────\n\n/**\n * Fire-and-forget metric send. Never throws.\n */\nexport function sendMetric(\n host: string,\n event: string,\n properties: Record<string, unknown>\n): void {\n if (typeof window === \"undefined\") return;\n\n const ctx = buildEventContext();\n const payload: MetricPayload = {\n event,\n environment: detectEnvironment(),\n properties: {\n ...ctx,\n source: \"react-sdk\",\n captured_at: new Date().toISOString(),\n ...properties,\n },\n };\n\n try {\n const url = `${host.replace(/\\/$/, \"\")}/experiment/metrics`;\n fetch(url, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n credentials: \"include\",\n body: JSON.stringify(payload),\n }).catch(() => {});\n } catch {\n // silently drop\n }\n}\n\n// ── Click metadata extraction ──────────────────────────────────────────────\n\nexport interface ClickMeta {\n click_target_tag: string;\n click_target_text?: string;\n click_target_id?: string;\n click_is_primary: boolean;\n}\n\n/**\n * Given a click event inside an experiment boundary, extract metadata.\n * Prioritizes elements with data-probat-click=\"primary\",\n * then falls back to button/a/role=button.\n */\nexport function extractClickMeta(target: EventTarget | null): ClickMeta | null {\n if (!target || !(target instanceof HTMLElement)) return null;\n\n // Priority 1: explicit primary marker\n const primary = target.closest('[data-probat-click=\"primary\"]');\n if (primary) return buildMeta(primary as HTMLElement, true);\n\n // Priority 2: interactive elements\n const interactive = target.closest('button, a, [role=\"button\"]');\n if (interactive) return buildMeta(interactive as HTMLElement, false);\n\n return null;\n}\n\nfunction buildMeta(el: HTMLElement, isPrimary: boolean): ClickMeta {\n const meta: ClickMeta = {\n click_target_tag: el.tagName,\n click_is_primary: isPrimary,\n };\n if (el.id) meta.click_target_id = el.id;\n const text = el.textContent?.trim();\n if (text) meta.click_target_text = text.slice(0, 120);\n return meta;\n}\n","/**\n * Dedupe storage for experiment exposures.\n * Uses sessionStorage + in-memory Set fallback.\n * Key format: probat:seen:{id}:{variantKey}:{instanceId}:{pageKey}\n */\n\nconst PREFIX = \"probat:seen:\";\nconst memorySet = new Set<string>();\n\nexport function makeDedupeKey(\n experimentId: string,\n variantKey: string,\n instanceId: string,\n pageKey: string\n): string {\n return `${PREFIX}${experimentId}:${variantKey}:${instanceId}:${pageKey}`;\n}\n\nexport function hasSeen(key: string): boolean {\n if (memorySet.has(key)) return true;\n if (typeof window === \"undefined\") return false;\n try {\n return sessionStorage.getItem(key) === \"1\";\n } catch {\n return false;\n }\n}\n\nexport function markSeen(key: string): void {\n memorySet.add(key);\n if (typeof window === \"undefined\") return;\n try {\n sessionStorage.setItem(key, \"1\");\n } catch {}\n}\n\n/** Reset all dedupe state — useful for testing. */\nexport function resetDedupe(): void {\n memorySet.clear();\n}\n","/**\n * Stable auto-generated instance IDs for <Experiment />.\n *\n * Problem: a naïve useRef + module counter gives a different ID on every mount,\n * so StrictMode double-mount or unmount/remount changes the dedupe key.\n *\n * Solution:\n * 1. React 18+ → useId() is stable per fiber position.\n * 2. Fallback → sessionStorage-backed slot counter per (experimentId, pageKey).\n * 3. Both paths persist a mapping in sessionStorage:\n * probat:instance:{experimentId}:{pageKey}:{positionKey} → stableId\n * so the same position resolves to the same ID across mounts.\n */\n\nimport React, { useRef } from \"react\";\nimport { getPageKey } from \"./eventContext\";\n\nconst INSTANCE_PREFIX = \"probat:instance:\";\n\n// ── Helpers ────────────────────────────────────────────────────────────────\n\nfunction shortId(): string {\n const bytes = new Uint8Array(4);\n if (typeof crypto !== \"undefined\" && crypto.getRandomValues) {\n crypto.getRandomValues(bytes);\n } else {\n for (let i = 0; i < 4; i++) bytes[i] = Math.floor(Math.random() * 256);\n }\n return Array.from(bytes, (b) => b.toString(16).padStart(2, \"0\")).join(\"\");\n}\n\n/**\n * Look up or create a stable instance ID in sessionStorage.\n */\nfunction resolveStableId(storageKey: string): string {\n if (typeof window !== \"undefined\") {\n try {\n const stored = sessionStorage.getItem(storageKey);\n if (stored) return stored;\n } catch {}\n }\n const id = `inst_${shortId()}`;\n if (typeof window !== \"undefined\") {\n try {\n sessionStorage.setItem(storageKey, id);\n } catch {}\n }\n return id;\n}\n\n// ── Fallback: render-wave slot counter ─────────────────────────────────────\n// Each synchronous render batch claims sequential slots per (experimentId,\n// pageKey). A microtask resets the counters so the next batch starts at 0,\n// giving the same component position the same slot across mounts.\n\nconst slotCounters = new Map<string, number>();\nlet resetScheduled = false;\n\nfunction claimSlot(groupKey: string): number {\n const idx = slotCounters.get(groupKey) ?? 0;\n slotCounters.set(groupKey, idx + 1);\n if (!resetScheduled) {\n resetScheduled = true;\n Promise.resolve().then(() => {\n slotCounters.clear();\n resetScheduled = false;\n });\n }\n return idx;\n}\n\n// ── Hook: React 18+ path (useId available) ─────────────────────────────────\n\nfunction useStableInstanceIdV18(experimentId: string): string {\n const reactId = (React as any).useId() as string;\n const ref = useRef(\"\");\n if (!ref.current) {\n const key = `${INSTANCE_PREFIX}${experimentId}:${getPageKey()}:${reactId}`;\n ref.current = resolveStableId(key);\n }\n return ref.current;\n}\n\n// ── Hook: fallback path (no useId) ─────────────────────────────────────────\n\nfunction useStableInstanceIdFallback(experimentId: string): string {\n const slotRef = useRef(-1);\n const ref = useRef(\"\");\n if (slotRef.current === -1) {\n slotRef.current = claimSlot(`${experimentId}:${getPageKey()}`);\n }\n if (!ref.current) {\n const key = `${INSTANCE_PREFIX}${experimentId}:${getPageKey()}:${slotRef.current}`;\n ref.current = resolveStableId(key);\n }\n return ref.current;\n}\n\n// ── Exported hook ──────────────────────────────────────────────────────────\n// Selection is a module-level constant so the hook-call count never changes\n// between renders — safe for the rules of hooks.\n\nexport const useStableInstanceId: (experimentId: string) => string =\n typeof (React as any).useId === \"function\"\n ? useStableInstanceIdV18\n : useStableInstanceIdFallback;\n\n// ── Test utility ───────────────────────────────────────────────────────────\n\nexport function resetInstanceIdState(): void {\n slotCounters.clear();\n resetScheduled = false;\n}\n","\"use client\";\n\nimport React, {\n useEffect,\n useRef,\n useState,\n useCallback,\n useMemo,\n} from \"react\";\nimport { useProbatContext } from \"../context/ProbatContext\";\nimport { fetchDecision, sendMetric, extractClickMeta } from \"../utils/api\";\nimport { getDistinctId, getPageKey } from \"../utils/eventContext\";\nimport { makeDedupeKey, hasSeen, markSeen } from \"../utils/dedupeStorage\";\nimport { useStableInstanceId } from \"../utils/stableInstanceId\";\n\n// ── localStorage assignment cache ──────────────────────────────────────────\n\nconst ASSIGNMENT_PREFIX = \"probat:assignment:\";\n\ninterface StoredAssignment {\n variantKey: string;\n ts: number;\n}\n\nfunction readAssignment(id: string): string | null {\n if (typeof window === \"undefined\") return null;\n try {\n const raw = localStorage.getItem(ASSIGNMENT_PREFIX + id);\n if (!raw) return null;\n const parsed: StoredAssignment = JSON.parse(raw);\n return parsed.variantKey ?? null;\n } catch {\n return null;\n }\n}\n\nfunction writeAssignment(id: string, variantKey: string): void {\n if (typeof window === \"undefined\") return;\n try {\n const entry: StoredAssignment = { variantKey, ts: Date.now() };\n localStorage.setItem(ASSIGNMENT_PREFIX + id, JSON.stringify(entry));\n } catch {}\n}\n\n// ── Types ──────────────────────────────────────────────────────────────────\n\nexport interface ExperimentTrackOptions {\n /** Auto-track impressions (default true) */\n impression?: boolean;\n /** Auto-track clicks (default true) */\n primaryClick?: boolean;\n /** Custom impression event name (default \"$experiment_exposure\") */\n impressionEventName?: string;\n /** Custom click event name (default \"$experiment_click\") */\n clickEventName?: string;\n}\n\nexport interface ExperimentProps {\n /** Experiment key / identifier */\n id: string;\n /** Control variant ReactNode */\n control: React.ReactNode;\n /** Named variant ReactNodes, keyed by variant key (e.g. { ai_v1: <MyVariant /> }) */\n variants: Record<string, React.ReactNode>;\n /** Tracking configuration */\n track?: ExperimentTrackOptions;\n /** Stable instance id when multiple instances of the same experiment exist on a page */\n componentInstanceId?: string;\n /** Behavior when assignment fetch fails: \"control\" (default) renders control, \"suspend\" throws */\n fallback?: \"control\" | \"suspend\";\n /** Log decisions + events to console */\n debug?: boolean;\n}\n\nexport function Experiment({\n id,\n control,\n variants,\n track,\n componentInstanceId,\n fallback = \"control\",\n debug = false,\n}: ExperimentProps) {\n const { host, bootstrap, customerId } = useProbatContext();\n\n // Stable instance id (useId + sessionStorage for cross-mount stability)\n const autoInstanceId = useStableInstanceId(id);\n const instanceId = componentInstanceId ?? autoInstanceId;\n\n // Track options with defaults\n const trackImpression = track?.impression !== false;\n const trackClick = track?.primaryClick !== false;\n const impressionEvent = track?.impressionEventName ?? \"$experiment_exposure\";\n const clickEvent = track?.clickEventName ?? \"$experiment_click\";\n\n // ── Assignment resolution ──────────────────────────────────────────────\n\n const [variantKey, setVariantKey] = useState<string>(() => {\n // Defer localStorage read to useEffect to avoid hydration mismatch.\n if (bootstrap[id]) return bootstrap[id];\n return \"control\";\n });\n const [resolved, setResolved] = useState<boolean>(() => {\n return !!bootstrap[id];\n });\n\n useEffect(() => {\n // Already resolved from bootstrap or cache\n if (bootstrap[id] || readAssignment(id)) {\n // Ensure state is synced (StrictMode may re-mount)\n const key = bootstrap[id] ?? readAssignment(id) ?? \"control\";\n setVariantKey(key);\n setResolved(true);\n return;\n }\n\n let cancelled = false;\n\n (async () => {\n try {\n const distinctId = customerId ?? getDistinctId();\n const key = await fetchDecision(host, id, distinctId);\n if (cancelled) return;\n\n // Validate variant key\n if (key !== \"control\" && !(key in variants)) {\n if (debug) {\n console.warn(\n `[probat] Unknown variant \"${key}\" for experiment \"${id}\", falling back to control`\n );\n }\n setVariantKey(\"control\");\n } else {\n setVariantKey(key);\n writeAssignment(id, key);\n }\n } catch (err) {\n if (cancelled) return;\n if (debug) {\n console.error(`[probat] fetchDecision failed for \"${id}\":`, err);\n }\n if (fallback === \"suspend\") throw err;\n setVariantKey(\"control\");\n } finally {\n if (!cancelled) setResolved(true);\n }\n })();\n\n return () => {\n cancelled = true;\n };\n }, [id, host]); // eslint-disable-line react-hooks/exhaustive-deps\n\n // ── Debug logging ──────────────────────────────────────────────────────\n\n useEffect(() => {\n if (debug && resolved) {\n console.log(`[probat] Experiment \"${id}\" → variant \"${variantKey}\"`, {\n instanceId,\n pageKey: getPageKey(),\n });\n }\n }, [debug, id, variantKey, resolved, instanceId]);\n\n // ── Shared event properties ────────────────────────────────────────────\n\n const eventProps = useMemo(\n () => ({\n experiment_id: id,\n variant_key: variantKey,\n component_instance_id: instanceId,\n ...(customerId ? { customer_id: customerId } : {}),\n }),\n [id, variantKey, instanceId, customerId]\n );\n\n // ── Impression tracking via IntersectionObserver ────────────────────────\n\n const containerRef = useRef<HTMLDivElement>(null);\n const impressionSent = useRef(false);\n\n useEffect(() => {\n if (!trackImpression || !resolved) return;\n\n // Reset on re-mount (StrictMode safety)\n impressionSent.current = false;\n\n const pageKey = getPageKey();\n const dedupeKey = makeDedupeKey(id, variantKey, instanceId, pageKey);\n\n // Already seen this session\n if (hasSeen(dedupeKey)) {\n impressionSent.current = true;\n return;\n }\n\n const el = containerRef.current;\n if (!el) return;\n\n // Fallback: no IntersectionObserver (SSR, old browser)\n if (typeof IntersectionObserver === \"undefined\") {\n if (!impressionSent.current) {\n impressionSent.current = true;\n markSeen(dedupeKey);\n sendMetric(host, impressionEvent, eventProps);\n if (debug) console.log(`[probat] Impression sent (no IO) for \"${id}\"`);\n }\n return;\n }\n\n let timer: ReturnType<typeof setTimeout> | null = null;\n\n const observer = new IntersectionObserver(\n ([entry]) => {\n if (!entry || impressionSent.current) return;\n\n if (entry.isIntersecting) {\n timer = setTimeout(() => {\n if (impressionSent.current) return;\n impressionSent.current = true;\n markSeen(dedupeKey);\n sendMetric(host, impressionEvent, eventProps);\n if (debug) console.log(`[probat] Impression sent for \"${id}\"`);\n observer.disconnect();\n }, 250);\n } else if (timer) {\n clearTimeout(timer);\n timer = null;\n }\n },\n { threshold: 0.5 }\n );\n\n observer.observe(el);\n\n return () => {\n observer.disconnect();\n if (timer) clearTimeout(timer);\n };\n }, [\n trackImpression,\n resolved,\n id,\n variantKey,\n instanceId,\n host,\n impressionEvent,\n eventProps,\n debug,\n ]);\n\n // ── Click tracking ─────────────────────────────────────────────────────\n\n const handleClick = useCallback(\n (e: React.MouseEvent) => {\n if (!trackClick) return;\n\n const meta = extractClickMeta(e.target as EventTarget);\n if (!meta) return;\n\n sendMetric(host, clickEvent, {\n ...eventProps,\n ...meta,\n });\n if (debug) {\n console.log(`[probat] Click tracked for \"${id}\"`, meta);\n }\n },\n [trackClick, host, clickEvent, eventProps, id, debug]\n );\n\n // ── Render ─────────────────────────────────────────────────────────────\n\n const content =\n variantKey === \"control\" || !(variantKey in variants)\n ? control\n : variants[variantKey];\n\n return (\n <div\n ref={containerRef}\n onClick={handleClick}\n data-probat-experiment={id}\n data-probat-variant={variantKey}\n style={{\n display: \"block\",\n margin: 0,\n padding: 0,\n opacity: resolved ? 1 : 0,\n transition: resolved ? \"opacity 0.15s ease-in\" : \"none\",\n }}\n >\n {content}\n </div>\n );\n}\n","\"use client\";\n\nimport { useCallback } from \"react\";\nimport { useProbatContext } from \"../context/ProbatContext\";\nimport { sendMetric } from \"../utils/api\";\n\nexport interface UseProbatMetricsReturn {\n /**\n * Send a custom event with arbitrary properties.\n * Never throws — failures are silently dropped.\n *\n * @example\n * ```tsx\n * const { capture } = useProbatMetrics();\n * capture(\"purchase\", { revenue: 42, currency: \"USD\" });\n * ```\n */\n capture: (event: string, properties?: Record<string, unknown>) => void;\n}\n\n/**\n * Minimal metrics hook. Provides a single `capture(event, props)` function\n * that sends events to the Probat backend using the provider's host config.\n */\nexport function useProbatMetrics(): UseProbatMetricsReturn {\n const { host, customerId } = useProbatContext();\n\n const capture = useCallback(\n (event: string, properties: Record<string, unknown> = {}) => {\n sendMetric(host, event, {\n ...(customerId ? { customer_id: customerId } : {}),\n ...properties,\n });\n },\n [host, customerId]\n );\n\n return { capture };\n}\n"]}
1
+ {"version":3,"sources":["../src/context/ProbatContext.tsx","../src/components/ProbatProviderClient.tsx","../src/utils/environment.ts","../src/utils/eventContext.ts","../src/utils/api.ts","../src/hooks/useExperiment.ts","../src/utils/dedupeStorage.ts","../src/utils/stableInstanceId.ts","../src/hooks/useTrack.ts","../src/components/Experiment.tsx","../src/components/Track.tsx","../src/hooks/useProbatMetrics.ts","../src/utils/createExperimentContext.ts"],"names":["createContext","useMemo","React","useContext","useState","useEffect","useRef","useCallback"],"mappings":"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","file":"index.js","sourcesContent":["\"use client\";\n\nimport React, { createContext, useContext, useMemo } from \"react\";\n\nexport interface ProbatContextValue {\n host: string;\n customerId?: string;\n bootstrap: Record<string, string>;\n}\n\nconst ProbatContext = createContext<ProbatContextValue | null>(null);\n\nconst DEFAULT_HOST = \"https://gushi.onrender.com\";\n\nexport interface ProbatProviderProps {\n /** Your end-user's ID. When provided, used as the distinct_id for variant\n * assignment (consistent across devices) and attached to all events. */\n customerId?: string;\n /** Base URL for the Probat API. Defaults to https://gushi.onrender.com */\n host?: string;\n /**\n * Bootstrap assignments to avoid flash on first render.\n * Map of experiment id → variant key.\n * e.g. { \"cta-copy-test\": \"ai_v1\" }\n */\n bootstrap?: Record<string, string>;\n children: React.ReactNode;\n}\n\nexport function ProbatProvider({\n customerId,\n host = DEFAULT_HOST,\n bootstrap,\n children,\n}: ProbatProviderProps) {\n const value = useMemo<ProbatContextValue>(\n () => ({\n host: host.replace(/\\/$/, \"\"),\n customerId,\n bootstrap: bootstrap ?? {},\n }),\n [customerId, host, bootstrap]\n );\n\n return (\n <ProbatContext.Provider value={value}>\n {children}\n </ProbatContext.Provider>\n );\n}\n\nexport function useProbatContext(): ProbatContextValue {\n const ctx = useContext(ProbatContext);\n if (!ctx) {\n throw new Error(\n \"useProbatContext must be used within <ProbatProviderClient>. Wrap your app with <ProbatProviderClient>.\"\n );\n }\n return ctx;\n}\n","\"use client\";\n\nimport React from \"react\";\nimport { ProbatProvider } from \"../context/ProbatContext\";\nimport type { ProbatProviderProps } from \"../context/ProbatContext\";\n\n/**\n * Client-only provider for Next.js App Router.\n * Import this in your layout/providers file.\n *\n * @example\n * ```tsx\n * // app/providers.tsx\n * \"use client\";\n * import { ProbatProviderClient } from \"@probat/react\";\n *\n * export function Providers({ children }) {\n * return (\n * <ProbatProviderClient customerId={user.id}>\n * {children}\n * </ProbatProviderClient>\n * );\n * }\n * ```\n */\nexport function ProbatProviderClient(props: ProbatProviderProps) {\n return React.createElement(ProbatProvider, props);\n}\n\nexport type { ProbatProviderProps };\n","/**\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","/**\n * Event context helpers: distinct_id, session_id, page info.\n * All browser-safe — no-ops when window is unavailable.\n */\n\nconst DISTINCT_ID_KEY = \"probat:distinct_id\";\nconst SESSION_ID_KEY = \"probat:session_id\";\n\nlet cachedDistinctId: string | null = null;\nlet cachedSessionId: string | null = null;\n\nfunction generateId(): string {\n // crypto.randomUUID where available, else fallback\n if (typeof crypto !== \"undefined\" && crypto.randomUUID) {\n return crypto.randomUUID();\n }\n // fallback: random hex\n const bytes = new Uint8Array(16);\n if (typeof crypto !== \"undefined\" && crypto.getRandomValues) {\n crypto.getRandomValues(bytes);\n } else {\n for (let i = 0; i < 16; i++) bytes[i] = Math.floor(Math.random() * 256);\n }\n return Array.from(bytes, (b) => b.toString(16).padStart(2, \"0\")).join(\"\");\n}\n\nexport function getDistinctId(): string {\n if (cachedDistinctId) return cachedDistinctId;\n if (typeof window === \"undefined\") return \"server\";\n try {\n const stored = localStorage.getItem(DISTINCT_ID_KEY);\n if (stored) {\n cachedDistinctId = stored;\n return stored;\n }\n } catch {}\n const id = `anon_${generateId()}`;\n cachedDistinctId = id;\n try {\n localStorage.setItem(DISTINCT_ID_KEY, id);\n } catch {}\n return id;\n}\n\nexport function getSessionId(): string {\n if (cachedSessionId) return cachedSessionId;\n if (typeof window === \"undefined\") return \"server\";\n try {\n const stored = sessionStorage.getItem(SESSION_ID_KEY);\n if (stored) {\n cachedSessionId = stored;\n return stored;\n }\n } catch {}\n const id = `sess_${generateId()}`;\n cachedSessionId = id;\n try {\n sessionStorage.setItem(SESSION_ID_KEY, id);\n } catch {}\n return id;\n}\n\nexport function getPageKey(): string {\n if (typeof window === \"undefined\") return \"\";\n return window.location.pathname + window.location.search;\n}\n\nexport function getPageUrl(): string {\n if (typeof window === \"undefined\") return \"\";\n return window.location.href;\n}\n\nexport function getReferrer(): string {\n if (typeof document === \"undefined\") return \"\";\n return document.referrer;\n}\n\nexport interface EventContext {\n distinct_id: string;\n session_id: string;\n $page_url: string;\n $pathname: string;\n $referrer: string;\n}\n\nexport function buildEventContext(): EventContext {\n return {\n distinct_id: getDistinctId(),\n session_id: getSessionId(),\n $page_url: getPageUrl(),\n $pathname: typeof window !== \"undefined\" ? window.location.pathname : \"\",\n $referrer: getReferrer(),\n };\n}\n","import { detectEnvironment } from \"./environment\";\nimport { buildEventContext } from \"./eventContext\";\n\n// ── Types ──────────────────────────────────────────────────────────────────\n\nexport interface DecisionResponse {\n variant_key: string;\n}\n\nexport interface MetricPayload {\n event: string;\n environment: \"dev\" | \"prod\";\n properties: Record<string, unknown>;\n}\n\n// ── Assignment fetching ────────────────────────────────────────────────────\n\nconst pendingDecisions = new Map<string, Promise<string>>();\n\n/**\n * Fetch the variant assignment for an experiment.\n * Returns the variant key string (e.g. \"control\", \"ai_v1\").\n * Deduplicates concurrent calls for the same experiment.\n */\nexport async function fetchDecision(\n host: string,\n experimentId: string,\n distinctId: string\n): Promise<string> {\n const existing = pendingDecisions.get(experimentId);\n if (existing) return existing;\n\n const promise = (async () => {\n try {\n const url = `${host.replace(/\\/$/, \"\")}/experiment/decide`;\n const res = await fetch(url, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n },\n credentials: \"include\",\n body: JSON.stringify({\n experiment_id: experimentId,\n distinct_id: distinctId,\n }),\n });\n if (!res.ok) throw new Error(`HTTP ${res.status}`);\n const data = (await res.json()) as DecisionResponse;\n return data.variant_key || \"control\";\n } finally {\n pendingDecisions.delete(experimentId);\n }\n })();\n\n pendingDecisions.set(experimentId, promise);\n return promise;\n}\n\n// ── Metric sending ─────────────────────────────────────────────────────────\n\n/**\n * Fire-and-forget metric send. Never throws.\n */\nexport function sendMetric(\n host: string,\n event: string,\n properties: Record<string, unknown>\n): void {\n if (typeof window === \"undefined\") return;\n\n const ctx = buildEventContext();\n const payload: MetricPayload = {\n event,\n environment: detectEnvironment(),\n properties: {\n ...ctx,\n source: \"react-sdk\",\n captured_at: new Date().toISOString(),\n ...properties,\n },\n };\n\n try {\n const url = `${host.replace(/\\/$/, \"\")}/experiment/metrics`;\n fetch(url, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n credentials: \"include\",\n body: JSON.stringify(payload),\n }).catch(() => {});\n } catch {\n // silently drop\n }\n}\n\n// ── Click metadata extraction ──────────────────────────────────────────────\n\nexport interface ClickMeta {\n click_target_tag: string;\n click_target_text?: string;\n click_target_id?: string;\n click_is_primary: boolean;\n}\n\n/**\n * Given a click event inside an experiment boundary, extract metadata.\n * Prioritizes elements with data-probat-click=\"primary\",\n * then falls back to button/a/role=button.\n */\nexport function extractClickMeta(target: EventTarget | null): ClickMeta | null {\n if (!target || !(target instanceof HTMLElement)) return null;\n\n // Priority 1: explicit primary marker\n const primary = target.closest('[data-probat-click=\"primary\"]');\n if (primary) return buildMeta(primary as HTMLElement, true);\n\n // Priority 2: interactive elements\n const interactive = target.closest('button, a, [role=\"button\"]');\n if (interactive) return buildMeta(interactive as HTMLElement, false);\n\n return null;\n}\n\nfunction buildMeta(el: HTMLElement, isPrimary: boolean): ClickMeta {\n const meta: ClickMeta = {\n click_target_tag: el.tagName,\n click_is_primary: isPrimary,\n };\n if (el.id) meta.click_target_id = el.id;\n const text = el.textContent?.trim();\n if (text) meta.click_target_text = text.slice(0, 120);\n return meta;\n}\n","\"use client\";\n\nimport { useEffect, useState } from \"react\";\nimport { useProbatContext } from \"../context/ProbatContext\";\nimport { fetchDecision } from \"../utils/api\";\nimport { getDistinctId } from \"../utils/eventContext\";\n\n// ── localStorage assignment cache ──────────────────────────────────────────\n\nconst ASSIGNMENT_PREFIX = \"probat:assignment:\";\n\ninterface StoredAssignment {\n variantKey: string;\n ts: number;\n}\n\nexport function readAssignment(id: string): string | null {\n if (typeof window === \"undefined\") return null;\n try {\n const raw = localStorage.getItem(ASSIGNMENT_PREFIX + id);\n if (!raw) return null;\n const parsed: StoredAssignment = JSON.parse(raw);\n return parsed.variantKey ?? null;\n } catch {\n return null;\n }\n}\n\nexport function writeAssignment(id: string, variantKey: string): void {\n if (typeof window === \"undefined\") return;\n try {\n const entry: StoredAssignment = { variantKey, ts: Date.now() };\n localStorage.setItem(ASSIGNMENT_PREFIX + id, JSON.stringify(entry));\n } catch {}\n}\n\n// ── Types ──────────────────────────────────────────────────────────────────\n\nexport interface UseExperimentOptions {\n /** Behavior when assignment fetch fails: \"control\" (default) renders control, \"suspend\" throws */\n fallback?: \"control\" | \"suspend\";\n /** Log decisions to console */\n debug?: boolean;\n}\n\nexport interface UseExperimentReturn {\n /** The resolved variant key (e.g. \"control\", \"ai_v1\") */\n variantKey: string;\n /** Whether the assignment has been resolved (bootstrap, cache, or fetch) */\n resolved: boolean;\n}\n\n// ── Hook ───────────────────────────────────────────────────────────────────\n\n/**\n * Resolves the variant assignment for an experiment.\n * No tracking — use `useTrack` or `<Track>` to observe impressions/clicks.\n *\n * Priority: bootstrap > localStorage cache > fetchDecision.\n */\nexport function useExperiment(\n id: string,\n options: UseExperimentOptions = {}\n): UseExperimentReturn {\n const { fallback = \"control\", debug = false } = options;\n const { host, bootstrap, customerId } = useProbatContext();\n\n const [variantKey, setVariantKey] = useState<string>(() => {\n if (bootstrap[id]) return bootstrap[id];\n return \"control\";\n });\n const [resolved, setResolved] = useState<boolean>(() => {\n return !!bootstrap[id];\n });\n\n useEffect(() => {\n if (bootstrap[id] || readAssignment(id)) {\n const key = bootstrap[id] ?? readAssignment(id) ?? \"control\";\n setVariantKey(key);\n setResolved(true);\n return;\n }\n\n let cancelled = false;\n\n (async () => {\n try {\n const distinctId = customerId ?? getDistinctId();\n const key = await fetchDecision(host, id, distinctId);\n if (cancelled) return;\n\n setVariantKey(key);\n writeAssignment(id, key);\n } catch (err) {\n if (cancelled) return;\n if (debug) {\n console.error(`[probat] fetchDecision failed for \"${id}\":`, err);\n }\n if (fallback === \"suspend\") throw err;\n setVariantKey(\"control\");\n } finally {\n if (!cancelled) setResolved(true);\n }\n })();\n\n return () => {\n cancelled = true;\n };\n }, [id, host]); // eslint-disable-line react-hooks/exhaustive-deps\n\n useEffect(() => {\n if (debug && resolved) {\n console.log(`[probat] Experiment \"${id}\" -> variant \"${variantKey}\"`);\n }\n }, [debug, id, variantKey, resolved]);\n\n return { variantKey, resolved };\n}\n","/**\n * Dedupe storage for experiment exposures.\n * Uses sessionStorage + in-memory Set fallback.\n * Key format: probat:seen:{id}:{variantKey}:{instanceId}:{pageKey}\n */\n\nconst PREFIX = \"probat:seen:\";\nconst memorySet = new Set<string>();\n\nexport function makeDedupeKey(\n experimentId: string,\n variantKey: string,\n instanceId: string,\n pageKey: string\n): string {\n return `${PREFIX}${experimentId}:${variantKey}:${instanceId}:${pageKey}`;\n}\n\nexport function hasSeen(key: string): boolean {\n if (memorySet.has(key)) return true;\n if (typeof window === \"undefined\") return false;\n try {\n return sessionStorage.getItem(key) === \"1\";\n } catch {\n return false;\n }\n}\n\nexport function markSeen(key: string): void {\n memorySet.add(key);\n if (typeof window === \"undefined\") return;\n try {\n sessionStorage.setItem(key, \"1\");\n } catch {}\n}\n\n/** Reset all dedupe state — useful for testing. */\nexport function resetDedupe(): void {\n memorySet.clear();\n}\n","/**\n * Stable auto-generated instance IDs for <Experiment />.\n *\n * Problem: a naïve useRef + module counter gives a different ID on every mount,\n * so StrictMode double-mount or unmount/remount changes the dedupe key.\n *\n * Solution:\n * 1. React 18+ → useId() is stable per fiber position.\n * 2. Fallback → sessionStorage-backed slot counter per (experimentId, pageKey).\n * 3. Both paths persist a mapping in sessionStorage:\n * probat:instance:{experimentId}:{pageKey}:{positionKey} → stableId\n * so the same position resolves to the same ID across mounts.\n */\n\nimport React, { useRef } from \"react\";\nimport { getPageKey } from \"./eventContext\";\n\nconst INSTANCE_PREFIX = \"probat:instance:\";\n\n// ── Helpers ────────────────────────────────────────────────────────────────\n\nfunction shortId(): string {\n const bytes = new Uint8Array(4);\n if (typeof crypto !== \"undefined\" && crypto.getRandomValues) {\n crypto.getRandomValues(bytes);\n } else {\n for (let i = 0; i < 4; i++) bytes[i] = Math.floor(Math.random() * 256);\n }\n return Array.from(bytes, (b) => b.toString(16).padStart(2, \"0\")).join(\"\");\n}\n\n/**\n * Look up or create a stable instance ID in sessionStorage.\n */\nfunction resolveStableId(storageKey: string): string {\n if (typeof window !== \"undefined\") {\n try {\n const stored = sessionStorage.getItem(storageKey);\n if (stored) return stored;\n } catch {}\n }\n const id = `inst_${shortId()}`;\n if (typeof window !== \"undefined\") {\n try {\n sessionStorage.setItem(storageKey, id);\n } catch {}\n }\n return id;\n}\n\n// ── Fallback: render-wave slot counter ─────────────────────────────────────\n// Each synchronous render batch claims sequential slots per (experimentId,\n// pageKey). A microtask resets the counters so the next batch starts at 0,\n// giving the same component position the same slot across mounts.\n\nconst slotCounters = new Map<string, number>();\nlet resetScheduled = false;\n\nfunction claimSlot(groupKey: string): number {\n const idx = slotCounters.get(groupKey) ?? 0;\n slotCounters.set(groupKey, idx + 1);\n if (!resetScheduled) {\n resetScheduled = true;\n Promise.resolve().then(() => {\n slotCounters.clear();\n resetScheduled = false;\n });\n }\n return idx;\n}\n\n// ── Hook: React 18+ path (useId available) ─────────────────────────────────\n\nfunction useStableInstanceIdV18(experimentId: string): string {\n const reactId = (React as any).useId() as string;\n const ref = useRef(\"\");\n if (!ref.current) {\n const key = `${INSTANCE_PREFIX}${experimentId}:${getPageKey()}:${reactId}`;\n ref.current = resolveStableId(key);\n }\n return ref.current;\n}\n\n// ── Hook: fallback path (no useId) ─────────────────────────────────────────\n\nfunction useStableInstanceIdFallback(experimentId: string): string {\n const slotRef = useRef(-1);\n const ref = useRef(\"\");\n if (slotRef.current === -1) {\n slotRef.current = claimSlot(`${experimentId}:${getPageKey()}`);\n }\n if (!ref.current) {\n const key = `${INSTANCE_PREFIX}${experimentId}:${getPageKey()}:${slotRef.current}`;\n ref.current = resolveStableId(key);\n }\n return ref.current;\n}\n\n// ── Exported hook ──────────────────────────────────────────────────────────\n// Selection is a module-level constant so the hook-call count never changes\n// between renders — safe for the rules of hooks.\n\nexport const useStableInstanceId: (experimentId: string) => string =\n typeof (React as any).useId === \"function\"\n ? useStableInstanceIdV18\n : useStableInstanceIdFallback;\n\n// ── Test utility ───────────────────────────────────────────────────────────\n\nexport function resetInstanceIdState(): void {\n slotCounters.clear();\n resetScheduled = false;\n}\n","\"use client\";\n\nimport { useEffect, useRef, useMemo, useCallback } from \"react\";\nimport { useProbatContext } from \"../context/ProbatContext\";\nimport { sendMetric, extractClickMeta } from \"../utils/api\";\nimport { getPageKey } from \"../utils/eventContext\";\nimport { makeDedupeKey, hasSeen, markSeen } from \"../utils/dedupeStorage\";\nimport { useStableInstanceId } from \"../utils/stableInstanceId\";\n\n// ── Types ──────────────────────────────────────────────────────────────────\n\nexport interface UseTrackOptions {\n /** Experiment identifier */\n experimentId: string;\n /** The variant key to attach to events */\n variantKey: string;\n /** Stable instance id when multiple instances of the same experiment exist on a page */\n componentInstanceId?: string;\n /** Auto-track impressions (default true) */\n impression?: boolean;\n /** Auto-track clicks (default true) */\n click?: boolean;\n /** Custom impression event name (default \"$experiment_exposure\") */\n impressionEventName?: string;\n /** Custom click event name (default \"$experiment_click\") */\n clickEventName?: string;\n /** Log events to console */\n debug?: boolean;\n}\n\n// ── Hook ───────────────────────────────────────────────────────────────────\n\n/**\n * Attaches impression and click tracking to a DOM element via a ref.\n * Completely independent of variant assignment — pass the variantKey explicitly.\n *\n * @example\n * ```tsx\n * const trackRef = useTrack({ experimentId: \"pricing\", variantKey: \"ai_v1\" });\n * return <div ref={trackRef}>...</div>;\n * ```\n */\nexport function useTrack(options: UseTrackOptions): React.RefObject<HTMLElement | null> {\n const {\n experimentId,\n variantKey,\n componentInstanceId,\n impression: trackImpression = true,\n click: trackClick = true,\n impressionEventName = \"$experiment_exposure\",\n clickEventName = \"$experiment_click\",\n debug = false,\n } = options;\n\n const { host, customerId } = useProbatContext();\n\n const autoInstanceId = useStableInstanceId(experimentId);\n const instanceId = componentInstanceId ?? autoInstanceId;\n\n const containerRef = useRef<HTMLElement | null>(null);\n const impressionSent = useRef(false);\n\n const eventProps = useMemo(\n () => ({\n experiment_id: experimentId,\n variant_key: variantKey,\n component_instance_id: instanceId,\n ...(customerId ? { distinct_id: customerId } : {}),\n }),\n [experimentId, variantKey, instanceId, customerId]\n );\n\n // ── Impression tracking via IntersectionObserver ────────────────────────\n\n useEffect(() => {\n if (!trackImpression) return;\n\n impressionSent.current = false;\n\n const pageKey = getPageKey();\n const dedupeKey = makeDedupeKey(experimentId, variantKey, instanceId, pageKey);\n\n if (hasSeen(dedupeKey)) {\n impressionSent.current = true;\n return;\n }\n\n const el = containerRef.current;\n if (!el) return;\n\n // Fallback: no IntersectionObserver (SSR, old browser)\n if (typeof IntersectionObserver === \"undefined\") {\n if (!impressionSent.current) {\n impressionSent.current = true;\n markSeen(dedupeKey);\n sendMetric(host, impressionEventName, eventProps);\n if (debug) console.log(`[probat] Impression sent (no IO) for \"${experimentId}\"`);\n }\n return;\n }\n\n let timer: ReturnType<typeof setTimeout> | null = null;\n\n const observer = new IntersectionObserver(\n ([entry]) => {\n if (!entry || impressionSent.current) return;\n\n if (entry.isIntersecting) {\n timer = setTimeout(() => {\n if (impressionSent.current) return;\n impressionSent.current = true;\n markSeen(dedupeKey);\n sendMetric(host, impressionEventName, eventProps);\n if (debug) console.log(`[probat] Impression sent for \"${experimentId}\"`);\n observer.disconnect();\n }, 250);\n } else if (timer) {\n clearTimeout(timer);\n timer = null;\n }\n },\n { threshold: 0.5 }\n );\n\n observer.observe(el);\n\n return () => {\n observer.disconnect();\n if (timer) clearTimeout(timer);\n };\n }, [\n trackImpression,\n experimentId,\n variantKey,\n instanceId,\n host,\n impressionEventName,\n eventProps,\n debug,\n ]);\n\n // ── Click tracking ─────────────────────────────────────────────────────\n\n const handleClick = useCallback(\n (e: Event) => {\n if (!trackClick) return;\n\n const meta = extractClickMeta(e.target as EventTarget);\n if (!meta) return;\n\n sendMetric(host, clickEventName, {\n ...eventProps,\n ...meta,\n });\n if (debug) {\n console.log(`[probat] Click tracked for \"${experimentId}\"`, meta);\n }\n },\n [trackClick, host, clickEventName, eventProps, experimentId, debug]\n );\n\n useEffect(() => {\n const el = containerRef.current;\n if (!el || !trackClick) return;\n\n el.addEventListener(\"click\", handleClick);\n return () => {\n el.removeEventListener(\"click\", handleClick);\n };\n }, [handleClick, trackClick]);\n\n return containerRef;\n}\n","\"use client\";\n\nimport React from \"react\";\nimport { useExperiment } from \"../hooks/useExperiment\";\nimport { useTrack } from \"../hooks/useTrack\";\n\n// ── Types ──────────────────────────────────────────────────────────────────\n\nexport interface ExperimentTrackOptions {\n /** Auto-track impressions (default true) */\n impression?: boolean;\n /** Auto-track clicks (default true) */\n primaryClick?: boolean;\n /** Custom impression event name (default \"$experiment_exposure\") */\n impressionEventName?: string;\n /** Custom click event name (default \"$experiment_click\") */\n clickEventName?: string;\n}\n\nexport interface ExperimentProps {\n /** Experiment key / identifier */\n id: string;\n /** Control variant ReactNode */\n control: React.ReactNode;\n /** Named variant ReactNodes, keyed by variant key (e.g. { ai_v1: <MyVariant /> }) */\n variants: Record<string, React.ReactNode>;\n /** Tracking configuration */\n track?: ExperimentTrackOptions;\n /** Stable instance id when multiple instances of the same experiment exist on a page */\n componentInstanceId?: string;\n /** Behavior when assignment fetch fails: \"control\" (default) renders control, \"suspend\" throws */\n fallback?: \"control\" | \"suspend\";\n /** Log decisions + events to console */\n debug?: boolean;\n}\n\nexport function Experiment({\n id,\n control,\n variants,\n track,\n componentInstanceId,\n fallback = \"control\",\n debug = false,\n}: ExperimentProps) {\n // ── Assignment (decoupled) ──────────────────────────────────────────────\n\n const { variantKey: rawKey, resolved } = useExperiment(id, { fallback, debug });\n\n // Validate variant key against the ReactNode map\n const variantKey =\n rawKey === \"control\" || rawKey in variants ? rawKey : \"control\";\n\n if (debug && rawKey !== variantKey) {\n console.warn(\n `[probat] Unknown variant \"${rawKey}\" for experiment \"${id}\", falling back to control`\n );\n }\n\n // ── Tracking (decoupled) ────────────────────────────────────────────────\n\n const trackRef = useTrack({\n experimentId: id,\n variantKey,\n componentInstanceId,\n impression: resolved ? (track?.impression !== false) : false,\n click: track?.primaryClick !== false,\n impressionEventName: track?.impressionEventName,\n clickEventName: track?.clickEventName,\n debug,\n });\n\n // ── Render ─────────────────────────────────────────────────────────────\n\n const content =\n variantKey === \"control\" || !(variantKey in variants)\n ? control\n : variants[variantKey];\n\n return (\n <div\n ref={trackRef as React.RefObject<HTMLDivElement>}\n data-probat-experiment={id}\n data-probat-variant={variantKey}\n style={{\n display: \"block\",\n margin: 0,\n padding: 0,\n opacity: resolved ? 1 : 0,\n transition: resolved ? \"opacity 0.15s ease-in\" : \"none\",\n }}\n >\n {content}\n </div>\n );\n}\n","\"use client\";\n\nimport React from \"react\";\nimport { useTrack, type UseTrackOptions } from \"../hooks/useTrack\";\n\nexport interface TrackProps extends UseTrackOptions {\n children: React.ReactNode;\n}\n\n/**\n * Wrapper component that attaches impression and click tracking to its children.\n * Alternative to the `useTrack` hook when you prefer a component over a ref.\n *\n * @example\n * ```tsx\n * <Track experimentId=\"pricing\" variantKey=\"ai_v1\">\n * <PricingCard />\n * </Track>\n * ```\n */\nexport function Track({ children, ...trackOptions }: TrackProps) {\n const trackRef = useTrack(trackOptions);\n\n return (\n <div\n ref={trackRef as React.RefObject<HTMLDivElement>}\n data-probat-track={trackOptions.experimentId}\n data-probat-variant={trackOptions.variantKey}\n style={{ display: \"contents\" }}\n >\n {children}\n </div>\n );\n}\n","\"use client\";\n\nimport { useCallback } from \"react\";\nimport { useProbatContext } from \"../context/ProbatContext\";\nimport { sendMetric } from \"../utils/api\";\n\nexport interface UseProbatMetricsReturn {\n /**\n * Send a custom event with arbitrary properties.\n * Never throws — failures are silently dropped.\n *\n * @example\n * ```tsx\n * const { capture } = useProbatMetrics();\n * capture(\"purchase\", { revenue: 42, currency: \"USD\" });\n * ```\n */\n capture: (event: string, properties?: Record<string, unknown>) => void;\n}\n\n/**\n * Minimal metrics hook. Provides a single `capture(event, props)` function\n * that sends events to the Probat backend using the provider's host config.\n */\nexport function useProbatMetrics(): UseProbatMetricsReturn {\n const { host, customerId } = useProbatContext();\n\n const capture = useCallback(\n (event: string, properties: Record<string, unknown> = {}) => {\n sendMetric(host, event, {\n ...(customerId ? { distinct_id: customerId } : {}),\n ...properties,\n });\n },\n [host, customerId]\n );\n\n return { capture };\n}\n","\"use client\";\n\nimport React, { createContext, useContext, type ReactNode } from \"react\";\n\n/**\n * Factory that creates a typed context + hook pair for passing a variantKey\n * between components in different files without prop-drilling.\n *\n * @example\n * ```tsx\n * // experiment-context.ts\n * export const { ExperimentProvider, useVariantKey } = createExperimentContext(\"pricing-test\");\n *\n * // Parent.tsx\n * const { variantKey } = useExperiment(\"pricing-test\");\n * <ExperimentProvider value={variantKey}><Child /></ExperimentProvider>\n *\n * // Child.tsx (different file)\n * const variantKey = useVariantKey();\n * const trackRef = useTrack({ experimentId: \"pricing-test\", variantKey });\n * ```\n */\nexport function createExperimentContext(experimentId: string) {\n const Ctx = createContext<string | null>(null);\n\n function ExperimentProvider({\n value,\n children,\n }: {\n value: string;\n children: ReactNode;\n }) {\n return React.createElement(Ctx.Provider, { value }, children);\n }\n\n function useVariantKey(): string {\n const v = useContext(Ctx);\n if (v === null) {\n throw new Error(\n `useVariantKey() must be used inside <ExperimentProvider> for \"${experimentId}\"`\n );\n }\n return v;\n }\n\n return { ExperimentProvider, useVariantKey };\n}\n"]}
package/dist/index.mjs CHANGED
@@ -198,6 +198,75 @@ function buildMeta(el, isPrimary) {
198
198
  return meta;
199
199
  }
200
200
 
201
+ // src/hooks/useExperiment.ts
202
+ var ASSIGNMENT_PREFIX = "probat:assignment:";
203
+ function readAssignment(id) {
204
+ if (typeof window === "undefined") return null;
205
+ try {
206
+ const raw = localStorage.getItem(ASSIGNMENT_PREFIX + id);
207
+ if (!raw) return null;
208
+ const parsed = JSON.parse(raw);
209
+ return parsed.variantKey ?? null;
210
+ } catch {
211
+ return null;
212
+ }
213
+ }
214
+ function writeAssignment(id, variantKey) {
215
+ if (typeof window === "undefined") return;
216
+ try {
217
+ const entry = { variantKey, ts: Date.now() };
218
+ localStorage.setItem(ASSIGNMENT_PREFIX + id, JSON.stringify(entry));
219
+ } catch {
220
+ }
221
+ }
222
+ function useExperiment(id, options = {}) {
223
+ const { fallback = "control", debug = false } = options;
224
+ const { host, bootstrap, customerId } = useProbatContext();
225
+ const [variantKey, setVariantKey] = useState(() => {
226
+ if (bootstrap[id]) return bootstrap[id];
227
+ return "control";
228
+ });
229
+ const [resolved, setResolved] = useState(() => {
230
+ return !!bootstrap[id];
231
+ });
232
+ useEffect(() => {
233
+ if (bootstrap[id] || readAssignment(id)) {
234
+ const key = bootstrap[id] ?? readAssignment(id) ?? "control";
235
+ setVariantKey(key);
236
+ setResolved(true);
237
+ return;
238
+ }
239
+ let cancelled = false;
240
+ (async () => {
241
+ try {
242
+ const distinctId = customerId ?? getDistinctId();
243
+ const key = await fetchDecision(host, id, distinctId);
244
+ if (cancelled) return;
245
+ setVariantKey(key);
246
+ writeAssignment(id, key);
247
+ } catch (err) {
248
+ if (cancelled) return;
249
+ if (debug) {
250
+ console.error(`[probat] fetchDecision failed for "${id}":`, err);
251
+ }
252
+ if (fallback === "suspend") throw err;
253
+ setVariantKey("control");
254
+ } finally {
255
+ if (!cancelled) setResolved(true);
256
+ }
257
+ })();
258
+ return () => {
259
+ cancelled = true;
260
+ };
261
+ }, [id, host]);
262
+ useEffect(() => {
263
+ if (debug && resolved) {
264
+ console.log(`[probat] Experiment "${id}" -> variant "${variantKey}"`);
265
+ }
266
+ }, [debug, id, variantKey, resolved]);
267
+ return { variantKey, resolved };
268
+ }
269
+
201
270
  // src/utils/dedupeStorage.ts
202
271
  var PREFIX = "probat:seen:";
203
272
  var memorySet = /* @__PURE__ */ new Set();
@@ -285,113 +354,37 @@ function useStableInstanceIdFallback(experimentId) {
285
354
  }
286
355
  var useStableInstanceId = typeof React3.useId === "function" ? useStableInstanceIdV18 : useStableInstanceIdFallback;
287
356
 
288
- // src/components/Experiment.tsx
289
- var ASSIGNMENT_PREFIX = "probat:assignment:";
290
- function readAssignment(id) {
291
- if (typeof window === "undefined") return null;
292
- try {
293
- const raw = localStorage.getItem(ASSIGNMENT_PREFIX + id);
294
- if (!raw) return null;
295
- const parsed = JSON.parse(raw);
296
- return parsed.variantKey ?? null;
297
- } catch {
298
- return null;
299
- }
300
- }
301
- function writeAssignment(id, variantKey) {
302
- if (typeof window === "undefined") return;
303
- try {
304
- const entry = { variantKey, ts: Date.now() };
305
- localStorage.setItem(ASSIGNMENT_PREFIX + id, JSON.stringify(entry));
306
- } catch {
307
- }
308
- }
309
- function Experiment({
310
- id,
311
- control,
312
- variants,
313
- track,
314
- componentInstanceId,
315
- fallback = "control",
316
- debug = false
317
- }) {
318
- const { host, bootstrap, customerId } = useProbatContext();
319
- const autoInstanceId = useStableInstanceId(id);
357
+ // src/hooks/useTrack.ts
358
+ function useTrack(options) {
359
+ const {
360
+ experimentId,
361
+ variantKey,
362
+ componentInstanceId,
363
+ impression: trackImpression = true,
364
+ click: trackClick = true,
365
+ impressionEventName = "$experiment_exposure",
366
+ clickEventName = "$experiment_click",
367
+ debug = false
368
+ } = options;
369
+ const { host, customerId } = useProbatContext();
370
+ const autoInstanceId = useStableInstanceId(experimentId);
320
371
  const instanceId = componentInstanceId ?? autoInstanceId;
321
- const trackImpression = track?.impression !== false;
322
- const trackClick = track?.primaryClick !== false;
323
- const impressionEvent = track?.impressionEventName ?? "$experiment_exposure";
324
- const clickEvent = track?.clickEventName ?? "$experiment_click";
325
- const [variantKey, setVariantKey] = useState(() => {
326
- if (bootstrap[id]) return bootstrap[id];
327
- return "control";
328
- });
329
- const [resolved, setResolved] = useState(() => {
330
- return !!bootstrap[id];
331
- });
332
- useEffect(() => {
333
- if (bootstrap[id] || readAssignment(id)) {
334
- const key = bootstrap[id] ?? readAssignment(id) ?? "control";
335
- setVariantKey(key);
336
- setResolved(true);
337
- return;
338
- }
339
- let cancelled = false;
340
- (async () => {
341
- try {
342
- const distinctId = customerId ?? getDistinctId();
343
- const key = await fetchDecision(host, id, distinctId);
344
- if (cancelled) return;
345
- if (key !== "control" && !(key in variants)) {
346
- if (debug) {
347
- console.warn(
348
- `[probat] Unknown variant "${key}" for experiment "${id}", falling back to control`
349
- );
350
- }
351
- setVariantKey("control");
352
- } else {
353
- setVariantKey(key);
354
- writeAssignment(id, key);
355
- }
356
- } catch (err) {
357
- if (cancelled) return;
358
- if (debug) {
359
- console.error(`[probat] fetchDecision failed for "${id}":`, err);
360
- }
361
- if (fallback === "suspend") throw err;
362
- setVariantKey("control");
363
- } finally {
364
- if (!cancelled) setResolved(true);
365
- }
366
- })();
367
- return () => {
368
- cancelled = true;
369
- };
370
- }, [id, host]);
371
- useEffect(() => {
372
- if (debug && resolved) {
373
- console.log(`[probat] Experiment "${id}" \u2192 variant "${variantKey}"`, {
374
- instanceId,
375
- pageKey: getPageKey()
376
- });
377
- }
378
- }, [debug, id, variantKey, resolved, instanceId]);
372
+ const containerRef = useRef(null);
373
+ const impressionSent = useRef(false);
379
374
  const eventProps = useMemo(
380
375
  () => ({
381
- experiment_id: id,
376
+ experiment_id: experimentId,
382
377
  variant_key: variantKey,
383
378
  component_instance_id: instanceId,
384
- ...customerId ? { customer_id: customerId } : {}
379
+ ...customerId ? { distinct_id: customerId } : {}
385
380
  }),
386
- [id, variantKey, instanceId, customerId]
381
+ [experimentId, variantKey, instanceId, customerId]
387
382
  );
388
- const containerRef = useRef(null);
389
- const impressionSent = useRef(false);
390
383
  useEffect(() => {
391
- if (!trackImpression || !resolved) return;
384
+ if (!trackImpression) return;
392
385
  impressionSent.current = false;
393
386
  const pageKey = getPageKey();
394
- const dedupeKey = makeDedupeKey(id, variantKey, instanceId, pageKey);
387
+ const dedupeKey = makeDedupeKey(experimentId, variantKey, instanceId, pageKey);
395
388
  if (hasSeen(dedupeKey)) {
396
389
  impressionSent.current = true;
397
390
  return;
@@ -402,8 +395,8 @@ function Experiment({
402
395
  if (!impressionSent.current) {
403
396
  impressionSent.current = true;
404
397
  markSeen(dedupeKey);
405
- sendMetric(host, impressionEvent, eventProps);
406
- if (debug) console.log(`[probat] Impression sent (no IO) for "${id}"`);
398
+ sendMetric(host, impressionEventName, eventProps);
399
+ if (debug) console.log(`[probat] Impression sent (no IO) for "${experimentId}"`);
407
400
  }
408
401
  return;
409
402
  }
@@ -416,8 +409,8 @@ function Experiment({
416
409
  if (impressionSent.current) return;
417
410
  impressionSent.current = true;
418
411
  markSeen(dedupeKey);
419
- sendMetric(host, impressionEvent, eventProps);
420
- if (debug) console.log(`[probat] Impression sent for "${id}"`);
412
+ sendMetric(host, impressionEventName, eventProps);
413
+ if (debug) console.log(`[probat] Impression sent for "${experimentId}"`);
421
414
  observer.disconnect();
422
415
  }, 250);
423
416
  } else if (timer) {
@@ -434,12 +427,11 @@ function Experiment({
434
427
  };
435
428
  }, [
436
429
  trackImpression,
437
- resolved,
438
- id,
430
+ experimentId,
439
431
  variantKey,
440
432
  instanceId,
441
433
  host,
442
- impressionEvent,
434
+ impressionEventName,
443
435
  eventProps,
444
436
  debug
445
437
  ]);
@@ -448,22 +440,59 @@ function Experiment({
448
440
  if (!trackClick) return;
449
441
  const meta = extractClickMeta(e.target);
450
442
  if (!meta) return;
451
- sendMetric(host, clickEvent, {
443
+ sendMetric(host, clickEventName, {
452
444
  ...eventProps,
453
445
  ...meta
454
446
  });
455
447
  if (debug) {
456
- console.log(`[probat] Click tracked for "${id}"`, meta);
448
+ console.log(`[probat] Click tracked for "${experimentId}"`, meta);
457
449
  }
458
450
  },
459
- [trackClick, host, clickEvent, eventProps, id, debug]
451
+ [trackClick, host, clickEventName, eventProps, experimentId, debug]
460
452
  );
453
+ useEffect(() => {
454
+ const el = containerRef.current;
455
+ if (!el || !trackClick) return;
456
+ el.addEventListener("click", handleClick);
457
+ return () => {
458
+ el.removeEventListener("click", handleClick);
459
+ };
460
+ }, [handleClick, trackClick]);
461
+ return containerRef;
462
+ }
463
+
464
+ // src/components/Experiment.tsx
465
+ function Experiment({
466
+ id,
467
+ control,
468
+ variants,
469
+ track,
470
+ componentInstanceId,
471
+ fallback = "control",
472
+ debug = false
473
+ }) {
474
+ const { variantKey: rawKey, resolved } = useExperiment(id, { fallback, debug });
475
+ const variantKey = rawKey === "control" || rawKey in variants ? rawKey : "control";
476
+ if (debug && rawKey !== variantKey) {
477
+ console.warn(
478
+ `[probat] Unknown variant "${rawKey}" for experiment "${id}", falling back to control`
479
+ );
480
+ }
481
+ const trackRef = useTrack({
482
+ experimentId: id,
483
+ variantKey,
484
+ componentInstanceId,
485
+ impression: resolved ? track?.impression !== false : false,
486
+ click: track?.primaryClick !== false,
487
+ impressionEventName: track?.impressionEventName,
488
+ clickEventName: track?.clickEventName,
489
+ debug
490
+ });
461
491
  const content = variantKey === "control" || !(variantKey in variants) ? control : variants[variantKey];
462
492
  return /* @__PURE__ */ React3.createElement(
463
493
  "div",
464
494
  {
465
- ref: containerRef,
466
- onClick: handleClick,
495
+ ref: trackRef,
467
496
  "data-probat-experiment": id,
468
497
  "data-probat-variant": variantKey,
469
498
  style: {
@@ -477,12 +506,25 @@ function Experiment({
477
506
  content
478
507
  );
479
508
  }
509
+ function Track({ children, ...trackOptions }) {
510
+ const trackRef = useTrack(trackOptions);
511
+ return /* @__PURE__ */ React3.createElement(
512
+ "div",
513
+ {
514
+ ref: trackRef,
515
+ "data-probat-track": trackOptions.experimentId,
516
+ "data-probat-variant": trackOptions.variantKey,
517
+ style: { display: "contents" }
518
+ },
519
+ children
520
+ );
521
+ }
480
522
  function useProbatMetrics() {
481
523
  const { host, customerId } = useProbatContext();
482
524
  const capture = useCallback(
483
525
  (event, properties = {}) => {
484
526
  sendMetric(host, event, {
485
- ...customerId ? { customer_id: customerId } : {},
527
+ ...customerId ? { distinct_id: customerId } : {},
486
528
  ...properties
487
529
  });
488
530
  },
@@ -490,7 +532,26 @@ function useProbatMetrics() {
490
532
  );
491
533
  return { capture };
492
534
  }
535
+ function createExperimentContext(experimentId) {
536
+ const Ctx = createContext(null);
537
+ function ExperimentProvider({
538
+ value,
539
+ children
540
+ }) {
541
+ return React3.createElement(Ctx.Provider, { value }, children);
542
+ }
543
+ function useVariantKey() {
544
+ const v = useContext(Ctx);
545
+ if (v === null) {
546
+ throw new Error(
547
+ `useVariantKey() must be used inside <ExperimentProvider> for "${experimentId}"`
548
+ );
549
+ }
550
+ return v;
551
+ }
552
+ return { ExperimentProvider, useVariantKey };
553
+ }
493
554
 
494
- export { Experiment, ProbatProviderClient, fetchDecision, sendMetric, useProbatMetrics };
555
+ export { Experiment, ProbatProviderClient, Track, createExperimentContext, fetchDecision, sendMetric, useExperiment, useProbatMetrics, useTrack };
495
556
  //# sourceMappingURL=index.mjs.map
496
557
  //# sourceMappingURL=index.mjs.map