@v-tilt/browser 1.0.7 → 1.0.9
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 +0 -1
- package/dist/extensions/history-autocapture.d.ts +0 -2
- package/dist/main.js +1 -1
- package/dist/main.js.map +1 -1
- package/dist/module.d.ts +52 -132
- package/dist/module.js +1 -1
- package/dist/module.js.map +1 -1
- package/dist/module.no-external.d.ts +52 -132
- package/dist/module.no-external.js +1 -1
- package/dist/module.no-external.js.map +1 -1
- package/dist/session.d.ts +5 -5
- package/dist/types.d.ts +1 -0
- package/dist/user-manager.d.ts +30 -20
- package/dist/utils/event-utils.d.ts +7 -8
- package/dist/utils/index.d.ts +0 -5
- package/dist/utils/patch.d.ts +0 -2
- package/dist/utils/type-utils.d.ts +4 -0
- package/dist/vtilt.d.ts +54 -14
- package/dist/web-vitals.d.ts +3 -3
- package/lib/constants.d.ts +0 -1
- package/lib/constants.js +1 -23
- package/lib/extensions/history-autocapture.d.ts +0 -2
- package/lib/extensions/history-autocapture.js +3 -5
- package/lib/session.d.ts +5 -5
- package/lib/session.js +8 -8
- package/lib/types.d.ts +1 -0
- package/lib/user-manager.d.ts +30 -20
- package/lib/user-manager.js +103 -92
- package/lib/utils/event-utils.d.ts +7 -8
- package/lib/utils/event-utils.js +8 -9
- package/lib/utils/index.d.ts +0 -5
- package/lib/utils/index.js +0 -13
- package/lib/utils/patch.d.ts +0 -2
- package/lib/utils/patch.js +2 -7
- package/lib/utils/type-utils.d.ts +4 -0
- package/lib/utils/type-utils.js +9 -0
- package/lib/utils/user-agent-utils.js +5 -17
- package/lib/vtilt.d.ts +54 -14
- package/lib/vtilt.js +328 -45
- package/lib/web-vitals.d.ts +3 -3
- package/lib/web-vitals.js +3 -3
- package/package.json +13 -12
- package/LICENSE +0 -21
- package/dist/tracking.d.ts +0 -120
- package/lib/tracking.d.ts +0 -120
- package/lib/tracking.js +0 -338
package/lib/user-manager.js
CHANGED
|
@@ -5,7 +5,7 @@ const constants_1 = require("./constants");
|
|
|
5
5
|
const utils_1 = require("./utils");
|
|
6
6
|
class UserManager {
|
|
7
7
|
constructor(storageMethod = "localStorage", domain) {
|
|
8
|
-
this._cachedPersonProperties = null; //
|
|
8
|
+
this._cachedPersonProperties = null; // Cache for deduplication
|
|
9
9
|
this.storageMethod = storageMethod;
|
|
10
10
|
this.domain = domain;
|
|
11
11
|
this.userIdentity = this.loadUserIdentity();
|
|
@@ -41,25 +41,24 @@ class UserManager {
|
|
|
41
41
|
}
|
|
42
42
|
/**
|
|
43
43
|
* Identify a user with distinct ID and properties
|
|
44
|
-
* Copied from PostHog's identify method implementation
|
|
45
44
|
*/
|
|
46
45
|
identify(newDistinctId, userPropertiesToSet, userPropertiesToSetOnce) {
|
|
47
|
-
//
|
|
46
|
+
// Validation: Convert number to string
|
|
48
47
|
if (typeof newDistinctId === "number") {
|
|
49
48
|
newDistinctId = newDistinctId.toString();
|
|
50
49
|
console.warn("The first argument to vTilt.identify was a number, but it should be a string. It has been converted to a string.");
|
|
51
50
|
}
|
|
52
|
-
//
|
|
51
|
+
// Validation: Check if distinct_id is provided
|
|
53
52
|
if (!newDistinctId) {
|
|
54
53
|
console.error("Unique user id has not been set in vTilt.identify");
|
|
55
54
|
return;
|
|
56
55
|
}
|
|
57
|
-
//
|
|
56
|
+
// Validation: Check for hardcoded strings
|
|
58
57
|
if (this.isDistinctIdStringLike(newDistinctId)) {
|
|
59
58
|
console.error(`The string "${newDistinctId}" was set in vTilt.identify which indicates an error. This ID should be unique to the user and not a hardcoded string.`);
|
|
60
59
|
return;
|
|
61
60
|
}
|
|
62
|
-
//
|
|
61
|
+
// Validation: Check for cookieless sentinel value
|
|
63
62
|
if (newDistinctId === "COOKIELESS_SENTINEL_VALUE") {
|
|
64
63
|
console.error(`The string "${newDistinctId}" was set in vTilt.identify which indicates an error. This ID is only used as a sentinel value.`);
|
|
65
64
|
return;
|
|
@@ -67,9 +66,9 @@ class UserManager {
|
|
|
67
66
|
const previousDistinctId = this.userIdentity.distinct_id;
|
|
68
67
|
const anonymousId = this.userIdentity.anonymous_id;
|
|
69
68
|
const deviceId = this.userIdentity.device_id;
|
|
70
|
-
//
|
|
69
|
+
// Register user ID
|
|
71
70
|
this.userIdentity.distinct_id = newDistinctId;
|
|
72
|
-
//
|
|
71
|
+
// Handle device ID if not already set
|
|
73
72
|
if (!this.userIdentity.device_id) {
|
|
74
73
|
// The persisted distinct id might not actually be a device id at all
|
|
75
74
|
// it might be a distinct id of the user from before
|
|
@@ -81,14 +80,14 @@ class UserManager {
|
|
|
81
80
|
$device_id: device_id,
|
|
82
81
|
};
|
|
83
82
|
}
|
|
84
|
-
//
|
|
83
|
+
// Clear alias if distinct_id is changing
|
|
85
84
|
if (newDistinctId !== previousDistinctId) {
|
|
86
|
-
// Clear any stored alias
|
|
85
|
+
// Clear any stored alias
|
|
87
86
|
this.userIdentity.distinct_id = newDistinctId;
|
|
88
87
|
}
|
|
89
|
-
//
|
|
88
|
+
// Check if user was anonymous
|
|
90
89
|
const isKnownAnonymous = this.userIdentity.user_state === "anonymous";
|
|
91
|
-
//
|
|
90
|
+
// Send $identify event only when distinct_id is changing AND user was anonymous
|
|
92
91
|
// - logic on the server will determine whether or not to do anything with it.
|
|
93
92
|
if (newDistinctId !== previousDistinctId && isKnownAnonymous) {
|
|
94
93
|
// Update user state to identified
|
|
@@ -110,14 +109,11 @@ class UserManager {
|
|
|
110
109
|
}
|
|
111
110
|
// Save to storage
|
|
112
111
|
this.saveUserIdentity();
|
|
113
|
-
//
|
|
114
|
-
|
|
115
|
-
$set: userPropertiesToSet || {},
|
|
116
|
-
$set_once: userPropertiesToSetOnce || {},
|
|
117
|
-
});
|
|
112
|
+
// Note: Event sending is now handled by VTilt.identify()
|
|
113
|
+
// This method is kept for backward compatibility but should not be called directly
|
|
118
114
|
}
|
|
119
115
|
else if (userPropertiesToSet || userPropertiesToSetOnce) {
|
|
120
|
-
//
|
|
116
|
+
// If distinct_id is not changing but we have properties to set
|
|
121
117
|
// Update user state if not already identified
|
|
122
118
|
if (this.userIdentity.user_state === "anonymous") {
|
|
123
119
|
this.userIdentity.user_state = "identified";
|
|
@@ -139,10 +135,8 @@ class UserManager {
|
|
|
139
135
|
}
|
|
140
136
|
// Save to storage
|
|
141
137
|
this.saveUserIdentity();
|
|
142
|
-
//
|
|
143
|
-
// This
|
|
144
|
-
// but no $identify event is sent (user was already identified)
|
|
145
|
-
this.sendSetEvent(userPropertiesToSet || {}, userPropertiesToSetOnce || {});
|
|
138
|
+
// Note: Event sending is now handled by VTilt.identify()
|
|
139
|
+
// This method is kept for backward compatibility but should not be called directly
|
|
146
140
|
}
|
|
147
141
|
else {
|
|
148
142
|
// If distinct_id is changing but user was already identified, just update the distinct_id
|
|
@@ -153,7 +147,7 @@ class UserManager {
|
|
|
153
147
|
}
|
|
154
148
|
}
|
|
155
149
|
/**
|
|
156
|
-
* Set user properties without changing distinct ID
|
|
150
|
+
* Set user properties without changing distinct ID
|
|
157
151
|
* Sets properties on the person profile associated with the current distinct_id
|
|
158
152
|
*
|
|
159
153
|
* @example
|
|
@@ -175,26 +169,26 @@ class UserManager {
|
|
|
175
169
|
* @param userPropertiesToSetOnce Optional: Properties to set once (preserves first value)
|
|
176
170
|
*/
|
|
177
171
|
setUserProperties(userPropertiesToSet, userPropertiesToSetOnce) {
|
|
178
|
-
//
|
|
172
|
+
// Return early if no properties provided
|
|
179
173
|
if (!userPropertiesToSet && !userPropertiesToSetOnce) {
|
|
180
|
-
return;
|
|
174
|
+
return false;
|
|
181
175
|
}
|
|
182
|
-
//
|
|
176
|
+
// Create hash for deduplication
|
|
183
177
|
const distinctId = this.userIdentity.distinct_id || this.userIdentity.anonymous_id;
|
|
184
178
|
const hash = this.getPersonPropertiesHash(distinctId, userPropertiesToSet, userPropertiesToSetOnce);
|
|
185
|
-
//
|
|
179
|
+
// Skip if exactly this $set call has been sent before
|
|
186
180
|
if (this._cachedPersonProperties === hash) {
|
|
187
181
|
console.info("VTilt: A duplicate setUserProperties call was made with the same properties. It has been ignored.");
|
|
188
|
-
return;
|
|
182
|
+
return false;
|
|
189
183
|
}
|
|
190
|
-
//
|
|
184
|
+
// Handle $set properties (update existing)
|
|
191
185
|
if (userPropertiesToSet) {
|
|
192
186
|
this.userIdentity.properties = {
|
|
193
187
|
...this.userIdentity.properties,
|
|
194
188
|
...userPropertiesToSet,
|
|
195
189
|
};
|
|
196
190
|
}
|
|
197
|
-
//
|
|
191
|
+
// Handle $set_once properties (preserve first value)
|
|
198
192
|
if (userPropertiesToSetOnce) {
|
|
199
193
|
Object.keys(userPropertiesToSetOnce).forEach((key) => {
|
|
200
194
|
if (!(key in this.userIdentity.properties)) {
|
|
@@ -204,45 +198,31 @@ class UserManager {
|
|
|
204
198
|
}
|
|
205
199
|
// Save to storage
|
|
206
200
|
this.saveUserIdentity();
|
|
207
|
-
//
|
|
208
|
-
this.sendSetEvent(userPropertiesToSet || {}, userPropertiesToSetOnce || {});
|
|
209
|
-
// PostHog behavior: Cache the hash to prevent duplicate sends
|
|
201
|
+
// Cache the hash to prevent duplicate sends
|
|
210
202
|
this._cachedPersonProperties = hash;
|
|
203
|
+
// Note: Event sending is now handled by VTilt.setUserProperties()
|
|
204
|
+
return true;
|
|
211
205
|
}
|
|
212
206
|
/**
|
|
213
|
-
* Get hash for person properties
|
|
207
|
+
* Get hash for person properties
|
|
214
208
|
* Used for deduplication of identical setUserProperties calls
|
|
215
209
|
*/
|
|
216
210
|
getPersonPropertiesHash(distinctId, userPropertiesToSet, userPropertiesToSetOnce) {
|
|
217
|
-
//
|
|
211
|
+
// Create deterministic hash from distinct_id and properties
|
|
218
212
|
return JSON.stringify({
|
|
219
213
|
distinct_id: distinctId,
|
|
220
214
|
userPropertiesToSet,
|
|
221
215
|
userPropertiesToSetOnce,
|
|
222
216
|
});
|
|
223
217
|
}
|
|
224
|
-
/**
|
|
225
|
-
* Send $set event for property updates (PostHog behavior)
|
|
226
|
-
* This notifies the server when user properties are updated
|
|
227
|
-
*/
|
|
228
|
-
sendSetEvent(userPropertiesToSet, userPropertiesToSetOnce) {
|
|
229
|
-
// Emit a custom event that TrackingManager can listen to
|
|
230
|
-
const setEvent = new CustomEvent("vtilt:set", {
|
|
231
|
-
detail: {
|
|
232
|
-
$set: userPropertiesToSet || {},
|
|
233
|
-
$set_once: userPropertiesToSetOnce || {},
|
|
234
|
-
},
|
|
235
|
-
});
|
|
236
|
-
window.dispatchEvent(setEvent);
|
|
237
|
-
}
|
|
238
218
|
/**
|
|
239
219
|
* Reset user identity (logout)
|
|
240
|
-
*
|
|
220
|
+
* Generates new anonymous ID, clears user data, optionally resets device ID
|
|
241
221
|
*
|
|
242
222
|
* @param reset_device_id - If true, also resets device_id. Default: false (preserves device_id)
|
|
243
223
|
*/
|
|
244
224
|
reset(reset_device_id) {
|
|
245
|
-
//
|
|
225
|
+
// Generate completely new anonymous ID (don't revert to original)
|
|
246
226
|
const newAnonymousId = this.generateAnonymousId();
|
|
247
227
|
const device_id = this.userIdentity.device_id;
|
|
248
228
|
// Generate new device ID if reset_device_id is true
|
|
@@ -254,14 +234,14 @@ class UserManager {
|
|
|
254
234
|
properties: {},
|
|
255
235
|
user_state: "anonymous",
|
|
256
236
|
};
|
|
257
|
-
//
|
|
237
|
+
// Clear cached person properties on reset
|
|
258
238
|
this._cachedPersonProperties = null;
|
|
259
239
|
this.saveUserIdentity();
|
|
260
|
-
//
|
|
240
|
+
// Set $last_vtilt_reset property
|
|
261
241
|
// Store it in properties, it will be sent on the next event
|
|
262
242
|
this.userIdentity.properties = {
|
|
263
243
|
...this.userIdentity.properties,
|
|
264
|
-
$
|
|
244
|
+
$last_vtilt_reset: new Date().toISOString(),
|
|
265
245
|
};
|
|
266
246
|
this.saveUserIdentity();
|
|
267
247
|
}
|
|
@@ -283,53 +263,105 @@ class UserManager {
|
|
|
283
263
|
getUserState() {
|
|
284
264
|
return this.userIdentity.user_state;
|
|
285
265
|
}
|
|
266
|
+
/**
|
|
267
|
+
* Update distinct ID (internal use - for VTilt)
|
|
268
|
+
*/
|
|
269
|
+
setDistinctId(distinctId) {
|
|
270
|
+
this.userIdentity.distinct_id = distinctId;
|
|
271
|
+
this.saveUserIdentity();
|
|
272
|
+
}
|
|
273
|
+
/**
|
|
274
|
+
* Update user state (internal use - for VTilt)
|
|
275
|
+
*/
|
|
276
|
+
setUserState(state) {
|
|
277
|
+
this.userIdentity.user_state = state;
|
|
278
|
+
this.saveUserIdentity();
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* Update user properties (internal use - for VTilt)
|
|
282
|
+
*/
|
|
283
|
+
updateUserProperties(userPropertiesToSet, userPropertiesToSetOnce) {
|
|
284
|
+
// Handle $set properties (update existing)
|
|
285
|
+
if (userPropertiesToSet) {
|
|
286
|
+
this.userIdentity.properties = {
|
|
287
|
+
...this.userIdentity.properties,
|
|
288
|
+
...userPropertiesToSet,
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
// Handle $set_once properties (preserve first value)
|
|
292
|
+
if (userPropertiesToSetOnce) {
|
|
293
|
+
Object.keys(userPropertiesToSetOnce).forEach((key) => {
|
|
294
|
+
if (!(key in this.userIdentity.properties)) {
|
|
295
|
+
this.userIdentity.properties[key] = userPropertiesToSetOnce[key];
|
|
296
|
+
}
|
|
297
|
+
});
|
|
298
|
+
}
|
|
299
|
+
this.saveUserIdentity();
|
|
300
|
+
}
|
|
301
|
+
/**
|
|
302
|
+
* Set device ID if not already set (internal use - for VTilt)
|
|
303
|
+
*/
|
|
304
|
+
ensureDeviceId(deviceId) {
|
|
305
|
+
if (!this.userIdentity.device_id) {
|
|
306
|
+
this.userIdentity.device_id = deviceId;
|
|
307
|
+
this.userIdentity.properties = {
|
|
308
|
+
...this.userIdentity.properties,
|
|
309
|
+
$had_persisted_distinct_id: true,
|
|
310
|
+
$device_id: deviceId,
|
|
311
|
+
};
|
|
312
|
+
this.saveUserIdentity();
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
/**
|
|
316
|
+
* Check if distinct ID is string-like (hardcoded string) - public for validation
|
|
317
|
+
* This is a wrapper to expose the private method
|
|
318
|
+
*/
|
|
319
|
+
isDistinctIdStringLikePublic(distinctId) {
|
|
320
|
+
return this.isDistinctIdStringLike(distinctId);
|
|
321
|
+
}
|
|
286
322
|
/**
|
|
287
323
|
* Create an alias to link two distinct IDs
|
|
288
|
-
*
|
|
289
|
-
* If alias matches original,
|
|
324
|
+
* If original is not provided, uses current distinct_id
|
|
325
|
+
* If alias matches original, returns null (caller should use identify instead)
|
|
290
326
|
*
|
|
291
327
|
* @param alias - A unique identifier that you want to use for this user in the future
|
|
292
328
|
* @param original - The current identifier being used for this user (optional, defaults to current distinct_id)
|
|
329
|
+
* @returns AliasEvent if alias was created, null if alias matches original or invalid
|
|
293
330
|
*/
|
|
294
331
|
createAlias(alias, original) {
|
|
295
332
|
if (!this.isValidDistinctId(alias)) {
|
|
296
333
|
console.warn("Invalid alias provided");
|
|
297
|
-
return;
|
|
334
|
+
return null;
|
|
298
335
|
}
|
|
299
|
-
//
|
|
336
|
+
// If original is not provided, use current distinct_id
|
|
300
337
|
if (original === undefined) {
|
|
301
338
|
original = this.getDistinctId() || this.getAnonymousId();
|
|
302
339
|
}
|
|
303
340
|
if (!this.isValidDistinctId(original)) {
|
|
304
341
|
console.warn("Invalid original distinct ID");
|
|
305
|
-
return;
|
|
342
|
+
return null;
|
|
306
343
|
}
|
|
307
|
-
//
|
|
344
|
+
// If alias matches original, return null (caller should use identify)
|
|
308
345
|
if (alias === original) {
|
|
309
|
-
console.warn("alias matches current distinct_id -
|
|
310
|
-
|
|
311
|
-
return;
|
|
346
|
+
console.warn("alias matches current distinct_id - should use identify instead");
|
|
347
|
+
return null;
|
|
312
348
|
}
|
|
313
349
|
// { distinct_id: alias, original: original }
|
|
314
350
|
const aliasEvent = {
|
|
315
351
|
distinct_id: alias,
|
|
316
352
|
original,
|
|
317
353
|
};
|
|
318
|
-
//
|
|
319
|
-
|
|
320
|
-
detail: aliasEvent,
|
|
321
|
-
});
|
|
322
|
-
window.dispatchEvent(customEvent);
|
|
354
|
+
// Note: Event sending is now handled by VTilt.createAlias()
|
|
355
|
+
return aliasEvent;
|
|
323
356
|
}
|
|
324
357
|
/**
|
|
325
358
|
* Validate distinct ID to prevent hardcoded strings
|
|
326
|
-
* Copied from PostHog's validation logic
|
|
327
359
|
*/
|
|
328
360
|
isValidDistinctId(distinctId) {
|
|
329
361
|
if (!distinctId || typeof distinctId !== "string") {
|
|
330
362
|
return false;
|
|
331
363
|
}
|
|
332
|
-
//
|
|
364
|
+
// Validation patterns
|
|
333
365
|
const invalidPatterns = [
|
|
334
366
|
"null",
|
|
335
367
|
"undefined",
|
|
@@ -356,13 +388,12 @@ class UserManager {
|
|
|
356
388
|
}
|
|
357
389
|
/**
|
|
358
390
|
* Check if distinct ID is string-like (hardcoded string)
|
|
359
|
-
* Copied from PostHog's isDistinctIdStringLike function
|
|
360
391
|
*/
|
|
361
392
|
isDistinctIdStringLike(distinctId) {
|
|
362
393
|
if (!distinctId || typeof distinctId !== "string") {
|
|
363
394
|
return false;
|
|
364
395
|
}
|
|
365
|
-
//
|
|
396
|
+
// Hardcoded string patterns
|
|
366
397
|
const hardcodedPatterns = [
|
|
367
398
|
"null",
|
|
368
399
|
"undefined",
|
|
@@ -432,26 +463,6 @@ class UserManager {
|
|
|
432
463
|
generateDeviceId() {
|
|
433
464
|
return `device_${(0, utils_1.uuidv4)()}`;
|
|
434
465
|
}
|
|
435
|
-
/**
|
|
436
|
-
* Send identify event for session merging
|
|
437
|
-
*/
|
|
438
|
-
sendIdentifyEvent(distinctId, anonymousId, deviceId, propertyOperations) {
|
|
439
|
-
// This will be handled by the TrackingManager
|
|
440
|
-
// We'll emit a custom event that the TrackingManager can listen to
|
|
441
|
-
const identifyEvent = new CustomEvent("vtilt:identify", {
|
|
442
|
-
detail: {
|
|
443
|
-
distinct_id: distinctId,
|
|
444
|
-
anonymous_id: anonymousId,
|
|
445
|
-
device_id: deviceId,
|
|
446
|
-
properties: {
|
|
447
|
-
$anon_distinct_id: anonymousId,
|
|
448
|
-
$device_id: deviceId,
|
|
449
|
-
...propertyOperations,
|
|
450
|
-
},
|
|
451
|
-
},
|
|
452
|
-
});
|
|
453
|
-
window.dispatchEvent(identifyEvent);
|
|
454
|
-
}
|
|
455
466
|
/**
|
|
456
467
|
* Get stored value from storage
|
|
457
468
|
*/
|
|
@@ -1,35 +1,34 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Get browser language
|
|
2
|
+
* Get browser language
|
|
3
3
|
* Returns the browser's language setting (e.g., "en-US")
|
|
4
4
|
*/
|
|
5
5
|
export declare function getBrowserLanguage(): string | undefined;
|
|
6
6
|
/**
|
|
7
|
-
* Get browser language prefix
|
|
7
|
+
* Get browser language prefix
|
|
8
8
|
* Returns the language code without region (e.g., "en" from "en-US")
|
|
9
9
|
*/
|
|
10
10
|
export declare function getBrowserLanguagePrefix(): string | undefined;
|
|
11
11
|
/**
|
|
12
|
-
* Get referrer
|
|
12
|
+
* Get referrer
|
|
13
13
|
* Returns document.referrer or '$direct' if no referrer
|
|
14
14
|
*/
|
|
15
15
|
export declare function getReferrer(): string;
|
|
16
16
|
/**
|
|
17
|
-
* Get referring domain
|
|
17
|
+
* Get referring domain
|
|
18
18
|
* Returns the hostname of the referrer URL or '$direct' if no referrer
|
|
19
19
|
*/
|
|
20
20
|
export declare function getReferringDomain(): string;
|
|
21
21
|
/**
|
|
22
|
-
* Get timezone
|
|
22
|
+
* Get timezone
|
|
23
23
|
* Returns the timezone (e.g., "America/New_York")
|
|
24
24
|
*/
|
|
25
25
|
export declare function getTimezone(): string | undefined;
|
|
26
26
|
/**
|
|
27
|
-
* Get timezone offset
|
|
27
|
+
* Get timezone offset
|
|
28
28
|
* Returns the timezone offset in minutes
|
|
29
29
|
*/
|
|
30
30
|
export declare function getTimezoneOffset(): number | undefined;
|
|
31
31
|
/**
|
|
32
|
-
* Get event properties that should be added to all events
|
|
33
|
-
* Matches PostHog's getEventProperties() implementation
|
|
32
|
+
* Get event properties that should be added to all events
|
|
34
33
|
*/
|
|
35
34
|
export declare function getEventProperties(): Record<string, any>;
|
package/lib/utils/event-utils.js
CHANGED
|
@@ -12,7 +12,7 @@ const user_agent_utils_1 = require("./user-agent-utils");
|
|
|
12
12
|
// Library version - should match package.json version
|
|
13
13
|
const LIB_VERSION = "1.0.7"; // TODO: Auto-import from package.json
|
|
14
14
|
/**
|
|
15
|
-
* Get browser language
|
|
15
|
+
* Get browser language
|
|
16
16
|
* Returns the browser's language setting (e.g., "en-US")
|
|
17
17
|
*/
|
|
18
18
|
function getBrowserLanguage() {
|
|
@@ -24,7 +24,7 @@ function getBrowserLanguage() {
|
|
|
24
24
|
);
|
|
25
25
|
}
|
|
26
26
|
/**
|
|
27
|
-
* Get browser language prefix
|
|
27
|
+
* Get browser language prefix
|
|
28
28
|
* Returns the language code without region (e.g., "en" from "en-US")
|
|
29
29
|
*/
|
|
30
30
|
function getBrowserLanguagePrefix() {
|
|
@@ -32,14 +32,14 @@ function getBrowserLanguagePrefix() {
|
|
|
32
32
|
return typeof lang === "string" ? lang.split("-")[0] : undefined;
|
|
33
33
|
}
|
|
34
34
|
/**
|
|
35
|
-
* Get referrer
|
|
35
|
+
* Get referrer
|
|
36
36
|
* Returns document.referrer or '$direct' if no referrer
|
|
37
37
|
*/
|
|
38
38
|
function getReferrer() {
|
|
39
39
|
return (globals_1.document === null || globals_1.document === void 0 ? void 0 : globals_1.document.referrer) || "$direct";
|
|
40
40
|
}
|
|
41
41
|
/**
|
|
42
|
-
* Get referring domain
|
|
42
|
+
* Get referring domain
|
|
43
43
|
* Returns the hostname of the referrer URL or '$direct' if no referrer
|
|
44
44
|
*/
|
|
45
45
|
function getReferringDomain() {
|
|
@@ -55,7 +55,7 @@ function getReferringDomain() {
|
|
|
55
55
|
}
|
|
56
56
|
}
|
|
57
57
|
/**
|
|
58
|
-
* Get timezone
|
|
58
|
+
* Get timezone
|
|
59
59
|
* Returns the timezone (e.g., "America/New_York")
|
|
60
60
|
*/
|
|
61
61
|
function getTimezone() {
|
|
@@ -67,7 +67,7 @@ function getTimezone() {
|
|
|
67
67
|
}
|
|
68
68
|
}
|
|
69
69
|
/**
|
|
70
|
-
* Get timezone offset
|
|
70
|
+
* Get timezone offset
|
|
71
71
|
* Returns the timezone offset in minutes
|
|
72
72
|
*/
|
|
73
73
|
function getTimezoneOffset() {
|
|
@@ -79,15 +79,14 @@ function getTimezoneOffset() {
|
|
|
79
79
|
}
|
|
80
80
|
}
|
|
81
81
|
/**
|
|
82
|
-
* Generate insert ID for deduplication
|
|
82
|
+
* Generate insert ID for deduplication
|
|
83
83
|
*/
|
|
84
84
|
function generateInsertId() {
|
|
85
85
|
return (Math.random().toString(36).substring(2, 10) +
|
|
86
86
|
Math.random().toString(36).substring(2, 10));
|
|
87
87
|
}
|
|
88
88
|
/**
|
|
89
|
-
* Get event properties that should be added to all events
|
|
90
|
-
* Matches PostHog's getEventProperties() implementation
|
|
89
|
+
* Get event properties that should be added to all events
|
|
91
90
|
*/
|
|
92
91
|
function getEventProperties() {
|
|
93
92
|
const props = {};
|
package/lib/utils/index.d.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { EventPayload } from "../types";
|
|
2
1
|
/**
|
|
3
2
|
* Generate uuid to identify the session. Random, not data-derived
|
|
4
3
|
*/
|
|
@@ -11,10 +10,6 @@ export declare function isValidUserAgent(userAgent: string): boolean;
|
|
|
11
10
|
* Validate payload string
|
|
12
11
|
*/
|
|
13
12
|
export declare function isValidPayload(payloadStr: string): boolean;
|
|
14
|
-
/**
|
|
15
|
-
* Try to mask PPI and potential sensible attributes
|
|
16
|
-
*/
|
|
17
|
-
export declare function maskSuspiciousAttributes(payload: EventPayload): string;
|
|
18
13
|
/**
|
|
19
14
|
* Check if current environment is a test environment
|
|
20
15
|
*/
|
package/lib/utils/index.js
CHANGED
|
@@ -3,11 +3,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.uuidv4 = uuidv4;
|
|
4
4
|
exports.isValidUserAgent = isValidUserAgent;
|
|
5
5
|
exports.isValidPayload = isValidPayload;
|
|
6
|
-
exports.maskSuspiciousAttributes = maskSuspiciousAttributes;
|
|
7
6
|
exports.isTestEnvironment = isTestEnvironment;
|
|
8
7
|
exports.each = each;
|
|
9
8
|
exports.addEventListener = addEventListener;
|
|
10
|
-
const constants_1 = require("../constants");
|
|
11
9
|
/**
|
|
12
10
|
* Generate uuid to identify the session. Random, not data-derived
|
|
13
11
|
*/
|
|
@@ -40,17 +38,6 @@ function isValidPayload(payloadStr) {
|
|
|
40
38
|
}
|
|
41
39
|
return true;
|
|
42
40
|
}
|
|
43
|
-
/**
|
|
44
|
-
* Try to mask PPI and potential sensible attributes
|
|
45
|
-
*/
|
|
46
|
-
function maskSuspiciousAttributes(payload) {
|
|
47
|
-
// Deep copy
|
|
48
|
-
let _payload = JSON.stringify(payload);
|
|
49
|
-
constants_1.ATTRIBUTES_TO_MASK.forEach((attr) => {
|
|
50
|
-
_payload = _payload.replace(new RegExp(`("${attr}"):(".+?"|\\d+)`, "gmi"), '$1:"********"');
|
|
51
|
-
});
|
|
52
|
-
return _payload;
|
|
53
|
-
}
|
|
54
41
|
/**
|
|
55
42
|
* Check if current environment is a test environment
|
|
56
43
|
*/
|
package/lib/utils/patch.d.ts
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Patch utility for wrapping native methods
|
|
3
|
-
* Based on PostHog's patch implementation from rrweb
|
|
4
3
|
*/
|
|
5
|
-
export declare const isFunction: (f: any) => f is (...args: any[]) => any;
|
|
6
4
|
export declare function patch(source: {
|
|
7
5
|
[key: string]: any;
|
|
8
6
|
}, name: string, replacement: (...args: unknown[]) => unknown): () => void;
|
package/lib/utils/patch.js
CHANGED
|
@@ -1,15 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/**
|
|
3
3
|
* Patch utility for wrapping native methods
|
|
4
|
-
* Based on PostHog's patch implementation from rrweb
|
|
5
4
|
*/
|
|
6
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
-
exports.isFunction = void 0;
|
|
8
6
|
exports.patch = patch;
|
|
9
|
-
const
|
|
10
|
-
return typeof f === "function";
|
|
11
|
-
};
|
|
12
|
-
exports.isFunction = isFunction;
|
|
7
|
+
const type_utils_1 = require("./type-utils");
|
|
13
8
|
function patch(source, name, replacement) {
|
|
14
9
|
try {
|
|
15
10
|
if (!(name in source)) {
|
|
@@ -21,7 +16,7 @@ function patch(source, name, replacement) {
|
|
|
21
16
|
const wrapped = replacement(original);
|
|
22
17
|
// Make sure it's a function first, as we need to attach an empty prototype for `defineProperties` to work
|
|
23
18
|
// otherwise it'll throw "TypeError: Object.defineProperties called on non-object"
|
|
24
|
-
if ((0,
|
|
19
|
+
if ((0, type_utils_1.isFunction)(wrapped)) {
|
|
25
20
|
wrapped.prototype = wrapped.prototype || {};
|
|
26
21
|
Object.defineProperties(wrapped, {
|
|
27
22
|
__vtilt_wrapped__: {
|
|
@@ -213,12 +213,7 @@ const detectBrowserVersion = function (userAgent, vendor) {
|
|
|
213
213
|
return null;
|
|
214
214
|
};
|
|
215
215
|
exports.detectBrowserVersion = detectBrowserVersion;
|
|
216
|
-
|
|
217
|
-
* Helper to check if value is a function (type guard)
|
|
218
|
-
*/
|
|
219
|
-
function isFunction(value) {
|
|
220
|
-
return typeof value === "function";
|
|
221
|
-
}
|
|
216
|
+
const type_utils_1 = require("./type-utils");
|
|
222
217
|
// to avoid repeating regexes or calling them twice, we have an array of matches
|
|
223
218
|
// the first regex that matches uses its matcher function to return the result
|
|
224
219
|
const osMatchers = [
|
|
@@ -308,17 +303,10 @@ const detectOS = function (user_agent) {
|
|
|
308
303
|
for (let i = 0; i < osMatchers.length; i++) {
|
|
309
304
|
const [rgex, resultOrFn] = osMatchers[i];
|
|
310
305
|
const match = rgex.exec(user_agent);
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
}
|
|
316
|
-
else {
|
|
317
|
-
result = resultOrFn;
|
|
318
|
-
}
|
|
319
|
-
if (result) {
|
|
320
|
-
return result;
|
|
321
|
-
}
|
|
306
|
+
const result = match &&
|
|
307
|
+
((0, type_utils_1.isFunction)(resultOrFn) ? resultOrFn(match, user_agent) : resultOrFn);
|
|
308
|
+
if (result) {
|
|
309
|
+
return result;
|
|
322
310
|
}
|
|
323
311
|
}
|
|
324
312
|
return ["", ""];
|