Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/web/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@vercel/analytics",
"version": "2.2.0-canary",
"version": "2.3.0-canary",
"description": "Gain real-time traffic insights with Vercel Web Analytics",
"keywords": [
"analytics",
Expand Down
27 changes: 25 additions & 2 deletions packages/web/src/server/browser.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
import { beforeEach, describe, expect, it, vi } from 'vitest';
import { track } from './index';
import { track, trackExposure } from './index';

const exposure = {
experimentId: 'checkout-redesign',
variantId: 'treatment',
unitKey: 'user' as const,
unitValue: 'user_123',
};

describe('server track in browser environment', () => {
global.fetch = vi.fn();
Expand All @@ -13,7 +20,7 @@ describe('server track in browser environment', () => {
(global as { window?: { vam?: string } }).window = { vam: 'development' };

await expect(track('test-event')).rejects.toThrow(
/imported the `track` function from `@vercel\/web-analytics\/server` in a browser environment/,
/imported the `track` function from `@vercel\/analytics\/server` in a browser environment/,
);
});

Expand All @@ -24,4 +31,20 @@ describe('server track in browser environment', () => {

expect(fetchMock).not.toHaveBeenCalled();
});

it('throws for trackExposure in development mode', async () => {
(global as { window?: { vam?: string } }).window = { vam: 'development' };

await expect(trackExposure(exposure)).rejects.toThrow(
/imported the `trackExposure` function from `@vercel\/analytics\/server` in a browser environment/,
);
});

it('returns early for trackExposure in production mode', async () => {
(global as { window?: object }).window = {};

await trackExposure(exposure);

expect(fetchMock).not.toHaveBeenCalled();
});
});
46 changes: 46 additions & 0 deletions packages/web/src/server/experiments-types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import type { AllowedPropertyValues } from '../types';

/**
* Which unit an exposure applies to.
*
* `user`, `device` and `group` point at the attribution that the SDK attaches
* to every event itself. Do not put these in the data of your `track()` calls.
*
* `event_data.${property}` points at a property in the data of your `track()`
* calls. So `event_data.user` is a `user` property that you send yourself,
* which is a different unit than `user`.
*/
export type ExposureUnitKey =
| 'user'
| 'device'
| 'group'
| `event_data.${string}`;

export type ExposureAssignmentReason =
| 'experiment'
| 'not-enrolled'
| 'targeted'
| 'split'
| 'variant'
| 'rollout'
| 'override';

export interface ExposureInput {
experimentId: string;
variantId: string;
unitKey: ExposureUnitKey;
unitValue: string;
assignmentReason?: ExposureAssignmentReason;
rampId?: string;
rampPercentage?: number;
}

/**
* The browser runtime reads `userId`, `groupId` and `props` from persisted
* attribution state, which does not exist on the server. Pass them explicitly.
*/
export interface ServerExposureInput extends ExposureInput {
userId?: string;
groupId?: string;
props?: Record<string, AllowedPropertyValues>;
}
Loading
Loading