@v-tilt/browser 1.0.1

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.
Files changed (64) hide show
  1. package/dist/array.js +2 -0
  2. package/dist/array.js.map +1 -0
  3. package/dist/array.no-external.js +2 -0
  4. package/dist/array.no-external.js.map +1 -0
  5. package/dist/config.d.ts +17 -0
  6. package/dist/constants.d.ts +10 -0
  7. package/dist/entrypoints/array.d.ts +1 -0
  8. package/dist/entrypoints/array.no-external.d.ts +1 -0
  9. package/dist/entrypoints/main.cjs.d.ts +4 -0
  10. package/dist/entrypoints/module.es.d.ts +3 -0
  11. package/dist/entrypoints/module.no-external.es.d.ts +4 -0
  12. package/dist/geolocation.d.ts +5 -0
  13. package/dist/main.js +2 -0
  14. package/dist/main.js.map +1 -0
  15. package/dist/module.d.ts +214 -0
  16. package/dist/module.js +2 -0
  17. package/dist/module.js.map +1 -0
  18. package/dist/module.no-external.d.ts +214 -0
  19. package/dist/module.no-external.js +2 -0
  20. package/dist/module.no-external.js.map +1 -0
  21. package/dist/session.d.ts +26 -0
  22. package/dist/tracking.d.ts +112 -0
  23. package/dist/types.d.ts +67 -0
  24. package/dist/user-manager.d.ts +152 -0
  25. package/dist/utils/globals.d.ts +4 -0
  26. package/dist/utils/index.d.ts +30 -0
  27. package/dist/utils.d.ts +21 -0
  28. package/dist/vtilt.d.ts +178 -0
  29. package/dist/web-vitals.d.ts +11 -0
  30. package/lib/config.d.ts +17 -0
  31. package/lib/config.js +76 -0
  32. package/lib/constants.d.ts +10 -0
  33. package/lib/constants.js +463 -0
  34. package/lib/entrypoints/array.d.ts +1 -0
  35. package/lib/entrypoints/array.js +3 -0
  36. package/lib/entrypoints/array.no-external.d.ts +1 -0
  37. package/lib/entrypoints/array.no-external.js +4 -0
  38. package/lib/entrypoints/main.cjs.d.ts +4 -0
  39. package/lib/entrypoints/main.cjs.js +29 -0
  40. package/lib/entrypoints/module.es.d.ts +3 -0
  41. package/lib/entrypoints/module.es.js +22 -0
  42. package/lib/entrypoints/module.no-external.es.d.ts +4 -0
  43. package/lib/entrypoints/module.no-external.es.js +23 -0
  44. package/lib/geolocation.d.ts +5 -0
  45. package/lib/geolocation.js +26 -0
  46. package/lib/session.d.ts +26 -0
  47. package/lib/session.js +115 -0
  48. package/lib/tracking.d.ts +112 -0
  49. package/lib/tracking.js +326 -0
  50. package/lib/types.d.ts +67 -0
  51. package/lib/types.js +2 -0
  52. package/lib/user-manager.d.ts +152 -0
  53. package/lib/user-manager.js +565 -0
  54. package/lib/utils/globals.d.ts +4 -0
  55. package/lib/utils/globals.js +5 -0
  56. package/lib/utils/index.d.ts +30 -0
  57. package/lib/utils/index.js +89 -0
  58. package/lib/utils.d.ts +21 -0
  59. package/lib/utils.js +57 -0
  60. package/lib/vtilt.d.ts +178 -0
  61. package/lib/vtilt.js +403 -0
  62. package/lib/web-vitals.d.ts +11 -0
  63. package/lib/web-vitals.js +67 -0
  64. package/package.json +61 -0
@@ -0,0 +1,565 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.UserManager = void 0;
4
+ const constants_1 = require("./constants");
5
+ const utils_1 = require("./utils");
6
+ class UserManager {
7
+ constructor(storageMethod = "localStorage", domain) {
8
+ this._cachedPersonProperties = null; // PostHog behavior: cache for deduplication
9
+ this.storageMethod = storageMethod;
10
+ this.domain = domain;
11
+ this.userIdentity = this.loadUserIdentity();
12
+ }
13
+ /**
14
+ * Get current user identity
15
+ */
16
+ getUserIdentity() {
17
+ return { ...this.userIdentity };
18
+ }
19
+ /**
20
+ * Get current distinct ID (identified user ID)
21
+ */
22
+ getDistinctId() {
23
+ return this.userIdentity.distinct_id;
24
+ }
25
+ /**
26
+ * Get current anonymous ID
27
+ */
28
+ getAnonymousId() {
29
+ if (!this.userIdentity.anonymous_id) {
30
+ // Regenerate if somehow undefined
31
+ this.userIdentity.anonymous_id = this.generateAnonymousId();
32
+ this.saveUserIdentity();
33
+ }
34
+ return this.userIdentity.anonymous_id;
35
+ }
36
+ /**
37
+ * Get current user properties
38
+ */
39
+ getUserProperties() {
40
+ return { ...this.userIdentity.properties };
41
+ }
42
+ /**
43
+ * Identify a user with distinct ID and properties
44
+ * Copied from PostHog's identify method implementation
45
+ */
46
+ identify(newDistinctId, userPropertiesToSet, userPropertiesToSetOnce) {
47
+ // PostHog validation: Convert number to string
48
+ if (typeof newDistinctId === "number") {
49
+ newDistinctId = newDistinctId.toString();
50
+ 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
+ }
52
+ // PostHog validation: Check if distinct_id is provided
53
+ if (!newDistinctId) {
54
+ console.error("Unique user id has not been set in vTilt.identify");
55
+ return;
56
+ }
57
+ // PostHog validation: Check for hardcoded strings
58
+ if (this.isDistinctIdStringLike(newDistinctId)) {
59
+ 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
+ return;
61
+ }
62
+ // PostHog validation: Check for cookieless sentinel value
63
+ if (newDistinctId === "COOKIELESS_SENTINEL_VALUE") {
64
+ console.error(`The string "${newDistinctId}" was set in vTilt.identify which indicates an error. This ID is only used as a sentinel value.`);
65
+ return;
66
+ }
67
+ const previousDistinctId = this.userIdentity.distinct_id;
68
+ const anonymousId = this.userIdentity.anonymous_id;
69
+ const deviceId = this.userIdentity.device_id;
70
+ // PostHog behavior: Register user ID
71
+ this.userIdentity.distinct_id = newDistinctId;
72
+ // PostHog behavior: Handle device ID if not already set
73
+ if (!this.userIdentity.device_id) {
74
+ // The persisted distinct id might not actually be a device id at all
75
+ // it might be a distinct id of the user from before
76
+ const device_id = previousDistinctId || this.userIdentity.anonymous_id;
77
+ this.userIdentity.device_id = device_id;
78
+ this.userIdentity.properties = {
79
+ ...this.userIdentity.properties,
80
+ $had_persisted_distinct_id: true,
81
+ $device_id: device_id,
82
+ };
83
+ }
84
+ // PostHog behavior: Clear alias if distinct_id is changing
85
+ if (newDistinctId !== previousDistinctId) {
86
+ // Clear any stored alias (we don't have alias support yet, but keeping PostHog structure)
87
+ this.userIdentity.distinct_id = newDistinctId;
88
+ }
89
+ // PostHog behavior: Check if user was anonymous
90
+ const isKnownAnonymous = this.userIdentity.user_state === "anonymous";
91
+ // PostHog behavior: Send $identify event only when distinct_id is changing AND user was anonymous
92
+ // - logic on the server will determine whether or not to do anything with it.
93
+ if (newDistinctId !== previousDistinctId && isKnownAnonymous) {
94
+ // Update user state to identified
95
+ this.userIdentity.user_state = "identified";
96
+ // Handle $set properties (update existing)
97
+ if (userPropertiesToSet) {
98
+ this.userIdentity.properties = {
99
+ ...this.userIdentity.properties,
100
+ ...userPropertiesToSet,
101
+ };
102
+ }
103
+ // Handle $set_once properties (preserve first value)
104
+ if (userPropertiesToSetOnce) {
105
+ Object.keys(userPropertiesToSetOnce).forEach((key) => {
106
+ if (!(key in this.userIdentity.properties)) {
107
+ this.userIdentity.properties[key] = userPropertiesToSetOnce[key];
108
+ }
109
+ });
110
+ }
111
+ // Save to storage
112
+ this.saveUserIdentity();
113
+ // PostHog behavior: Send $identify event for session merging
114
+ this.sendIdentifyEvent(newDistinctId, anonymousId, deviceId, {
115
+ $set: userPropertiesToSet || {},
116
+ $set_once: userPropertiesToSetOnce || {},
117
+ });
118
+ }
119
+ else if (userPropertiesToSet || userPropertiesToSetOnce) {
120
+ // PostHog behavior: If distinct_id is not changing but we have properties to set
121
+ // Update user state if not already identified
122
+ if (this.userIdentity.user_state === "anonymous") {
123
+ this.userIdentity.user_state = "identified";
124
+ }
125
+ // Handle $set properties (update existing)
126
+ if (userPropertiesToSet) {
127
+ this.userIdentity.properties = {
128
+ ...this.userIdentity.properties,
129
+ ...userPropertiesToSet,
130
+ };
131
+ }
132
+ // Handle $set_once properties (preserve first value)
133
+ if (userPropertiesToSetOnce) {
134
+ Object.keys(userPropertiesToSetOnce).forEach((key) => {
135
+ if (!(key in this.userIdentity.properties)) {
136
+ this.userIdentity.properties[key] = userPropertiesToSetOnce[key];
137
+ }
138
+ });
139
+ }
140
+ // Save to storage
141
+ this.saveUserIdentity();
142
+ // PostHog behavior: Send $set event to notify server of property updates
143
+ // This allows Tinybird to track property changes when identify() is called with properties
144
+ // but no $identify event is sent (user was already identified)
145
+ this.sendSetEvent(userPropertiesToSet || {}, userPropertiesToSetOnce || {});
146
+ }
147
+ else {
148
+ // If distinct_id is changing but user was already identified, just update the distinct_id
149
+ if (newDistinctId !== previousDistinctId) {
150
+ this.userIdentity.user_state = "identified";
151
+ this.saveUserIdentity();
152
+ }
153
+ }
154
+ }
155
+ /**
156
+ * Set user properties without changing distinct ID (PostHog-style)
157
+ * Sets properties on the person profile associated with the current distinct_id
158
+ *
159
+ * @example
160
+ * ```js
161
+ * // Set properties that can be updated
162
+ * vt.setUserProperties({ name: 'John Doe', email: 'john@example.com' })
163
+ * ```
164
+ *
165
+ * @example
166
+ * ```js
167
+ * // Set properties with $set and $set_once operations
168
+ * vt.setUserProperties(
169
+ * { name: 'John Doe', last_login: new Date().toISOString() }, // $set properties
170
+ * { first_login: new Date().toISOString() } // $set_once properties
171
+ * )
172
+ * ```
173
+ *
174
+ * @param userPropertiesToSet Optional: Properties to set (can be updated)
175
+ * @param userPropertiesToSetOnce Optional: Properties to set once (preserves first value)
176
+ */
177
+ setUserProperties(userPropertiesToSet, userPropertiesToSetOnce) {
178
+ // PostHog behavior: Return early if no properties provided
179
+ if (!userPropertiesToSet && !userPropertiesToSetOnce) {
180
+ return;
181
+ }
182
+ // PostHog behavior: Create hash for deduplication
183
+ const distinctId = this.userIdentity.distinct_id || this.userIdentity.anonymous_id;
184
+ const hash = this.getPersonPropertiesHash(distinctId, userPropertiesToSet, userPropertiesToSetOnce);
185
+ // PostHog behavior: Skip if exactly this $set call has been sent before
186
+ if (this._cachedPersonProperties === hash) {
187
+ console.info("VTilt: A duplicate setUserProperties call was made with the same properties. It has been ignored.");
188
+ return;
189
+ }
190
+ // PostHog behavior: Handle $set properties (update existing)
191
+ if (userPropertiesToSet) {
192
+ this.userIdentity.properties = {
193
+ ...this.userIdentity.properties,
194
+ ...userPropertiesToSet,
195
+ };
196
+ }
197
+ // PostHog behavior: Handle $set_once properties (preserve first value)
198
+ if (userPropertiesToSetOnce) {
199
+ Object.keys(userPropertiesToSetOnce).forEach((key) => {
200
+ if (!(key in this.userIdentity.properties)) {
201
+ this.userIdentity.properties[key] = userPropertiesToSetOnce[key];
202
+ }
203
+ });
204
+ }
205
+ // Save to storage
206
+ this.saveUserIdentity();
207
+ // PostHog behavior: Send $set event to notify server of property updates
208
+ this.sendSetEvent(userPropertiesToSet || {}, userPropertiesToSetOnce || {});
209
+ // PostHog behavior: Cache the hash to prevent duplicate sends
210
+ this._cachedPersonProperties = hash;
211
+ }
212
+ /**
213
+ * Get hash for person properties (PostHog behavior)
214
+ * Used for deduplication of identical setUserProperties calls
215
+ */
216
+ getPersonPropertiesHash(distinctId, userPropertiesToSet, userPropertiesToSetOnce) {
217
+ // PostHog behavior: Create deterministic hash from distinct_id and properties
218
+ return JSON.stringify({
219
+ distinct_id: distinctId,
220
+ userPropertiesToSet,
221
+ userPropertiesToSetOnce,
222
+ });
223
+ }
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
+ /**
239
+ * Reset user identity (logout)
240
+ * PostHog behavior: Generates new anonymous ID, clears user data, optionally resets device ID
241
+ *
242
+ * @param reset_device_id - If true, also resets device_id. Default: false (preserves device_id)
243
+ */
244
+ reset(reset_device_id) {
245
+ // PostHog behavior: Generate completely new anonymous ID (don't revert to original)
246
+ const newAnonymousId = this.generateAnonymousId();
247
+ const device_id = this.userIdentity.device_id;
248
+ // Generate new device ID if reset_device_id is true
249
+ const newDeviceId = reset_device_id ? this.generateDeviceId() : device_id;
250
+ this.userIdentity = {
251
+ distinct_id: null,
252
+ anonymous_id: newAnonymousId,
253
+ device_id: newDeviceId,
254
+ properties: {},
255
+ user_state: "anonymous",
256
+ };
257
+ // PostHog behavior: Clear cached person properties on reset
258
+ this._cachedPersonProperties = null;
259
+ this.saveUserIdentity();
260
+ // PostHog behavior: Set $last_posthog_reset property
261
+ // Store it in properties, it will be sent on the next event
262
+ this.userIdentity.properties = {
263
+ ...this.userIdentity.properties,
264
+ $last_posthog_reset: new Date().toISOString(),
265
+ };
266
+ this.saveUserIdentity();
267
+ }
268
+ /**
269
+ * Get the effective ID for event tracking
270
+ */
271
+ getEffectiveId() {
272
+ return this.userIdentity.distinct_id || this.getAnonymousId();
273
+ }
274
+ /**
275
+ * Get current device ID
276
+ */
277
+ getDeviceId() {
278
+ return this.userIdentity.device_id;
279
+ }
280
+ /**
281
+ * Get current user state
282
+ */
283
+ getUserState() {
284
+ return this.userIdentity.user_state;
285
+ }
286
+ /**
287
+ * Create an alias to link two distinct IDs
288
+ * PostHog behavior: If original is not provided, uses current distinct_id
289
+ * If alias matches original, just calls identify instead
290
+ *
291
+ * @param alias - A unique identifier that you want to use for this user in the future
292
+ * @param original - The current identifier being used for this user (optional, defaults to current distinct_id)
293
+ */
294
+ createAlias(alias, original) {
295
+ if (!this.isValidDistinctId(alias)) {
296
+ console.warn("Invalid alias provided");
297
+ return;
298
+ }
299
+ // PostHog behavior: If original is not provided, use current distinct_id
300
+ if (original === undefined) {
301
+ original = this.getDistinctId() || this.getAnonymousId();
302
+ }
303
+ if (!this.isValidDistinctId(original)) {
304
+ console.warn("Invalid original distinct ID");
305
+ return;
306
+ }
307
+ // PostHog behavior: If alias matches original, just call identify instead
308
+ if (alias === original) {
309
+ console.warn("alias matches current distinct_id - calling identify instead");
310
+ this.identify(alias);
311
+ return;
312
+ }
313
+ // { distinct_id: alias, original: original }
314
+ const aliasEvent = {
315
+ distinct_id: alias,
316
+ original,
317
+ };
318
+ // Emit alias event
319
+ const customEvent = new CustomEvent("vtilt:alias", {
320
+ detail: aliasEvent,
321
+ });
322
+ window.dispatchEvent(customEvent);
323
+ }
324
+ /**
325
+ * Validate distinct ID to prevent hardcoded strings
326
+ * Copied from PostHog's validation logic
327
+ */
328
+ isValidDistinctId(distinctId) {
329
+ if (!distinctId || typeof distinctId !== "string") {
330
+ return false;
331
+ }
332
+ // PostHog's validation patterns
333
+ const invalidPatterns = [
334
+ "null",
335
+ "undefined",
336
+ "false",
337
+ "true",
338
+ "anonymous",
339
+ "anon",
340
+ "user",
341
+ "test",
342
+ "guest",
343
+ "visitor",
344
+ "unknown",
345
+ "none",
346
+ ];
347
+ const lower = distinctId.toLowerCase().trim();
348
+ if (invalidPatterns.includes(lower)) {
349
+ return false;
350
+ }
351
+ // Check for empty or whitespace-only strings
352
+ if (distinctId.trim().length === 0) {
353
+ return false;
354
+ }
355
+ return true;
356
+ }
357
+ /**
358
+ * Check if distinct ID is string-like (hardcoded string)
359
+ * Copied from PostHog's isDistinctIdStringLike function
360
+ */
361
+ isDistinctIdStringLike(distinctId) {
362
+ if (!distinctId || typeof distinctId !== "string") {
363
+ return false;
364
+ }
365
+ // PostHog's hardcoded string patterns
366
+ const hardcodedPatterns = [
367
+ "null",
368
+ "undefined",
369
+ "false",
370
+ "true",
371
+ "anonymous",
372
+ "anon",
373
+ "user",
374
+ "test",
375
+ "guest",
376
+ "visitor",
377
+ "unknown",
378
+ "none",
379
+ "demo",
380
+ "example",
381
+ "sample",
382
+ "placeholder",
383
+ ];
384
+ const lower = distinctId.toLowerCase().trim();
385
+ return hardcodedPatterns.includes(lower);
386
+ }
387
+ /**
388
+ * Load user identity from storage
389
+ */
390
+ loadUserIdentity() {
391
+ const anonymousId = this.getStoredValue(constants_1.ANONYMOUS_ID_KEY) || this.generateAnonymousId();
392
+ const distinctId = this.getStoredValue(constants_1.DISTINCT_ID_KEY) || null;
393
+ const deviceId = this.getStoredValue(constants_1.DEVICE_ID_KEY) || this.generateDeviceId();
394
+ const properties = this.getStoredUserProperties();
395
+ const userState = this.getStoredValue(constants_1.USER_STATE_KEY) ||
396
+ "anonymous";
397
+ // Ensure anonymous_id is never undefined
398
+ const safeAnonymousId = anonymousId || this.generateAnonymousId();
399
+ const identity = {
400
+ distinct_id: distinctId,
401
+ anonymous_id: safeAnonymousId,
402
+ device_id: deviceId,
403
+ properties: properties,
404
+ user_state: userState,
405
+ };
406
+ return identity;
407
+ }
408
+ /**
409
+ * Save user identity to storage
410
+ */
411
+ saveUserIdentity() {
412
+ this.setStoredValue(constants_1.ANONYMOUS_ID_KEY, this.userIdentity.anonymous_id);
413
+ this.setStoredValue(constants_1.DEVICE_ID_KEY, this.userIdentity.device_id);
414
+ this.setStoredValue(constants_1.USER_STATE_KEY, this.userIdentity.user_state);
415
+ if (this.userIdentity.distinct_id) {
416
+ this.setStoredValue(constants_1.DISTINCT_ID_KEY, this.userIdentity.distinct_id);
417
+ }
418
+ else {
419
+ this.removeStoredValue(constants_1.DISTINCT_ID_KEY);
420
+ }
421
+ this.setStoredUserProperties(this.userIdentity.properties);
422
+ }
423
+ /**
424
+ * Generate a new anonymous ID
425
+ */
426
+ generateAnonymousId() {
427
+ return `anon_${(0, utils_1.uuidv4)()}`;
428
+ }
429
+ /**
430
+ * Generate a new device ID
431
+ */
432
+ generateDeviceId() {
433
+ return `device_${(0, utils_1.uuidv4)()}`;
434
+ }
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
+ /**
456
+ * Get stored value from storage
457
+ */
458
+ getStoredValue(key) {
459
+ try {
460
+ if (this.storageMethod === constants_1.STORAGE_METHODS.localStorage) {
461
+ return localStorage.getItem(key);
462
+ }
463
+ else if (this.storageMethod === constants_1.STORAGE_METHODS.sessionStorage) {
464
+ return sessionStorage.getItem(key);
465
+ }
466
+ else {
467
+ return this.getCookieValue(key);
468
+ }
469
+ }
470
+ catch (error) {
471
+ // If storage access fails, return null
472
+ console.warn("Failed to access storage:", error);
473
+ return null;
474
+ }
475
+ }
476
+ /**
477
+ * Set stored value in storage
478
+ */
479
+ setStoredValue(key, value) {
480
+ try {
481
+ if (this.storageMethod === constants_1.STORAGE_METHODS.localStorage) {
482
+ localStorage.setItem(key, value);
483
+ }
484
+ else if (this.storageMethod === constants_1.STORAGE_METHODS.sessionStorage) {
485
+ sessionStorage.setItem(key, value);
486
+ }
487
+ else {
488
+ this.setCookieValue(key, value);
489
+ }
490
+ }
491
+ catch (error) {
492
+ // If storage access fails, log warning but don't throw
493
+ console.warn("Failed to save to storage:", error);
494
+ }
495
+ }
496
+ /**
497
+ * Remove stored value from storage
498
+ */
499
+ removeStoredValue(key) {
500
+ if (this.storageMethod === constants_1.STORAGE_METHODS.localStorage) {
501
+ localStorage.removeItem(key);
502
+ }
503
+ else if (this.storageMethod === constants_1.STORAGE_METHODS.sessionStorage) {
504
+ sessionStorage.removeItem(key);
505
+ }
506
+ else {
507
+ this.removeCookieValue(key);
508
+ }
509
+ }
510
+ /**
511
+ * Get user properties from storage
512
+ */
513
+ getStoredUserProperties() {
514
+ const stored = this.getStoredValue(constants_1.USER_PROPERTIES_KEY);
515
+ if (!stored) {
516
+ return {};
517
+ }
518
+ try {
519
+ return JSON.parse(stored);
520
+ }
521
+ catch (_a) {
522
+ return {};
523
+ }
524
+ }
525
+ /**
526
+ * Set user properties in storage
527
+ */
528
+ setStoredUserProperties(properties) {
529
+ this.setStoredValue(constants_1.USER_PROPERTIES_KEY, JSON.stringify(properties));
530
+ }
531
+ /**
532
+ * Get cookie value
533
+ */
534
+ getCookieValue(name) {
535
+ const cookies = document.cookie.split(";");
536
+ for (const cookie of cookies) {
537
+ const [key, value] = cookie.trim().split("=");
538
+ if (key === name) {
539
+ return decodeURIComponent(value);
540
+ }
541
+ }
542
+ return null;
543
+ }
544
+ /**
545
+ * Set cookie value
546
+ */
547
+ setCookieValue(name, value) {
548
+ let cookieValue = `${name}=${encodeURIComponent(value)}; Max-Age=31536000; path=/; secure; SameSite=Lax`;
549
+ if (this.domain) {
550
+ cookieValue += `; domain=${this.domain}`;
551
+ }
552
+ document.cookie = cookieValue;
553
+ }
554
+ /**
555
+ * Remove cookie value
556
+ */
557
+ removeCookieValue(name) {
558
+ let cookieValue = `${name}=; Max-Age=0; path=/`;
559
+ if (this.domain) {
560
+ cookieValue += `; domain=${this.domain}`;
561
+ }
562
+ document.cookie = cookieValue;
563
+ }
564
+ }
565
+ exports.UserManager = UserManager;
@@ -0,0 +1,4 @@
1
+ export type AssignableWindow = Window & typeof globalThis & {
2
+ vt: any;
3
+ };
4
+ export declare const assignableWindow: AssignableWindow;
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.assignableWindow = void 0;
4
+ const win = typeof window !== "undefined" ? window : undefined;
5
+ exports.assignableWindow = win !== null && win !== void 0 ? win : {};
@@ -0,0 +1,30 @@
1
+ import { EventPayload } from "../types";
2
+ /**
3
+ * Generate uuid to identify the session. Random, not data-derived
4
+ */
5
+ export declare function uuidv4(): string;
6
+ /**
7
+ * Validate user agent string
8
+ */
9
+ export declare function isValidUserAgent(userAgent: string): boolean;
10
+ /**
11
+ * Validate payload string
12
+ */
13
+ 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
+ /**
19
+ * Check if current environment is a test environment
20
+ */
21
+ export declare function isTestEnvironment(): boolean;
22
+ /**
23
+ * Iterate over an array or object
24
+ */
25
+ export declare function each<T>(obj: T[] | Record<string, T> | null | undefined, iterator: (value: T, key: string | number) => void, thisArg?: any): void;
26
+ /**
27
+ * Use this instead of element.addEventListener to avoid eslint errors
28
+ * This properly implements the default options for passive event listeners
29
+ */
30
+ export declare function addEventListener(element: Window | Document | Element | undefined, event: string, callback: EventListener, options?: AddEventListenerOptions): void;
@@ -0,0 +1,89 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.uuidv4 = uuidv4;
4
+ exports.isValidUserAgent = isValidUserAgent;
5
+ exports.isValidPayload = isValidPayload;
6
+ exports.maskSuspiciousAttributes = maskSuspiciousAttributes;
7
+ exports.isTestEnvironment = isTestEnvironment;
8
+ exports.each = each;
9
+ exports.addEventListener = addEventListener;
10
+ const constants_1 = require("../constants");
11
+ /**
12
+ * Generate uuid to identify the session. Random, not data-derived
13
+ */
14
+ function uuidv4() {
15
+ return `${1e7}-${1e3}-${4e3}-${8e3}-${1e11}`.replace(/[018]/g, (c) => (+c ^
16
+ (crypto.getRandomValues(new Uint8Array(1))[0] & (15 >> (+c / 4)))).toString(16));
17
+ }
18
+ /**
19
+ * Validate user agent string
20
+ */
21
+ function isValidUserAgent(userAgent) {
22
+ // empty is fine
23
+ if (!userAgent || typeof userAgent !== "string") {
24
+ return true;
25
+ }
26
+ if (userAgent.length > 500) {
27
+ return false;
28
+ }
29
+ return true;
30
+ }
31
+ /**
32
+ * Validate payload string
33
+ */
34
+ function isValidPayload(payloadStr) {
35
+ if (!payloadStr || typeof payloadStr !== "string") {
36
+ return false;
37
+ }
38
+ if (payloadStr.length < 2 || payloadStr.length > 10240) {
39
+ return false;
40
+ }
41
+ return true;
42
+ }
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
+ /**
55
+ * Check if current environment is a test environment
56
+ */
57
+ function isTestEnvironment() {
58
+ return !!("__nightmare" in window ||
59
+ window.navigator.webdriver ||
60
+ "Cypress" in window);
61
+ }
62
+ /**
63
+ * Iterate over an array or object
64
+ */
65
+ function each(obj, iterator, thisArg) {
66
+ if (!obj) {
67
+ return;
68
+ }
69
+ if (Array.isArray(obj)) {
70
+ obj.forEach((value, index) => {
71
+ iterator.call(thisArg, value, index);
72
+ });
73
+ }
74
+ else {
75
+ for (const key in obj) {
76
+ if (Object.prototype.hasOwnProperty.call(obj, key)) {
77
+ iterator.call(thisArg, obj[key], key);
78
+ }
79
+ }
80
+ }
81
+ }
82
+ /**
83
+ * Use this instead of element.addEventListener to avoid eslint errors
84
+ * This properly implements the default options for passive event listeners
85
+ */
86
+ function addEventListener(element, event, callback, options) {
87
+ const { capture = false, passive = true } = options !== null && options !== void 0 ? options : {};
88
+ element === null || element === void 0 ? void 0 : element.addEventListener(event, callback, { capture, passive });
89
+ }