@v-tilt/browser 1.1.1 → 1.1.3
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 +2 -2
- package/dist/main.js +1 -1
- package/dist/main.js.map +1 -1
- package/dist/module.d.ts +8 -8
- package/dist/module.js +1 -1
- package/dist/module.js.map +1 -1
- package/dist/module.no-external.d.ts +8 -8
- package/dist/module.no-external.js +1 -1
- package/dist/module.no-external.js.map +1 -1
- package/dist/session.d.ts +22 -41
- package/dist/storage.d.ts +95 -0
- package/dist/types.d.ts +8 -8
- package/dist/user-manager.d.ts +49 -92
- package/lib/config.js +4 -1
- package/lib/constants.d.ts +2 -2
- package/lib/constants.js +510 -510
- package/lib/session.d.ts +22 -41
- package/lib/session.js +104 -150
- package/lib/storage.d.ts +95 -0
- package/lib/storage.js +291 -0
- package/lib/types.d.ts +8 -8
- package/lib/user-manager.d.ts +49 -92
- package/lib/user-manager.js +183 -293
- package/lib/vtilt.js +4 -2
- package/package.json +1 -1
package/lib/user-manager.js
CHANGED
|
@@ -1,16 +1,35 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* User Manager - Handles user identity and properties
|
|
4
|
+
*
|
|
5
|
+
* Uses shared StorageManager for consistent storage operations.
|
|
6
|
+
*
|
|
7
|
+
* Manages:
|
|
8
|
+
* - anonymous_id: Generated ID for anonymous users
|
|
9
|
+
* - distinct_id: User-provided ID after identification
|
|
10
|
+
* - device_id: Persistent device identifier
|
|
11
|
+
* - user_properties: Custom properties set via identify/setUserProperties
|
|
12
|
+
* - user_state: "anonymous" or "identified"
|
|
13
|
+
*/
|
|
2
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
15
|
exports.UserManager = void 0;
|
|
4
16
|
const constants_1 = require("./constants");
|
|
5
17
|
const utils_1 = require("./utils");
|
|
6
18
|
const event_utils_1 = require("./utils/event-utils");
|
|
19
|
+
const storage_1 = require("./storage");
|
|
7
20
|
class UserManager {
|
|
8
21
|
constructor(storageMethod = "localStorage", domain) {
|
|
9
22
|
this._cachedPersonProperties = null; // Cache for deduplication
|
|
10
|
-
this.
|
|
11
|
-
|
|
23
|
+
this.storage = new storage_1.StorageManager({
|
|
24
|
+
method: storageMethod,
|
|
25
|
+
domain,
|
|
26
|
+
sameSite: "Lax",
|
|
27
|
+
});
|
|
12
28
|
this.userIdentity = this.loadUserIdentity();
|
|
13
29
|
}
|
|
30
|
+
// ============================================================================
|
|
31
|
+
// Public Getters
|
|
32
|
+
// ============================================================================
|
|
14
33
|
/**
|
|
15
34
|
* Get current user identity
|
|
16
35
|
*/
|
|
@@ -30,8 +49,7 @@ class UserManager {
|
|
|
30
49
|
if (!this.userIdentity.anonymous_id) {
|
|
31
50
|
// Regenerate if somehow undefined
|
|
32
51
|
this.userIdentity.anonymous_id = this.generateAnonymousId();
|
|
33
|
-
|
|
34
|
-
this.setStoredValue(constants_1.ANONYMOUS_ID_KEY, this.userIdentity.anonymous_id);
|
|
52
|
+
this.storage.set(constants_1.ANONYMOUS_ID_KEY, this.userIdentity.anonymous_id, storage_1.USER_COOKIE_MAX_AGE);
|
|
35
53
|
}
|
|
36
54
|
return this.userIdentity.anonymous_id;
|
|
37
55
|
}
|
|
@@ -41,6 +59,27 @@ class UserManager {
|
|
|
41
59
|
getUserProperties() {
|
|
42
60
|
return { ...this.userIdentity.properties };
|
|
43
61
|
}
|
|
62
|
+
/**
|
|
63
|
+
* Get the effective ID for event tracking
|
|
64
|
+
*/
|
|
65
|
+
getEffectiveId() {
|
|
66
|
+
return this.userIdentity.distinct_id || this.getAnonymousId();
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Get current device ID
|
|
70
|
+
*/
|
|
71
|
+
getDeviceId() {
|
|
72
|
+
return this.userIdentity.device_id;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Get current user state
|
|
76
|
+
*/
|
|
77
|
+
getUserState() {
|
|
78
|
+
return this.userIdentity.user_state;
|
|
79
|
+
}
|
|
80
|
+
// ============================================================================
|
|
81
|
+
// Identity Operations
|
|
82
|
+
// ============================================================================
|
|
44
83
|
/**
|
|
45
84
|
* Identify a user with distinct ID and properties
|
|
46
85
|
*/
|
|
@@ -148,25 +187,6 @@ class UserManager {
|
|
|
148
187
|
}
|
|
149
188
|
/**
|
|
150
189
|
* Set user properties without changing distinct ID
|
|
151
|
-
* Sets properties on the person profile associated with the current distinct_id
|
|
152
|
-
*
|
|
153
|
-
* @example
|
|
154
|
-
* ```js
|
|
155
|
-
* // Set properties that can be updated
|
|
156
|
-
* vt.setUserProperties({ name: 'John Doe', email: 'john@example.com' })
|
|
157
|
-
* ```
|
|
158
|
-
*
|
|
159
|
-
* @example
|
|
160
|
-
* ```js
|
|
161
|
-
* // Set properties with $set and $set_once operations
|
|
162
|
-
* vt.setUserProperties(
|
|
163
|
-
* { name: 'John Doe', last_login: new Date().toISOString() }, // $set properties
|
|
164
|
-
* { first_login: new Date().toISOString() } // $set_once properties
|
|
165
|
-
* )
|
|
166
|
-
* ```
|
|
167
|
-
*
|
|
168
|
-
* @param userPropertiesToSet Optional: Properties to set (can be updated)
|
|
169
|
-
* @param userPropertiesToSetOnce Optional: Properties to set once (preserves first value)
|
|
170
190
|
*/
|
|
171
191
|
setUserProperties(userPropertiesToSet, userPropertiesToSetOnce) {
|
|
172
192
|
// Return early if no properties provided
|
|
@@ -203,23 +223,9 @@ class UserManager {
|
|
|
203
223
|
// Note: Event sending is now handled by VTilt.setUserProperties()
|
|
204
224
|
return true;
|
|
205
225
|
}
|
|
206
|
-
/**
|
|
207
|
-
* Get hash for person properties
|
|
208
|
-
* Used for deduplication of identical setUserProperties calls
|
|
209
|
-
*/
|
|
210
|
-
getPersonPropertiesHash(distinctId, userPropertiesToSet, userPropertiesToSetOnce) {
|
|
211
|
-
// Create deterministic hash from distinct_id and properties
|
|
212
|
-
return JSON.stringify({
|
|
213
|
-
distinct_id: distinctId,
|
|
214
|
-
userPropertiesToSet,
|
|
215
|
-
userPropertiesToSetOnce,
|
|
216
|
-
});
|
|
217
|
-
}
|
|
218
226
|
/**
|
|
219
227
|
* Reset user identity (logout)
|
|
220
228
|
* Generates new anonymous ID, clears user data, optionally resets device ID
|
|
221
|
-
*
|
|
222
|
-
* @param reset_device_id - If true, also resets device_id. Default: false (preserves device_id)
|
|
223
229
|
*/
|
|
224
230
|
reset(reset_device_id) {
|
|
225
231
|
// Generate completely new anonymous ID (don't revert to original)
|
|
@@ -245,24 +251,9 @@ class UserManager {
|
|
|
245
251
|
};
|
|
246
252
|
this.saveUserIdentity();
|
|
247
253
|
}
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
getEffectiveId() {
|
|
252
|
-
return this.userIdentity.distinct_id || this.getAnonymousId();
|
|
253
|
-
}
|
|
254
|
-
/**
|
|
255
|
-
* Get current device ID
|
|
256
|
-
*/
|
|
257
|
-
getDeviceId() {
|
|
258
|
-
return this.userIdentity.device_id;
|
|
259
|
-
}
|
|
260
|
-
/**
|
|
261
|
-
* Get current user state
|
|
262
|
-
*/
|
|
263
|
-
getUserState() {
|
|
264
|
-
return this.userIdentity.user_state;
|
|
265
|
-
}
|
|
254
|
+
// ============================================================================
|
|
255
|
+
// Internal Setters (for VTilt class)
|
|
256
|
+
// ============================================================================
|
|
266
257
|
/**
|
|
267
258
|
* Update distinct ID (internal use - for VTilt)
|
|
268
259
|
*/
|
|
@@ -312,21 +303,11 @@ class UserManager {
|
|
|
312
303
|
this.saveUserIdentity();
|
|
313
304
|
}
|
|
314
305
|
}
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
*/
|
|
319
|
-
isDistinctIdStringLikePublic(distinctId) {
|
|
320
|
-
return this.isDistinctIdStringLike(distinctId);
|
|
321
|
-
}
|
|
306
|
+
// ============================================================================
|
|
307
|
+
// Alias Operations
|
|
308
|
+
// ============================================================================
|
|
322
309
|
/**
|
|
323
310
|
* Create an alias to link two distinct IDs
|
|
324
|
-
* If original is not provided, uses current distinct_id
|
|
325
|
-
* If alias matches original, returns null (caller should use identify instead)
|
|
326
|
-
*
|
|
327
|
-
* @param alias - A unique identifier that you want to use for this user in the future
|
|
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
|
|
330
311
|
*/
|
|
331
312
|
createAlias(alias, original) {
|
|
332
313
|
if (!this.isValidDistinctId(alias)) {
|
|
@@ -355,75 +336,58 @@ class UserManager {
|
|
|
355
336
|
return aliasEvent;
|
|
356
337
|
}
|
|
357
338
|
/**
|
|
358
|
-
*
|
|
339
|
+
* Check if distinct ID is string-like (hardcoded string) - public for validation
|
|
359
340
|
*/
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
"guest",
|
|
375
|
-
"visitor",
|
|
376
|
-
"unknown",
|
|
377
|
-
"none",
|
|
378
|
-
];
|
|
379
|
-
const lower = distinctId.toLowerCase().trim();
|
|
380
|
-
if (invalidPatterns.includes(lower)) {
|
|
381
|
-
return false;
|
|
382
|
-
}
|
|
383
|
-
// Check for empty or whitespace-only strings
|
|
384
|
-
if (distinctId.trim().length === 0) {
|
|
385
|
-
return false;
|
|
341
|
+
isDistinctIdStringLikePublic(distinctId) {
|
|
342
|
+
return this.isDistinctIdStringLike(distinctId);
|
|
343
|
+
}
|
|
344
|
+
// ============================================================================
|
|
345
|
+
// Initial Person Info
|
|
346
|
+
// ============================================================================
|
|
347
|
+
/**
|
|
348
|
+
* Set initial person info
|
|
349
|
+
*/
|
|
350
|
+
set_initial_person_info(maskPersonalDataProperties, customPersonalDataProperties) {
|
|
351
|
+
const stored = this.getStoredUserProperties();
|
|
352
|
+
// Check if already set (backwards compatibility check)
|
|
353
|
+
if (stored[constants_1.INITIAL_PERSON_INFO]) {
|
|
354
|
+
return;
|
|
386
355
|
}
|
|
387
|
-
|
|
356
|
+
const personInfo = (0, event_utils_1.getPersonInfo)(maskPersonalDataProperties, customPersonalDataProperties);
|
|
357
|
+
this.register_once({
|
|
358
|
+
[constants_1.INITIAL_PERSON_INFO]: personInfo,
|
|
359
|
+
}, undefined);
|
|
388
360
|
}
|
|
389
361
|
/**
|
|
390
|
-
*
|
|
362
|
+
* Get initial props
|
|
391
363
|
*/
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
364
|
+
get_initial_props() {
|
|
365
|
+
const stored = this.getStoredUserProperties();
|
|
366
|
+
const initialPersonInfo = stored[constants_1.INITIAL_PERSON_INFO];
|
|
367
|
+
if (!initialPersonInfo) {
|
|
368
|
+
return {};
|
|
395
369
|
}
|
|
396
|
-
|
|
397
|
-
const hardcodedPatterns = [
|
|
398
|
-
"null",
|
|
399
|
-
"undefined",
|
|
400
|
-
"false",
|
|
401
|
-
"true",
|
|
402
|
-
"anonymous",
|
|
403
|
-
"anon",
|
|
404
|
-
"user",
|
|
405
|
-
"test",
|
|
406
|
-
"guest",
|
|
407
|
-
"visitor",
|
|
408
|
-
"unknown",
|
|
409
|
-
"none",
|
|
410
|
-
"demo",
|
|
411
|
-
"example",
|
|
412
|
-
"sample",
|
|
413
|
-
"placeholder",
|
|
414
|
-
];
|
|
415
|
-
const lower = distinctId.toLowerCase().trim();
|
|
416
|
-
return hardcodedPatterns.includes(lower);
|
|
370
|
+
return (0, event_utils_1.getInitialPersonPropsFromInfo)(initialPersonInfo);
|
|
417
371
|
}
|
|
372
|
+
/**
|
|
373
|
+
* Update referrer info
|
|
374
|
+
*/
|
|
375
|
+
update_referrer_info() {
|
|
376
|
+
const referrerInfo = (0, event_utils_1.getReferrerInfo)();
|
|
377
|
+
this.register_once(referrerInfo, undefined);
|
|
378
|
+
}
|
|
379
|
+
// ============================================================================
|
|
380
|
+
// Storage Operations (using StorageManager)
|
|
381
|
+
// ============================================================================
|
|
418
382
|
/**
|
|
419
383
|
* Load user identity from storage
|
|
420
384
|
*/
|
|
421
385
|
loadUserIdentity() {
|
|
422
|
-
const anonymousId = this.
|
|
423
|
-
const distinctId = this.
|
|
424
|
-
const deviceId = this.
|
|
386
|
+
const anonymousId = this.storage.get(constants_1.ANONYMOUS_ID_KEY) || this.generateAnonymousId();
|
|
387
|
+
const distinctId = this.storage.get(constants_1.DISTINCT_ID_KEY) || null;
|
|
388
|
+
const deviceId = this.storage.get(constants_1.DEVICE_ID_KEY) || this.generateDeviceId();
|
|
425
389
|
const properties = this.getStoredUserProperties();
|
|
426
|
-
const userState = this.
|
|
390
|
+
const userState = this.storage.get(constants_1.USER_STATE_KEY) ||
|
|
427
391
|
"anonymous";
|
|
428
392
|
// Ensure anonymous_id is never undefined
|
|
429
393
|
const safeAnonymousId = anonymousId || this.generateAnonymousId();
|
|
@@ -440,167 +404,31 @@ class UserManager {
|
|
|
440
404
|
* Save user identity to storage
|
|
441
405
|
*/
|
|
442
406
|
saveUserIdentity() {
|
|
443
|
-
this.
|
|
444
|
-
this.
|
|
445
|
-
this.
|
|
407
|
+
this.storage.set(constants_1.ANONYMOUS_ID_KEY, this.userIdentity.anonymous_id, storage_1.USER_COOKIE_MAX_AGE);
|
|
408
|
+
this.storage.set(constants_1.DEVICE_ID_KEY, this.userIdentity.device_id, storage_1.USER_COOKIE_MAX_AGE);
|
|
409
|
+
this.storage.set(constants_1.USER_STATE_KEY, this.userIdentity.user_state, storage_1.USER_COOKIE_MAX_AGE);
|
|
446
410
|
if (this.userIdentity.distinct_id) {
|
|
447
|
-
this.
|
|
411
|
+
this.storage.set(constants_1.DISTINCT_ID_KEY, this.userIdentity.distinct_id, storage_1.USER_COOKIE_MAX_AGE);
|
|
448
412
|
}
|
|
449
413
|
else {
|
|
450
|
-
this.
|
|
414
|
+
this.storage.remove(constants_1.DISTINCT_ID_KEY);
|
|
451
415
|
}
|
|
452
416
|
this.setStoredUserProperties(this.userIdentity.properties);
|
|
453
417
|
}
|
|
454
|
-
/**
|
|
455
|
-
* Generate a new anonymous ID
|
|
456
|
-
*/
|
|
457
|
-
generateAnonymousId() {
|
|
458
|
-
return `anon_${(0, utils_1.uuidv4)()}`;
|
|
459
|
-
}
|
|
460
|
-
/**
|
|
461
|
-
* Generate a new device ID
|
|
462
|
-
*/
|
|
463
|
-
generateDeviceId() {
|
|
464
|
-
return `device_${(0, utils_1.uuidv4)()}`;
|
|
465
|
-
}
|
|
466
|
-
/**
|
|
467
|
-
* Get stored value from storage
|
|
468
|
-
*/
|
|
469
|
-
getStoredValue(key) {
|
|
470
|
-
try {
|
|
471
|
-
// Memory mode doesn't persist - return null (will use in-memory userIdentity)
|
|
472
|
-
if (this.storageMethod === constants_1.PERSISTENCE_METHODS.memory) {
|
|
473
|
-
return null;
|
|
474
|
-
}
|
|
475
|
-
if (this.storageMethod === constants_1.PERSISTENCE_METHODS.localStorage ||
|
|
476
|
-
this.storageMethod === constants_1.PERSISTENCE_METHODS.localStoragePlusCookie) {
|
|
477
|
-
// Try localStorage first for localStorage and localStorage+cookie modes
|
|
478
|
-
const value = localStorage.getItem(key);
|
|
479
|
-
if (value !== null) {
|
|
480
|
-
return value;
|
|
481
|
-
}
|
|
482
|
-
// Fall back to cookie for localStorage+cookie mode
|
|
483
|
-
if (this.storageMethod === constants_1.PERSISTENCE_METHODS.localStoragePlusCookie) {
|
|
484
|
-
return this.getCookieValue(key);
|
|
485
|
-
}
|
|
486
|
-
return null;
|
|
487
|
-
}
|
|
488
|
-
else {
|
|
489
|
-
// Cookie-only mode
|
|
490
|
-
return this.getCookieValue(key);
|
|
491
|
-
}
|
|
492
|
-
}
|
|
493
|
-
catch (error) {
|
|
494
|
-
// If storage access fails, return null
|
|
495
|
-
console.warn("Failed to access storage:", error);
|
|
496
|
-
return null;
|
|
497
|
-
}
|
|
498
|
-
}
|
|
499
|
-
/**
|
|
500
|
-
* Set stored value in storage
|
|
501
|
-
*/
|
|
502
|
-
setStoredValue(key, value) {
|
|
503
|
-
try {
|
|
504
|
-
// Memory mode doesn't persist
|
|
505
|
-
if (this.storageMethod === constants_1.PERSISTENCE_METHODS.memory) {
|
|
506
|
-
return;
|
|
507
|
-
}
|
|
508
|
-
if (this.storageMethod === constants_1.PERSISTENCE_METHODS.localStorage) {
|
|
509
|
-
localStorage.setItem(key, value);
|
|
510
|
-
}
|
|
511
|
-
else if (this.storageMethod === constants_1.PERSISTENCE_METHODS.localStoragePlusCookie) {
|
|
512
|
-
// Store in both localStorage and cookie
|
|
513
|
-
localStorage.setItem(key, value);
|
|
514
|
-
this.setCookieValue(key, value);
|
|
515
|
-
}
|
|
516
|
-
else {
|
|
517
|
-
// Cookie-only mode
|
|
518
|
-
this.setCookieValue(key, value);
|
|
519
|
-
}
|
|
520
|
-
}
|
|
521
|
-
catch (error) {
|
|
522
|
-
// If storage access fails, log warning but don't throw
|
|
523
|
-
console.warn("Failed to save to storage:", error);
|
|
524
|
-
}
|
|
525
|
-
}
|
|
526
|
-
/**
|
|
527
|
-
* Remove stored value from storage
|
|
528
|
-
*/
|
|
529
|
-
removeStoredValue(key) {
|
|
530
|
-
// Memory mode doesn't persist
|
|
531
|
-
if (this.storageMethod === constants_1.PERSISTENCE_METHODS.memory) {
|
|
532
|
-
return;
|
|
533
|
-
}
|
|
534
|
-
if (this.storageMethod === constants_1.PERSISTENCE_METHODS.localStorage) {
|
|
535
|
-
localStorage.removeItem(key);
|
|
536
|
-
}
|
|
537
|
-
else if (this.storageMethod === constants_1.PERSISTENCE_METHODS.localStoragePlusCookie) {
|
|
538
|
-
// Remove from both localStorage and cookie
|
|
539
|
-
localStorage.removeItem(key);
|
|
540
|
-
this.removeCookieValue(key);
|
|
541
|
-
}
|
|
542
|
-
else {
|
|
543
|
-
// Cookie-only mode
|
|
544
|
-
this.removeCookieValue(key);
|
|
545
|
-
}
|
|
546
|
-
}
|
|
547
418
|
/**
|
|
548
419
|
* Get user properties from storage
|
|
549
420
|
*/
|
|
550
421
|
getStoredUserProperties() {
|
|
551
|
-
|
|
552
|
-
if (!stored) {
|
|
553
|
-
return {};
|
|
554
|
-
}
|
|
555
|
-
try {
|
|
556
|
-
return JSON.parse(stored);
|
|
557
|
-
}
|
|
558
|
-
catch (_a) {
|
|
559
|
-
return {};
|
|
560
|
-
}
|
|
422
|
+
return this.storage.getJSON(constants_1.USER_PROPERTIES_KEY) || {};
|
|
561
423
|
}
|
|
562
424
|
/**
|
|
563
425
|
* Set user properties in storage
|
|
564
426
|
*/
|
|
565
427
|
setStoredUserProperties(properties) {
|
|
566
|
-
this.
|
|
567
|
-
}
|
|
568
|
-
/**
|
|
569
|
-
* Get cookie value
|
|
570
|
-
*/
|
|
571
|
-
getCookieValue(name) {
|
|
572
|
-
const cookies = document.cookie.split(";");
|
|
573
|
-
for (const cookie of cookies) {
|
|
574
|
-
const [key, value] = cookie.trim().split("=");
|
|
575
|
-
if (key === name) {
|
|
576
|
-
return decodeURIComponent(value);
|
|
577
|
-
}
|
|
578
|
-
}
|
|
579
|
-
return null;
|
|
580
|
-
}
|
|
581
|
-
/**
|
|
582
|
-
* Set cookie value
|
|
583
|
-
*/
|
|
584
|
-
setCookieValue(name, value) {
|
|
585
|
-
let cookieValue = `${name}=${encodeURIComponent(value)}; Max-Age=31536000; path=/; secure; SameSite=Lax`;
|
|
586
|
-
if (this.domain) {
|
|
587
|
-
cookieValue += `; domain=${this.domain}`;
|
|
588
|
-
}
|
|
589
|
-
document.cookie = cookieValue;
|
|
590
|
-
}
|
|
591
|
-
/**
|
|
592
|
-
* Remove cookie value
|
|
593
|
-
*/
|
|
594
|
-
removeCookieValue(name) {
|
|
595
|
-
let cookieValue = `${name}=; Max-Age=0; path=/`;
|
|
596
|
-
if (this.domain) {
|
|
597
|
-
cookieValue += `; domain=${this.domain}`;
|
|
598
|
-
}
|
|
599
|
-
document.cookie = cookieValue;
|
|
428
|
+
this.storage.setJSON(constants_1.USER_PROPERTIES_KEY, properties, storage_1.USER_COOKIE_MAX_AGE);
|
|
600
429
|
}
|
|
601
430
|
/**
|
|
602
431
|
* Register a value once (only if not already set)
|
|
603
|
-
* Stores properties in localStorage only if they don't already exist
|
|
604
432
|
*/
|
|
605
433
|
register_once(props, defaultValues) {
|
|
606
434
|
const stored = this.getStoredUserProperties();
|
|
@@ -627,41 +455,103 @@ class UserManager {
|
|
|
627
455
|
this.setStoredUserProperties(stored);
|
|
628
456
|
}
|
|
629
457
|
}
|
|
458
|
+
// ============================================================================
|
|
459
|
+
// Utility Methods
|
|
460
|
+
// ============================================================================
|
|
630
461
|
/**
|
|
631
|
-
*
|
|
632
|
-
* Stores referrer and URL info on first visit for generating $initial_* properties
|
|
462
|
+
* Generate a new anonymous ID
|
|
633
463
|
*/
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
464
|
+
generateAnonymousId() {
|
|
465
|
+
return `anon_${(0, utils_1.uuidv4)()}`;
|
|
466
|
+
}
|
|
467
|
+
/**
|
|
468
|
+
* Generate a new device ID
|
|
469
|
+
*/
|
|
470
|
+
generateDeviceId() {
|
|
471
|
+
return `device_${(0, utils_1.uuidv4)()}`;
|
|
472
|
+
}
|
|
473
|
+
/**
|
|
474
|
+
* Get hash for person properties (for deduplication)
|
|
475
|
+
*/
|
|
476
|
+
getPersonPropertiesHash(distinctId, userPropertiesToSet, userPropertiesToSetOnce) {
|
|
477
|
+
return JSON.stringify({
|
|
478
|
+
distinct_id: distinctId,
|
|
479
|
+
userPropertiesToSet,
|
|
480
|
+
userPropertiesToSetOnce,
|
|
481
|
+
});
|
|
482
|
+
}
|
|
483
|
+
/**
|
|
484
|
+
* Validate distinct ID
|
|
485
|
+
*/
|
|
486
|
+
isValidDistinctId(distinctId) {
|
|
487
|
+
if (!distinctId || typeof distinctId !== "string") {
|
|
488
|
+
return false;
|
|
639
489
|
}
|
|
640
|
-
const
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
490
|
+
const invalidPatterns = [
|
|
491
|
+
"null",
|
|
492
|
+
"undefined",
|
|
493
|
+
"false",
|
|
494
|
+
"true",
|
|
495
|
+
"anonymous",
|
|
496
|
+
"anon",
|
|
497
|
+
"user",
|
|
498
|
+
"test",
|
|
499
|
+
"guest",
|
|
500
|
+
"visitor",
|
|
501
|
+
"unknown",
|
|
502
|
+
"none",
|
|
503
|
+
];
|
|
504
|
+
const lower = distinctId.toLowerCase().trim();
|
|
505
|
+
if (invalidPatterns.includes(lower)) {
|
|
506
|
+
return false;
|
|
507
|
+
}
|
|
508
|
+
if (distinctId.trim().length === 0) {
|
|
509
|
+
return false;
|
|
510
|
+
}
|
|
511
|
+
return true;
|
|
644
512
|
}
|
|
645
513
|
/**
|
|
646
|
-
*
|
|
647
|
-
* Generates $initial_* properties from stored initial person info
|
|
648
|
-
* These are sent with events as $set_once to preserve first values
|
|
514
|
+
* Check if distinct ID is string-like (hardcoded string)
|
|
649
515
|
*/
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
if (!initialPersonInfo) {
|
|
654
|
-
return {};
|
|
516
|
+
isDistinctIdStringLike(distinctId) {
|
|
517
|
+
if (!distinctId || typeof distinctId !== "string") {
|
|
518
|
+
return false;
|
|
655
519
|
}
|
|
656
|
-
|
|
520
|
+
const hardcodedPatterns = [
|
|
521
|
+
"null",
|
|
522
|
+
"undefined",
|
|
523
|
+
"false",
|
|
524
|
+
"true",
|
|
525
|
+
"anonymous",
|
|
526
|
+
"anon",
|
|
527
|
+
"user",
|
|
528
|
+
"test",
|
|
529
|
+
"guest",
|
|
530
|
+
"visitor",
|
|
531
|
+
"unknown",
|
|
532
|
+
"none",
|
|
533
|
+
"demo",
|
|
534
|
+
"example",
|
|
535
|
+
"sample",
|
|
536
|
+
"placeholder",
|
|
537
|
+
];
|
|
538
|
+
const lower = distinctId.toLowerCase().trim();
|
|
539
|
+
return hardcodedPatterns.includes(lower);
|
|
657
540
|
}
|
|
541
|
+
// ============================================================================
|
|
542
|
+
// Storage Management
|
|
543
|
+
// ============================================================================
|
|
658
544
|
/**
|
|
659
|
-
* Update
|
|
660
|
-
* Stores current referrer information if not already stored
|
|
545
|
+
* Update storage method at runtime
|
|
661
546
|
*/
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
547
|
+
updateStorageMethod(method, domain) {
|
|
548
|
+
this.storage = new storage_1.StorageManager({
|
|
549
|
+
method,
|
|
550
|
+
domain,
|
|
551
|
+
sameSite: "Lax",
|
|
552
|
+
});
|
|
553
|
+
// Reload identity from new storage
|
|
554
|
+
this.userIdentity = this.loadUserIdentity();
|
|
665
555
|
}
|
|
666
556
|
}
|
|
667
557
|
exports.UserManager = UserManager;
|
package/lib/vtilt.js
CHANGED
|
@@ -388,7 +388,8 @@ class VTilt {
|
|
|
388
388
|
// and cause unnecessary server processing for identity creation/updates.
|
|
389
389
|
const setOnce = {};
|
|
390
390
|
// Only include initial props if we haven't sent them yet this page load
|
|
391
|
-
if (!this._set_once_properties_sent &&
|
|
391
|
+
if (!this._set_once_properties_sent &&
|
|
392
|
+
Object.keys(initialProps).length > 0) {
|
|
392
393
|
Object.assign(setOnce, initialProps);
|
|
393
394
|
}
|
|
394
395
|
// Always merge with user-provided $set_once if present
|
|
@@ -410,7 +411,8 @@ class VTilt {
|
|
|
410
411
|
...payload, // User-provided payload (can override base and person properties)
|
|
411
412
|
};
|
|
412
413
|
// Mark that $set_once with initial props has been sent (only do this once per page load)
|
|
413
|
-
if (!this._set_once_properties_sent &&
|
|
414
|
+
if (!this._set_once_properties_sent &&
|
|
415
|
+
Object.keys(initialProps).length > 0) {
|
|
414
416
|
this._set_once_properties_sent = true;
|
|
415
417
|
}
|
|
416
418
|
// Add title only to $pageview events
|