@experiwall/react 0.2.0 โ 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 +161 -3
- package/dist/index.js +23 -7
- package/dist/index.mjs +23 -7
- package/dist/server.d.mts +44 -0
- package/dist/server.d.ts +44 -0
- package/dist/server.js +45 -0
- package/dist/server.mjs +20 -0
- package/package.json +15 -3
package/README.md
CHANGED
|
@@ -6,10 +6,9 @@
|
|
|
6
6
|
alt="Experiwall React SDK"
|
|
7
7
|
title="Experiwall React SDK"
|
|
8
8
|
/>
|
|
9
|
-
<h1 align="center"
|
|
9
|
+
<h1 align="center">Experiwall React SDK</h1>
|
|
10
10
|
</p>
|
|
11
11
|
|
|
12
|
-
|
|
13
12
|
<p align="center">
|
|
14
13
|
<img
|
|
15
14
|
src=".github/preview.png"
|
|
@@ -20,5 +19,164 @@
|
|
|
20
19
|
</p>
|
|
21
20
|
|
|
22
21
|
<p align="center">
|
|
23
|
-
|
|
22
|
+
Code-first A/B testing for React. Define experiments inline, track conversions, and let the dashboard show you what wins.
|
|
24
23
|
</p>
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## Install
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
npm install @experiwall/react
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Quick start
|
|
34
|
+
|
|
35
|
+
### 1. Wrap your app with the provider
|
|
36
|
+
|
|
37
|
+
```tsx
|
|
38
|
+
import { ExperiwallProvider } from "@experiwall/react";
|
|
39
|
+
|
|
40
|
+
export default function App() {
|
|
41
|
+
return (
|
|
42
|
+
<ExperiwallProvider
|
|
43
|
+
apiKey="your-api-key"
|
|
44
|
+
userId={currentUser.id}
|
|
45
|
+
environment={process.env.NODE_ENV === "production" ? "production" : "development"}
|
|
46
|
+
>
|
|
47
|
+
<YourApp />
|
|
48
|
+
</ExperiwallProvider>
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### 2. Run an experiment
|
|
54
|
+
|
|
55
|
+
```tsx
|
|
56
|
+
import { useExperiment } from "@experiwall/react";
|
|
57
|
+
|
|
58
|
+
function CheckoutButton() {
|
|
59
|
+
const variant = useExperiment("checkout-flow", ["control", "new-checkout"]);
|
|
60
|
+
|
|
61
|
+
if (variant === null) return null; // loading
|
|
62
|
+
|
|
63
|
+
if (variant === "new-checkout") {
|
|
64
|
+
return <NewCheckoutButton />;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return <OriginalCheckoutButton />;
|
|
68
|
+
}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
That's it. The hook automatically:
|
|
72
|
+
- Assigns the user to a variant (deterministic, based on their seed)
|
|
73
|
+
- Tracks an `$exposure` event once per mount
|
|
74
|
+
- Registers the assignment with the server
|
|
75
|
+
|
|
76
|
+
### 3. Track conversions
|
|
77
|
+
|
|
78
|
+
```tsx
|
|
79
|
+
import { useTrack } from "@experiwall/react";
|
|
80
|
+
|
|
81
|
+
function PurchaseConfirmation({ amount }: { amount: number }) {
|
|
82
|
+
const track = useTrack();
|
|
83
|
+
|
|
84
|
+
useEffect(() => {
|
|
85
|
+
track("purchase", { revenue: amount });
|
|
86
|
+
}, []);
|
|
87
|
+
|
|
88
|
+
return <p>Thanks for your order!</p>;
|
|
89
|
+
}
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Events are batched (flushed every 30s) and automatically flushed when the user leaves the page.
|
|
93
|
+
|
|
94
|
+
## API
|
|
95
|
+
|
|
96
|
+
### `<ExperiwallProvider>`
|
|
97
|
+
|
|
98
|
+
| Prop | Type | Required | Description |
|
|
99
|
+
|---|---|---|---|
|
|
100
|
+
| `apiKey` | `string` | Yes | Your project API key |
|
|
101
|
+
| `userId` | `string` | No | Stable user identifier for consistent bucketing |
|
|
102
|
+
| `aliasId` | `string` | No | Alternative identifier (e.g. anonymous ID) |
|
|
103
|
+
| `environment` | `string` | No | `"production"` (default) or `"development"` โ segments traffic in the dashboard |
|
|
104
|
+
| `overrides` | `Record<string, string>` | No | Force specific variants for QA (skips tracking) |
|
|
105
|
+
| `baseUrl` | `string` | No | Custom API URL (defaults to `https://experiwall.com`) |
|
|
106
|
+
|
|
107
|
+
### `useExperiment(flagKey, variants, options?)`
|
|
108
|
+
|
|
109
|
+
Returns the assigned variant (`string`) or `null` while loading.
|
|
110
|
+
|
|
111
|
+
```tsx
|
|
112
|
+
const variant = useExperiment("hero-banner", ["control", "large-cta", "video"]);
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
**Options:**
|
|
116
|
+
|
|
117
|
+
| Option | Type | Description |
|
|
118
|
+
|---|---|---|
|
|
119
|
+
| `force` | `string` | Override the variant for this hook only (skips tracking) |
|
|
120
|
+
|
|
121
|
+
### `useTrack()`
|
|
122
|
+
|
|
123
|
+
Returns a `track(eventName, properties?)` function.
|
|
124
|
+
|
|
125
|
+
```tsx
|
|
126
|
+
const track = useTrack();
|
|
127
|
+
track("signup", { plan: "pro" });
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### `useExperiwall()`
|
|
131
|
+
|
|
132
|
+
Low-level access to the full SDK context.
|
|
133
|
+
|
|
134
|
+
| Field | Type | Description |
|
|
135
|
+
|---|---|---|
|
|
136
|
+
| `userSeed` | `number \| null` | Server-provided seed for deterministic bucketing. `null` while loading. |
|
|
137
|
+
| `assignments` | `Record<string, string>` | Map of flag key to assigned variant key |
|
|
138
|
+
| `experiments` | `Record<string, { variants: { key: string; weight: number }[] }> \| undefined` | Server-provided experiment definitions with variant weights |
|
|
139
|
+
| `overrides` | `Record<string, string>` | Provider-level forced variants |
|
|
140
|
+
| `isLoading` | `boolean` | `true` during the initial `/init` fetch |
|
|
141
|
+
| `error` | `Error \| null` | Error object if the `/init` fetch failed |
|
|
142
|
+
| `trackEvent` | `(event: ExperiwallEvent) => void` | Queue a raw event for batching |
|
|
143
|
+
| `registerLocalFlag` | `(flagKey, variants, assignedVariant) => void` | Register a client-side flag assignment with the server |
|
|
144
|
+
|
|
145
|
+
## QA and testing
|
|
146
|
+
|
|
147
|
+
Use `overrides` to force variants without contaminating experiment data:
|
|
148
|
+
|
|
149
|
+
```tsx
|
|
150
|
+
<ExperiwallProvider
|
|
151
|
+
apiKey="your-api-key"
|
|
152
|
+
userId={currentUser.id}
|
|
153
|
+
overrides={{ "checkout-flow": "new-checkout" }}
|
|
154
|
+
>
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
Or per-hook:
|
|
158
|
+
|
|
159
|
+
```tsx
|
|
160
|
+
const variant = useExperiment("checkout-flow", ["control", "new-checkout"], {
|
|
161
|
+
force: "new-checkout", etc.
|
|
162
|
+
});
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
Both skip exposure tracking and server registration entirely.
|
|
166
|
+
|
|
167
|
+
## Environment separation
|
|
168
|
+
|
|
169
|
+
Pass `environment` to keep development traffic out of your production results:
|
|
170
|
+
|
|
171
|
+
```tsx
|
|
172
|
+
<ExperiwallProvider
|
|
173
|
+
apiKey="your-api-key"
|
|
174
|
+
environment={process.env.NODE_ENV === "production" ? "production" : "development"}
|
|
175
|
+
>
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
The dashboard lets you toggle between Production and Development to view metrics separately.
|
|
179
|
+
|
|
180
|
+
## License
|
|
181
|
+
|
|
182
|
+
MIT
|
package/dist/index.js
CHANGED
|
@@ -31,7 +31,7 @@ module.exports = __toCommonJS(index_exports);
|
|
|
31
31
|
var import_react = require("react");
|
|
32
32
|
|
|
33
33
|
// src/lib/api-client.ts
|
|
34
|
-
var DEFAULT_BASE_URL = "https://experiwall.com";
|
|
34
|
+
var DEFAULT_BASE_URL = "https://www.experiwall.com";
|
|
35
35
|
async function fetchInit(apiKey, options) {
|
|
36
36
|
const base = options?.baseUrl ?? DEFAULT_BASE_URL;
|
|
37
37
|
const url = new URL("/api/sdk/init", base);
|
|
@@ -191,6 +191,18 @@ function setCache(key, data) {
|
|
|
191
191
|
|
|
192
192
|
// src/provider.tsx
|
|
193
193
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
194
|
+
var ANON_ID_KEY = "experiwall_anon_id";
|
|
195
|
+
function getOrCreateAnonId() {
|
|
196
|
+
try {
|
|
197
|
+
const existing = localStorage.getItem(ANON_ID_KEY);
|
|
198
|
+
if (existing) return existing;
|
|
199
|
+
const id = crypto.randomUUID();
|
|
200
|
+
localStorage.setItem(ANON_ID_KEY, id);
|
|
201
|
+
return id;
|
|
202
|
+
} catch {
|
|
203
|
+
return crypto.randomUUID();
|
|
204
|
+
}
|
|
205
|
+
}
|
|
194
206
|
function getCacheKey(userId, aliasId, environment) {
|
|
195
207
|
const identity = userId || aliasId || "anon";
|
|
196
208
|
const env = environment || "production";
|
|
@@ -203,6 +215,10 @@ function ExperiwallProvider({
|
|
|
203
215
|
children,
|
|
204
216
|
...config
|
|
205
217
|
}) {
|
|
218
|
+
const [anonId] = (0, import_react.useState)(
|
|
219
|
+
() => !config.userId && !config.aliasId ? getOrCreateAnonId() : void 0
|
|
220
|
+
);
|
|
221
|
+
const effectiveAliasId = config.aliasId ?? anonId;
|
|
206
222
|
const [userSeed, setUserSeed] = (0, import_react.useState)(null);
|
|
207
223
|
const [assignments, setAssignments] = (0, import_react.useState)({});
|
|
208
224
|
const [experiments, setExperiments] = (0, import_react.useState)();
|
|
@@ -214,7 +230,7 @@ function ExperiwallProvider({
|
|
|
214
230
|
const load = async () => {
|
|
215
231
|
setIsLoading(true);
|
|
216
232
|
setError(null);
|
|
217
|
-
const cacheKey = getCacheKey(config.userId,
|
|
233
|
+
const cacheKey = getCacheKey(config.userId, effectiveAliasId, config.environment);
|
|
218
234
|
const cached = getCached(cacheKey);
|
|
219
235
|
if (cached) {
|
|
220
236
|
setUserSeed(cached.user_seed);
|
|
@@ -228,7 +244,7 @@ function ExperiwallProvider({
|
|
|
228
244
|
const data = await fetchInit(config.apiKey, {
|
|
229
245
|
baseUrl: config.baseUrl,
|
|
230
246
|
userId: config.userId,
|
|
231
|
-
aliasId:
|
|
247
|
+
aliasId: effectiveAliasId,
|
|
232
248
|
environment
|
|
233
249
|
});
|
|
234
250
|
if (!cancelled) {
|
|
@@ -254,7 +270,7 @@ function ExperiwallProvider({
|
|
|
254
270
|
apiKey: config.apiKey,
|
|
255
271
|
baseUrl: config.baseUrl,
|
|
256
272
|
userId: config.userId,
|
|
257
|
-
aliasId:
|
|
273
|
+
aliasId: effectiveAliasId,
|
|
258
274
|
environment: config.environment ?? "production"
|
|
259
275
|
});
|
|
260
276
|
batcher.start();
|
|
@@ -273,7 +289,7 @@ function ExperiwallProvider({
|
|
|
273
289
|
window.removeEventListener("beforeunload", handleBeforeUnload);
|
|
274
290
|
batcher.stop();
|
|
275
291
|
};
|
|
276
|
-
}, [config.apiKey, config.userId,
|
|
292
|
+
}, [config.apiKey, config.userId, effectiveAliasId, config.environment]);
|
|
277
293
|
const trackEvent = (0, import_react.useCallback)((event) => {
|
|
278
294
|
batcherRef.current?.push(event);
|
|
279
295
|
}, []);
|
|
@@ -287,13 +303,13 @@ function ExperiwallProvider({
|
|
|
287
303
|
variants,
|
|
288
304
|
assigned_variant: assignedVariant,
|
|
289
305
|
user_id: config.userId,
|
|
290
|
-
alias_id:
|
|
306
|
+
alias_id: effectiveAliasId
|
|
291
307
|
},
|
|
292
308
|
{ baseUrl: config.baseUrl, environment: config.environment ?? "production" }
|
|
293
309
|
).catch(() => {
|
|
294
310
|
});
|
|
295
311
|
},
|
|
296
|
-
[config.apiKey, config.baseUrl, config.userId,
|
|
312
|
+
[config.apiKey, config.baseUrl, config.userId, effectiveAliasId, config.environment]
|
|
297
313
|
);
|
|
298
314
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
299
315
|
ExperiwallContext.Provider,
|
package/dist/index.mjs
CHANGED
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
} from "react";
|
|
9
9
|
|
|
10
10
|
// src/lib/api-client.ts
|
|
11
|
-
var DEFAULT_BASE_URL = "https://experiwall.com";
|
|
11
|
+
var DEFAULT_BASE_URL = "https://www.experiwall.com";
|
|
12
12
|
async function fetchInit(apiKey, options) {
|
|
13
13
|
const base = options?.baseUrl ?? DEFAULT_BASE_URL;
|
|
14
14
|
const url = new URL("/api/sdk/init", base);
|
|
@@ -168,6 +168,18 @@ function setCache(key, data) {
|
|
|
168
168
|
|
|
169
169
|
// src/provider.tsx
|
|
170
170
|
import { jsx } from "react/jsx-runtime";
|
|
171
|
+
var ANON_ID_KEY = "experiwall_anon_id";
|
|
172
|
+
function getOrCreateAnonId() {
|
|
173
|
+
try {
|
|
174
|
+
const existing = localStorage.getItem(ANON_ID_KEY);
|
|
175
|
+
if (existing) return existing;
|
|
176
|
+
const id = crypto.randomUUID();
|
|
177
|
+
localStorage.setItem(ANON_ID_KEY, id);
|
|
178
|
+
return id;
|
|
179
|
+
} catch {
|
|
180
|
+
return crypto.randomUUID();
|
|
181
|
+
}
|
|
182
|
+
}
|
|
171
183
|
function getCacheKey(userId, aliasId, environment) {
|
|
172
184
|
const identity = userId || aliasId || "anon";
|
|
173
185
|
const env = environment || "production";
|
|
@@ -180,6 +192,10 @@ function ExperiwallProvider({
|
|
|
180
192
|
children,
|
|
181
193
|
...config
|
|
182
194
|
}) {
|
|
195
|
+
const [anonId] = useState(
|
|
196
|
+
() => !config.userId && !config.aliasId ? getOrCreateAnonId() : void 0
|
|
197
|
+
);
|
|
198
|
+
const effectiveAliasId = config.aliasId ?? anonId;
|
|
183
199
|
const [userSeed, setUserSeed] = useState(null);
|
|
184
200
|
const [assignments, setAssignments] = useState({});
|
|
185
201
|
const [experiments, setExperiments] = useState();
|
|
@@ -191,7 +207,7 @@ function ExperiwallProvider({
|
|
|
191
207
|
const load = async () => {
|
|
192
208
|
setIsLoading(true);
|
|
193
209
|
setError(null);
|
|
194
|
-
const cacheKey = getCacheKey(config.userId,
|
|
210
|
+
const cacheKey = getCacheKey(config.userId, effectiveAliasId, config.environment);
|
|
195
211
|
const cached = getCached(cacheKey);
|
|
196
212
|
if (cached) {
|
|
197
213
|
setUserSeed(cached.user_seed);
|
|
@@ -205,7 +221,7 @@ function ExperiwallProvider({
|
|
|
205
221
|
const data = await fetchInit(config.apiKey, {
|
|
206
222
|
baseUrl: config.baseUrl,
|
|
207
223
|
userId: config.userId,
|
|
208
|
-
aliasId:
|
|
224
|
+
aliasId: effectiveAliasId,
|
|
209
225
|
environment
|
|
210
226
|
});
|
|
211
227
|
if (!cancelled) {
|
|
@@ -231,7 +247,7 @@ function ExperiwallProvider({
|
|
|
231
247
|
apiKey: config.apiKey,
|
|
232
248
|
baseUrl: config.baseUrl,
|
|
233
249
|
userId: config.userId,
|
|
234
|
-
aliasId:
|
|
250
|
+
aliasId: effectiveAliasId,
|
|
235
251
|
environment: config.environment ?? "production"
|
|
236
252
|
});
|
|
237
253
|
batcher.start();
|
|
@@ -250,7 +266,7 @@ function ExperiwallProvider({
|
|
|
250
266
|
window.removeEventListener("beforeunload", handleBeforeUnload);
|
|
251
267
|
batcher.stop();
|
|
252
268
|
};
|
|
253
|
-
}, [config.apiKey, config.userId,
|
|
269
|
+
}, [config.apiKey, config.userId, effectiveAliasId, config.environment]);
|
|
254
270
|
const trackEvent = useCallback((event) => {
|
|
255
271
|
batcherRef.current?.push(event);
|
|
256
272
|
}, []);
|
|
@@ -264,13 +280,13 @@ function ExperiwallProvider({
|
|
|
264
280
|
variants,
|
|
265
281
|
assigned_variant: assignedVariant,
|
|
266
282
|
user_id: config.userId,
|
|
267
|
-
alias_id:
|
|
283
|
+
alias_id: effectiveAliasId
|
|
268
284
|
},
|
|
269
285
|
{ baseUrl: config.baseUrl, environment: config.environment ?? "production" }
|
|
270
286
|
).catch(() => {
|
|
271
287
|
});
|
|
272
288
|
},
|
|
273
|
-
[config.apiKey, config.baseUrl, config.userId,
|
|
289
|
+
[config.apiKey, config.baseUrl, config.userId, effectiveAliasId, config.environment]
|
|
274
290
|
);
|
|
275
291
|
return /* @__PURE__ */ jsx(
|
|
276
292
|
ExperiwallContext.Provider,
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Server-side helpers for Experiwall.
|
|
3
|
+
*
|
|
4
|
+
* Use this module in Next.js server components, Route Handlers,
|
|
5
|
+
* or any server runtime to resolve experiments during SSR โ
|
|
6
|
+
* the variant is in the initial HTML with zero loading state.
|
|
7
|
+
*
|
|
8
|
+
* ```ts
|
|
9
|
+
* import { fetchExperiments } from "@experiwall/react/server";
|
|
10
|
+
*
|
|
11
|
+
* // In a server component:
|
|
12
|
+
* const { assignments } = await fetchExperiments({
|
|
13
|
+
* apiKey: "ew_pub_...",
|
|
14
|
+
* aliasId: cookies().get("ew_anon_id")?.value,
|
|
15
|
+
* });
|
|
16
|
+
* const variant = assignments["my-experiment"] ?? "control";
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
interface ServerConfig {
|
|
20
|
+
apiKey: string;
|
|
21
|
+
baseUrl?: string;
|
|
22
|
+
userId?: string;
|
|
23
|
+
aliasId?: string;
|
|
24
|
+
environment?: string;
|
|
25
|
+
}
|
|
26
|
+
interface ExperimentsResponse {
|
|
27
|
+
user_seed: number;
|
|
28
|
+
assignments: Record<string, string>;
|
|
29
|
+
experiments?: Record<string, {
|
|
30
|
+
variants: {
|
|
31
|
+
key: string;
|
|
32
|
+
weight: number;
|
|
33
|
+
}[];
|
|
34
|
+
}>;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Fetch experiment assignments from the Experiwall API.
|
|
38
|
+
*
|
|
39
|
+
* Call this from server components to resolve variants at SSR time.
|
|
40
|
+
* Pass a `userId` or `aliasId` to identify the visitor (e.g. from a cookie).
|
|
41
|
+
*/
|
|
42
|
+
declare function fetchExperiments(config: ServerConfig): Promise<ExperimentsResponse>;
|
|
43
|
+
|
|
44
|
+
export { type ExperimentsResponse, type ServerConfig, fetchExperiments };
|
package/dist/server.d.ts
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Server-side helpers for Experiwall.
|
|
3
|
+
*
|
|
4
|
+
* Use this module in Next.js server components, Route Handlers,
|
|
5
|
+
* or any server runtime to resolve experiments during SSR โ
|
|
6
|
+
* the variant is in the initial HTML with zero loading state.
|
|
7
|
+
*
|
|
8
|
+
* ```ts
|
|
9
|
+
* import { fetchExperiments } from "@experiwall/react/server";
|
|
10
|
+
*
|
|
11
|
+
* // In a server component:
|
|
12
|
+
* const { assignments } = await fetchExperiments({
|
|
13
|
+
* apiKey: "ew_pub_...",
|
|
14
|
+
* aliasId: cookies().get("ew_anon_id")?.value,
|
|
15
|
+
* });
|
|
16
|
+
* const variant = assignments["my-experiment"] ?? "control";
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
interface ServerConfig {
|
|
20
|
+
apiKey: string;
|
|
21
|
+
baseUrl?: string;
|
|
22
|
+
userId?: string;
|
|
23
|
+
aliasId?: string;
|
|
24
|
+
environment?: string;
|
|
25
|
+
}
|
|
26
|
+
interface ExperimentsResponse {
|
|
27
|
+
user_seed: number;
|
|
28
|
+
assignments: Record<string, string>;
|
|
29
|
+
experiments?: Record<string, {
|
|
30
|
+
variants: {
|
|
31
|
+
key: string;
|
|
32
|
+
weight: number;
|
|
33
|
+
}[];
|
|
34
|
+
}>;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Fetch experiment assignments from the Experiwall API.
|
|
38
|
+
*
|
|
39
|
+
* Call this from server components to resolve variants at SSR time.
|
|
40
|
+
* Pass a `userId` or `aliasId` to identify the visitor (e.g. from a cookie).
|
|
41
|
+
*/
|
|
42
|
+
declare function fetchExperiments(config: ServerConfig): Promise<ExperimentsResponse>;
|
|
43
|
+
|
|
44
|
+
export { type ExperimentsResponse, type ServerConfig, fetchExperiments };
|
package/dist/server.js
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/server.ts
|
|
21
|
+
var server_exports = {};
|
|
22
|
+
__export(server_exports, {
|
|
23
|
+
fetchExperiments: () => fetchExperiments
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(server_exports);
|
|
26
|
+
var DEFAULT_BASE_URL = "https://www.experiwall.com";
|
|
27
|
+
async function fetchExperiments(config) {
|
|
28
|
+
const base = config.baseUrl ?? DEFAULT_BASE_URL;
|
|
29
|
+
const url = new URL("/api/sdk/init", base);
|
|
30
|
+
if (config.userId) url.searchParams.set("user_id", config.userId);
|
|
31
|
+
if (config.aliasId) url.searchParams.set("alias_id", config.aliasId);
|
|
32
|
+
if (config.environment) url.searchParams.set("environment", config.environment);
|
|
33
|
+
const res = await fetch(url.toString(), {
|
|
34
|
+
headers: { "x-api-key": config.apiKey },
|
|
35
|
+
cache: "no-store"
|
|
36
|
+
});
|
|
37
|
+
if (!res.ok) {
|
|
38
|
+
throw new Error(`Experiwall API error: ${res.status}`);
|
|
39
|
+
}
|
|
40
|
+
return res.json();
|
|
41
|
+
}
|
|
42
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
43
|
+
0 && (module.exports = {
|
|
44
|
+
fetchExperiments
|
|
45
|
+
});
|
package/dist/server.mjs
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
// src/server.ts
|
|
2
|
+
var DEFAULT_BASE_URL = "https://www.experiwall.com";
|
|
3
|
+
async function fetchExperiments(config) {
|
|
4
|
+
const base = config.baseUrl ?? DEFAULT_BASE_URL;
|
|
5
|
+
const url = new URL("/api/sdk/init", base);
|
|
6
|
+
if (config.userId) url.searchParams.set("user_id", config.userId);
|
|
7
|
+
if (config.aliasId) url.searchParams.set("alias_id", config.aliasId);
|
|
8
|
+
if (config.environment) url.searchParams.set("environment", config.environment);
|
|
9
|
+
const res = await fetch(url.toString(), {
|
|
10
|
+
headers: { "x-api-key": config.apiKey },
|
|
11
|
+
cache: "no-store"
|
|
12
|
+
});
|
|
13
|
+
if (!res.ok) {
|
|
14
|
+
throw new Error(`Experiwall API error: ${res.status}`);
|
|
15
|
+
}
|
|
16
|
+
return res.json();
|
|
17
|
+
}
|
|
18
|
+
export {
|
|
19
|
+
fetchExperiments
|
|
20
|
+
};
|
package/package.json
CHANGED
|
@@ -1,16 +1,28 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@experiwall/react",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Experiwall React SDK โ code-first experimentation and A/B testing",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|
|
7
7
|
"types": "dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.mjs",
|
|
12
|
+
"require": "./dist/index.js"
|
|
13
|
+
},
|
|
14
|
+
"./server": {
|
|
15
|
+
"types": "./dist/server.d.ts",
|
|
16
|
+
"import": "./dist/server.mjs",
|
|
17
|
+
"require": "./dist/server.js"
|
|
18
|
+
}
|
|
19
|
+
},
|
|
8
20
|
"files": [
|
|
9
21
|
"dist"
|
|
10
22
|
],
|
|
11
23
|
"scripts": {
|
|
12
|
-
"build": "tsup src/index.ts --format cjs,esm --dts --clean",
|
|
13
|
-
"dev": "tsup src/index.ts --format cjs,esm --dts --watch"
|
|
24
|
+
"build": "tsup src/index.ts src/server.ts --format cjs,esm --dts --clean",
|
|
25
|
+
"dev": "tsup src/index.ts src/server.ts --format cjs,esm --dts --watch"
|
|
14
26
|
},
|
|
15
27
|
"peerDependencies": {
|
|
16
28
|
"react": ">=18",
|