@statsig/web-analytics 3.18.2 → 3.19.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/package.json +4 -3
- package/src/AutoCapture.d.ts +4 -0
- package/src/AutoCapture.js +36 -7
- package/src/AutoCaptureEvent.d.ts +1 -0
- package/src/AutoCaptureEvent.js +1 -0
- package/src/WebVitalsManager.d.ts +9 -0
- package/src/WebVitalsManager.js +55 -0
- package/src/{commonUtils.d.ts → utils/commonUtils.d.ts} +1 -0
- package/src/{commonUtils.js → utils/commonUtils.js} +9 -1
- package/src/{metadataUtils.d.ts → utils/metadataUtils.d.ts} +1 -0
- package/src/{metadataUtils.js → utils/metadataUtils.js} +17 -1
- /package/src/{eventUtils.d.ts → utils/eventUtils.d.ts} +0 -0
- /package/src/{eventUtils.js → utils/eventUtils.js} +0 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@statsig/web-analytics",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.19.0",
|
|
4
4
|
"license": "ISC",
|
|
5
5
|
"homepage": "https://github.com/statsig-io/js-client-monorepo",
|
|
6
6
|
"repository": {
|
|
@@ -9,8 +9,9 @@
|
|
|
9
9
|
"directory": "packages/web-analytics"
|
|
10
10
|
},
|
|
11
11
|
"dependencies": {
|
|
12
|
-
"@statsig/client-core": "3.
|
|
13
|
-
"@statsig/js-client": "3.
|
|
12
|
+
"@statsig/client-core": "3.19.0",
|
|
13
|
+
"@statsig/js-client": "3.19.0",
|
|
14
|
+
"web-vitals": "5.0.3"
|
|
14
15
|
},
|
|
15
16
|
"jsdelivr": "./build/statsig-web-analytics.min.js",
|
|
16
17
|
"type": "commonjs",
|
package/src/AutoCapture.d.ts
CHANGED
|
@@ -19,6 +19,8 @@ export declare class AutoCapture {
|
|
|
19
19
|
private _hasLoggedPageViewEnd;
|
|
20
20
|
private _engagementManager;
|
|
21
21
|
private _rageClickManager;
|
|
22
|
+
private _pageViewLogged;
|
|
23
|
+
private _webVitalsManager;
|
|
22
24
|
constructor(_client: PrecomputedEvaluationsInterface, options?: AutoCaptureOptions);
|
|
23
25
|
private _addEventHandlers;
|
|
24
26
|
private _addPageViewTracking;
|
|
@@ -31,6 +33,8 @@ export declare class AutoCapture {
|
|
|
31
33
|
private _logRageClick;
|
|
32
34
|
private _logPerformance;
|
|
33
35
|
private _enqueueAutoCapture;
|
|
36
|
+
private _updateClientWithPossibleFirstTouchMetadata;
|
|
37
|
+
private _flushImmediately;
|
|
34
38
|
private _isNewSession;
|
|
35
39
|
private _getSessionFromClient;
|
|
36
40
|
}
|
package/src/AutoCapture.js
CHANGED
|
@@ -5,9 +5,10 @@ const client_core_1 = require("@statsig/client-core");
|
|
|
5
5
|
const AutoCaptureEvent_1 = require("./AutoCaptureEvent");
|
|
6
6
|
const EngagementManager_1 = require("./EngagementManager");
|
|
7
7
|
const RageClickManager_1 = require("./RageClickManager");
|
|
8
|
-
const
|
|
9
|
-
const
|
|
10
|
-
const
|
|
8
|
+
const WebVitalsManager_1 = require("./WebVitalsManager");
|
|
9
|
+
const commonUtils_1 = require("./utils/commonUtils");
|
|
10
|
+
const eventUtils_1 = require("./utils/eventUtils");
|
|
11
|
+
const metadataUtils_1 = require("./utils/metadataUtils");
|
|
11
12
|
const AUTO_EVENT_MAPPING = {
|
|
12
13
|
submit: AutoCaptureEvent_1.AutoCaptureEventName.FORM_SUBMIT,
|
|
13
14
|
click: AutoCaptureEvent_1.AutoCaptureEventName.CLICK,
|
|
@@ -23,6 +24,15 @@ class StatsigAutoCapturePlugin {
|
|
|
23
24
|
}
|
|
24
25
|
exports.StatsigAutoCapturePlugin = StatsigAutoCapturePlugin;
|
|
25
26
|
function runStatsigAutoCapture(client, options) {
|
|
27
|
+
var _a;
|
|
28
|
+
const { sdkKey } = client.getContext();
|
|
29
|
+
if (!(0, client_core_1._isServerEnv)()) {
|
|
30
|
+
const global = (0, client_core_1._getStatsigGlobal)();
|
|
31
|
+
const instances = (_a = global.acInstances) !== null && _a !== void 0 ? _a : {};
|
|
32
|
+
if (instances[sdkKey]) {
|
|
33
|
+
return instances[sdkKey];
|
|
34
|
+
}
|
|
35
|
+
}
|
|
26
36
|
return new AutoCapture(client, options);
|
|
27
37
|
}
|
|
28
38
|
exports.runStatsigAutoCapture = runStatsigAutoCapture;
|
|
@@ -33,6 +43,7 @@ class AutoCapture {
|
|
|
33
43
|
this._disabledEvents = {};
|
|
34
44
|
this._previousLoggedPageViewUrl = null;
|
|
35
45
|
this._hasLoggedPageViewEnd = false;
|
|
46
|
+
this._pageViewLogged = false;
|
|
36
47
|
const { sdkKey, errorBoundary, values } = _client.getContext();
|
|
37
48
|
this._disabledEvents = (_b = (_a = values === null || values === void 0 ? void 0 : values.auto_capture_settings) === null || _a === void 0 ? void 0 : _a.disabled_events) !== null && _b !== void 0 ? _b : {};
|
|
38
49
|
this._errorBoundary = errorBoundary;
|
|
@@ -45,6 +56,7 @@ class AutoCapture {
|
|
|
45
56
|
});
|
|
46
57
|
this._engagementManager = new EngagementManager_1.EngagementManager();
|
|
47
58
|
this._rageClickManager = new RageClickManager_1.default();
|
|
59
|
+
this._webVitalsManager = new WebVitalsManager_1.WebVitalsManager(this._enqueueAutoCapture.bind(this));
|
|
48
60
|
this._eventFilterFunc = options === null || options === void 0 ? void 0 : options.eventFilterFunc;
|
|
49
61
|
const doc = (0, client_core_1._getDocumentSafe)();
|
|
50
62
|
if (!(0, client_core_1._isServerEnv)()) {
|
|
@@ -123,6 +135,7 @@ class AutoCapture {
|
|
|
123
135
|
this._enqueueAutoCapture(eventName, value, Object.assign(Object.assign({}, allMetadata), metadata));
|
|
124
136
|
}
|
|
125
137
|
_initialize() {
|
|
138
|
+
this._webVitalsManager.startTracking();
|
|
126
139
|
this._engagementManager.startInactivityTracking(() => this._tryLogPageViewEnd(true));
|
|
127
140
|
this._addEventHandlers();
|
|
128
141
|
this._addPageViewTracking();
|
|
@@ -170,13 +183,20 @@ class AutoCapture {
|
|
|
170
183
|
return;
|
|
171
184
|
}
|
|
172
185
|
this._engagementManager.setLastPageViewTime(Date.now());
|
|
173
|
-
this._previousLoggedPageViewUrl = url;
|
|
174
186
|
this._hasLoggedPageViewEnd = false;
|
|
175
187
|
const payload = (0, metadataUtils_1._gatherAllMetadata)(url);
|
|
188
|
+
if (this._previousLoggedPageViewUrl) {
|
|
189
|
+
payload['last_page_view_url'] = this._previousLoggedPageViewUrl.href;
|
|
190
|
+
}
|
|
191
|
+
if (!this._pageViewLogged) {
|
|
192
|
+
this._updateClientWithPossibleFirstTouchMetadata();
|
|
193
|
+
this._pageViewLogged = true;
|
|
194
|
+
}
|
|
176
195
|
this._enqueueAutoCapture(AutoCaptureEvent_1.AutoCaptureEventName.PAGE_VIEW, (0, commonUtils_1._getSanitizedPageUrl)(), payload, {
|
|
177
196
|
flushImmediately: true,
|
|
178
197
|
addNewSessionMetadata: true,
|
|
179
198
|
});
|
|
199
|
+
this._previousLoggedPageViewUrl = url;
|
|
180
200
|
this._engagementManager.bumpInactiveTimer();
|
|
181
201
|
}
|
|
182
202
|
_tryLogPageViewEnd(dueToInactivity = false) {
|
|
@@ -249,15 +269,24 @@ class AutoCapture {
|
|
|
249
269
|
}
|
|
250
270
|
this._client.logEvent(event);
|
|
251
271
|
if (options === null || options === void 0 ? void 0 : options.flushImmediately) {
|
|
252
|
-
this.
|
|
253
|
-
client_core_1.Log.error(e);
|
|
254
|
-
});
|
|
272
|
+
this._flushImmediately();
|
|
255
273
|
}
|
|
256
274
|
}
|
|
257
275
|
catch (err) {
|
|
258
276
|
this._errorBoundary.logError('AC::enqueue', err);
|
|
259
277
|
}
|
|
260
278
|
}
|
|
279
|
+
_updateClientWithPossibleFirstTouchMetadata() {
|
|
280
|
+
const typedClient = this._client;
|
|
281
|
+
typedClient._possibleFirstTouchMetadata =
|
|
282
|
+
(0, metadataUtils_1._getPossibleFirstTouchMetadata)((0, commonUtils_1._getSafeUrl)());
|
|
283
|
+
typedClient._user = Object.assign(Object.assign({}, typedClient._user), { analyticsOnlyMetadata: Object.assign(Object.assign({}, typedClient._possibleFirstTouchMetadata), typedClient._user.analyticsOnlyMetadata) });
|
|
284
|
+
}
|
|
285
|
+
_flushImmediately() {
|
|
286
|
+
this._client.flush().catch((e) => {
|
|
287
|
+
client_core_1.Log.error(e);
|
|
288
|
+
});
|
|
289
|
+
}
|
|
261
290
|
_isNewSession(session) {
|
|
262
291
|
// within the last second
|
|
263
292
|
return Math.abs(session.data.startTime - Date.now()) < 1000;
|
|
@@ -8,6 +8,7 @@ export declare const AutoCaptureEventName: {
|
|
|
8
8
|
readonly FORM_SUBMIT: "auto_capture::form_submit";
|
|
9
9
|
readonly CLICK: "auto_capture::click";
|
|
10
10
|
readonly RAGE_CLICK: "auto_capture::rage_click";
|
|
11
|
+
readonly WEB_VITALS: "auto_capture::web_vitals";
|
|
11
12
|
};
|
|
12
13
|
export type AutoCaptureEventName = (typeof AutoCaptureEventName)[keyof typeof AutoCaptureEventName] & string;
|
|
13
14
|
export type AutoCaptureEvent = StatsigEvent & {
|
package/src/AutoCaptureEvent.js
CHANGED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { AutoCaptureEventName } from './AutoCaptureEvent';
|
|
2
|
+
export declare class WebVitalsManager {
|
|
3
|
+
private _enqueueFn;
|
|
4
|
+
private _isInitialized;
|
|
5
|
+
constructor(_enqueueFn: (eventName: AutoCaptureEventName, value: string, metadata: Record<string, unknown>) => void);
|
|
6
|
+
startTracking(): void;
|
|
7
|
+
private _handleMetric;
|
|
8
|
+
private _enqueueWebVitalsAutoCaptureEvent;
|
|
9
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.WebVitalsManager = void 0;
|
|
4
|
+
const web_vitals_1 = require("web-vitals");
|
|
5
|
+
const client_core_1 = require("@statsig/client-core");
|
|
6
|
+
const AutoCaptureEvent_1 = require("./AutoCaptureEvent");
|
|
7
|
+
const commonUtils_1 = require("./utils/commonUtils");
|
|
8
|
+
const VALID_METRIC_NAMES = ['CLS', 'FCP', 'LCP', 'TTFB'];
|
|
9
|
+
class WebVitalsManager {
|
|
10
|
+
constructor(_enqueueFn) {
|
|
11
|
+
this._enqueueFn = _enqueueFn;
|
|
12
|
+
this._isInitialized = false;
|
|
13
|
+
}
|
|
14
|
+
startTracking() {
|
|
15
|
+
var _a, _b;
|
|
16
|
+
if (this._isInitialized) {
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
const protocol = (_b = (_a = (0, client_core_1._getWindowSafe)()) === null || _a === void 0 ? void 0 : _a.location) === null || _b === void 0 ? void 0 : _b.protocol;
|
|
20
|
+
if (protocol !== 'https:' && protocol !== 'http:') {
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
(0, web_vitals_1.onCLS)((metric) => this._handleMetric(metric));
|
|
24
|
+
(0, web_vitals_1.onFCP)((metric) => this._handleMetric(metric));
|
|
25
|
+
(0, web_vitals_1.onLCP)((metric) => this._handleMetric(metric));
|
|
26
|
+
(0, web_vitals_1.onTTFB)((metric) => this._handleMetric(metric));
|
|
27
|
+
this._isInitialized = true;
|
|
28
|
+
}
|
|
29
|
+
_handleMetric(metric) {
|
|
30
|
+
if (metric === undefined || (metric === null || metric === void 0 ? void 0 : metric.name) === undefined) {
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
const currentUrl = (0, commonUtils_1._getSafeUrlString)();
|
|
34
|
+
if (currentUrl === '') {
|
|
35
|
+
// If the URL is not valid, we don't want to track the metric
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
if (!VALID_METRIC_NAMES.includes(metric.name)) {
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
this._enqueueWebVitalsAutoCaptureEvent(metric, currentUrl);
|
|
42
|
+
}
|
|
43
|
+
_enqueueWebVitalsAutoCaptureEvent(metric, url) {
|
|
44
|
+
if (url === '') {
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
this._enqueueFn(AutoCaptureEvent_1.AutoCaptureEventName.WEB_VITALS, url, {
|
|
48
|
+
name: metric.name,
|
|
49
|
+
value: metric.value,
|
|
50
|
+
delta: metric.delta,
|
|
51
|
+
id: metric.id,
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
exports.WebVitalsManager = WebVitalsManager;
|
|
@@ -8,6 +8,7 @@ export declare function _stripEmptyValues<T extends Record<string, string | numb
|
|
|
8
8
|
export declare function _getTargetNode(e: Event): Element | null;
|
|
9
9
|
export declare function _shouldLogEvent(e: Event, el: Element): boolean;
|
|
10
10
|
export declare function _getSafeUrl(): URL;
|
|
11
|
+
export declare function _getSafeUrlString(): string;
|
|
11
12
|
export declare function _getSanitizedPageUrl(): string;
|
|
12
13
|
export declare function _registerEventHandler(element: Document | Window, eventType: string, handler: (event: Event) => void): void;
|
|
13
14
|
export declare function _getSafeNetworkInformation(): NetworkInformation | null;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports._getAnchorNodeInHierarchy = exports._getSafeTimezoneOffset = exports._getSafeTimezone = exports._getSafeNetworkInformation = exports._registerEventHandler = exports._getSanitizedPageUrl = exports._getSafeUrl = exports._shouldLogEvent = exports._getTargetNode = exports._stripEmptyValues = void 0;
|
|
3
|
+
exports._getAnchorNodeInHierarchy = exports._getSafeTimezoneOffset = exports._getSafeTimezone = exports._getSafeNetworkInformation = exports._registerEventHandler = exports._getSanitizedPageUrl = exports._getSafeUrlString = exports._getSafeUrl = exports._shouldLogEvent = exports._getTargetNode = exports._stripEmptyValues = void 0;
|
|
4
4
|
const client_core_1 = require("@statsig/client-core");
|
|
5
5
|
function _stripEmptyValues(obj) {
|
|
6
6
|
return Object.fromEntries(Object.entries(obj).filter(([_, value]) => value != null && value !== '' && value !== undefined));
|
|
@@ -62,6 +62,14 @@ function _getSafeUrl() {
|
|
|
62
62
|
return url;
|
|
63
63
|
}
|
|
64
64
|
exports._getSafeUrl = _getSafeUrl;
|
|
65
|
+
function _getSafeUrlString() {
|
|
66
|
+
const urlString = _getSafeUrl().toString();
|
|
67
|
+
if (urlString.startsWith('error:')) {
|
|
68
|
+
return '';
|
|
69
|
+
}
|
|
70
|
+
return urlString;
|
|
71
|
+
}
|
|
72
|
+
exports._getSafeUrlString = _getSafeUrlString;
|
|
65
73
|
function _getSanitizedPageUrl() {
|
|
66
74
|
return (0, client_core_1._getCurrentPageUrlSafe)() || '';
|
|
67
75
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
export declare function _gatherCommonMetadata(url: URL): Record<string, string | number | null>;
|
|
2
2
|
export declare function _gatherAllMetadata(url: URL): Record<string, string | number>;
|
|
3
3
|
export declare function _getNetworkInfo(): Record<string, string | number | boolean>;
|
|
4
|
+
export declare function _getPossibleFirstTouchMetadata(url: URL): Record<string, string | number>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports._getNetworkInfo = exports._gatherAllMetadata = exports._gatherCommonMetadata = void 0;
|
|
3
|
+
exports._getPossibleFirstTouchMetadata = exports._getNetworkInfo = exports._gatherAllMetadata = exports._gatherCommonMetadata = void 0;
|
|
4
4
|
const client_core_1 = require("@statsig/client-core");
|
|
5
5
|
const commonUtils_1 = require("./commonUtils");
|
|
6
6
|
function _gatherCommonMetadata(url) {
|
|
@@ -48,6 +48,22 @@ function _getNetworkInfo() {
|
|
|
48
48
|
return result;
|
|
49
49
|
}
|
|
50
50
|
exports._getNetworkInfo = _getNetworkInfo;
|
|
51
|
+
function _getPossibleFirstTouchMetadata(url) {
|
|
52
|
+
const safeDoc = (0, client_core_1._getDocumentSafe)();
|
|
53
|
+
const safeWnd = (0, client_core_1._getWindowSafe)();
|
|
54
|
+
if (!safeDoc || !safeWnd) {
|
|
55
|
+
return {};
|
|
56
|
+
}
|
|
57
|
+
const referrerInfo = getReferrerInfo(safeDoc);
|
|
58
|
+
const campaignParams = getCampaignParams(url);
|
|
59
|
+
const combined = (0, commonUtils_1._stripEmptyValues)(Object.assign(Object.assign({}, referrerInfo), campaignParams));
|
|
60
|
+
const prefixed = {};
|
|
61
|
+
for (const [key, value] of Object.entries(combined)) {
|
|
62
|
+
prefixed[`$s_${key}`] = value;
|
|
63
|
+
}
|
|
64
|
+
return prefixed;
|
|
65
|
+
}
|
|
66
|
+
exports._getPossibleFirstTouchMetadata = _getPossibleFirstTouchMetadata;
|
|
51
67
|
function getReferrerInfo(safeDoc) {
|
|
52
68
|
const referrer = (safeDoc === null || safeDoc === void 0 ? void 0 : safeDoc.referrer) || '';
|
|
53
69
|
if (!referrer) {
|
|
File without changes
|
|
File without changes
|