@probat/react 0.2.1 → 0.3.1

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.d.ts CHANGED
@@ -1,274 +1,103 @@
1
- import React, { MouseEvent } from 'react';
1
+ import React from 'react';
2
2
 
3
- declare global {
4
- interface Window {
5
- __PROBAT_API?: string;
6
- }
7
- }
8
- interface ProbatContextValue {
9
- apiBaseUrl: string;
10
- environment: "dev" | "prod";
11
- clientKey?: string;
12
- repoFullName?: string;
13
- proposalId?: string;
14
- variantLabel?: string;
15
- }
16
3
  interface ProbatProviderProps {
4
+ /** Gushi user ID (UUID) — used to scope SDK requests to a customer */
5
+ userId: string;
6
+ /** Base URL for the Probat API. Defaults to https://gushi.onrender.com */
7
+ host?: string;
17
8
  /**
18
- * The base URL for the Probat API.
19
- * If not provided, will try to read from:
20
- * - VITE_PROBAT_API (Vite)
21
- * - NEXT_PUBLIC_PROBAT_API (Next.js)
22
- * - window.__PROBAT_API
23
- * - Default: "https://gushi.onrender.com"
24
- */
25
- apiBaseUrl?: string;
26
- /**
27
- * Optional: proposal/experiment id for heatmap segregation
28
- */
29
- proposalId?: string;
30
- /**
31
- * Optional: variant label for heatmap segregation
32
- */
33
- variantLabel?: string;
34
- /**
35
- * Client key for identification (optional)
36
- */
37
- clientKey?: string;
38
- /**
39
- * Explicitly set environment. If not provided, will auto-detect based on hostname.
40
- * "dev" for localhost, "prod" for production.
41
- */
42
- environment?: "dev" | "prod";
43
- /**
44
- * Repository full name (e.g., "owner/repo") for component-based experiments.
45
- * If not provided, will try to read from:
46
- * - NEXT_PUBLIC_PROBAT_REPO (Next.js)
47
- * - VITE_PROBAT_REPO (Vite)
48
- * - window.__PROBAT_REPO
9
+ * Bootstrap assignments to avoid flash on first render.
10
+ * Map of experiment id variant key.
11
+ * e.g. { "cta-copy-test": "ai_v1" }
49
12
  */
50
- repoFullName?: string;
13
+ bootstrap?: Record<string, string>;
51
14
  children: React.ReactNode;
52
15
  }
53
- declare function ProbatProvider({ apiBaseUrl, clientKey, environment: explicitEnvironment, repoFullName: explicitRepoFullName, proposalId, variantLabel, children, }: ProbatProviderProps): React.JSX.Element;
54
- declare function useProbatContext(): ProbatContextValue;
55
16
 
56
17
  /**
57
- * ProbatProviderClient - Can be imported directly in Next.js Server Components
58
- * This is a re-export with "use client" directive to ensure it works in Server Components
59
- */
60
- declare function ProbatProviderClient(props: ProbatProviderProps): React.FunctionComponentElement<ProbatProviderProps>;
61
-
62
- interface UseProbatMetricsReturn {
63
- /**
64
- * Track a click event
65
- * @param event - Optional React mouse event (will extract metadata automatically)
66
- * @param options - Optional configuration
67
- * @param options.force - Force tracking even if no actionable element is found
68
- * @param options.proposalId - Override the proposal ID (usually not needed)
69
- * @param options.variantLabel - Override the variant label (usually not needed)
70
- * @param options.dimensions - Additional dimensions to include
71
- */
72
- trackClick: (event?: MouseEvent | null, options?: {
73
- force?: boolean;
74
- proposalId?: string;
75
- variantLabel?: string;
76
- dimensions?: Record<string, any>;
77
- }) => boolean;
78
- /**
79
- * Track a custom metric
80
- * @param metricName - Name of the metric
81
- * @param proposalId - Proposal ID
82
- * @param variantLabel - Variant label (defaults to "control")
83
- * @param dimensions - Additional dimensions
84
- */
85
- trackMetric: (metricName: string, proposalId: string, variantLabel?: string, dimensions?: Record<string, any>) => void;
86
- /**
87
- * Track an impression/view
88
- * @param proposalId - Proposal ID
89
- * @param variantLabel - Variant label (defaults to "control")
90
- * @param experimentId - Optional experiment ID
91
- */
92
- trackImpression: (proposalId: string, variantLabel?: string, experimentId?: string) => void;
93
- }
94
- /**
95
- * Hook for tracking Probat metrics (clicks, impressions, custom metrics)
18
+ * Client-only provider for Next.js App Router.
19
+ * Import this in your layout/providers file.
96
20
  *
97
21
  * @example
98
22
  * ```tsx
99
- * const { trackClick, trackImpression } = useProbatMetrics();
100
- *
101
- * // Track click on button
102
- * <button onClick={(e) => trackClick(e)}>Click me</button>
23
+ * // app/providers.tsx
24
+ * "use client";
25
+ * import { ProbatProviderClient } from "@probat/react";
103
26
  *
104
- * // Track impression
105
- * useEffect(() => {
106
- * trackImpression(proposalId, variantLabel, experimentId);
107
- * }, [proposalId, variantLabel, experimentId]);
27
+ * export function Providers({ children }) {
28
+ * return (
29
+ * <ProbatProviderClient userId="your-user-uuid">
30
+ * {children}
31
+ * </ProbatProviderClient>
32
+ * );
33
+ * }
108
34
  * ```
109
35
  */
110
- declare function useProbatMetrics(): UseProbatMetricsReturn;
36
+ declare function ProbatProviderClient(props: ProbatProviderProps): React.FunctionComponentElement<ProbatProviderProps>;
111
37
 
112
- interface UseExperimentReturn {
113
- /**
114
- * The current variant label (e.g., "control", "variant-a")
115
- */
116
- variantLabel: string;
117
- /**
118
- * The experiment ID
119
- */
120
- experimentId: string | null;
121
- /**
122
- * Whether the experiment decision is still loading
123
- */
124
- isLoading: boolean;
125
- /**
126
- * Any error that occurred while fetching the experiment
127
- */
128
- error: Error | null;
38
+ interface ExperimentTrackOptions {
39
+ /** Auto-track impressions (default true) */
40
+ impression?: boolean;
41
+ /** Auto-track clicks (default true) */
42
+ primaryClick?: boolean;
43
+ /** Custom impression event name (default "$experiment_exposure") */
44
+ impressionEventName?: string;
45
+ /** Custom click event name (default "$experiment_click") */
46
+ clickEventName?: string;
47
+ }
48
+ interface ExperimentProps {
49
+ /** Experiment key / identifier */
50
+ id: string;
51
+ /** Control variant ReactNode */
52
+ control: React.ReactNode;
53
+ /** Named variant ReactNodes, keyed by variant key (e.g. { ai_v1: <MyVariant /> }) */
54
+ variants: Record<string, React.ReactNode>;
55
+ /** Tracking configuration */
56
+ track?: ExperimentTrackOptions;
57
+ /** Stable instance id when multiple instances of the same experiment exist on a page */
58
+ componentInstanceId?: string;
59
+ /** Behavior when assignment fetch fails: "control" (default) renders control, "suspend" throws */
60
+ fallback?: "control" | "suspend";
61
+ /** Log decisions + events to console */
62
+ debug?: boolean;
63
+ }
64
+ declare function Experiment({ id, control, variants, track, componentInstanceId, fallback, debug, }: ExperimentProps): React.JSX.Element;
65
+
66
+ interface UseProbatMetricsReturn {
129
67
  /**
130
- * Manually track a click for this experiment
68
+ * Send a custom event with arbitrary properties.
69
+ * Never throws — failures are silently dropped.
70
+ *
71
+ * @example
72
+ * ```tsx
73
+ * const { capture } = useProbatMetrics();
74
+ * capture("purchase", { revenue: 42, currency: "USD" });
75
+ * ```
131
76
  */
132
- trackClick: (event?: MouseEvent | null) => void;
77
+ capture: (event: string, properties?: Record<string, unknown>) => void;
133
78
  }
134
79
  /**
135
- * Hook for fetching and applying experiment variants
136
- *
137
- * @param proposalId - The proposal ID for the experiment
138
- * @param options - Optional configuration
139
- * @param options.autoTrackImpression - Automatically track impression when variant is loaded (default: true)
140
- *
141
- * @example
142
- * ```tsx
143
- * const { variantLabel, isLoading, trackClick } = useExperiment("proposal-id");
144
- *
145
- * if (isLoading) return <div>Loading...</div>;
146
- *
147
- * return (
148
- * <div onClick={trackClick}>
149
- * {variantLabel === "control" ? <ControlComponent /> : <VariantComponent />}
150
- * </div>
151
- * );
152
- * ```
80
+ * Minimal metrics hook. Provides a single `capture(event, props)` function
81
+ * that sends events to the Probat backend using the provider's host config.
153
82
  */
154
- declare function useExperiment(proposalId: string, options?: {
155
- autoTrackImpression?: boolean;
156
- }): UseExperimentReturn;
83
+ declare function useProbatMetrics(): UseProbatMetricsReturn;
157
84
 
158
- interface WithExperimentOptions {
159
- componentPath?: string;
160
- repoFullName?: string;
161
- proposalId?: string;
162
- registry?: Record<string, React.ComponentType<any>>;
85
+ interface DecisionResponse {
86
+ variant_key: string;
87
+ }
88
+ interface MetricPayload {
89
+ event: string;
90
+ properties: Record<string, unknown>;
163
91
  }
164
92
  /**
165
- * Higher-Order Component for wrapping components with experiment variants
166
- */
167
- declare function withExperiment<P = any>(Control: React.ComponentType<P>, options: WithExperimentOptions): React.ComponentType<P & {
168
- probat?: {
169
- trackClick: () => void;
170
- };
171
- }>;
172
-
173
- /**
174
- * Detect if the code is running on localhost (development environment).
175
- * Returns "dev" for localhost, "prod" for production.
176
- */
177
- declare function detectEnvironment(): "dev" | "prod";
178
-
179
- type RetrieveResponse = {
180
- proposal_id: string;
181
- experiment_id: string | null;
182
- label: string | null;
183
- };
184
- declare function fetchDecision(baseUrl: string, proposalId: string): Promise<{
185
- experiment_id: string;
186
- label: string;
187
- }>;
188
- declare function sendMetric(baseUrl: string, proposalId: string, metricName: "visit" | "click" | string, variantLabel?: string, experimentId?: string, dimensions?: Record<string, any>): Promise<void>;
189
- declare function extractClickMeta(event?: {
190
- target?: EventTarget | null;
191
- } | null): Record<string, any> | undefined;
192
-
193
- /**
194
- * Universal Heatmap Tracker for User Websites
195
- *
196
- * Tracks all clicks across the entire user website for heatmap visualization.
197
- * This is injected into user websites via the probat-react package.
93
+ * Fetch the variant assignment for an experiment.
94
+ * Returns the variant key string (e.g. "control", "ai_v1").
95
+ * Deduplicates concurrent calls for the same experiment.
198
96
  */
199
- interface HeatmapConfig {
200
- apiBaseUrl: string;
201
- batchSize?: number;
202
- batchInterval?: number;
203
- enabled?: boolean;
204
- excludeSelectors?: string[];
205
- trackCursor?: boolean;
206
- cursorThrottle?: number;
207
- cursorBatchSize?: number;
208
- proposalId?: string;
209
- variantLabel?: string;
210
- }
211
- declare class HeatmapTracker {
212
- private clicks;
213
- private movements;
214
- private sessionId;
215
- private config;
216
- private batchTimer;
217
- private cursorBatchTimer;
218
- private lastCursorTime;
219
- private isInitialized;
220
- constructor(config: HeatmapConfig);
221
- private getOrCreateSessionId;
222
- private shouldExcludeElement;
223
- private extractElementInfo;
224
- private handleMouseMove;
225
- private scheduleCursorBatchSend;
226
- private sendCursorBatch;
227
- private handleClick;
228
- private scheduleBatchSend;
229
- private sendBatch;
230
- init(): void;
231
- stop(): void;
232
- /**
233
- * Enable visualization mode
234
- */
235
- /**
236
- * Enable visualization mode
237
- */
238
- private enableVisualization;
239
- /**
240
- * Render heatmap overlay on valid points
241
- */
242
- private renderHeatmapOverlay;
243
- /**
244
- * Draw points on canvas
245
- */
246
- private renderPoints;
247
- /**
248
- * Get heatmap color based on intensity
249
- */
250
- private getHeatmapColor;
251
- /**
252
- * Convert RGB to RGBA
253
- */
254
- private rgbToRgba;
255
- }
97
+ declare function fetchDecision(host: string, experimentId: string, distinctId: string): Promise<string>;
256
98
  /**
257
- * Initialize heatmap tracking for user websites
258
- * Called automatically by ProbatProvider
99
+ * Fire-and-forget metric send. Never throws.
259
100
  */
260
- declare function initHeatmapTracking(config: HeatmapConfig): HeatmapTracker;
261
- declare function getHeatmapTracker(): HeatmapTracker | null;
262
- declare function stopHeatmapTracking(): void;
263
-
264
- type Choice = {
265
- experiment_id: string;
266
- label: string;
267
- ts: number;
268
- };
269
- declare function readChoice(proposalId: string): Choice | null;
270
- declare function writeChoice(proposalId: string, experiment_id: string, label: string): void;
271
- declare function hasTrackedVisit(proposalId: string, label: string): boolean;
272
- declare function markTrackedVisit(proposalId: string, label: string): void;
101
+ declare function sendMetric(host: string, event: string, properties: Record<string, unknown>): void;
273
102
 
274
- export { type Choice, type ProbatContextValue, ProbatProvider, ProbatProviderClient, type ProbatProviderProps as ProbatProviderClientProps, type ProbatProviderProps, type RetrieveResponse, type UseExperimentReturn, type UseProbatMetricsReturn, type WithExperimentOptions, detectEnvironment, extractClickMeta, fetchDecision, getHeatmapTracker, hasTrackedVisit, initHeatmapTracking, markTrackedVisit, readChoice, sendMetric, stopHeatmapTracking, useExperiment, useProbatContext, useProbatMetrics, withExperiment, writeChoice };
103
+ export { type DecisionResponse, Experiment, type ExperimentProps, type ExperimentTrackOptions, type MetricPayload, ProbatProviderClient, type ProbatProviderProps, type UseProbatMetricsReturn, fetchDecision, sendMetric, useProbatMetrics };