@v-tilt/browser 1.0.10 → 1.0.11
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/dist/array.js +1 -1
- package/dist/array.js.map +1 -1
- package/dist/array.no-external.js +1 -1
- package/dist/array.no-external.js.map +1 -1
- package/dist/constants.d.ts +1 -0
- package/dist/main.js +1 -1
- package/dist/main.js.map +1 -1
- package/dist/module.d.ts +2 -1
- package/dist/module.js +1 -1
- package/dist/module.js.map +1 -1
- package/dist/module.no-external.d.ts +2 -1
- package/dist/module.no-external.js +1 -1
- package/dist/module.no-external.js.map +1 -1
- package/dist/user-manager.d.ts +21 -0
- package/dist/utils/event-utils.d.ts +35 -17
- package/dist/utils/index.d.ts +21 -0
- package/dist/utils/request-utils.d.ts +17 -0
- package/dist/vtilt.d.ts +2 -1
- package/lib/constants.d.ts +1 -0
- package/lib/constants.js +2 -1
- package/lib/user-manager.d.ts +21 -0
- package/lib/user-manager.js +66 -0
- package/lib/utils/event-utils.d.ts +35 -17
- package/lib/utils/event-utils.js +245 -122
- package/lib/utils/index.d.ts +21 -0
- package/lib/utils/index.js +58 -0
- package/lib/utils/request-utils.d.ts +17 -0
- package/lib/utils/request-utils.js +78 -0
- package/lib/vtilt.d.ts +2 -1
- package/lib/vtilt.js +24 -2
- package/package.json +61 -61
package/lib/utils/index.d.ts
CHANGED
|
@@ -23,3 +23,24 @@ export declare function each<T>(obj: T[] | Record<string, T> | null | undefined,
|
|
|
23
23
|
* This properly implements the default options for passive event listeners
|
|
24
24
|
*/
|
|
25
25
|
export declare function addEventListener(element: Window | Document | Element | undefined, event: string, callback: EventListener, options?: AddEventListenerOptions): void;
|
|
26
|
+
/**
|
|
27
|
+
* Extend object with properties from another object
|
|
28
|
+
*/
|
|
29
|
+
export declare function extend<T extends Record<string, any>>(target: T, source: Record<string, any> | null | undefined): T;
|
|
30
|
+
/**
|
|
31
|
+
* Extend array with additional items
|
|
32
|
+
* Mutates the base array and returns it (matches PostHog's behavior)
|
|
33
|
+
*/
|
|
34
|
+
export declare function extendArray<T>(base: T[], ...additional: T[][]): T[];
|
|
35
|
+
/**
|
|
36
|
+
* Strip properties with empty values (null, undefined, empty string)
|
|
37
|
+
*/
|
|
38
|
+
export declare function stripEmptyProperties<T extends Record<string, any>>(obj: T): Partial<T>;
|
|
39
|
+
/**
|
|
40
|
+
* Strip leading dollar sign from string
|
|
41
|
+
*/
|
|
42
|
+
export declare function stripLeadingDollar(str: string): string;
|
|
43
|
+
/**
|
|
44
|
+
* Check if value is null
|
|
45
|
+
*/
|
|
46
|
+
export declare function isNull(value: any): boolean;
|
package/lib/utils/index.js
CHANGED
|
@@ -6,6 +6,11 @@ exports.isValidPayload = isValidPayload;
|
|
|
6
6
|
exports.isTestEnvironment = isTestEnvironment;
|
|
7
7
|
exports.each = each;
|
|
8
8
|
exports.addEventListener = addEventListener;
|
|
9
|
+
exports.extend = extend;
|
|
10
|
+
exports.extendArray = extendArray;
|
|
11
|
+
exports.stripEmptyProperties = stripEmptyProperties;
|
|
12
|
+
exports.stripLeadingDollar = stripLeadingDollar;
|
|
13
|
+
exports.isNull = isNull;
|
|
9
14
|
/**
|
|
10
15
|
* Generate uuid to identify the session. Random, not data-derived
|
|
11
16
|
*/
|
|
@@ -74,3 +79,56 @@ function addEventListener(element, event, callback, options) {
|
|
|
74
79
|
const { capture = false, passive = true } = options !== null && options !== void 0 ? options : {};
|
|
75
80
|
element === null || element === void 0 ? void 0 : element.addEventListener(event, callback, { capture, passive });
|
|
76
81
|
}
|
|
82
|
+
/**
|
|
83
|
+
* Extend object with properties from another object
|
|
84
|
+
*/
|
|
85
|
+
function extend(target, source) {
|
|
86
|
+
if (!source) {
|
|
87
|
+
return target;
|
|
88
|
+
}
|
|
89
|
+
for (const key in source) {
|
|
90
|
+
if (Object.prototype.hasOwnProperty.call(source, key)) {
|
|
91
|
+
target[key] = source[key];
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return target;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Extend array with additional items
|
|
98
|
+
* Mutates the base array and returns it (matches PostHog's behavior)
|
|
99
|
+
*/
|
|
100
|
+
function extendArray(base, ...additional) {
|
|
101
|
+
for (const arr of additional) {
|
|
102
|
+
for (const item of arr) {
|
|
103
|
+
base.push(item);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return base;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Strip properties with empty values (null, undefined, empty string)
|
|
110
|
+
*/
|
|
111
|
+
function stripEmptyProperties(obj) {
|
|
112
|
+
const result = {};
|
|
113
|
+
for (const key in obj) {
|
|
114
|
+
if (Object.prototype.hasOwnProperty.call(obj, key)) {
|
|
115
|
+
const value = obj[key];
|
|
116
|
+
if (value !== null && value !== undefined && value !== '') {
|
|
117
|
+
result[key] = value;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
return result;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Strip leading dollar sign from string
|
|
125
|
+
*/
|
|
126
|
+
function stripLeadingDollar(str) {
|
|
127
|
+
return str.startsWith('$') ? str.substring(1) : str;
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Check if value is null
|
|
131
|
+
*/
|
|
132
|
+
function isNull(value) {
|
|
133
|
+
return value === null;
|
|
134
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Request utilities
|
|
3
|
+
* Functions for parsing URLs, query parameters, and masking sensitive data
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Convert string URL to HTMLAnchorElement for parsing
|
|
7
|
+
* IE11 doesn't support `new URL`, so we use anchor element
|
|
8
|
+
*/
|
|
9
|
+
export declare function convertToURL(url: string): HTMLAnchorElement | null;
|
|
10
|
+
/**
|
|
11
|
+
* Get query parameter from URL
|
|
12
|
+
*/
|
|
13
|
+
export declare function getQueryParam(url: string, param: string): string;
|
|
14
|
+
/**
|
|
15
|
+
* Mask query parameters in URL
|
|
16
|
+
*/
|
|
17
|
+
export declare function maskQueryParams<T extends string | undefined>(url: T, maskedParams: string[] | undefined, mask: string): T extends string ? string : undefined;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Request utilities
|
|
4
|
+
* Functions for parsing URLs, query parameters, and masking sensitive data
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.convertToURL = convertToURL;
|
|
8
|
+
exports.getQueryParam = getQueryParam;
|
|
9
|
+
exports.maskQueryParams = maskQueryParams;
|
|
10
|
+
const globals_1 = require("./globals");
|
|
11
|
+
/**
|
|
12
|
+
* Convert string URL to HTMLAnchorElement for parsing
|
|
13
|
+
* IE11 doesn't support `new URL`, so we use anchor element
|
|
14
|
+
*/
|
|
15
|
+
function convertToURL(url) {
|
|
16
|
+
if (!globals_1.document) {
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
const anchor = globals_1.document.createElement('a');
|
|
20
|
+
anchor.href = url;
|
|
21
|
+
return anchor;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Get query parameter from URL
|
|
25
|
+
*/
|
|
26
|
+
function getQueryParam(url, param) {
|
|
27
|
+
const withoutHash = url.split('#')[0] || '';
|
|
28
|
+
const queryParams = withoutHash.split(/\?(.*)/)[1] || '';
|
|
29
|
+
const cleanedQueryParams = queryParams.replace(/^\?+/g, '');
|
|
30
|
+
const queryParts = cleanedQueryParams.split('&');
|
|
31
|
+
for (let i = 0; i < queryParts.length; i++) {
|
|
32
|
+
const parts = queryParts[i].split('=');
|
|
33
|
+
if (parts[0] === param) {
|
|
34
|
+
if (parts.length < 2) {
|
|
35
|
+
return '';
|
|
36
|
+
}
|
|
37
|
+
let result = parts[1];
|
|
38
|
+
try {
|
|
39
|
+
result = decodeURIComponent(result);
|
|
40
|
+
}
|
|
41
|
+
catch (_a) {
|
|
42
|
+
// Skip decoding for malformed query param
|
|
43
|
+
}
|
|
44
|
+
return result.replace(/\+/g, ' ');
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return '';
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Mask query parameters in URL
|
|
51
|
+
*/
|
|
52
|
+
function maskQueryParams(url, maskedParams, mask) {
|
|
53
|
+
if (!url || !maskedParams || !maskedParams.length) {
|
|
54
|
+
return url;
|
|
55
|
+
}
|
|
56
|
+
const splitHash = url.split('#');
|
|
57
|
+
const withoutHash = splitHash[0] || '';
|
|
58
|
+
const hash = splitHash[1];
|
|
59
|
+
const splitQuery = withoutHash.split('?');
|
|
60
|
+
const queryString = splitQuery[1];
|
|
61
|
+
const urlWithoutQueryAndHash = splitQuery[0];
|
|
62
|
+
const queryParts = (queryString || '').split('&');
|
|
63
|
+
const paramStrings = [];
|
|
64
|
+
for (let i = 0; i < queryParts.length; i++) {
|
|
65
|
+
const parts = queryParts[i].split('=');
|
|
66
|
+
const key = parts[0];
|
|
67
|
+
const value = parts.slice(1).join('=');
|
|
68
|
+
if (maskedParams.indexOf(key) !== -1) {
|
|
69
|
+
paramStrings.push(key + '=' + mask);
|
|
70
|
+
}
|
|
71
|
+
else if (key) {
|
|
72
|
+
paramStrings.push(key + (value ? '=' + value : ''));
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
const newQueryString = paramStrings.join('&');
|
|
76
|
+
const newUrl = urlWithoutQueryAndHash + (newQueryString ? '?' + newQueryString : '') + (hash ? '#' + hash : '');
|
|
77
|
+
return newUrl;
|
|
78
|
+
}
|
package/lib/vtilt.d.ts
CHANGED
|
@@ -86,7 +86,8 @@ export declare class VTilt {
|
|
|
86
86
|
/**
|
|
87
87
|
* Capture an event
|
|
88
88
|
* Automatically adds common properties to all events
|
|
89
|
-
* ($current_url, $host, $pathname, $referrer, $referring_domain, $
|
|
89
|
+
* ($current_url, $host, $pathname, $referrer, $referring_domain, $browser, $os, $device, $timezone, etc.)
|
|
90
|
+
* Only properties in EVENT_TO_PERSON_PROPERTIES are copied to person properties
|
|
90
91
|
* Also adds title property for $pageview events only
|
|
91
92
|
*
|
|
92
93
|
* @param name - Event name
|
package/lib/vtilt.js
CHANGED
|
@@ -93,6 +93,9 @@ class VTilt {
|
|
|
93
93
|
name: name,
|
|
94
94
|
});
|
|
95
95
|
this.__loaded = true;
|
|
96
|
+
// Set initial person info: stores referrer and URL on first visit
|
|
97
|
+
const fullConfig = this.configManager.getConfig();
|
|
98
|
+
this.userManager.set_initial_person_info(fullConfig.mask_personal_data_properties, fullConfig.custom_personal_data_properties);
|
|
96
99
|
// Initialize history autocapture
|
|
97
100
|
this.historyAutocapture = new history_autocapture_1.HistoryAutocapture(this);
|
|
98
101
|
this.historyAutocapture.startIfEnabled();
|
|
@@ -204,7 +207,8 @@ class VTilt {
|
|
|
204
207
|
/**
|
|
205
208
|
* Capture an event
|
|
206
209
|
* Automatically adds common properties to all events
|
|
207
|
-
* ($current_url, $host, $pathname, $referrer, $referring_domain, $
|
|
210
|
+
* ($current_url, $host, $pathname, $referrer, $referring_domain, $browser, $os, $device, $timezone, etc.)
|
|
211
|
+
* Only properties in EVENT_TO_PERSON_PROPERTIES are copied to person properties
|
|
208
212
|
* Also adds title property for $pageview events only
|
|
209
213
|
*
|
|
210
214
|
* @param name - Event name
|
|
@@ -221,11 +225,14 @@ class VTilt {
|
|
|
221
225
|
}
|
|
222
226
|
const url = this.buildUrl();
|
|
223
227
|
// Add properties to all events
|
|
224
|
-
// This includes: $current_url, $host, $pathname, $referrer, $referring_domain, $
|
|
228
|
+
// This includes: $current_url, $host, $pathname, $referrer, $referring_domain, $browser, $os, $device, $timezone, etc.
|
|
229
|
+
// (Only properties in EVENT_TO_PERSON_PROPERTIES are copied to person properties)
|
|
225
230
|
const eventProperties = (0, event_utils_1.getEventProperties)();
|
|
226
231
|
// Get person properties (includes $device_id and other user properties)
|
|
227
232
|
// These are automatically included in all events
|
|
228
233
|
const personProperties = this.userManager.getUserProperties();
|
|
234
|
+
// Get initial props: $initial_* properties from stored initial person info
|
|
235
|
+
const initialProps = this.userManager.get_initial_props();
|
|
229
236
|
// Get session and window IDs
|
|
230
237
|
// Both methods ensure IDs always exist (generate if needed)
|
|
231
238
|
const session_id = this.sessionManager.getSessionId();
|
|
@@ -234,6 +241,17 @@ class VTilt {
|
|
|
234
241
|
// This allows linking events with different distinct_ids that share the same anonymous_id
|
|
235
242
|
// This is especially important for handling race conditions when $identify events arrive
|
|
236
243
|
const anonymousId = this.userManager.getAnonymousId();
|
|
244
|
+
// Build $set and $set_once from initial props
|
|
245
|
+
// Initial props are added to $set_once (only first time, preserves first values)
|
|
246
|
+
// Regular event properties that match EVENT_TO_PERSON_PROPERTIES will be added to $set by server
|
|
247
|
+
const setOnce = {};
|
|
248
|
+
if (Object.keys(initialProps).length > 0) {
|
|
249
|
+
Object.assign(setOnce, initialProps);
|
|
250
|
+
}
|
|
251
|
+
// Merge with user-provided $set_once if present
|
|
252
|
+
if (payload.$set_once) {
|
|
253
|
+
Object.assign(setOnce, payload.$set_once);
|
|
254
|
+
}
|
|
237
255
|
const enrichedPayload = {
|
|
238
256
|
...eventProperties, // Base properties for all events
|
|
239
257
|
...personProperties, // Person properties (includes $device_id)
|
|
@@ -242,6 +260,10 @@ class VTilt {
|
|
|
242
260
|
// Always include $anon_distinct_id for identity linking (even for identified users)
|
|
243
261
|
// This allows the server to merge identities proactively when events arrive out of order
|
|
244
262
|
...(anonymousId ? { $anon_distinct_id: anonymousId } : {}),
|
|
263
|
+
// Add $set_once with initial props
|
|
264
|
+
...(Object.keys(setOnce).length > 0 ? { $set_once: setOnce } : {}),
|
|
265
|
+
// Merge user-provided $set if present
|
|
266
|
+
...(payload.$set ? { $set: payload.$set } : {}),
|
|
245
267
|
...payload, // User-provided payload (can override base and person properties)
|
|
246
268
|
};
|
|
247
269
|
// Add title only to $pageview events
|
package/package.json
CHANGED
|
@@ -1,61 +1,61 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@v-tilt/browser",
|
|
3
|
-
"version": "1.0.
|
|
4
|
-
"description": "vTilt browser tracking library",
|
|
5
|
-
"main": "dist/main.js",
|
|
6
|
-
"module": "dist/module.js",
|
|
7
|
-
"types": "dist/module.d.ts",
|
|
8
|
-
"files": [
|
|
9
|
-
"lib/*",
|
|
10
|
-
"dist/*"
|
|
11
|
-
],
|
|
12
|
-
"publishConfig": {
|
|
13
|
-
"access": "public"
|
|
14
|
-
},
|
|
15
|
-
"scripts": {
|
|
16
|
-
"build": "tsc -b && rollup -c",
|
|
17
|
-
"dev": "rollup -c -w",
|
|
18
|
-
"type-check": "tsc --noEmit",
|
|
19
|
-
"lint": "eslint src --ext .ts",
|
|
20
|
-
"lint:fix": "eslint src --ext .ts --fix",
|
|
21
|
-
"clean": "rimraf lib dist",
|
|
22
|
-
"prepublishOnly": "pnpm run build"
|
|
23
|
-
},
|
|
24
|
-
"keywords": [
|
|
25
|
-
"analytics",
|
|
26
|
-
"tracking",
|
|
27
|
-
"web-vitals",
|
|
28
|
-
"performance"
|
|
29
|
-
],
|
|
30
|
-
"author": "vTilt",
|
|
31
|
-
"license": "MIT",
|
|
32
|
-
"devDependencies": {
|
|
33
|
-
"@babel/preset-env": "^7.28.3",
|
|
34
|
-
"@rollup/plugin-babel": "^6.0.4",
|
|
35
|
-
"@rollup/plugin-commonjs": "^25.0.8",
|
|
36
|
-
"@rollup/plugin-json": "^6.1.0",
|
|
37
|
-
"@rollup/plugin-node-resolve": "^15.3.1",
|
|
38
|
-
"@rollup/plugin-terser": "^0.4.4",
|
|
39
|
-
"@rollup/plugin-typescript": "^11.1.6",
|
|
40
|
-
"@types/node": "^20.10.5",
|
|
41
|
-
"@v-tilt/eslint-config": "workspace:*",
|
|
42
|
-
"eslint": "^9.0.0",
|
|
43
|
-
"rimraf": "^5.0.5",
|
|
44
|
-
"rollup": "^4.9.1",
|
|
45
|
-
"rollup-plugin-dts": "^6.2.3",
|
|
46
|
-
"rollup-plugin-terser": "^7.0.2",
|
|
47
|
-
"rollup-plugin-visualizer": "^6.0.3",
|
|
48
|
-
"typescript": "^5.3.3"
|
|
49
|
-
},
|
|
50
|
-
"dependencies": {
|
|
51
|
-
"web-vitals": "^3.5.0"
|
|
52
|
-
},
|
|
53
|
-
"peerDependencies": {
|
|
54
|
-
"web-vitals": "^3.0.0"
|
|
55
|
-
},
|
|
56
|
-
"peerDependenciesMeta": {
|
|
57
|
-
"web-vitals": {
|
|
58
|
-
"optional": true
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@v-tilt/browser",
|
|
3
|
+
"version": "1.0.11",
|
|
4
|
+
"description": "vTilt browser tracking library",
|
|
5
|
+
"main": "dist/main.js",
|
|
6
|
+
"module": "dist/module.js",
|
|
7
|
+
"types": "dist/module.d.ts",
|
|
8
|
+
"files": [
|
|
9
|
+
"lib/*",
|
|
10
|
+
"dist/*"
|
|
11
|
+
],
|
|
12
|
+
"publishConfig": {
|
|
13
|
+
"access": "public"
|
|
14
|
+
},
|
|
15
|
+
"scripts": {
|
|
16
|
+
"build": "tsc -b && rollup -c",
|
|
17
|
+
"dev": "rollup -c -w",
|
|
18
|
+
"type-check": "tsc --noEmit",
|
|
19
|
+
"lint": "eslint src --ext .ts",
|
|
20
|
+
"lint:fix": "eslint src --ext .ts --fix",
|
|
21
|
+
"clean": "rimraf lib dist",
|
|
22
|
+
"prepublishOnly": "pnpm run build"
|
|
23
|
+
},
|
|
24
|
+
"keywords": [
|
|
25
|
+
"analytics",
|
|
26
|
+
"tracking",
|
|
27
|
+
"web-vitals",
|
|
28
|
+
"performance"
|
|
29
|
+
],
|
|
30
|
+
"author": "vTilt",
|
|
31
|
+
"license": "MIT",
|
|
32
|
+
"devDependencies": {
|
|
33
|
+
"@babel/preset-env": "^7.28.3",
|
|
34
|
+
"@rollup/plugin-babel": "^6.0.4",
|
|
35
|
+
"@rollup/plugin-commonjs": "^25.0.8",
|
|
36
|
+
"@rollup/plugin-json": "^6.1.0",
|
|
37
|
+
"@rollup/plugin-node-resolve": "^15.3.1",
|
|
38
|
+
"@rollup/plugin-terser": "^0.4.4",
|
|
39
|
+
"@rollup/plugin-typescript": "^11.1.6",
|
|
40
|
+
"@types/node": "^20.10.5",
|
|
41
|
+
"@v-tilt/eslint-config": "workspace:*",
|
|
42
|
+
"eslint": "^9.0.0",
|
|
43
|
+
"rimraf": "^5.0.5",
|
|
44
|
+
"rollup": "^4.9.1",
|
|
45
|
+
"rollup-plugin-dts": "^6.2.3",
|
|
46
|
+
"rollup-plugin-terser": "^7.0.2",
|
|
47
|
+
"rollup-plugin-visualizer": "^6.0.3",
|
|
48
|
+
"typescript": "^5.3.3"
|
|
49
|
+
},
|
|
50
|
+
"dependencies": {
|
|
51
|
+
"web-vitals": "^3.5.0"
|
|
52
|
+
},
|
|
53
|
+
"peerDependencies": {
|
|
54
|
+
"web-vitals": "^3.0.0"
|
|
55
|
+
},
|
|
56
|
+
"peerDependenciesMeta": {
|
|
57
|
+
"web-vitals": {
|
|
58
|
+
"optional": true
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|