wolves-react-client 1.0.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 ADDED
@@ -0,0 +1,367 @@
1
+ # Wolves React Client SDK
2
+
3
+ React SDK for the Wolves A/B Testing & Experimentation Platform. This library provides React hooks and components for easy integration of Wolves into your React applications.
4
+
5
+ ## Features
6
+
7
+ - 🎣 **React Hooks** - `useExperiment`, `useWolvesClient`, `useWolvesEvent`
8
+ - ⚡ **Fast Initialization** - Async and sync initialization modes with caching
9
+ - 🔄 **Automatic Exposure Logging** - Experiments automatically log exposures
10
+ - 📦 **TypeScript Support** - Full TypeScript type definitions
11
+ - 🌐 **SSR Compatible** - Works with Next.js and other SSR frameworks
12
+ - 🎯 **Zero Config** - Works out of the box with sensible defaults
13
+
14
+ ## Installation
15
+
16
+ ```bash
17
+ npm install wolves-react-client wolves-js-client react
18
+ ```
19
+
20
+ or with yarn:
21
+
22
+ ```bash
23
+ yarn add wolves-react-client wolves-js-client react
24
+ ```
25
+
26
+ ## Quick Start
27
+
28
+ ### 1. Wrap your app with WolvesProvider
29
+
30
+ ```tsx
31
+ import { WolvesProvider } from 'wolves-react-client';
32
+
33
+ function App() {
34
+ const user = {
35
+ userID: 'user-123',
36
+ email: 'user@example.com',
37
+ };
38
+
39
+ return (
40
+ <WolvesProvider sdkKey="your-sdk-key" user={user}>
41
+ <YourApp />
42
+ </WolvesProvider>
43
+ );
44
+ }
45
+ ```
46
+
47
+ ### 2. Use experiments in your components
48
+
49
+ ```tsx
50
+ import { useExperiment } from 'wolves-react-client';
51
+
52
+ function FeatureComponent() {
53
+ const experiment = useExperiment('my-experiment');
54
+
55
+ const buttonColor = experiment.get('button_color', 'blue');
56
+ const buttonText = experiment.get('button_text', 'Click Me');
57
+
58
+ return (
59
+ <button style={{ backgroundColor: buttonColor }}>
60
+ {buttonText}
61
+ </button>
62
+ );
63
+ }
64
+ ```
65
+
66
+ ### 3. Log custom events
67
+
68
+ ```tsx
69
+ import { useWolvesEvent } from 'wolves-react-client';
70
+
71
+ function CheckoutButton() {
72
+ const { logEvent } = useWolvesEvent();
73
+
74
+ const handleCheckout = () => {
75
+ logEvent('checkout_completed', 99.99, {
76
+ currency: 'USD',
77
+ items: '3',
78
+ });
79
+ };
80
+
81
+ return <button onClick={handleCheckout}>Checkout</button>;
82
+ }
83
+ ```
84
+
85
+ ## API Reference
86
+
87
+ ### WolvesProvider
88
+
89
+ The root component that initializes the Wolves client and provides context to child components.
90
+
91
+ #### Props
92
+
93
+ | Prop | Type | Required | Description |
94
+ |------|------|----------|-------------|
95
+ | `sdkKey` | `string` | Yes | Your Wolves SDK key |
96
+ | `user` | `WolvesUser` | Yes | User identification and attributes |
97
+ | `children` | `React.ReactNode` | Yes | Child components |
98
+ | `options` | `WolvesProviderOptions` | No | Configuration options |
99
+ | `waitForInitialization` | `boolean` | No | Wait for init before rendering children |
100
+ | `loadingComponent` | `React.ReactNode` | No | Component to show while loading |
101
+
102
+ #### Example with Options
103
+
104
+ ```tsx
105
+ <WolvesProvider
106
+ sdkKey="your-sdk-key"
107
+ user={{ userID: 'user-123' }}
108
+ options={{
109
+ initMode: 'async',
110
+ onInitialized: (details) => console.log('Initialized:', details),
111
+ onError: (error) => console.error('Error:', error),
112
+ }}
113
+ waitForInitialization={true}
114
+ loadingComponent={<LoadingSpinner />}
115
+ >
116
+ <App />
117
+ </WolvesProvider>
118
+ ```
119
+
120
+ ### useExperiment
121
+
122
+ Hook to access experiment configurations and automatically log exposures.
123
+
124
+ ```tsx
125
+ const experiment = useExperiment<T>(experimentName, options?);
126
+ ```
127
+
128
+ #### Parameters
129
+
130
+ - `experimentName` (string): Name of the experiment
131
+ - `options` (optional):
132
+ - `skipExposure` (boolean): Skip automatic exposure logging
133
+ - `defaultValue` (T): Default value if experiment not found
134
+
135
+ #### Returns
136
+
137
+ - `value` (T): The experiment configuration value
138
+ - `groupName` (string | null): The assigned group/variant
139
+ - `experimentID` (string): The experiment ID
140
+ - `get<K>(key, defaultValue)`: Get a specific parameter
141
+ - `isLoading` (boolean): Whether client is still loading
142
+
143
+ #### Example
144
+
145
+ ```tsx
146
+ function MyComponent() {
147
+ const experiment = useExperiment('button-test', {
148
+ defaultValue: { color: 'blue', text: 'Click' }
149
+ });
150
+
151
+ if (experiment.isLoading) {
152
+ return <div>Loading...</div>;
153
+ }
154
+
155
+ return (
156
+ <div>
157
+ <p>Group: {experiment.groupName}</p>
158
+ <button style={{ color: experiment.get('color', 'blue') }}>
159
+ {experiment.get('text', 'Click')}
160
+ </button>
161
+ </div>
162
+ );
163
+ }
164
+ ```
165
+
166
+ ### useWolvesClient
167
+
168
+ Hook to access the Wolves client instance and initialization state.
169
+
170
+ ```tsx
171
+ const { client, isInitialized, isLoading, error, updateUser } = useWolvesClient();
172
+ ```
173
+
174
+ #### Returns
175
+
176
+ - `client` (WolvesClient | null): The client instance
177
+ - `isInitialized` (boolean): Whether initialization completed
178
+ - `isLoading` (boolean): Whether currently loading
179
+ - `initializationDetails` (WolvesUpdateDetails | null): Init details
180
+ - `error` (Error | null): Any initialization error
181
+ - `updateUser` (function): Function to update the current user
182
+
183
+ ### useWolvesEvent
184
+
185
+ Hook to log custom events.
186
+
187
+ ```tsx
188
+ const { logEvent } = useWolvesEvent();
189
+ ```
190
+
191
+ #### Returns
192
+
193
+ - `logEvent(eventName, value?, metadata?)`: Function to log events
194
+ - `eventName` (string): Event name
195
+ - `value` (string | number, optional): Event value
196
+ - `metadata` (Record<string, string>, optional): Event metadata
197
+
198
+ #### Example
199
+
200
+ ```tsx
201
+ function PurchaseButton() {
202
+ const { logEvent } = useWolvesEvent();
203
+
204
+ const handlePurchase = () => {
205
+ logEvent('purchase', 49.99, {
206
+ product_id: 'abc123',
207
+ category: 'electronics'
208
+ });
209
+ };
210
+
211
+ return <button onClick={handlePurchase}>Buy Now</button>;
212
+ }
213
+ ```
214
+
215
+ ### useWolvesInitialization
216
+
217
+ Hook to monitor initialization status.
218
+
219
+ ```tsx
220
+ const { isLoading, isReady, loadingStatus, error, details } = useWolvesInitialization();
221
+ ```
222
+
223
+ ## Initialization Modes
224
+
225
+ ### Async Mode (Default)
226
+
227
+ Loads from cache first (if available), then fetches from network. Waits for network response before completing initialization.
228
+
229
+ ```tsx
230
+ <WolvesProvider
231
+ sdkKey="your-sdk-key"
232
+ user={user}
233
+ options={{ initMode: 'async' }}
234
+ >
235
+ <App />
236
+ </WolvesProvider>
237
+ ```
238
+
239
+ ### Sync Mode
240
+
241
+ Immediately loads from cache and starts rendering. Fetches from network in the background to update cache for next session.
242
+
243
+ ```tsx
244
+ <WolvesProvider
245
+ sdkKey="your-sdk-key"
246
+ user={user}
247
+ options={{
248
+ initMode: 'sync',
249
+ syncOptions: {
250
+ disableBackgroundCacheRefresh: false
251
+ }
252
+ }}
253
+ >
254
+ <App />
255
+ </WolvesProvider>
256
+ ```
257
+
258
+ ## Server-Side Rendering (SSR)
259
+
260
+ The SDK is SSR-compatible and works with Next.js and other SSR frameworks.
261
+
262
+ ### Next.js App Router Example
263
+
264
+ ```tsx
265
+ // app/layout.tsx
266
+ 'use client';
267
+
268
+ import { WolvesProvider } from 'wolves-react-client';
269
+
270
+ export default function RootLayout({ children }) {
271
+ return (
272
+ <html>
273
+ <body>
274
+ <WolvesProvider
275
+ sdkKey={process.env.NEXT_PUBLIC_WOLVES_SDK_KEY!}
276
+ user={{ userID: 'user-123' }}
277
+ >
278
+ {children}
279
+ </WolvesProvider>
280
+ </body>
281
+ </html>
282
+ );
283
+ }
284
+ ```
285
+
286
+ ### Next.js Pages Router Example
287
+
288
+ ```tsx
289
+ // pages/_app.tsx
290
+ import { WolvesProvider } from 'wolves-react-client';
291
+
292
+ function MyApp({ Component, pageProps }) {
293
+ return (
294
+ <WolvesProvider
295
+ sdkKey={process.env.NEXT_PUBLIC_WOLVES_SDK_KEY!}
296
+ user={{ userID: 'user-123' }}
297
+ >
298
+ <Component {...pageProps} />
299
+ </WolvesProvider>
300
+ );
301
+ }
302
+
303
+ export default MyApp;
304
+ ```
305
+
306
+ ## TypeScript
307
+
308
+ The SDK is written in TypeScript and provides full type safety.
309
+
310
+ ```tsx
311
+ interface ButtonExperiment {
312
+ color: string;
313
+ text: string;
314
+ size: 'small' | 'medium' | 'large';
315
+ }
316
+
317
+ function MyButton() {
318
+ const experiment = useExperiment<ButtonExperiment>('button-test');
319
+
320
+ // Fully typed!
321
+ const color = experiment.get('color', 'blue');
322
+ const size = experiment.get('size', 'medium');
323
+
324
+ return <button>{experiment.value.text}</button>;
325
+ }
326
+ ```
327
+
328
+ ## Best Practices
329
+
330
+ 1. **Initialize Once**: Place `WolvesProvider` at the root of your app, not in individual components
331
+ 2. **Memoize User**: Use `useMemo` for the user object to prevent unnecessary re-initializations
332
+ 3. **Handle Loading States**: Check `isLoading` before rendering experiment-dependent UI
333
+ 4. **Use Default Values**: Always provide default values for experiment parameters
334
+ 5. **Log Meaningful Events**: Use descriptive event names and include relevant metadata
335
+
336
+ ## Troubleshooting
337
+
338
+ ### Provider Error
339
+
340
+ If you see "useWolvesClient must be used within WolvesProvider", ensure that your component is a child of `WolvesProvider`.
341
+
342
+ ### SSR Errors
343
+
344
+ The SDK automatically detects SSR environments and skips initialization on the server. Make sure to use `'use client'` directive in Next.js App Router.
345
+
346
+ ### Experiments Not Loading
347
+
348
+ - Verify your SDK key is correct
349
+ - Check network requests in browser DevTools
350
+ - Ensure the experiment exists in your Wolves dashboard
351
+ - Check for initialization errors using `useWolvesClient().error`
352
+
353
+ ## Examples
354
+
355
+ See the `examples/` directory for complete working examples:
356
+
357
+ - `basic-usage/` - Simple React app example
358
+ - `nextjs-ssr/` - Next.js with SSR support
359
+ - `typescript-example/` - TypeScript with full type safety
360
+
361
+ ## License
362
+
363
+ ISC
364
+
365
+ ## Support
366
+
367
+ For issues and questions, please open an issue on GitHub.
@@ -0,0 +1,25 @@
1
+ import React from 'react';
2
+ import { WolvesClient, WolvesUpdateDetails, WolvesUser } from 'wolves-js-client';
3
+ /**
4
+ * Context value provided to consuming components.
5
+ */
6
+ export interface WolvesContextValue {
7
+ /** The WolvesClient instance, null if not yet initialized */
8
+ client: WolvesClient | null;
9
+ /** Whether the client has completed initialization */
10
+ isInitialized: boolean;
11
+ /** Whether the client is currently initializing */
12
+ isLoading: boolean;
13
+ /** Details from the last initialization/update */
14
+ initializationDetails: WolvesUpdateDetails | null;
15
+ /** Any error that occurred during initialization */
16
+ error: Error | null;
17
+ /** Function to update the current user */
18
+ updateUser: (user: WolvesUser) => Promise<void>;
19
+ }
20
+ /**
21
+ * React Context for sharing Wolves client state across the component tree.
22
+ * Use the useWolvesClient hook to access this context instead of using it directly.
23
+ */
24
+ export declare const WolvesContext: React.Context<WolvesContextValue | null>;
25
+ //# sourceMappingURL=WolvesContext.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"WolvesContext.d.ts","sourceRoot":"","sources":["../src/WolvesContext.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,YAAY,EAAE,mBAAmB,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAEjF;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,6DAA6D;IAC7D,MAAM,EAAE,YAAY,GAAG,IAAI,CAAC;IAC5B,sDAAsD;IACtD,aAAa,EAAE,OAAO,CAAC;IACvB,mDAAmD;IACnD,SAAS,EAAE,OAAO,CAAC;IACnB,kDAAkD;IAClD,qBAAqB,EAAE,mBAAmB,GAAG,IAAI,CAAC;IAClD,oDAAoD;IACpD,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACpB,0CAA0C;IAC1C,UAAU,EAAE,CAAC,IAAI,EAAE,UAAU,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACjD;AAED;;;GAGG;AACH,eAAO,MAAM,aAAa,0CAAuD,CAAC"}
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.WolvesContext = void 0;
7
+ const react_1 = __importDefault(require("react"));
8
+ /**
9
+ * React Context for sharing Wolves client state across the component tree.
10
+ * Use the useWolvesClient hook to access this context instead of using it directly.
11
+ */
12
+ exports.WolvesContext = react_1.default.createContext(null);
13
+ exports.WolvesContext.displayName = 'WolvesContext';
@@ -0,0 +1,24 @@
1
+ import React from 'react';
2
+ import { WolvesProviderProps } from './types';
3
+ /**
4
+ * WolvesProvider is the root component for integrating Wolves SDK with React.
5
+ * It initializes the WolvesClient and provides it to child components via React Context.
6
+ *
7
+ * @example
8
+ * ```tsx
9
+ * import { WolvesProvider } from 'wolves-react-client';
10
+ *
11
+ * function App() {
12
+ * return (
13
+ * <WolvesProvider
14
+ * sdkKey="your-sdk-key"
15
+ * user={{ userID: 'user-123' }}
16
+ * >
17
+ * <YourApp />
18
+ * </WolvesProvider>
19
+ * );
20
+ * }
21
+ * ```
22
+ */
23
+ export declare const WolvesProvider: React.FC<WolvesProviderProps>;
24
+ //# sourceMappingURL=WolvesProvider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"WolvesProvider.d.ts","sourceRoot":"","sources":["../src/WolvesProvider.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA+C,MAAM,OAAO,CAAC;AAGpE,OAAO,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAC;AAG9C;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,cAAc,EAAE,KAAK,CAAC,EAAE,CAAC,mBAAmB,CAoKxD,CAAC"}
@@ -0,0 +1,202 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
36
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
37
+ return new (P || (P = Promise))(function (resolve, reject) {
38
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
39
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
40
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
41
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
42
+ });
43
+ };
44
+ Object.defineProperty(exports, "__esModule", { value: true });
45
+ exports.WolvesProvider = void 0;
46
+ const react_1 = __importStar(require("react"));
47
+ const wolves_js_client_1 = require("wolves-js-client");
48
+ const WolvesContext_1 = require("./WolvesContext");
49
+ const ssrHelpers_1 = require("./utils/ssrHelpers");
50
+ /**
51
+ * WolvesProvider is the root component for integrating Wolves SDK with React.
52
+ * It initializes the WolvesClient and provides it to child components via React Context.
53
+ *
54
+ * @example
55
+ * ```tsx
56
+ * import { WolvesProvider } from 'wolves-react-client';
57
+ *
58
+ * function App() {
59
+ * return (
60
+ * <WolvesProvider
61
+ * sdkKey="your-sdk-key"
62
+ * user={{ userID: 'user-123' }}
63
+ * >
64
+ * <YourApp />
65
+ * </WolvesProvider>
66
+ * );
67
+ * }
68
+ * ```
69
+ */
70
+ const WolvesProvider = ({ sdkKey, user, children, options = {}, waitForInitialization = false, loadingComponent = null, }) => {
71
+ const [client, setClient] = (0, react_1.useState)(null);
72
+ const [isInitialized, setIsInitialized] = (0, react_1.useState)(false);
73
+ const [isLoading, setIsLoading] = (0, react_1.useState)(true);
74
+ const [initializationDetails, setInitializationDetails] = (0, react_1.useState)(null);
75
+ const [error, setError] = (0, react_1.useState)(null);
76
+ const userRef = (0, react_1.useRef)(user);
77
+ // Skip initialization on server
78
+ const shouldInitialize = !(0, ssrHelpers_1.isServer)();
79
+ // Initialize client on mount
80
+ (0, react_1.useEffect)(() => {
81
+ if (!shouldInitialize) {
82
+ setIsLoading(false);
83
+ return;
84
+ }
85
+ let isMounted = true;
86
+ const initMode = options.initMode || 'async';
87
+ const initializeClient = () => __awaiter(void 0, void 0, void 0, function* () {
88
+ try {
89
+ const newClient = new wolves_js_client_1.WolvesClient(sdkKey, user, options.apiEnv || 'prod');
90
+ if (initMode === 'async') {
91
+ // Async initialization
92
+ const details = yield newClient.initializeAsync(options.asyncOptions);
93
+ if (!isMounted)
94
+ return;
95
+ setInitializationDetails(details);
96
+ setIsInitialized(true);
97
+ setIsLoading(false);
98
+ setClient(newClient);
99
+ if (options.onInitialized) {
100
+ options.onInitialized(details);
101
+ }
102
+ }
103
+ else {
104
+ // Sync initialization
105
+ const details = newClient.initializeSync(options.syncOptions);
106
+ if (!isMounted)
107
+ return;
108
+ setInitializationDetails(details);
109
+ setIsInitialized(true);
110
+ setIsLoading(false);
111
+ setClient(newClient);
112
+ if (options.onInitialized) {
113
+ options.onInitialized(details);
114
+ }
115
+ }
116
+ }
117
+ catch (err) {
118
+ if (!isMounted)
119
+ return;
120
+ const error = err instanceof Error ? err : new Error(String(err));
121
+ setError(error);
122
+ setIsLoading(false);
123
+ if (options.onError) {
124
+ options.onError(error);
125
+ }
126
+ }
127
+ });
128
+ initializeClient();
129
+ // Cleanup on unmount
130
+ return () => {
131
+ isMounted = false;
132
+ if (client) {
133
+ client.shutdown().catch((e) => {
134
+ console.error('Failed to shutdown Wolves client:', e);
135
+ });
136
+ }
137
+ };
138
+ // Intentionally only depend on sdkKey and shouldInitialize
139
+ // User and options changes are handled separately
140
+ // eslint-disable-next-line react-hooks/exhaustive-deps
141
+ }, [sdkKey, shouldInitialize]);
142
+ // Handle user changes
143
+ (0, react_1.useEffect)(() => {
144
+ if (!client || !isInitialized)
145
+ return;
146
+ // Check if user actually changed
147
+ if (JSON.stringify(userRef.current) === JSON.stringify(user)) {
148
+ return;
149
+ }
150
+ userRef.current = user;
151
+ const updateUser = () => __awaiter(void 0, void 0, void 0, function* () {
152
+ try {
153
+ const details = yield client.updateUserAsync(user, options.asyncOptions);
154
+ setInitializationDetails(details);
155
+ if (options.onInitialized) {
156
+ options.onInitialized(details);
157
+ }
158
+ }
159
+ catch (err) {
160
+ const error = err instanceof Error ? err : new Error(String(err));
161
+ setError(error);
162
+ if (options.onError) {
163
+ options.onError(error);
164
+ }
165
+ }
166
+ });
167
+ updateUser();
168
+ // Intentionally don't include options in deps as we only want to react to user changes
169
+ // eslint-disable-next-line react-hooks/exhaustive-deps
170
+ }, [user, client, isInitialized]);
171
+ // Create updateUser function for manual user updates
172
+ const updateUser = (newUser) => __awaiter(void 0, void 0, void 0, function* () {
173
+ if (!client) {
174
+ throw new Error('Wolves client is not initialized');
175
+ }
176
+ userRef.current = newUser;
177
+ const details = yield client.updateUserAsync(newUser, options.asyncOptions);
178
+ setInitializationDetails(details);
179
+ if (options.onInitialized) {
180
+ options.onInitialized(details);
181
+ }
182
+ });
183
+ // Memoize context value to prevent unnecessary re-renders
184
+ const contextValue = (0, react_1.useMemo)(() => ({
185
+ client,
186
+ isInitialized,
187
+ isLoading,
188
+ initializationDetails,
189
+ error,
190
+ updateUser,
191
+ }),
192
+ // updateUser function is stable (defined outside useEffect)
193
+ // eslint-disable-next-line react-hooks/exhaustive-deps
194
+ [client, isInitialized, isLoading, initializationDetails, error]);
195
+ // Show loading component if waiting for initialization
196
+ if (waitForInitialization && isLoading && !error) {
197
+ return react_1.default.createElement(react_1.default.Fragment, null, loadingComponent);
198
+ }
199
+ return (react_1.default.createElement(WolvesContext_1.WolvesContext.Provider, { value: contextValue }, children));
200
+ };
201
+ exports.WolvesProvider = WolvesProvider;
202
+ exports.WolvesProvider.displayName = 'WolvesProvider';
@@ -0,0 +1,37 @@
1
+ import { UseExperimentOptions, UseExperimentReturn } from '../types';
2
+ /**
3
+ * Hook to access experiment configurations and automatically log exposure events.
4
+ *
5
+ * This hook retrieves experiment values from the Wolves client and automatically
6
+ * logs an exposure event (unless skipExposure is true). It handles loading states
7
+ * and provides default values when experiments are not found.
8
+ *
9
+ * @param experimentName - The name of the experiment to retrieve
10
+ * @param options - Optional configuration
11
+ * @param options.skipExposure - If true, skip logging exposure event (default: false)
12
+ * @param options.defaultValue - Default value to return if experiment not found
13
+ *
14
+ * @returns Experiment configuration with typed value access
15
+ *
16
+ * @example
17
+ * ```tsx
18
+ * function MyButton() {
19
+ * const experiment = useExperiment('button-test', {
20
+ * defaultValue: { color: 'blue', text: 'Click Me' }
21
+ * });
22
+ *
23
+ * if (experiment.isLoading) {
24
+ * return <button>Loading...</button>;
25
+ * }
26
+ *
27
+ * return (
28
+ * <button style={{ backgroundColor: experiment.get('color', 'blue') }}>
29
+ * {experiment.get('text', 'Click Me')}
30
+ * </button>
31
+ * );
32
+ * }
33
+ * ```
34
+ */
35
+ export declare function useExperiment<T extends Record<string, any> = Record<string, any>>(// eslint-disable-line @typescript-eslint/no-explicit-any
36
+ experimentName: string, options?: UseExperimentOptions<T>): UseExperimentReturn<T>;
37
+ //# sourceMappingURL=useExperiment.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useExperiment.d.ts","sourceRoot":"","sources":["../../src/hooks/useExperiment.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAC;AAErE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,wBAAgB,aAAa,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAG,yDAAyD;AAC3I,cAAc,EAAE,MAAM,EACtB,OAAO,CAAC,EAAE,oBAAoB,CAAC,CAAC,CAAC,GAChC,mBAAmB,CAAC,CAAC,CAAC,CAmDxB"}
@@ -0,0 +1,87 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.useExperiment = useExperiment;
4
+ const react_1 = require("react");
5
+ const useWolvesClient_1 = require("./useWolvesClient");
6
+ /**
7
+ * Hook to access experiment configurations and automatically log exposure events.
8
+ *
9
+ * This hook retrieves experiment values from the Wolves client and automatically
10
+ * logs an exposure event (unless skipExposure is true). It handles loading states
11
+ * and provides default values when experiments are not found.
12
+ *
13
+ * @param experimentName - The name of the experiment to retrieve
14
+ * @param options - Optional configuration
15
+ * @param options.skipExposure - If true, skip logging exposure event (default: false)
16
+ * @param options.defaultValue - Default value to return if experiment not found
17
+ *
18
+ * @returns Experiment configuration with typed value access
19
+ *
20
+ * @example
21
+ * ```tsx
22
+ * function MyButton() {
23
+ * const experiment = useExperiment('button-test', {
24
+ * defaultValue: { color: 'blue', text: 'Click Me' }
25
+ * });
26
+ *
27
+ * if (experiment.isLoading) {
28
+ * return <button>Loading...</button>;
29
+ * }
30
+ *
31
+ * return (
32
+ * <button style={{ backgroundColor: experiment.get('color', 'blue') }}>
33
+ * {experiment.get('text', 'Click Me')}
34
+ * </button>
35
+ * );
36
+ * }
37
+ * ```
38
+ */
39
+ function useExperiment(// eslint-disable-line @typescript-eslint/no-explicit-any
40
+ experimentName, options) {
41
+ var _a;
42
+ const { client, isLoading: clientIsLoading } = (0, useWolvesClient_1.useWolvesClient)();
43
+ const skipExposure = (_a = options === null || options === void 0 ? void 0 : options.skipExposure) !== null && _a !== void 0 ? _a : false;
44
+ // Memoize defaultValue to prevent unnecessary re-evaluations
45
+ const defaultValue = (0, react_1.useMemo)(() => { var _a; return ((_a = options === null || options === void 0 ? void 0 : options.defaultValue) !== null && _a !== void 0 ? _a : {}); }, [options === null || options === void 0 ? void 0 : options.defaultValue]);
46
+ // Memoize the experiment result to prevent unnecessary re-evaluations
47
+ const experimentResult = (0, react_1.useMemo)(() => {
48
+ // Return loading state if client is not ready
49
+ if (clientIsLoading || !client) {
50
+ return {
51
+ value: defaultValue,
52
+ groupName: null,
53
+ experimentID: '',
54
+ get: (key, fallback) => {
55
+ if (defaultValue && key in defaultValue) {
56
+ return defaultValue[key];
57
+ }
58
+ return fallback;
59
+ },
60
+ isLoading: true,
61
+ };
62
+ }
63
+ // Get experiment from client (automatically logs exposure unless we skip it)
64
+ let experiment;
65
+ if (skipExposure) {
66
+ // TODO: Implement a way to get experiment without logging exposure
67
+ // For now, we'll use the regular method
68
+ experiment = client.getExperiment(experimentName);
69
+ }
70
+ else {
71
+ experiment = client.getExperiment(experimentName);
72
+ }
73
+ const value = experiment.value || defaultValue;
74
+ const groupName = experiment.groupName;
75
+ const experimentID = experiment.experimentID;
76
+ return {
77
+ value,
78
+ groupName,
79
+ experimentID,
80
+ get: (key, fallback) => {
81
+ return experiment.get(key, fallback);
82
+ },
83
+ isLoading: false,
84
+ };
85
+ }, [client, clientIsLoading, experimentName, skipExposure, defaultValue]);
86
+ return experimentResult;
87
+ }
@@ -0,0 +1,30 @@
1
+ import { WolvesContextValue } from '../WolvesContext';
2
+ /**
3
+ * Hook to access the Wolves client instance and initialization state.
4
+ *
5
+ * This hook must be used within a WolvesProvider. It provides access to:
6
+ * - The WolvesClient instance
7
+ * - Initialization status (loading, initialized, error)
8
+ * - Function to manually update the user
9
+ *
10
+ * @throws Error if used outside of WolvesProvider
11
+ *
12
+ * @example
13
+ * ```tsx
14
+ * function MyComponent() {
15
+ * const { client, isInitialized, isLoading, error } = useWolvesClient();
16
+ *
17
+ * if (isLoading) {
18
+ * return <div>Loading...</div>;
19
+ * }
20
+ *
21
+ * if (error) {
22
+ * return <div>Error: {error.message}</div>;
23
+ * }
24
+ *
25
+ * return <div>Client ready!</div>;
26
+ * }
27
+ * ```
28
+ */
29
+ export declare function useWolvesClient(): WolvesContextValue;
30
+ //# sourceMappingURL=useWolvesClient.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useWolvesClient.d.ts","sourceRoot":"","sources":["../../src/hooks/useWolvesClient.ts"],"names":[],"mappings":"AACA,OAAO,EAAiB,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAErE;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,eAAe,IAAI,kBAAkB,CAWpD"}
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.useWolvesClient = useWolvesClient;
4
+ const react_1 = require("react");
5
+ const WolvesContext_1 = require("../WolvesContext");
6
+ /**
7
+ * Hook to access the Wolves client instance and initialization state.
8
+ *
9
+ * This hook must be used within a WolvesProvider. It provides access to:
10
+ * - The WolvesClient instance
11
+ * - Initialization status (loading, initialized, error)
12
+ * - Function to manually update the user
13
+ *
14
+ * @throws Error if used outside of WolvesProvider
15
+ *
16
+ * @example
17
+ * ```tsx
18
+ * function MyComponent() {
19
+ * const { client, isInitialized, isLoading, error } = useWolvesClient();
20
+ *
21
+ * if (isLoading) {
22
+ * return <div>Loading...</div>;
23
+ * }
24
+ *
25
+ * if (error) {
26
+ * return <div>Error: {error.message}</div>;
27
+ * }
28
+ *
29
+ * return <div>Client ready!</div>;
30
+ * }
31
+ * ```
32
+ */
33
+ function useWolvesClient() {
34
+ const context = (0, react_1.useContext)(WolvesContext_1.WolvesContext);
35
+ if (context === null) {
36
+ throw new Error('useWolvesClient must be used within a WolvesProvider. ' +
37
+ 'Wrap your component tree with <WolvesProvider> to use Wolves hooks.');
38
+ }
39
+ return context;
40
+ }
@@ -0,0 +1,27 @@
1
+ import { UseWolvesEventReturn } from '../types';
2
+ /**
3
+ * Hook to log custom events to the Wolves platform.
4
+ *
5
+ * This hook provides a stable callback function to log events. The callback
6
+ * function reference remains the same across renders for performance.
7
+ *
8
+ * @returns Object containing the logEvent function
9
+ *
10
+ * @example
11
+ * ```tsx
12
+ * function PurchaseButton() {
13
+ * const { logEvent } = useWolvesEvent();
14
+ *
15
+ * const handlePurchase = () => {
16
+ * logEvent('purchase_completed', 99.99, {
17
+ * product_id: 'abc123',
18
+ * category: 'electronics'
19
+ * });
20
+ * };
21
+ *
22
+ * return <button onClick={handlePurchase}>Buy Now</button>;
23
+ * }
24
+ * ```
25
+ */
26
+ export declare function useWolvesEvent(): UseWolvesEventReturn;
27
+ //# sourceMappingURL=useWolvesEvent.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useWolvesEvent.d.ts","sourceRoot":"","sources":["../../src/hooks/useWolvesEvent.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,oBAAoB,EAAE,MAAM,UAAU,CAAC;AAEhD;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,cAAc,IAAI,oBAAoB,CAqCrD"}
@@ -0,0 +1,56 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.useWolvesEvent = useWolvesEvent;
4
+ const react_1 = require("react");
5
+ const useWolvesClient_1 = require("./useWolvesClient");
6
+ /**
7
+ * Hook to log custom events to the Wolves platform.
8
+ *
9
+ * This hook provides a stable callback function to log events. The callback
10
+ * function reference remains the same across renders for performance.
11
+ *
12
+ * @returns Object containing the logEvent function
13
+ *
14
+ * @example
15
+ * ```tsx
16
+ * function PurchaseButton() {
17
+ * const { logEvent } = useWolvesEvent();
18
+ *
19
+ * const handlePurchase = () => {
20
+ * logEvent('purchase_completed', 99.99, {
21
+ * product_id: 'abc123',
22
+ * category: 'electronics'
23
+ * });
24
+ * };
25
+ *
26
+ * return <button onClick={handlePurchase}>Buy Now</button>;
27
+ * }
28
+ * ```
29
+ */
30
+ function useWolvesEvent() {
31
+ const { client, isInitialized } = (0, useWolvesClient_1.useWolvesClient)();
32
+ /**
33
+ * Log a custom event with optional value and metadata.
34
+ *
35
+ * @param eventName - Name of the event (e.g., 'purchase', 'click', 'signup')
36
+ * @param value - Optional numeric or string value associated with the event
37
+ * @param metadata - Optional key-value metadata for additional context
38
+ */
39
+ const logEvent = (0, react_1.useCallback)((eventName, value, metadata) => {
40
+ if (!client || !isInitialized) {
41
+ if (process.env.NODE_ENV === 'development') {
42
+ console.warn(`[Wolves] Cannot log event "${eventName}": Client is not initialized yet.`);
43
+ }
44
+ return;
45
+ }
46
+ try {
47
+ client.logEvent(eventName, value, metadata);
48
+ }
49
+ catch (error) {
50
+ if (process.env.NODE_ENV === 'development') {
51
+ console.error(`[Wolves] Failed to log event "${eventName}":`, error);
52
+ }
53
+ }
54
+ }, [client, isInitialized]);
55
+ return { logEvent };
56
+ }
@@ -0,0 +1,43 @@
1
+ import { LoadingStatus, WolvesUpdateDetails } from 'wolves-js-client';
2
+ /**
3
+ * Return type for useWolvesInitialization hook
4
+ */
5
+ export interface UseWolvesInitializationReturn {
6
+ /** Whether the client is currently loading/initializing */
7
+ isLoading: boolean;
8
+ /** Whether the client is ready for use */
9
+ isReady: boolean;
10
+ /** The current loading status */
11
+ loadingStatus: LoadingStatus;
12
+ /** Any error that occurred during initialization */
13
+ error: Error | null;
14
+ /** Details from the initialization process */
15
+ details: WolvesUpdateDetails | null;
16
+ }
17
+ /**
18
+ * Hook to monitor the initialization status of the Wolves client.
19
+ *
20
+ * This hook provides detailed information about the client's initialization
21
+ * state, which is useful for displaying loading screens or handling errors.
22
+ *
23
+ * @returns Object containing initialization status information
24
+ *
25
+ * @example
26
+ * ```tsx
27
+ * function InitializationStatus() {
28
+ * const { isLoading, isReady, loadingStatus, error } = useWolvesInitialization();
29
+ *
30
+ * if (error) {
31
+ * return <div>Error: {error.message}</div>;
32
+ * }
33
+ *
34
+ * if (isLoading) {
35
+ * return <div>Loading experiments... ({loadingStatus})</div>;
36
+ * }
37
+ *
38
+ * return <div>Ready! Experiments loaded.</div>;
39
+ * }
40
+ * ```
41
+ */
42
+ export declare function useWolvesInitialization(): UseWolvesInitializationReturn;
43
+ //# sourceMappingURL=useWolvesInitialization.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useWolvesInitialization.d.ts","sourceRoot":"","sources":["../../src/hooks/useWolvesInitialization.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,aAAa,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAEtE;;GAEG;AACH,MAAM,WAAW,6BAA6B;IAC5C,2DAA2D;IAC3D,SAAS,EAAE,OAAO,CAAC;IACnB,0CAA0C;IAC1C,OAAO,EAAE,OAAO,CAAC;IACjB,iCAAiC;IACjC,aAAa,EAAE,aAAa,CAAC;IAC7B,oDAAoD;IACpD,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACpB,8CAA8C;IAC9C,OAAO,EAAE,mBAAmB,GAAG,IAAI,CAAC;CACrC;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,uBAAuB,IAAI,6BAA6B,CA8BvE"}
@@ -0,0 +1,59 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.useWolvesInitialization = useWolvesInitialization;
4
+ const react_1 = require("react");
5
+ const useWolvesClient_1 = require("./useWolvesClient");
6
+ /**
7
+ * Hook to monitor the initialization status of the Wolves client.
8
+ *
9
+ * This hook provides detailed information about the client's initialization
10
+ * state, which is useful for displaying loading screens or handling errors.
11
+ *
12
+ * @returns Object containing initialization status information
13
+ *
14
+ * @example
15
+ * ```tsx
16
+ * function InitializationStatus() {
17
+ * const { isLoading, isReady, loadingStatus, error } = useWolvesInitialization();
18
+ *
19
+ * if (error) {
20
+ * return <div>Error: {error.message}</div>;
21
+ * }
22
+ *
23
+ * if (isLoading) {
24
+ * return <div>Loading experiments... ({loadingStatus})</div>;
25
+ * }
26
+ *
27
+ * return <div>Ready! Experiments loaded.</div>;
28
+ * }
29
+ * ```
30
+ */
31
+ function useWolvesInitialization() {
32
+ const { client, isInitialized, isLoading, initializationDetails, error } = (0, useWolvesClient_1.useWolvesClient)();
33
+ // Determine the loading status from the client
34
+ const loadingStatus = (0, react_1.useMemo)(() => {
35
+ if (!client) {
36
+ return 'Uninitialized';
37
+ }
38
+ try {
39
+ return client.getLoadingStatus();
40
+ }
41
+ catch (_a) {
42
+ // Fallback if method doesn't exist or errors
43
+ if (isInitialized) {
44
+ return 'Ready';
45
+ }
46
+ if (isLoading) {
47
+ return 'Loading';
48
+ }
49
+ return 'Uninitialized';
50
+ }
51
+ }, [client, isInitialized, isLoading]);
52
+ return {
53
+ isLoading,
54
+ isReady: isInitialized && !isLoading,
55
+ loadingStatus,
56
+ error,
57
+ details: initializationDetails,
58
+ };
59
+ }
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Main entry point for the Wolves React SDK
3
+ */
4
+ export { WolvesProvider } from './WolvesProvider';
5
+ export { WolvesContext } from './WolvesContext';
6
+ export type { WolvesContextValue } from './WolvesContext';
7
+ export { useWolvesClient } from './hooks/useWolvesClient';
8
+ export { useExperiment } from './hooks/useExperiment';
9
+ export { useWolvesEvent } from './hooks/useWolvesEvent';
10
+ export { useWolvesInitialization } from './hooks/useWolvesInitialization';
11
+ export type { UseWolvesInitializationReturn } from './hooks/useWolvesInitialization';
12
+ export type { WolvesUser, WolvesUpdateDetails, LoadingStatus, AsyncUpdateOptions, SyncUpdateOptions, } from 'wolves-js-client';
13
+ export type { WolvesProviderProps, WolvesProviderOptions, UseExperimentOptions, UseExperimentReturn, UseWolvesEventReturn, InitMode, } from './types';
14
+ export { isBrowser, isServer } from './utils/ssrHelpers';
15
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAGlD,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,YAAY,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAG1D,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,EAAE,uBAAuB,EAAE,MAAM,iCAAiC,CAAC;AAC1E,YAAY,EAAE,6BAA6B,EAAE,MAAM,iCAAiC,CAAC;AAGrF,YAAY,EACV,UAAU,EACV,mBAAmB,EACnB,aAAa,EACb,kBAAkB,EAClB,iBAAiB,GAClB,MAAM,kBAAkB,CAAC;AAG1B,YAAY,EACV,mBAAmB,EACnB,qBAAqB,EACrB,oBAAoB,EACpB,mBAAmB,EACnB,oBAAoB,EACpB,QAAQ,GACT,MAAM,SAAS,CAAC;AAGjB,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+ /**
3
+ * Main entry point for the Wolves React SDK
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.isServer = exports.isBrowser = exports.useWolvesInitialization = exports.useWolvesEvent = exports.useExperiment = exports.useWolvesClient = exports.WolvesContext = exports.WolvesProvider = void 0;
7
+ // Provider component
8
+ var WolvesProvider_1 = require("./WolvesProvider");
9
+ Object.defineProperty(exports, "WolvesProvider", { enumerable: true, get: function () { return WolvesProvider_1.WolvesProvider; } });
10
+ // Context (for advanced use cases)
11
+ var WolvesContext_1 = require("./WolvesContext");
12
+ Object.defineProperty(exports, "WolvesContext", { enumerable: true, get: function () { return WolvesContext_1.WolvesContext; } });
13
+ // Hooks
14
+ var useWolvesClient_1 = require("./hooks/useWolvesClient");
15
+ Object.defineProperty(exports, "useWolvesClient", { enumerable: true, get: function () { return useWolvesClient_1.useWolvesClient; } });
16
+ var useExperiment_1 = require("./hooks/useExperiment");
17
+ Object.defineProperty(exports, "useExperiment", { enumerable: true, get: function () { return useExperiment_1.useExperiment; } });
18
+ var useWolvesEvent_1 = require("./hooks/useWolvesEvent");
19
+ Object.defineProperty(exports, "useWolvesEvent", { enumerable: true, get: function () { return useWolvesEvent_1.useWolvesEvent; } });
20
+ var useWolvesInitialization_1 = require("./hooks/useWolvesInitialization");
21
+ Object.defineProperty(exports, "useWolvesInitialization", { enumerable: true, get: function () { return useWolvesInitialization_1.useWolvesInitialization; } });
22
+ // SSR utilities
23
+ var ssrHelpers_1 = require("./utils/ssrHelpers");
24
+ Object.defineProperty(exports, "isBrowser", { enumerable: true, get: function () { return ssrHelpers_1.isBrowser; } });
25
+ Object.defineProperty(exports, "isServer", { enumerable: true, get: function () { return ssrHelpers_1.isServer; } });
@@ -0,0 +1,75 @@
1
+ /**
2
+ * Type definitions for Wolves React SDK
3
+ */
4
+ import { WolvesUser, WolvesUpdateDetails, AsyncUpdateOptions, SyncUpdateOptions } from 'wolves-js-client';
5
+ import React from 'react';
6
+ /**
7
+ * Initialization mode for the Wolves client
8
+ */
9
+ export type InitMode = 'async' | 'sync';
10
+ /**
11
+ * Options for configuring WolvesProvider behavior
12
+ */
13
+ export interface WolvesProviderOptions {
14
+ /** Initialization mode: 'async' (default) or 'sync' */
15
+ initMode?: InitMode;
16
+ /** API environment: 'local', 'dev', or 'prod' (default) */
17
+ apiEnv?: 'local' | 'dev' | 'prod';
18
+ /** Options for async initialization */
19
+ asyncOptions?: AsyncUpdateOptions;
20
+ /** Options for sync initialization */
21
+ syncOptions?: SyncUpdateOptions;
22
+ /** Callback invoked when initialization completes */
23
+ onInitialized?: (details: WolvesUpdateDetails) => void;
24
+ /** Callback invoked when an error occurs */
25
+ onError?: (error: Error) => void;
26
+ }
27
+ /**
28
+ * Props for the WolvesProvider component
29
+ */
30
+ export interface WolvesProviderProps {
31
+ /** SDK key for authenticating with Wolves API */
32
+ sdkKey: string;
33
+ /** User object containing user identification and attributes */
34
+ user: WolvesUser;
35
+ /** Child components that will have access to Wolves context */
36
+ children: React.ReactNode;
37
+ /** Optional configuration options */
38
+ options?: WolvesProviderOptions;
39
+ /** Whether to wait for initialization before rendering children */
40
+ waitForInitialization?: boolean;
41
+ /** Component to display while waiting for initialization */
42
+ loadingComponent?: React.ReactNode;
43
+ }
44
+ /**
45
+ * Options for the useExperiment hook
46
+ */
47
+ export interface UseExperimentOptions<T = Record<string, any>> {
48
+ /** Whether to skip logging exposure events */
49
+ skipExposure?: boolean;
50
+ /** Default value to return if experiment is not found */
51
+ defaultValue?: T;
52
+ }
53
+ /**
54
+ * Return type for the useExperiment hook
55
+ */
56
+ export interface UseExperimentReturn<T = Record<string, any>> {
57
+ /** The experiment configuration value */
58
+ value: T;
59
+ /** The group/variant name assigned to the user */
60
+ groupName: string | null;
61
+ /** The experiment ID */
62
+ experimentID: string;
63
+ /** Get a specific parameter from the experiment with a default fallback */
64
+ get: <K extends keyof T>(key: K, defaultValue: T[K]) => T[K];
65
+ /** Whether the client is still loading */
66
+ isLoading: boolean;
67
+ }
68
+ /**
69
+ * Return type for the useWolvesEvent hook
70
+ */
71
+ export interface UseWolvesEventReturn {
72
+ /** Function to log a custom event */
73
+ logEvent: (eventName: string, value?: string | number, metadata?: Record<string, string>) => void;
74
+ }
75
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,UAAU,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAC1G,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B;;GAEG;AACH,MAAM,MAAM,QAAQ,GAAG,OAAO,GAAG,MAAM,CAAC;AAExC;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,uDAAuD;IACvD,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,2DAA2D;IAC3D,MAAM,CAAC,EAAE,OAAO,GAAG,KAAK,GAAG,MAAM,CAAC;IAClC,uCAAuC;IACvC,YAAY,CAAC,EAAE,kBAAkB,CAAC;IAClC,sCAAsC;IACtC,WAAW,CAAC,EAAE,iBAAiB,CAAC;IAChC,qDAAqD;IACrD,aAAa,CAAC,EAAE,CAAC,OAAO,EAAE,mBAAmB,KAAK,IAAI,CAAC;IACvD,4CAA4C;IAC5C,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;CAClC;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,iDAAiD;IACjD,MAAM,EAAE,MAAM,CAAC;IACf,gEAAgE;IAChE,IAAI,EAAE,UAAU,CAAC;IACjB,+DAA+D;IAC/D,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,qCAAqC;IACrC,OAAO,CAAC,EAAE,qBAAqB,CAAC;IAChC,mEAAmE;IACnE,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,4DAA4D;IAC5D,gBAAgB,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CACpC;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC;IAC3D,8CAA8C;IAC9C,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,yDAAyD;IACzD,YAAY,CAAC,EAAE,CAAC,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC;IAC1D,yCAAyC;IACzC,KAAK,EAAE,CAAC,CAAC;IACT,kDAAkD;IAClD,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,wBAAwB;IACxB,YAAY,EAAE,MAAM,CAAC;IACrB,2EAA2E;IAC3E,GAAG,EAAE,CAAC,CAAC,SAAS,MAAM,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,YAAY,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAC7D,0CAA0C;IAC1C,SAAS,EAAE,OAAO,CAAC;CACpB;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,qCAAqC;IACrC,QAAQ,EAAE,CACR,SAAS,EAAE,MAAM,EACjB,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,EACvB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KAC9B,IAAI,CAAC;CACX"}
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ /**
3
+ * Type definitions for Wolves React SDK
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Server-Side Rendering (SSR) helper utilities
3
+ */
4
+ /**
5
+ * Checks if the code is running in a browser environment.
6
+ * Returns false on the server (Node.js).
7
+ */
8
+ export declare function isBrowser(): boolean;
9
+ /**
10
+ * Checks if the code is running in a server environment.
11
+ * Returns true on the server (Node.js).
12
+ */
13
+ export declare function isServer(): boolean;
14
+ //# sourceMappingURL=ssrHelpers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ssrHelpers.d.ts","sourceRoot":"","sources":["../../src/utils/ssrHelpers.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;;GAGG;AACH,wBAAgB,SAAS,IAAI,OAAO,CAEnC;AAED;;;GAGG;AACH,wBAAgB,QAAQ,IAAI,OAAO,CAElC"}
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ /**
3
+ * Server-Side Rendering (SSR) helper utilities
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.isBrowser = isBrowser;
7
+ exports.isServer = isServer;
8
+ /**
9
+ * Checks if the code is running in a browser environment.
10
+ * Returns false on the server (Node.js).
11
+ */
12
+ function isBrowser() {
13
+ return typeof window !== 'undefined' && typeof window.document !== 'undefined';
14
+ }
15
+ /**
16
+ * Checks if the code is running in a server environment.
17
+ * Returns true on the server (Node.js).
18
+ */
19
+ function isServer() {
20
+ return !isBrowser();
21
+ }
package/package.json ADDED
@@ -0,0 +1,50 @@
1
+ {
2
+ "name": "wolves-react-client",
3
+ "version": "1.0.0",
4
+ "description": "React SDK for Wolves A/B Testing Platform",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "files": [
8
+ "dist"
9
+ ],
10
+ "keywords": [
11
+ "wolves",
12
+ "ab-testing",
13
+ "experiment",
14
+ "sdk",
15
+ "react",
16
+ "hooks"
17
+ ],
18
+ "scripts": {
19
+ "build": "tsc",
20
+ "test": "jest",
21
+ "lint": "eslint src --ext .ts,.tsx",
22
+ "format": "prettier --write \"src/**/*.{ts,tsx}\"",
23
+ "prepublishOnly": "npm run build"
24
+ },
25
+ "peerDependencies": {
26
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0",
27
+ "wolves-js-client": "^1.0.6"
28
+ },
29
+ "devDependencies": {
30
+ "@testing-library/jest-dom": "^6.1.5",
31
+ "@testing-library/react": "^14.0.0",
32
+ "@types/jest": "^29.0.0",
33
+ "@types/react": "^18.0.0",
34
+ "@typescript-eslint/eslint-plugin": "^6.0.0",
35
+ "@typescript-eslint/parser": "^6.0.0",
36
+ "eslint": "^8.0.0",
37
+ "eslint-plugin-react": "^7.33.0",
38
+ "eslint-plugin-react-hooks": "^4.6.0",
39
+ "jest": "^29.0.0",
40
+ "jest-environment-jsdom": "^29.0.0",
41
+ "prettier": "^3.0.0",
42
+ "react": "^18.2.0",
43
+ "react-dom": "^18.2.0",
44
+ "ts-jest": "^29.0.0",
45
+ "typescript": "^5.0.0",
46
+ "wolves-js-client": "^1.0.6"
47
+ },
48
+ "author": "",
49
+ "license": "ISC"
50
+ }