@v-tilt/browser 1.6.0 → 1.7.2
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.full.js +1 -1
- package/dist/array.full.js.map +1 -1
- 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/chat.js +1 -1
- package/dist/chat.js.map +1 -1
- package/dist/constants.d.ts +1 -1
- package/dist/entrypoints/server.es.d.ts +12 -0
- package/dist/external-scripts-loader.js +1 -1
- package/dist/main.js +1 -1
- package/dist/main.js.map +1 -1
- package/dist/module.d.ts +6 -3
- package/dist/module.js +1 -1
- package/dist/module.js.map +1 -1
- package/dist/module.no-external.d.ts +6 -3
- package/dist/module.no-external.js +1 -1
- package/dist/module.no-external.js.map +1 -1
- package/dist/server.d.ts +105 -0
- package/dist/server.js +2 -0
- package/dist/server.js.map +1 -0
- package/dist/types.d.ts +3 -1
- package/dist/vtilt.d.ts +3 -2
- package/package.json +1 -2
- package/lib/config.d.ts +0 -17
- package/lib/config.js +0 -76
- package/lib/constants.d.ts +0 -178
- package/lib/constants.js +0 -656
- package/lib/entrypoints/all-external-dependencies.d.ts +0 -8
- package/lib/entrypoints/all-external-dependencies.js +0 -10
- package/lib/entrypoints/array.d.ts +0 -2
- package/lib/entrypoints/array.full.d.ts +0 -17
- package/lib/entrypoints/array.full.js +0 -19
- package/lib/entrypoints/array.js +0 -4
- package/lib/entrypoints/array.no-external.d.ts +0 -1
- package/lib/entrypoints/array.no-external.js +0 -4
- package/lib/entrypoints/chat.d.ts +0 -22
- package/lib/entrypoints/chat.js +0 -32
- package/lib/entrypoints/external-scripts-loader.d.ts +0 -24
- package/lib/entrypoints/external-scripts-loader.js +0 -104
- package/lib/entrypoints/main.cjs.d.ts +0 -4
- package/lib/entrypoints/main.cjs.js +0 -29
- package/lib/entrypoints/module.es.d.ts +0 -4
- package/lib/entrypoints/module.es.js +0 -23
- package/lib/entrypoints/module.no-external.es.d.ts +0 -4
- package/lib/entrypoints/module.no-external.es.js +0 -23
- package/lib/entrypoints/recorder.d.ts +0 -23
- package/lib/entrypoints/recorder.js +0 -42
- package/lib/entrypoints/web-vitals.d.ts +0 -14
- package/lib/entrypoints/web-vitals.js +0 -29
- package/lib/extensions/chat/chat-wrapper.d.ts +0 -196
- package/lib/extensions/chat/chat-wrapper.js +0 -545
- package/lib/extensions/chat/chat.d.ts +0 -99
- package/lib/extensions/chat/chat.js +0 -1891
- package/lib/extensions/chat/index.d.ts +0 -10
- package/lib/extensions/chat/index.js +0 -27
- package/lib/extensions/chat/types.d.ts +0 -159
- package/lib/extensions/chat/types.js +0 -22
- package/lib/extensions/history-autocapture.d.ts +0 -17
- package/lib/extensions/history-autocapture.js +0 -105
- package/lib/extensions/replay/index.d.ts +0 -13
- package/lib/extensions/replay/index.js +0 -31
- package/lib/extensions/replay/session-recording-utils.d.ts +0 -92
- package/lib/extensions/replay/session-recording-utils.js +0 -212
- package/lib/extensions/replay/session-recording-wrapper.d.ts +0 -61
- package/lib/extensions/replay/session-recording-wrapper.js +0 -149
- package/lib/extensions/replay/session-recording.d.ts +0 -95
- package/lib/extensions/replay/session-recording.js +0 -700
- package/lib/extensions/replay/types.d.ts +0 -211
- package/lib/extensions/replay/types.js +0 -8
- package/lib/geolocation.d.ts +0 -5
- package/lib/geolocation.js +0 -31
- package/lib/rate-limiter.d.ts +0 -52
- package/lib/rate-limiter.js +0 -80
- package/lib/request-queue.d.ts +0 -78
- package/lib/request-queue.js +0 -156
- package/lib/request.d.ts +0 -54
- package/lib/request.js +0 -265
- package/lib/retry-queue.d.ts +0 -64
- package/lib/retry-queue.js +0 -182
- package/lib/session.d.ts +0 -66
- package/lib/session.js +0 -191
- package/lib/storage.d.ts +0 -117
- package/lib/storage.js +0 -438
- package/lib/types.d.ts +0 -350
- package/lib/types.js +0 -24
- package/lib/user-manager.d.ts +0 -154
- package/lib/user-manager.js +0 -589
- package/lib/utils/event-utils.d.ts +0 -52
- package/lib/utils/event-utils.js +0 -305
- package/lib/utils/globals.d.ts +0 -235
- package/lib/utils/globals.js +0 -30
- package/lib/utils/index.d.ts +0 -46
- package/lib/utils/index.js +0 -134
- package/lib/utils/patch.d.ts +0 -6
- package/lib/utils/patch.js +0 -39
- package/lib/utils/request-utils.d.ts +0 -17
- package/lib/utils/request-utils.js +0 -80
- package/lib/utils/type-utils.d.ts +0 -4
- package/lib/utils/type-utils.js +0 -9
- package/lib/utils/user-agent-utils.d.ts +0 -18
- package/lib/utils/user-agent-utils.js +0 -411
- package/lib/vtilt.d.ts +0 -359
- package/lib/vtilt.js +0 -1188
- package/lib/web-vitals.d.ts +0 -95
- package/lib/web-vitals.js +0 -380
package/lib/user-manager.js
DELETED
|
@@ -1,589 +0,0 @@
|
|
|
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
|
-
*/
|
|
14
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
-
exports.UserManager = void 0;
|
|
16
|
-
const constants_1 = require("./constants");
|
|
17
|
-
const utils_1 = require("./utils");
|
|
18
|
-
const event_utils_1 = require("./utils/event-utils");
|
|
19
|
-
const storage_1 = require("./storage");
|
|
20
|
-
class UserManager {
|
|
21
|
-
constructor(storageMethod = "localStorage", cross_subdomain) {
|
|
22
|
-
this._cachedPersonProperties = null; // Cache for deduplication
|
|
23
|
-
this.storage = new storage_1.StorageManager({
|
|
24
|
-
method: storageMethod,
|
|
25
|
-
cross_subdomain,
|
|
26
|
-
sameSite: "Lax",
|
|
27
|
-
});
|
|
28
|
-
this.userIdentity = this.loadUserIdentity();
|
|
29
|
-
}
|
|
30
|
-
// ============================================================================
|
|
31
|
-
// Public Getters
|
|
32
|
-
// ============================================================================
|
|
33
|
-
/**
|
|
34
|
-
* Get current user identity
|
|
35
|
-
*/
|
|
36
|
-
getUserIdentity() {
|
|
37
|
-
return { ...this.userIdentity };
|
|
38
|
-
}
|
|
39
|
-
/**
|
|
40
|
-
* Get current distinct ID (identified user ID)
|
|
41
|
-
*/
|
|
42
|
-
getDistinctId() {
|
|
43
|
-
return this.userIdentity.distinct_id;
|
|
44
|
-
}
|
|
45
|
-
/**
|
|
46
|
-
* Get current anonymous ID
|
|
47
|
-
*/
|
|
48
|
-
getAnonymousId() {
|
|
49
|
-
if (!this.userIdentity.anonymous_id) {
|
|
50
|
-
// Regenerate if somehow undefined
|
|
51
|
-
this.userIdentity.anonymous_id = this.generateAnonymousId();
|
|
52
|
-
this.storage.set(constants_1.ANONYMOUS_ID_KEY, this.userIdentity.anonymous_id, storage_1.USER_COOKIE_MAX_AGE);
|
|
53
|
-
}
|
|
54
|
-
return this.userIdentity.anonymous_id;
|
|
55
|
-
}
|
|
56
|
-
/**
|
|
57
|
-
* Get current user properties
|
|
58
|
-
*/
|
|
59
|
-
getUserProperties() {
|
|
60
|
-
return { ...this.userIdentity.properties };
|
|
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
|
-
// ============================================================================
|
|
83
|
-
/**
|
|
84
|
-
* Identify a user with distinct ID and properties
|
|
85
|
-
*/
|
|
86
|
-
identify(newDistinctId, userPropertiesToSet, userPropertiesToSetOnce) {
|
|
87
|
-
// Validation: Convert number to string
|
|
88
|
-
if (typeof newDistinctId === "number") {
|
|
89
|
-
newDistinctId = newDistinctId.toString();
|
|
90
|
-
console.warn("The first argument to vTilt.identify was a number, but it should be a string. It has been converted to a string.");
|
|
91
|
-
}
|
|
92
|
-
// Validation: Check if distinct_id is provided
|
|
93
|
-
if (!newDistinctId) {
|
|
94
|
-
console.error("Unique user id has not been set in vTilt.identify");
|
|
95
|
-
return;
|
|
96
|
-
}
|
|
97
|
-
// Validation: Check for hardcoded strings
|
|
98
|
-
if (this.isDistinctIdStringLike(newDistinctId)) {
|
|
99
|
-
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.`);
|
|
100
|
-
return;
|
|
101
|
-
}
|
|
102
|
-
// Validation: Check for cookieless sentinel value
|
|
103
|
-
if (newDistinctId === "COOKIELESS_SENTINEL_VALUE") {
|
|
104
|
-
console.error(`The string "${newDistinctId}" was set in vTilt.identify which indicates an error. This ID is only used as a sentinel value.`);
|
|
105
|
-
return;
|
|
106
|
-
}
|
|
107
|
-
const previousDistinctId = this.userIdentity.distinct_id;
|
|
108
|
-
// Register user ID
|
|
109
|
-
this.userIdentity.distinct_id = newDistinctId;
|
|
110
|
-
// Handle device ID if not already set
|
|
111
|
-
if (!this.userIdentity.device_id) {
|
|
112
|
-
// The persisted distinct id might not actually be a device id at all
|
|
113
|
-
// it might be a distinct id of the user from before
|
|
114
|
-
const device_id = previousDistinctId || this.userIdentity.anonymous_id;
|
|
115
|
-
this.userIdentity.device_id = device_id;
|
|
116
|
-
this.userIdentity.properties = {
|
|
117
|
-
...this.userIdentity.properties,
|
|
118
|
-
$had_persisted_distinct_id: true,
|
|
119
|
-
$device_id: device_id,
|
|
120
|
-
};
|
|
121
|
-
}
|
|
122
|
-
// Clear alias if distinct_id is changing
|
|
123
|
-
if (newDistinctId !== previousDistinctId) {
|
|
124
|
-
// Clear any stored alias
|
|
125
|
-
this.userIdentity.distinct_id = newDistinctId;
|
|
126
|
-
}
|
|
127
|
-
// Check if user was anonymous
|
|
128
|
-
const isKnownAnonymous = this.userIdentity.user_state === "anonymous";
|
|
129
|
-
// Send $identify event only when distinct_id is changing AND user was anonymous
|
|
130
|
-
// - logic on the server will determine whether or not to do anything with it.
|
|
131
|
-
if (newDistinctId !== previousDistinctId && isKnownAnonymous) {
|
|
132
|
-
// Update user state to identified
|
|
133
|
-
this.userIdentity.user_state = "identified";
|
|
134
|
-
// Handle $set properties (update existing)
|
|
135
|
-
if (userPropertiesToSet) {
|
|
136
|
-
this.userIdentity.properties = {
|
|
137
|
-
...this.userIdentity.properties,
|
|
138
|
-
...userPropertiesToSet,
|
|
139
|
-
};
|
|
140
|
-
}
|
|
141
|
-
// Handle $set_once properties (preserve first value)
|
|
142
|
-
if (userPropertiesToSetOnce) {
|
|
143
|
-
Object.keys(userPropertiesToSetOnce).forEach((key) => {
|
|
144
|
-
if (!(key in this.userIdentity.properties)) {
|
|
145
|
-
this.userIdentity.properties[key] = userPropertiesToSetOnce[key];
|
|
146
|
-
}
|
|
147
|
-
});
|
|
148
|
-
}
|
|
149
|
-
// Save to storage
|
|
150
|
-
this.saveUserIdentity();
|
|
151
|
-
// Note: Event sending is now handled by VTilt.identify()
|
|
152
|
-
// This method is kept for backward compatibility but should not be called directly
|
|
153
|
-
}
|
|
154
|
-
else if (userPropertiesToSet || userPropertiesToSetOnce) {
|
|
155
|
-
// If distinct_id is not changing but we have properties to set
|
|
156
|
-
// Update user state if not already identified
|
|
157
|
-
if (this.userIdentity.user_state === "anonymous") {
|
|
158
|
-
this.userIdentity.user_state = "identified";
|
|
159
|
-
}
|
|
160
|
-
// Handle $set properties (update existing)
|
|
161
|
-
if (userPropertiesToSet) {
|
|
162
|
-
this.userIdentity.properties = {
|
|
163
|
-
...this.userIdentity.properties,
|
|
164
|
-
...userPropertiesToSet,
|
|
165
|
-
};
|
|
166
|
-
}
|
|
167
|
-
// Handle $set_once properties (preserve first value)
|
|
168
|
-
if (userPropertiesToSetOnce) {
|
|
169
|
-
Object.keys(userPropertiesToSetOnce).forEach((key) => {
|
|
170
|
-
if (!(key in this.userIdentity.properties)) {
|
|
171
|
-
this.userIdentity.properties[key] = userPropertiesToSetOnce[key];
|
|
172
|
-
}
|
|
173
|
-
});
|
|
174
|
-
}
|
|
175
|
-
// Save to storage
|
|
176
|
-
this.saveUserIdentity();
|
|
177
|
-
// Note: Event sending is now handled by VTilt.identify()
|
|
178
|
-
// This method is kept for backward compatibility but should not be called directly
|
|
179
|
-
}
|
|
180
|
-
else {
|
|
181
|
-
// If distinct_id is changing but user was already identified, just update the distinct_id
|
|
182
|
-
if (newDistinctId !== previousDistinctId) {
|
|
183
|
-
this.userIdentity.user_state = "identified";
|
|
184
|
-
this.saveUserIdentity();
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
/**
|
|
189
|
-
* Set user properties without changing distinct ID
|
|
190
|
-
*/
|
|
191
|
-
setUserProperties(userPropertiesToSet, userPropertiesToSetOnce) {
|
|
192
|
-
// Return early if no properties provided
|
|
193
|
-
if (!userPropertiesToSet && !userPropertiesToSetOnce) {
|
|
194
|
-
return false;
|
|
195
|
-
}
|
|
196
|
-
// Create hash for deduplication
|
|
197
|
-
const distinctId = this.userIdentity.distinct_id || this.userIdentity.anonymous_id;
|
|
198
|
-
const hash = this.getPersonPropertiesHash(distinctId, userPropertiesToSet, userPropertiesToSetOnce);
|
|
199
|
-
// Skip if exactly this $set call has been sent before
|
|
200
|
-
if (this._cachedPersonProperties === hash) {
|
|
201
|
-
console.info("VTilt: A duplicate setUserProperties call was made with the same properties. It has been ignored.");
|
|
202
|
-
return false;
|
|
203
|
-
}
|
|
204
|
-
// Handle $set properties (update existing)
|
|
205
|
-
if (userPropertiesToSet) {
|
|
206
|
-
this.userIdentity.properties = {
|
|
207
|
-
...this.userIdentity.properties,
|
|
208
|
-
...userPropertiesToSet,
|
|
209
|
-
};
|
|
210
|
-
}
|
|
211
|
-
// Handle $set_once properties (preserve first value)
|
|
212
|
-
if (userPropertiesToSetOnce) {
|
|
213
|
-
Object.keys(userPropertiesToSetOnce).forEach((key) => {
|
|
214
|
-
if (!(key in this.userIdentity.properties)) {
|
|
215
|
-
this.userIdentity.properties[key] = userPropertiesToSetOnce[key];
|
|
216
|
-
}
|
|
217
|
-
});
|
|
218
|
-
}
|
|
219
|
-
// Save to storage
|
|
220
|
-
this.saveUserIdentity();
|
|
221
|
-
// Cache the hash to prevent duplicate sends
|
|
222
|
-
this._cachedPersonProperties = hash;
|
|
223
|
-
// Note: Event sending is now handled by VTilt.setUserProperties()
|
|
224
|
-
return true;
|
|
225
|
-
}
|
|
226
|
-
/**
|
|
227
|
-
* Reset user identity (logout)
|
|
228
|
-
* Generates new anonymous ID, clears user data, optionally resets device ID
|
|
229
|
-
*/
|
|
230
|
-
reset(reset_device_id) {
|
|
231
|
-
// Generate completely new anonymous ID (don't revert to original)
|
|
232
|
-
const newAnonymousId = this.generateAnonymousId();
|
|
233
|
-
const device_id = this.userIdentity.device_id;
|
|
234
|
-
// Generate new device ID if reset_device_id is true
|
|
235
|
-
const newDeviceId = reset_device_id ? this.generateDeviceId() : device_id;
|
|
236
|
-
this.userIdentity = {
|
|
237
|
-
distinct_id: null,
|
|
238
|
-
anonymous_id: newAnonymousId,
|
|
239
|
-
device_id: newDeviceId,
|
|
240
|
-
properties: {},
|
|
241
|
-
user_state: "anonymous",
|
|
242
|
-
};
|
|
243
|
-
// Clear cached person properties on reset
|
|
244
|
-
this._cachedPersonProperties = null;
|
|
245
|
-
this.saveUserIdentity();
|
|
246
|
-
// Set $last_vtilt_reset property
|
|
247
|
-
// Store it in properties, it will be sent on the next event
|
|
248
|
-
this.userIdentity.properties = {
|
|
249
|
-
...this.userIdentity.properties,
|
|
250
|
-
$last_vtilt_reset: new Date().toISOString(),
|
|
251
|
-
};
|
|
252
|
-
this.saveUserIdentity();
|
|
253
|
-
}
|
|
254
|
-
// ============================================================================
|
|
255
|
-
// Internal Setters (for VTilt class)
|
|
256
|
-
// ============================================================================
|
|
257
|
-
/**
|
|
258
|
-
* Update distinct ID (internal use - for VTilt)
|
|
259
|
-
*/
|
|
260
|
-
setDistinctId(distinctId) {
|
|
261
|
-
this.userIdentity.distinct_id = distinctId;
|
|
262
|
-
this.saveUserIdentity();
|
|
263
|
-
}
|
|
264
|
-
/**
|
|
265
|
-
* Update user state (internal use - for VTilt)
|
|
266
|
-
*/
|
|
267
|
-
setUserState(state) {
|
|
268
|
-
this.userIdentity.user_state = state;
|
|
269
|
-
this.saveUserIdentity();
|
|
270
|
-
}
|
|
271
|
-
/**
|
|
272
|
-
* Update user properties (internal use - for VTilt)
|
|
273
|
-
*/
|
|
274
|
-
updateUserProperties(userPropertiesToSet, userPropertiesToSetOnce) {
|
|
275
|
-
// Handle $set properties (update existing)
|
|
276
|
-
if (userPropertiesToSet) {
|
|
277
|
-
this.userIdentity.properties = {
|
|
278
|
-
...this.userIdentity.properties,
|
|
279
|
-
...userPropertiesToSet,
|
|
280
|
-
};
|
|
281
|
-
}
|
|
282
|
-
// Handle $set_once properties (preserve first value)
|
|
283
|
-
if (userPropertiesToSetOnce) {
|
|
284
|
-
Object.keys(userPropertiesToSetOnce).forEach((key) => {
|
|
285
|
-
if (!(key in this.userIdentity.properties)) {
|
|
286
|
-
this.userIdentity.properties[key] = userPropertiesToSetOnce[key];
|
|
287
|
-
}
|
|
288
|
-
});
|
|
289
|
-
}
|
|
290
|
-
this.saveUserIdentity();
|
|
291
|
-
}
|
|
292
|
-
/**
|
|
293
|
-
* Set device ID if not already set (internal use - for VTilt)
|
|
294
|
-
*/
|
|
295
|
-
ensureDeviceId(deviceId) {
|
|
296
|
-
if (!this.userIdentity.device_id) {
|
|
297
|
-
this.userIdentity.device_id = deviceId;
|
|
298
|
-
this.userIdentity.properties = {
|
|
299
|
-
...this.userIdentity.properties,
|
|
300
|
-
$had_persisted_distinct_id: true,
|
|
301
|
-
$device_id: deviceId,
|
|
302
|
-
};
|
|
303
|
-
this.saveUserIdentity();
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
|
-
// ============================================================================
|
|
307
|
-
// Alias Operations
|
|
308
|
-
// ============================================================================
|
|
309
|
-
/**
|
|
310
|
-
* Create an alias to link two distinct IDs
|
|
311
|
-
*/
|
|
312
|
-
createAlias(alias, original) {
|
|
313
|
-
if (!this.isValidDistinctId(alias)) {
|
|
314
|
-
console.warn("Invalid alias provided");
|
|
315
|
-
return null;
|
|
316
|
-
}
|
|
317
|
-
// If original is not provided, use current distinct_id
|
|
318
|
-
if (original === undefined) {
|
|
319
|
-
original = this.getDistinctId() || this.getAnonymousId();
|
|
320
|
-
}
|
|
321
|
-
if (!this.isValidDistinctId(original)) {
|
|
322
|
-
console.warn("Invalid original distinct ID");
|
|
323
|
-
return null;
|
|
324
|
-
}
|
|
325
|
-
// If alias matches original, return null (caller should use identify)
|
|
326
|
-
if (alias === original) {
|
|
327
|
-
console.warn("alias matches current distinct_id - should use identify instead");
|
|
328
|
-
return null;
|
|
329
|
-
}
|
|
330
|
-
// { distinct_id: alias, original: original }
|
|
331
|
-
const aliasEvent = {
|
|
332
|
-
distinct_id: alias,
|
|
333
|
-
original,
|
|
334
|
-
};
|
|
335
|
-
// Note: Event sending is now handled by VTilt.createAlias()
|
|
336
|
-
return aliasEvent;
|
|
337
|
-
}
|
|
338
|
-
/**
|
|
339
|
-
* Check if distinct ID is string-like (hardcoded string) - public for validation
|
|
340
|
-
*/
|
|
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;
|
|
355
|
-
}
|
|
356
|
-
const personInfo = (0, event_utils_1.getPersonInfo)(maskPersonalDataProperties, customPersonalDataProperties);
|
|
357
|
-
this.register_once({
|
|
358
|
-
[constants_1.INITIAL_PERSON_INFO]: personInfo,
|
|
359
|
-
}, undefined);
|
|
360
|
-
}
|
|
361
|
-
/**
|
|
362
|
-
* Get initial props
|
|
363
|
-
*/
|
|
364
|
-
get_initial_props() {
|
|
365
|
-
const stored = this.getStoredUserProperties();
|
|
366
|
-
const initialPersonInfo = stored[constants_1.INITIAL_PERSON_INFO];
|
|
367
|
-
if (!initialPersonInfo) {
|
|
368
|
-
return {};
|
|
369
|
-
}
|
|
370
|
-
return (0, event_utils_1.getInitialPersonPropsFromInfo)(initialPersonInfo);
|
|
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
|
-
// ============================================================================
|
|
382
|
-
/**
|
|
383
|
-
* Load user identity from storage.
|
|
384
|
-
*
|
|
385
|
-
* For traditional SSR websites where each page navigation reloads JavaScript,
|
|
386
|
-
* identity MUST be persisted immediately when generated to ensure the same
|
|
387
|
-
* anonymous_id is used across all page loads.
|
|
388
|
-
*
|
|
389
|
-
* Flow:
|
|
390
|
-
* 1. Load from storage (reads cookies first for critical properties in SSR mode)
|
|
391
|
-
* 2. Generate new IDs if not found
|
|
392
|
-
* 3. Immediately persist to storage (saved to both localStorage and cookies)
|
|
393
|
-
*
|
|
394
|
-
* With `localStorage+cookie` persistence (default):
|
|
395
|
-
* - Critical properties are stored in cookies for SSR compatibility
|
|
396
|
-
* - Full data is stored in localStorage for fast SPA-style access
|
|
397
|
-
* - Cookies ensure identity persists across full page reloads
|
|
398
|
-
*/
|
|
399
|
-
loadUserIdentity() {
|
|
400
|
-
// Try to load existing IDs from storage
|
|
401
|
-
// In localStorage+cookie mode, this reads from cookies first for critical properties
|
|
402
|
-
const storedAnonymousId = this.storage.get(constants_1.ANONYMOUS_ID_KEY);
|
|
403
|
-
const storedDeviceId = this.storage.get(constants_1.DEVICE_ID_KEY);
|
|
404
|
-
const storedDistinctId = this.storage.get(constants_1.DISTINCT_ID_KEY);
|
|
405
|
-
const storedUserState = this.storage.get(constants_1.USER_STATE_KEY);
|
|
406
|
-
const properties = this.getStoredUserProperties();
|
|
407
|
-
// Generate new IDs if not found in storage
|
|
408
|
-
const anonymousId = storedAnonymousId || this.generateAnonymousId();
|
|
409
|
-
const deviceId = storedDeviceId || this.generateDeviceId();
|
|
410
|
-
const distinctId = storedDistinctId || null;
|
|
411
|
-
const userState = storedUserState || "anonymous";
|
|
412
|
-
// Ensure anonymous_id is never undefined
|
|
413
|
-
const safeAnonymousId = anonymousId || this.generateAnonymousId();
|
|
414
|
-
// CRITICAL: Immediately persist newly generated IDs to storage
|
|
415
|
-
// This ensures identity survives page reloads in traditional SSR websites
|
|
416
|
-
// In localStorage+cookie mode, critical properties are saved to cookies automatically
|
|
417
|
-
if (!storedAnonymousId) {
|
|
418
|
-
this.storage.set(constants_1.ANONYMOUS_ID_KEY, safeAnonymousId, storage_1.USER_COOKIE_MAX_AGE);
|
|
419
|
-
}
|
|
420
|
-
if (!storedDeviceId) {
|
|
421
|
-
this.storage.set(constants_1.DEVICE_ID_KEY, deviceId, storage_1.USER_COOKIE_MAX_AGE);
|
|
422
|
-
}
|
|
423
|
-
if (!storedUserState) {
|
|
424
|
-
this.storage.set(constants_1.USER_STATE_KEY, userState, storage_1.USER_COOKIE_MAX_AGE);
|
|
425
|
-
}
|
|
426
|
-
const identity = {
|
|
427
|
-
distinct_id: distinctId,
|
|
428
|
-
anonymous_id: safeAnonymousId,
|
|
429
|
-
device_id: deviceId,
|
|
430
|
-
properties: properties,
|
|
431
|
-
user_state: userState,
|
|
432
|
-
};
|
|
433
|
-
return identity;
|
|
434
|
-
}
|
|
435
|
-
/**
|
|
436
|
-
* Save user identity to storage
|
|
437
|
-
*/
|
|
438
|
-
saveUserIdentity() {
|
|
439
|
-
this.storage.set(constants_1.ANONYMOUS_ID_KEY, this.userIdentity.anonymous_id, storage_1.USER_COOKIE_MAX_AGE);
|
|
440
|
-
this.storage.set(constants_1.DEVICE_ID_KEY, this.userIdentity.device_id, storage_1.USER_COOKIE_MAX_AGE);
|
|
441
|
-
this.storage.set(constants_1.USER_STATE_KEY, this.userIdentity.user_state, storage_1.USER_COOKIE_MAX_AGE);
|
|
442
|
-
if (this.userIdentity.distinct_id) {
|
|
443
|
-
this.storage.set(constants_1.DISTINCT_ID_KEY, this.userIdentity.distinct_id, storage_1.USER_COOKIE_MAX_AGE);
|
|
444
|
-
}
|
|
445
|
-
else {
|
|
446
|
-
this.storage.remove(constants_1.DISTINCT_ID_KEY);
|
|
447
|
-
}
|
|
448
|
-
this.setStoredUserProperties(this.userIdentity.properties);
|
|
449
|
-
}
|
|
450
|
-
/**
|
|
451
|
-
* Get user properties from storage
|
|
452
|
-
*/
|
|
453
|
-
getStoredUserProperties() {
|
|
454
|
-
return this.storage.getJSON(constants_1.USER_PROPERTIES_KEY) || {};
|
|
455
|
-
}
|
|
456
|
-
/**
|
|
457
|
-
* Set user properties in storage
|
|
458
|
-
*/
|
|
459
|
-
setStoredUserProperties(properties) {
|
|
460
|
-
this.storage.setJSON(constants_1.USER_PROPERTIES_KEY, properties, storage_1.USER_COOKIE_MAX_AGE);
|
|
461
|
-
}
|
|
462
|
-
/**
|
|
463
|
-
* Register a value once (only if not already set)
|
|
464
|
-
*/
|
|
465
|
-
register_once(props, defaultValues) {
|
|
466
|
-
const stored = this.getStoredUserProperties();
|
|
467
|
-
let changed = false;
|
|
468
|
-
for (const key in props) {
|
|
469
|
-
if (Object.prototype.hasOwnProperty.call(props, key)) {
|
|
470
|
-
if (!(key in stored)) {
|
|
471
|
-
stored[key] = props[key];
|
|
472
|
-
changed = true;
|
|
473
|
-
}
|
|
474
|
-
}
|
|
475
|
-
}
|
|
476
|
-
if (defaultValues) {
|
|
477
|
-
for (const key in defaultValues) {
|
|
478
|
-
if (Object.prototype.hasOwnProperty.call(defaultValues, key)) {
|
|
479
|
-
if (!(key in stored)) {
|
|
480
|
-
stored[key] = defaultValues[key];
|
|
481
|
-
changed = true;
|
|
482
|
-
}
|
|
483
|
-
}
|
|
484
|
-
}
|
|
485
|
-
}
|
|
486
|
-
if (changed) {
|
|
487
|
-
this.setStoredUserProperties(stored);
|
|
488
|
-
}
|
|
489
|
-
}
|
|
490
|
-
// ============================================================================
|
|
491
|
-
// Utility Methods
|
|
492
|
-
// ============================================================================
|
|
493
|
-
/**
|
|
494
|
-
* Generate a new anonymous ID
|
|
495
|
-
*/
|
|
496
|
-
generateAnonymousId() {
|
|
497
|
-
return `anon_${(0, utils_1.uuidv4)()}`;
|
|
498
|
-
}
|
|
499
|
-
/**
|
|
500
|
-
* Generate a new device ID
|
|
501
|
-
*/
|
|
502
|
-
generateDeviceId() {
|
|
503
|
-
return `device_${(0, utils_1.uuidv4)()}`;
|
|
504
|
-
}
|
|
505
|
-
/**
|
|
506
|
-
* Get hash for person properties (for deduplication)
|
|
507
|
-
*/
|
|
508
|
-
getPersonPropertiesHash(distinctId, userPropertiesToSet, userPropertiesToSetOnce) {
|
|
509
|
-
return JSON.stringify({
|
|
510
|
-
distinct_id: distinctId,
|
|
511
|
-
userPropertiesToSet,
|
|
512
|
-
userPropertiesToSetOnce,
|
|
513
|
-
});
|
|
514
|
-
}
|
|
515
|
-
/**
|
|
516
|
-
* Validate distinct ID
|
|
517
|
-
*/
|
|
518
|
-
isValidDistinctId(distinctId) {
|
|
519
|
-
if (!distinctId || typeof distinctId !== "string") {
|
|
520
|
-
return false;
|
|
521
|
-
}
|
|
522
|
-
const invalidPatterns = [
|
|
523
|
-
"null",
|
|
524
|
-
"undefined",
|
|
525
|
-
"false",
|
|
526
|
-
"true",
|
|
527
|
-
"anonymous",
|
|
528
|
-
"anon",
|
|
529
|
-
"user",
|
|
530
|
-
"test",
|
|
531
|
-
"guest",
|
|
532
|
-
"visitor",
|
|
533
|
-
"unknown",
|
|
534
|
-
"none",
|
|
535
|
-
];
|
|
536
|
-
const lower = distinctId.toLowerCase().trim();
|
|
537
|
-
if (invalidPatterns.includes(lower)) {
|
|
538
|
-
return false;
|
|
539
|
-
}
|
|
540
|
-
if (distinctId.trim().length === 0) {
|
|
541
|
-
return false;
|
|
542
|
-
}
|
|
543
|
-
return true;
|
|
544
|
-
}
|
|
545
|
-
/**
|
|
546
|
-
* Check if distinct ID is string-like (hardcoded string)
|
|
547
|
-
*/
|
|
548
|
-
isDistinctIdStringLike(distinctId) {
|
|
549
|
-
if (!distinctId || typeof distinctId !== "string") {
|
|
550
|
-
return false;
|
|
551
|
-
}
|
|
552
|
-
const hardcodedPatterns = [
|
|
553
|
-
"null",
|
|
554
|
-
"undefined",
|
|
555
|
-
"false",
|
|
556
|
-
"true",
|
|
557
|
-
"anonymous",
|
|
558
|
-
"anon",
|
|
559
|
-
"user",
|
|
560
|
-
"test",
|
|
561
|
-
"guest",
|
|
562
|
-
"visitor",
|
|
563
|
-
"unknown",
|
|
564
|
-
"none",
|
|
565
|
-
"demo",
|
|
566
|
-
"example",
|
|
567
|
-
"sample",
|
|
568
|
-
"placeholder",
|
|
569
|
-
];
|
|
570
|
-
const lower = distinctId.toLowerCase().trim();
|
|
571
|
-
return hardcodedPatterns.includes(lower);
|
|
572
|
-
}
|
|
573
|
-
// ============================================================================
|
|
574
|
-
// Storage Management
|
|
575
|
-
// ============================================================================
|
|
576
|
-
/**
|
|
577
|
-
* Update storage method at runtime
|
|
578
|
-
*/
|
|
579
|
-
updateStorageMethod(method, cross_subdomain) {
|
|
580
|
-
this.storage = new storage_1.StorageManager({
|
|
581
|
-
method,
|
|
582
|
-
cross_subdomain,
|
|
583
|
-
sameSite: "Lax",
|
|
584
|
-
});
|
|
585
|
-
// Reload identity from new storage
|
|
586
|
-
this.userIdentity = this.loadUserIdentity();
|
|
587
|
-
}
|
|
588
|
-
}
|
|
589
|
-
exports.UserManager = UserManager;
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Event utilities
|
|
3
|
-
* Functions for extracting event properties, campaign parameters, and person info
|
|
4
|
-
*/
|
|
5
|
-
export declare const PERSONAL_DATA_CAMPAIGN_PARAMS: string[];
|
|
6
|
-
export declare const CAMPAIGN_PARAMS: string[];
|
|
7
|
-
export declare const EVENT_TO_PERSON_PROPERTIES: string[];
|
|
8
|
-
export declare const MASKED = "<masked>";
|
|
9
|
-
export declare const COOKIE_CAMPAIGN_PARAMS: string[];
|
|
10
|
-
/**
|
|
11
|
-
* Get campaign parameters from URL
|
|
12
|
-
* Extracts UTM and other campaign tracking parameters from current page URL
|
|
13
|
-
* Masks personal data parameters if configured
|
|
14
|
-
*/
|
|
15
|
-
export declare function getCampaignParams(customTrackedParams?: string[], maskPersonalDataProperties?: boolean, customPersonalDataProperties?: string[] | undefined): Record<string, string>;
|
|
16
|
-
export declare function getSearchInfo(): Record<string, any>;
|
|
17
|
-
export declare function getBrowserLanguage(): string | undefined;
|
|
18
|
-
export declare function getBrowserLanguagePrefix(): string | undefined;
|
|
19
|
-
export declare function getReferrer(): string;
|
|
20
|
-
export declare function getReferringDomain(): string;
|
|
21
|
-
/**
|
|
22
|
-
* Get referrer information
|
|
23
|
-
* Returns current referrer and referring domain
|
|
24
|
-
*/
|
|
25
|
-
export declare function getReferrerInfo(): Record<string, any>;
|
|
26
|
-
/**
|
|
27
|
-
* Get person info for initial storage
|
|
28
|
-
* Extracts referrer and URL info, masks personal data if configured
|
|
29
|
-
* Returns compact format (r: referrer, u: url) for storage efficiency
|
|
30
|
-
*/
|
|
31
|
-
export declare function getPersonInfo(maskPersonalDataProperties?: boolean, customPersonalDataProperties?: string[]): {
|
|
32
|
-
r: string;
|
|
33
|
-
u: string | undefined;
|
|
34
|
-
};
|
|
35
|
-
/**
|
|
36
|
-
* Convert person info to person properties
|
|
37
|
-
* Extracts referrer, URL, campaign params, and search info from stored person info
|
|
38
|
-
*/
|
|
39
|
-
export declare function getPersonPropsFromInfo(info: Record<string, any>): Record<string, any>;
|
|
40
|
-
/**
|
|
41
|
-
* Convert person info to initial person properties
|
|
42
|
-
* Generates $initial_* properties from person info (preserves first values)
|
|
43
|
-
*/
|
|
44
|
-
export declare function getInitialPersonPropsFromInfo(info: Record<string, any>): Record<string, any>;
|
|
45
|
-
export declare function getTimezone(): string | undefined;
|
|
46
|
-
export declare function getTimezoneOffset(): number | undefined;
|
|
47
|
-
/**
|
|
48
|
-
* Get event properties that should be added to all events
|
|
49
|
-
* Returns all event context properties (browser, device, URL, etc.) plus event metadata
|
|
50
|
-
* Note: Only properties in EVENT_TO_PERSON_PROPERTIES are copied to person properties
|
|
51
|
-
*/
|
|
52
|
-
export declare function getEventProperties(maskPersonalDataProperties?: boolean, customPersonalDataProperties?: string[]): Record<string, any>;
|