@probat/react 0.2.1 → 0.3.0
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/README.md +33 -344
- package/dist/index.d.mts +76 -247
- package/dist/index.d.ts +76 -247
- package/dist/index.js +395 -1357
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +392 -1341
- package/dist/index.mjs.map +1 -1
- package/package.json +17 -11
- package/src/__tests__/Experiment.test.tsx +764 -0
- package/src/__tests__/setup.ts +63 -0
- package/src/__tests__/utils.test.ts +79 -0
- package/src/components/Experiment.tsx +291 -0
- package/src/components/ProbatProviderClient.tsx +19 -7
- package/src/context/ProbatContext.tsx +30 -152
- package/src/hooks/useProbatMetrics.ts +18 -134
- package/src/index.ts +9 -32
- package/src/utils/api.ts +96 -577
- package/src/utils/dedupeStorage.ts +40 -0
- package/src/utils/eventContext.ts +94 -0
- package/src/utils/stableInstanceId.ts +113 -0
- package/src/utils/storage.ts +18 -60
- package/src/hoc/itrt-frontend.code-workspace +0 -10
- package/src/hoc/withExperiment.tsx +0 -311
- package/src/hooks/useExperiment.ts +0 -188
- package/src/utils/documentClickTracker.ts +0 -215
- package/src/utils/heatmapTracker.ts +0 -665
package/dist/index.d.mts
CHANGED
|
@@ -1,274 +1,103 @@
|
|
|
1
|
-
import 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
|
-
*
|
|
19
|
-
*
|
|
20
|
-
* -
|
|
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
|
-
|
|
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
|
-
*
|
|
58
|
-
*
|
|
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
|
-
*
|
|
100
|
-
*
|
|
101
|
-
*
|
|
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
|
-
*
|
|
105
|
-
*
|
|
106
|
-
*
|
|
107
|
-
*
|
|
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
|
|
36
|
+
declare function ProbatProviderClient(props: ProbatProviderProps): React.FunctionComponentElement<ProbatProviderProps>;
|
|
111
37
|
|
|
112
|
-
interface
|
|
113
|
-
/**
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
/**
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
/**
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
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
|
-
*
|
|
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
|
-
|
|
77
|
+
capture: (event: string, properties?: Record<string, unknown>) => void;
|
|
133
78
|
}
|
|
134
79
|
/**
|
|
135
|
-
*
|
|
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
|
|
155
|
-
autoTrackImpression?: boolean;
|
|
156
|
-
}): UseExperimentReturn;
|
|
83
|
+
declare function useProbatMetrics(): UseProbatMetricsReturn;
|
|
157
84
|
|
|
158
|
-
interface
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
85
|
+
interface DecisionResponse {
|
|
86
|
+
variant_key: string;
|
|
87
|
+
}
|
|
88
|
+
interface MetricPayload {
|
|
89
|
+
event: string;
|
|
90
|
+
properties: Record<string, unknown>;
|
|
163
91
|
}
|
|
164
92
|
/**
|
|
165
|
-
*
|
|
166
|
-
|
|
167
|
-
|
|
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
|
-
|
|
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
|
-
*
|
|
258
|
-
* Called automatically by ProbatProvider
|
|
99
|
+
* Fire-and-forget metric send. Never throws.
|
|
259
100
|
*/
|
|
260
|
-
declare function
|
|
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
|
|
103
|
+
export { type DecisionResponse, Experiment, type ExperimentProps, type ExperimentTrackOptions, type MetricPayload, ProbatProviderClient, type ProbatProviderProps, type UseProbatMetricsReturn, fetchDecision, sendMetric, useProbatMetrics };
|