humanbehavior-js 0.4.20 → 0.4.21
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/cjs/angular/index.cjs +799 -13
- package/dist/cjs/angular/index.cjs.map +1 -1
- package/dist/cjs/index.cjs +815 -13
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/react/index.cjs +800 -14
- package/dist/cjs/react/index.cjs.map +1 -1
- package/dist/cjs/remix/index.cjs +800 -14
- package/dist/cjs/remix/index.cjs.map +1 -1
- package/dist/cjs/svelte/index.cjs +799 -13
- package/dist/cjs/svelte/index.cjs.map +1 -1
- package/dist/cjs/vue/index.cjs +799 -13
- package/dist/cjs/vue/index.cjs.map +1 -1
- package/dist/esm/angular/index.js +799 -13
- package/dist/esm/angular/index.js.map +1 -1
- package/dist/esm/index.js +807 -14
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/react/index.js +800 -14
- package/dist/esm/react/index.js.map +1 -1
- package/dist/esm/remix/index.js +800 -14
- package/dist/esm/remix/index.js.map +1 -1
- package/dist/esm/svelte/index.js +799 -13
- package/dist/esm/svelte/index.js.map +1 -1
- package/dist/esm/vue/index.js +799 -13
- package/dist/esm/vue/index.js.map +1 -1
- package/dist/index.min.js +1 -1
- package/dist/index.min.js.map +1 -1
- package/dist/types/angular/index.d.ts +60 -1
- package/dist/types/index.d.ts +258 -3
- package/dist/types/react/index.d.ts +60 -1
- package/dist/types/remix/index.d.ts +60 -1
- package/dist/types/svelte/index.d.ts +60 -1
- package/package/canvas-recording-demo.html +1 -1
- package/package/simple-spa.html +1 -1
- package/package/src/angular/index.ts +3 -3
- package/package/src/react/index.tsx +2 -2
- package/package/src/svelte/index.ts +1 -1
- package/package/src/tracker.ts +2 -2
- package/package/src/vue/index.ts +1 -1
- package/package.json +1 -1
- package/simple-spa.html +164 -2
- package/src/angular/index.ts +3 -3
- package/src/api.ts +40 -0
- package/src/index.ts +7 -0
- package/src/react/index.tsx +2 -2
- package/src/svelte/index.ts +1 -1
- package/src/tracker.ts +175 -11
- package/src/utils/ip-detector.ts +158 -0
- package/src/utils/property-detector.ts +345 -0
- package/src/utils/property-manager.ts +274 -0
- package/src/vue/index.ts +1 -1
- package/canvas-recording-demo.html +0 -143
- package/clean-console-demo.html +0 -39
- package/simple-demo.html +0 -26
package/dist/esm/index.js
CHANGED
|
@@ -12389,6 +12389,152 @@ const logWarn = (message, ...args) => logger.warn(message, ...args);
|
|
|
12389
12389
|
const logInfo = (message, ...args) => logger.info(message, ...args);
|
|
12390
12390
|
const logDebug = (message, ...args) => logger.debug(message, ...args);
|
|
12391
12391
|
|
|
12392
|
+
/**
|
|
12393
|
+
* IP Address Detection Utility
|
|
12394
|
+
* Attempts to get the client's public IP address using multiple methods
|
|
12395
|
+
*/
|
|
12396
|
+
/**
|
|
12397
|
+
* Get IP address using STUN server (most reliable)
|
|
12398
|
+
*/
|
|
12399
|
+
function getIPFromSTUN() {
|
|
12400
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
12401
|
+
try {
|
|
12402
|
+
const pc = new RTCPeerConnection({
|
|
12403
|
+
iceServers: [
|
|
12404
|
+
{ urls: 'stun:stun.l.google.com:19302' },
|
|
12405
|
+
{ urls: 'stun:stun1.l.google.com:19302' },
|
|
12406
|
+
{ urls: 'stun:stun2.l.google.com:19302' }
|
|
12407
|
+
]
|
|
12408
|
+
});
|
|
12409
|
+
return new Promise((resolve) => {
|
|
12410
|
+
const timeout = setTimeout(() => {
|
|
12411
|
+
pc.close();
|
|
12412
|
+
resolve(null);
|
|
12413
|
+
}, 5000);
|
|
12414
|
+
pc.createDataChannel('');
|
|
12415
|
+
pc.createOffer()
|
|
12416
|
+
.then(offer => pc.setLocalDescription(offer))
|
|
12417
|
+
.catch(() => resolve(null));
|
|
12418
|
+
pc.onicecandidate = (event) => {
|
|
12419
|
+
if (event.candidate) {
|
|
12420
|
+
const candidate = event.candidate.candidate;
|
|
12421
|
+
const match = candidate.match(/([0-9]{1,3}(\.[0-9]{1,3}){3})/);
|
|
12422
|
+
if (match) {
|
|
12423
|
+
clearTimeout(timeout);
|
|
12424
|
+
pc.close();
|
|
12425
|
+
resolve(match[1]);
|
|
12426
|
+
}
|
|
12427
|
+
}
|
|
12428
|
+
};
|
|
12429
|
+
});
|
|
12430
|
+
}
|
|
12431
|
+
catch (error) {
|
|
12432
|
+
return null;
|
|
12433
|
+
}
|
|
12434
|
+
});
|
|
12435
|
+
}
|
|
12436
|
+
/**
|
|
12437
|
+
* Get IP address using public IP service (fallback)
|
|
12438
|
+
*/
|
|
12439
|
+
function getIPFromPublicService() {
|
|
12440
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
12441
|
+
try {
|
|
12442
|
+
const response = yield fetch('https://api.ipify.org?format=json', {
|
|
12443
|
+
method: 'GET'
|
|
12444
|
+
});
|
|
12445
|
+
if (response.ok) {
|
|
12446
|
+
const data = yield response.json();
|
|
12447
|
+
return data.ip;
|
|
12448
|
+
}
|
|
12449
|
+
}
|
|
12450
|
+
catch (error) {
|
|
12451
|
+
// Try alternative service
|
|
12452
|
+
try {
|
|
12453
|
+
const response = yield fetch('https://httpbin.org/ip', {
|
|
12454
|
+
method: 'GET'
|
|
12455
|
+
});
|
|
12456
|
+
if (response.ok) {
|
|
12457
|
+
const data = yield response.json();
|
|
12458
|
+
return data.origin;
|
|
12459
|
+
}
|
|
12460
|
+
}
|
|
12461
|
+
catch (fallbackError) {
|
|
12462
|
+
// Last resort
|
|
12463
|
+
try {
|
|
12464
|
+
const response = yield fetch('https://api.myip.com', {
|
|
12465
|
+
method: 'GET'
|
|
12466
|
+
});
|
|
12467
|
+
if (response.ok) {
|
|
12468
|
+
const data = yield response.json();
|
|
12469
|
+
return data.ip;
|
|
12470
|
+
}
|
|
12471
|
+
}
|
|
12472
|
+
catch (lastError) {
|
|
12473
|
+
return null;
|
|
12474
|
+
}
|
|
12475
|
+
}
|
|
12476
|
+
}
|
|
12477
|
+
return null;
|
|
12478
|
+
});
|
|
12479
|
+
}
|
|
12480
|
+
/**
|
|
12481
|
+
* Get client's public IP address
|
|
12482
|
+
* Tries STUN first (most reliable), then falls back to public services
|
|
12483
|
+
*/
|
|
12484
|
+
function getClientIP() {
|
|
12485
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
12486
|
+
const startTime = Date.now();
|
|
12487
|
+
// Try STUN first (most reliable and privacy-friendly)
|
|
12488
|
+
const stunIP = yield getIPFromSTUN();
|
|
12489
|
+
if (stunIP) {
|
|
12490
|
+
return {
|
|
12491
|
+
ip: stunIP,
|
|
12492
|
+
method: 'stun',
|
|
12493
|
+
timestamp: startTime
|
|
12494
|
+
};
|
|
12495
|
+
}
|
|
12496
|
+
// Fallback to public IP service
|
|
12497
|
+
const publicIP = yield getIPFromPublicService();
|
|
12498
|
+
if (publicIP) {
|
|
12499
|
+
return {
|
|
12500
|
+
ip: publicIP,
|
|
12501
|
+
method: 'public-service',
|
|
12502
|
+
timestamp: startTime
|
|
12503
|
+
};
|
|
12504
|
+
}
|
|
12505
|
+
return null;
|
|
12506
|
+
});
|
|
12507
|
+
}
|
|
12508
|
+
/**
|
|
12509
|
+
* Get IP address with caching to avoid repeated requests
|
|
12510
|
+
*/
|
|
12511
|
+
let cachedIP = null;
|
|
12512
|
+
let cacheTimestamp = 0;
|
|
12513
|
+
const CACHE_DURATION = 5 * 60 * 1000; // 5 minutes
|
|
12514
|
+
function getCachedIP() {
|
|
12515
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
12516
|
+
const now = Date.now();
|
|
12517
|
+
// Return cached IP if still valid
|
|
12518
|
+
if (cachedIP && (now - cacheTimestamp) < CACHE_DURATION) {
|
|
12519
|
+
return cachedIP;
|
|
12520
|
+
}
|
|
12521
|
+
// Get fresh IP
|
|
12522
|
+
const ipInfo = yield getClientIP();
|
|
12523
|
+
if (ipInfo) {
|
|
12524
|
+
cachedIP = ipInfo;
|
|
12525
|
+
cacheTimestamp = now;
|
|
12526
|
+
}
|
|
12527
|
+
return ipInfo;
|
|
12528
|
+
});
|
|
12529
|
+
}
|
|
12530
|
+
/**
|
|
12531
|
+
* Clear IP cache (useful for testing or when network changes)
|
|
12532
|
+
*/
|
|
12533
|
+
function clearIPCache() {
|
|
12534
|
+
cachedIP = null;
|
|
12535
|
+
cacheTimestamp = 0;
|
|
12536
|
+
}
|
|
12537
|
+
|
|
12392
12538
|
const MAX_CHUNK_SIZE_BYTES = 1024 * 1024; // 1MB chunk size - more conservative
|
|
12393
12539
|
function isChunkSizeExceeded(currentChunk, newEvent, sessionId) {
|
|
12394
12540
|
const nextChunkSize = new TextEncoder().encode(JSON.stringify({
|
|
@@ -12492,6 +12638,45 @@ class HumanBehaviorAPI {
|
|
|
12492
12638
|
}
|
|
12493
12639
|
});
|
|
12494
12640
|
}
|
|
12641
|
+
/**
|
|
12642
|
+
* Send IP address information to the server
|
|
12643
|
+
* This is called after successful initialization
|
|
12644
|
+
*/
|
|
12645
|
+
sendIPInfo(sessionId) {
|
|
12646
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
12647
|
+
try {
|
|
12648
|
+
const ipInfo = yield getCachedIP();
|
|
12649
|
+
if (!ipInfo) {
|
|
12650
|
+
logWarn('No IP address available to send');
|
|
12651
|
+
return;
|
|
12652
|
+
}
|
|
12653
|
+
logDebug('Sending IP info:', ipInfo);
|
|
12654
|
+
const response = yield fetch(`${this.baseUrl}/api/ingestion/ip-info`, {
|
|
12655
|
+
method: 'POST',
|
|
12656
|
+
headers: {
|
|
12657
|
+
'Content-Type': 'application/json',
|
|
12658
|
+
'Authorization': `Bearer ${this.apiKey}`
|
|
12659
|
+
},
|
|
12660
|
+
body: JSON.stringify({
|
|
12661
|
+
sessionId: sessionId,
|
|
12662
|
+
clientIP: ipInfo.ip,
|
|
12663
|
+
ipDetectionMethod: ipInfo.method,
|
|
12664
|
+
timestamp: ipInfo.timestamp
|
|
12665
|
+
})
|
|
12666
|
+
});
|
|
12667
|
+
if (!response.ok) {
|
|
12668
|
+
const errorText = yield response.text();
|
|
12669
|
+
logWarn('Failed to send IP info:', response.status, errorText);
|
|
12670
|
+
}
|
|
12671
|
+
else {
|
|
12672
|
+
logDebug('IP info sent successfully');
|
|
12673
|
+
}
|
|
12674
|
+
}
|
|
12675
|
+
catch (error) {
|
|
12676
|
+
logWarn('Error sending IP info:', error);
|
|
12677
|
+
}
|
|
12678
|
+
});
|
|
12679
|
+
}
|
|
12495
12680
|
sendEvents(events, sessionId, userId) {
|
|
12496
12681
|
return __awaiter(this, void 0, void 0, function* () {
|
|
12497
12682
|
// ✅ SIMPLE VALIDATION FOR ALL EVENTS
|
|
@@ -12718,7 +12903,7 @@ class HumanBehaviorAPI {
|
|
|
12718
12903
|
// This module provides methods to configure rrweb's built-in masking
|
|
12719
12904
|
// Uses CSS selectors and classes for reliable redaction without event corruption
|
|
12720
12905
|
// Check if we're in a browser environment
|
|
12721
|
-
const isBrowser$
|
|
12906
|
+
const isBrowser$2 = typeof window !== 'undefined';
|
|
12722
12907
|
class RedactionManager {
|
|
12723
12908
|
constructor(options) {
|
|
12724
12909
|
this.redactedText = '[REDACTED]';
|
|
@@ -12877,7 +13062,7 @@ class RedactionManager {
|
|
|
12877
13062
|
* Check if a DOM change should be redacted based on its ID
|
|
12878
13063
|
*/
|
|
12879
13064
|
shouldRedactDOMChange(changeData) {
|
|
12880
|
-
if (!isBrowser$
|
|
13065
|
+
if (!isBrowser$2)
|
|
12881
13066
|
return false;
|
|
12882
13067
|
try {
|
|
12883
13068
|
// Check if this change has an ID that we can use to find the element
|
|
@@ -13020,7 +13205,7 @@ class RedactionManager {
|
|
|
13020
13205
|
* Check if an event is from a field that should be redacted
|
|
13021
13206
|
*/
|
|
13022
13207
|
isFieldSelected(eventData) {
|
|
13023
|
-
if (!isBrowser$
|
|
13208
|
+
if (!isBrowser$2)
|
|
13024
13209
|
return false;
|
|
13025
13210
|
try {
|
|
13026
13211
|
// For input events (source 5), we need to determine if this is a sensitive field
|
|
@@ -13171,6 +13356,485 @@ class RedactionManager {
|
|
|
13171
13356
|
// Export a default instance
|
|
13172
13357
|
const redactionManager = new RedactionManager();
|
|
13173
13358
|
|
|
13359
|
+
/**
|
|
13360
|
+
* Automatic Property Detection for HumanBehavior SDK
|
|
13361
|
+
* Captures device type, location, and initial referrer information
|
|
13362
|
+
*/
|
|
13363
|
+
// Check if we're in a browser environment
|
|
13364
|
+
const isBrowser$1 = typeof window !== 'undefined';
|
|
13365
|
+
/**
|
|
13366
|
+
* Detect device type based on user agent and screen size
|
|
13367
|
+
*/
|
|
13368
|
+
function detectDeviceType() {
|
|
13369
|
+
if (!isBrowser$1)
|
|
13370
|
+
return 'unknown';
|
|
13371
|
+
const userAgent = navigator.userAgent.toLowerCase();
|
|
13372
|
+
const screenWidth = window.screen.width;
|
|
13373
|
+
const screenHeight = window.screen.height;
|
|
13374
|
+
// Mobile detection
|
|
13375
|
+
if (/mobile|android|iphone|ipad|ipod|blackberry|windows phone/i.test(userAgent)) {
|
|
13376
|
+
if (/ipad/i.test(userAgent) || (screenWidth >= 768 && screenHeight >= 1024)) {
|
|
13377
|
+
return 'tablet';
|
|
13378
|
+
}
|
|
13379
|
+
return 'mobile';
|
|
13380
|
+
}
|
|
13381
|
+
// Desktop detection
|
|
13382
|
+
if (/windows|macintosh|linux/i.test(userAgent)) {
|
|
13383
|
+
return 'desktop';
|
|
13384
|
+
}
|
|
13385
|
+
return 'unknown';
|
|
13386
|
+
}
|
|
13387
|
+
/**
|
|
13388
|
+
* Extract browser information from user agent
|
|
13389
|
+
*/
|
|
13390
|
+
function detectBrowser() {
|
|
13391
|
+
if (!isBrowser$1)
|
|
13392
|
+
return { browser: 'unknown', browser_version: 'unknown' };
|
|
13393
|
+
const userAgent = navigator.userAgent;
|
|
13394
|
+
// Chrome
|
|
13395
|
+
if (/chrome/i.test(userAgent) && !/edge/i.test(userAgent)) {
|
|
13396
|
+
const match = userAgent.match(/chrome\/(\d+)/i);
|
|
13397
|
+
return {
|
|
13398
|
+
browser: 'chrome',
|
|
13399
|
+
browser_version: match ? match[1] : 'unknown'
|
|
13400
|
+
};
|
|
13401
|
+
}
|
|
13402
|
+
// Firefox
|
|
13403
|
+
if (/firefox/i.test(userAgent)) {
|
|
13404
|
+
const match = userAgent.match(/firefox\/(\d+)/i);
|
|
13405
|
+
return {
|
|
13406
|
+
browser: 'firefox',
|
|
13407
|
+
browser_version: match ? match[1] : 'unknown'
|
|
13408
|
+
};
|
|
13409
|
+
}
|
|
13410
|
+
// Safari
|
|
13411
|
+
if (/safari/i.test(userAgent) && !/chrome/i.test(userAgent)) {
|
|
13412
|
+
const match = userAgent.match(/version\/(\d+)/i);
|
|
13413
|
+
return {
|
|
13414
|
+
browser: 'safari',
|
|
13415
|
+
browser_version: match ? match[1] : 'unknown'
|
|
13416
|
+
};
|
|
13417
|
+
}
|
|
13418
|
+
// Edge
|
|
13419
|
+
if (/edge/i.test(userAgent)) {
|
|
13420
|
+
const match = userAgent.match(/edge\/(\d+)/i);
|
|
13421
|
+
return {
|
|
13422
|
+
browser: 'edge',
|
|
13423
|
+
browser_version: match ? match[1] : 'unknown'
|
|
13424
|
+
};
|
|
13425
|
+
}
|
|
13426
|
+
// Internet Explorer
|
|
13427
|
+
if (/msie|trident/i.test(userAgent)) {
|
|
13428
|
+
const match = userAgent.match(/msie (\d+)/i) || userAgent.match(/rv:(\d+)/i);
|
|
13429
|
+
return {
|
|
13430
|
+
browser: 'ie',
|
|
13431
|
+
browser_version: match ? match[1] : 'unknown'
|
|
13432
|
+
};
|
|
13433
|
+
}
|
|
13434
|
+
return { browser: 'unknown', browser_version: 'unknown' };
|
|
13435
|
+
}
|
|
13436
|
+
/**
|
|
13437
|
+
* Extract operating system information from user agent
|
|
13438
|
+
*/
|
|
13439
|
+
function detectOS() {
|
|
13440
|
+
if (!isBrowser$1)
|
|
13441
|
+
return { os: 'unknown', os_version: 'unknown' };
|
|
13442
|
+
const userAgent = navigator.userAgent;
|
|
13443
|
+
// Windows
|
|
13444
|
+
if (/windows/i.test(userAgent)) {
|
|
13445
|
+
const match = userAgent.match(/windows nt (\d+\.\d+)/i);
|
|
13446
|
+
let version = 'unknown';
|
|
13447
|
+
if (match) {
|
|
13448
|
+
const versionNum = parseFloat(match[1]);
|
|
13449
|
+
if (versionNum === 10.0)
|
|
13450
|
+
version = '10';
|
|
13451
|
+
else if (versionNum === 6.3)
|
|
13452
|
+
version = '8.1';
|
|
13453
|
+
else if (versionNum === 6.2)
|
|
13454
|
+
version = '8';
|
|
13455
|
+
else if (versionNum === 6.1)
|
|
13456
|
+
version = '7';
|
|
13457
|
+
else
|
|
13458
|
+
version = match[1];
|
|
13459
|
+
}
|
|
13460
|
+
return { os: 'windows', os_version: version };
|
|
13461
|
+
}
|
|
13462
|
+
// macOS
|
|
13463
|
+
if (/macintosh|mac os x/i.test(userAgent)) {
|
|
13464
|
+
const match = userAgent.match(/mac os x (\d+[._]\d+)/i);
|
|
13465
|
+
return {
|
|
13466
|
+
os: 'macos',
|
|
13467
|
+
os_version: match ? match[1].replace('_', '.') : 'unknown'
|
|
13468
|
+
};
|
|
13469
|
+
}
|
|
13470
|
+
// iOS
|
|
13471
|
+
if (/iphone|ipad|ipod/i.test(userAgent)) {
|
|
13472
|
+
const match = userAgent.match(/os (\d+[._]\d+)/i);
|
|
13473
|
+
return {
|
|
13474
|
+
os: 'ios',
|
|
13475
|
+
os_version: match ? match[1].replace('_', '.') : 'unknown'
|
|
13476
|
+
};
|
|
13477
|
+
}
|
|
13478
|
+
// Android
|
|
13479
|
+
if (/android/i.test(userAgent)) {
|
|
13480
|
+
const match = userAgent.match(/android (\d+\.\d+)/i);
|
|
13481
|
+
return {
|
|
13482
|
+
os: 'android',
|
|
13483
|
+
os_version: match ? match[1] : 'unknown'
|
|
13484
|
+
};
|
|
13485
|
+
}
|
|
13486
|
+
// Linux
|
|
13487
|
+
if (/linux/i.test(userAgent)) {
|
|
13488
|
+
return { os: 'linux', os_version: 'unknown' };
|
|
13489
|
+
}
|
|
13490
|
+
return { os: 'unknown', os_version: 'unknown' };
|
|
13491
|
+
}
|
|
13492
|
+
/**
|
|
13493
|
+
* Extract UTM parameters from URL
|
|
13494
|
+
*/
|
|
13495
|
+
function extractUTMParams(url) {
|
|
13496
|
+
const urlObj = new URL(url);
|
|
13497
|
+
const utmParams = {};
|
|
13498
|
+
const utmKeys = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content'];
|
|
13499
|
+
utmKeys.forEach(key => {
|
|
13500
|
+
const value = urlObj.searchParams.get(key);
|
|
13501
|
+
if (value) {
|
|
13502
|
+
utmParams[key] = value;
|
|
13503
|
+
}
|
|
13504
|
+
});
|
|
13505
|
+
return utmParams;
|
|
13506
|
+
}
|
|
13507
|
+
/**
|
|
13508
|
+
* Extract domain from URL
|
|
13509
|
+
*/
|
|
13510
|
+
function extractDomain(url) {
|
|
13511
|
+
try {
|
|
13512
|
+
const urlObj = new URL(url);
|
|
13513
|
+
return urlObj.hostname;
|
|
13514
|
+
}
|
|
13515
|
+
catch (_a) {
|
|
13516
|
+
return '';
|
|
13517
|
+
}
|
|
13518
|
+
}
|
|
13519
|
+
/**
|
|
13520
|
+
* Get device information
|
|
13521
|
+
*/
|
|
13522
|
+
function getDeviceInfo() {
|
|
13523
|
+
if (!isBrowser$1) {
|
|
13524
|
+
return {
|
|
13525
|
+
device_type: 'unknown',
|
|
13526
|
+
browser: 'unknown',
|
|
13527
|
+
browser_version: 'unknown',
|
|
13528
|
+
os: 'unknown',
|
|
13529
|
+
os_version: 'unknown',
|
|
13530
|
+
screen_resolution: 'unknown',
|
|
13531
|
+
viewport_size: 'unknown',
|
|
13532
|
+
color_depth: 0,
|
|
13533
|
+
timezone: 'unknown',
|
|
13534
|
+
language: 'unknown',
|
|
13535
|
+
languages: []
|
|
13536
|
+
};
|
|
13537
|
+
}
|
|
13538
|
+
const { browser, browser_version } = detectBrowser();
|
|
13539
|
+
const { os, os_version } = detectOS();
|
|
13540
|
+
return {
|
|
13541
|
+
device_type: detectDeviceType(),
|
|
13542
|
+
browser,
|
|
13543
|
+
browser_version,
|
|
13544
|
+
os,
|
|
13545
|
+
os_version,
|
|
13546
|
+
screen_resolution: `${window.screen.width}x${window.screen.height}`,
|
|
13547
|
+
viewport_size: `${window.innerWidth}x${window.innerHeight}`,
|
|
13548
|
+
color_depth: window.screen.colorDepth,
|
|
13549
|
+
timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
|
|
13550
|
+
language: navigator.language,
|
|
13551
|
+
languages: [...(navigator.languages || [navigator.language])],
|
|
13552
|
+
raw_user_agent: navigator.userAgent
|
|
13553
|
+
};
|
|
13554
|
+
}
|
|
13555
|
+
/**
|
|
13556
|
+
* Get location information
|
|
13557
|
+
*/
|
|
13558
|
+
function getLocationInfo() {
|
|
13559
|
+
if (!isBrowser$1) {
|
|
13560
|
+
return {
|
|
13561
|
+
current_url: '',
|
|
13562
|
+
pathname: '',
|
|
13563
|
+
search: '',
|
|
13564
|
+
hash: '',
|
|
13565
|
+
title: '',
|
|
13566
|
+
referrer: '',
|
|
13567
|
+
referrer_domain: '',
|
|
13568
|
+
initial_referrer: '',
|
|
13569
|
+
initial_referrer_domain: ''
|
|
13570
|
+
};
|
|
13571
|
+
}
|
|
13572
|
+
const currentUrl = window.location.href;
|
|
13573
|
+
const referrer = document.referrer;
|
|
13574
|
+
const utmParams = extractUTMParams(currentUrl);
|
|
13575
|
+
return Object.assign({ current_url: currentUrl, pathname: window.location.pathname, search: window.location.search, hash: window.location.hash, title: document.title, referrer, referrer_domain: extractDomain(referrer), initial_referrer: referrer, initial_referrer_domain: extractDomain(referrer), initial_host: window.location.hostname }, utmParams);
|
|
13576
|
+
}
|
|
13577
|
+
/**
|
|
13578
|
+
* Get all automatic properties
|
|
13579
|
+
*/
|
|
13580
|
+
function getAutomaticProperties() {
|
|
13581
|
+
return Object.assign(Object.assign({}, getDeviceInfo()), getLocationInfo());
|
|
13582
|
+
}
|
|
13583
|
+
/**
|
|
13584
|
+
* Get initial properties that should be captured once per session
|
|
13585
|
+
*/
|
|
13586
|
+
function getInitialProperties() {
|
|
13587
|
+
if (!isBrowser$1)
|
|
13588
|
+
return {};
|
|
13589
|
+
const locationInfo = getLocationInfo();
|
|
13590
|
+
return {
|
|
13591
|
+
initial_referrer: locationInfo.initial_referrer,
|
|
13592
|
+
initial_referrer_domain: locationInfo.initial_referrer_domain,
|
|
13593
|
+
initial_url: locationInfo.current_url,
|
|
13594
|
+
initial_pathname: locationInfo.pathname,
|
|
13595
|
+
initial_utm_source: locationInfo.utm_source,
|
|
13596
|
+
initial_utm_medium: locationInfo.utm_medium,
|
|
13597
|
+
initial_utm_campaign: locationInfo.utm_campaign,
|
|
13598
|
+
initial_utm_term: locationInfo.utm_term,
|
|
13599
|
+
initial_utm_content: locationInfo.utm_content
|
|
13600
|
+
};
|
|
13601
|
+
}
|
|
13602
|
+
/**
|
|
13603
|
+
* Get current page properties (changes with navigation)
|
|
13604
|
+
*/
|
|
13605
|
+
function getCurrentPageProperties() {
|
|
13606
|
+
if (!isBrowser$1)
|
|
13607
|
+
return {};
|
|
13608
|
+
const locationInfo = getLocationInfo();
|
|
13609
|
+
return {
|
|
13610
|
+
current_url: locationInfo.current_url,
|
|
13611
|
+
pathname: locationInfo.pathname,
|
|
13612
|
+
search: locationInfo.search,
|
|
13613
|
+
hash: locationInfo.hash,
|
|
13614
|
+
title: locationInfo.title,
|
|
13615
|
+
referrer: locationInfo.referrer,
|
|
13616
|
+
referrer_domain: locationInfo.referrer_domain,
|
|
13617
|
+
utm_source: locationInfo.utm_source,
|
|
13618
|
+
utm_medium: locationInfo.utm_medium,
|
|
13619
|
+
utm_campaign: locationInfo.utm_campaign,
|
|
13620
|
+
utm_term: locationInfo.utm_term,
|
|
13621
|
+
utm_content: locationInfo.utm_content
|
|
13622
|
+
};
|
|
13623
|
+
}
|
|
13624
|
+
|
|
13625
|
+
/**
|
|
13626
|
+
* Property Manager for HumanBehavior SDK
|
|
13627
|
+
* Handles automatic properties, session properties, and user properties
|
|
13628
|
+
*/
|
|
13629
|
+
class PropertyManager {
|
|
13630
|
+
constructor(config = {}) {
|
|
13631
|
+
this.sessionProperties = {};
|
|
13632
|
+
this.userProperties = {};
|
|
13633
|
+
this.initialProperties = {};
|
|
13634
|
+
this.isInitialized = false;
|
|
13635
|
+
this.config = Object.assign({ enableAutomaticProperties: true, enableSessionProperties: true, enableUserProperties: true, propertyDenylist: [] }, config);
|
|
13636
|
+
this.automaticProperties = getAutomaticProperties();
|
|
13637
|
+
this.initialize();
|
|
13638
|
+
}
|
|
13639
|
+
/**
|
|
13640
|
+
* Initialize the property manager
|
|
13641
|
+
*/
|
|
13642
|
+
initialize() {
|
|
13643
|
+
if (this.isInitialized)
|
|
13644
|
+
return;
|
|
13645
|
+
// Capture initial properties once
|
|
13646
|
+
this.initialProperties = getInitialProperties();
|
|
13647
|
+
// Load session properties from sessionStorage
|
|
13648
|
+
this.loadSessionProperties();
|
|
13649
|
+
this.isInitialized = true;
|
|
13650
|
+
}
|
|
13651
|
+
/**
|
|
13652
|
+
* Get all properties for an event
|
|
13653
|
+
*/
|
|
13654
|
+
getEventProperties(eventProperties = {}) {
|
|
13655
|
+
const properties = Object.assign({}, eventProperties);
|
|
13656
|
+
// Add automatic properties
|
|
13657
|
+
if (this.config.enableAutomaticProperties) {
|
|
13658
|
+
Object.assign(properties, this.getAutomaticProperties());
|
|
13659
|
+
}
|
|
13660
|
+
// Add session properties
|
|
13661
|
+
if (this.config.enableSessionProperties) {
|
|
13662
|
+
Object.assign(properties, this.sessionProperties);
|
|
13663
|
+
}
|
|
13664
|
+
// Add user properties
|
|
13665
|
+
if (this.config.enableUserProperties) {
|
|
13666
|
+
Object.assign(properties, this.userProperties);
|
|
13667
|
+
}
|
|
13668
|
+
// Add initial properties (only once per session)
|
|
13669
|
+
if (!this.sessionProperties['$initial_properties_captured']) {
|
|
13670
|
+
Object.assign(properties, this.initialProperties);
|
|
13671
|
+
this.setSessionProperty('$initial_properties_captured', true);
|
|
13672
|
+
}
|
|
13673
|
+
// Apply denylist
|
|
13674
|
+
this.applyDenylist(properties);
|
|
13675
|
+
return properties;
|
|
13676
|
+
}
|
|
13677
|
+
/**
|
|
13678
|
+
* Get automatic properties
|
|
13679
|
+
*/
|
|
13680
|
+
getAutomaticProperties() {
|
|
13681
|
+
return Object.assign(Object.assign({}, this.automaticProperties), getCurrentPageProperties() // Always get fresh page properties
|
|
13682
|
+
);
|
|
13683
|
+
}
|
|
13684
|
+
/**
|
|
13685
|
+
* Get automatic properties with GeoIP data merged in
|
|
13686
|
+
*/
|
|
13687
|
+
getAutomaticPropertiesWithGeoIP(geoIPProperties = {}) {
|
|
13688
|
+
return Object.assign(Object.assign(Object.assign({}, this.automaticProperties), getCurrentPageProperties()), geoIPProperties);
|
|
13689
|
+
}
|
|
13690
|
+
/**
|
|
13691
|
+
* Set a session property
|
|
13692
|
+
*/
|
|
13693
|
+
setSessionProperty(key, value) {
|
|
13694
|
+
this.sessionProperties[key] = value;
|
|
13695
|
+
this.saveSessionProperties();
|
|
13696
|
+
}
|
|
13697
|
+
/**
|
|
13698
|
+
* Set multiple session properties
|
|
13699
|
+
*/
|
|
13700
|
+
setSessionProperties(properties) {
|
|
13701
|
+
Object.assign(this.sessionProperties, properties);
|
|
13702
|
+
this.saveSessionProperties();
|
|
13703
|
+
}
|
|
13704
|
+
/**
|
|
13705
|
+
* Get a session property
|
|
13706
|
+
*/
|
|
13707
|
+
getSessionProperty(key) {
|
|
13708
|
+
return this.sessionProperties[key];
|
|
13709
|
+
}
|
|
13710
|
+
/**
|
|
13711
|
+
* Remove a session property
|
|
13712
|
+
*/
|
|
13713
|
+
removeSessionProperty(key) {
|
|
13714
|
+
delete this.sessionProperties[key];
|
|
13715
|
+
this.saveSessionProperties();
|
|
13716
|
+
}
|
|
13717
|
+
/**
|
|
13718
|
+
* Set a user property
|
|
13719
|
+
*/
|
|
13720
|
+
setUserProperty(key, value) {
|
|
13721
|
+
this.userProperties[key] = value;
|
|
13722
|
+
}
|
|
13723
|
+
/**
|
|
13724
|
+
* Set multiple user properties
|
|
13725
|
+
*/
|
|
13726
|
+
setUserProperties(properties) {
|
|
13727
|
+
Object.assign(this.userProperties, properties);
|
|
13728
|
+
}
|
|
13729
|
+
/**
|
|
13730
|
+
* Get a user property
|
|
13731
|
+
*/
|
|
13732
|
+
getUserProperty(key) {
|
|
13733
|
+
return this.userProperties[key];
|
|
13734
|
+
}
|
|
13735
|
+
/**
|
|
13736
|
+
* Remove a user property
|
|
13737
|
+
*/
|
|
13738
|
+
removeUserProperty(key) {
|
|
13739
|
+
delete this.userProperties[key];
|
|
13740
|
+
}
|
|
13741
|
+
/**
|
|
13742
|
+
* Set a property only if it hasn't been set before
|
|
13743
|
+
*/
|
|
13744
|
+
setOnce(key, value, scope = 'user') {
|
|
13745
|
+
if (scope === 'session') {
|
|
13746
|
+
if (!(key in this.sessionProperties)) {
|
|
13747
|
+
this.setSessionProperty(key, value);
|
|
13748
|
+
}
|
|
13749
|
+
}
|
|
13750
|
+
else {
|
|
13751
|
+
if (!(key in this.userProperties)) {
|
|
13752
|
+
this.setUserProperty(key, value);
|
|
13753
|
+
}
|
|
13754
|
+
}
|
|
13755
|
+
}
|
|
13756
|
+
/**
|
|
13757
|
+
* Clear all session properties
|
|
13758
|
+
*/
|
|
13759
|
+
clearSessionProperties() {
|
|
13760
|
+
this.sessionProperties = {};
|
|
13761
|
+
this.saveSessionProperties();
|
|
13762
|
+
}
|
|
13763
|
+
/**
|
|
13764
|
+
* Clear all user properties
|
|
13765
|
+
*/
|
|
13766
|
+
clearUserProperties() {
|
|
13767
|
+
this.userProperties = {};
|
|
13768
|
+
}
|
|
13769
|
+
/**
|
|
13770
|
+
* Reset all properties
|
|
13771
|
+
*/
|
|
13772
|
+
reset() {
|
|
13773
|
+
this.clearSessionProperties();
|
|
13774
|
+
this.clearUserProperties();
|
|
13775
|
+
this.initialProperties = {};
|
|
13776
|
+
this.isInitialized = false;
|
|
13777
|
+
this.initialize();
|
|
13778
|
+
}
|
|
13779
|
+
/**
|
|
13780
|
+
* Load session properties from sessionStorage
|
|
13781
|
+
*/
|
|
13782
|
+
loadSessionProperties() {
|
|
13783
|
+
if (typeof sessionStorage === 'undefined')
|
|
13784
|
+
return;
|
|
13785
|
+
try {
|
|
13786
|
+
const stored = sessionStorage.getItem('hb_session_properties');
|
|
13787
|
+
if (stored) {
|
|
13788
|
+
this.sessionProperties = JSON.parse(stored);
|
|
13789
|
+
}
|
|
13790
|
+
}
|
|
13791
|
+
catch (error) {
|
|
13792
|
+
console.warn('Failed to load session properties:', error);
|
|
13793
|
+
}
|
|
13794
|
+
}
|
|
13795
|
+
/**
|
|
13796
|
+
* Save session properties to sessionStorage
|
|
13797
|
+
*/
|
|
13798
|
+
saveSessionProperties() {
|
|
13799
|
+
if (typeof sessionStorage === 'undefined')
|
|
13800
|
+
return;
|
|
13801
|
+
try {
|
|
13802
|
+
sessionStorage.setItem('hb_session_properties', JSON.stringify(this.sessionProperties));
|
|
13803
|
+
}
|
|
13804
|
+
catch (error) {
|
|
13805
|
+
console.warn('Failed to save session properties:', error);
|
|
13806
|
+
}
|
|
13807
|
+
}
|
|
13808
|
+
/**
|
|
13809
|
+
* Apply property denylist
|
|
13810
|
+
*/
|
|
13811
|
+
applyDenylist(properties) {
|
|
13812
|
+
if (!this.config.propertyDenylist || this.config.propertyDenylist.length === 0) {
|
|
13813
|
+
return;
|
|
13814
|
+
}
|
|
13815
|
+
this.config.propertyDenylist.forEach(deniedKey => {
|
|
13816
|
+
delete properties[deniedKey];
|
|
13817
|
+
});
|
|
13818
|
+
}
|
|
13819
|
+
/**
|
|
13820
|
+
* Update automatic properties (call when page changes)
|
|
13821
|
+
*/
|
|
13822
|
+
updateAutomaticProperties() {
|
|
13823
|
+
this.automaticProperties = getAutomaticProperties();
|
|
13824
|
+
}
|
|
13825
|
+
/**
|
|
13826
|
+
* Get all properties for debugging
|
|
13827
|
+
*/
|
|
13828
|
+
getAllProperties() {
|
|
13829
|
+
return {
|
|
13830
|
+
automatic: this.getAutomaticProperties(),
|
|
13831
|
+
session: Object.assign({}, this.sessionProperties),
|
|
13832
|
+
user: Object.assign({}, this.userProperties),
|
|
13833
|
+
initial: Object.assign({}, this.initialProperties)
|
|
13834
|
+
};
|
|
13835
|
+
}
|
|
13836
|
+
}
|
|
13837
|
+
|
|
13174
13838
|
// Check if we're in a browser environment
|
|
13175
13839
|
const isBrowser = typeof window !== 'undefined';
|
|
13176
13840
|
class HumanBehaviorTracker {
|
|
@@ -13237,7 +13901,10 @@ class HumanBehaviorTracker {
|
|
|
13237
13901
|
this.configureLogging({ level: options.logLevel });
|
|
13238
13902
|
}
|
|
13239
13903
|
// Create new tracker instance
|
|
13240
|
-
const tracker = new HumanBehaviorTracker(apiKey, options === null || options === void 0 ? void 0 : options.ingestionUrl
|
|
13904
|
+
const tracker = new HumanBehaviorTracker(apiKey, options === null || options === void 0 ? void 0 : options.ingestionUrl, {
|
|
13905
|
+
enableAutomaticProperties: options === null || options === void 0 ? void 0 : options.enableAutomaticProperties,
|
|
13906
|
+
propertyDenylist: options === null || options === void 0 ? void 0 : options.propertyDenylist
|
|
13907
|
+
});
|
|
13241
13908
|
// Store canvas recording preference
|
|
13242
13909
|
tracker.recordCanvas = (_a = options === null || options === void 0 ? void 0 : options.recordCanvas) !== null && _a !== void 0 ? _a : false;
|
|
13243
13910
|
// Set redacted fields if specified
|
|
@@ -13254,7 +13921,7 @@ class HumanBehaviorTracker {
|
|
|
13254
13921
|
tracker.start();
|
|
13255
13922
|
return tracker;
|
|
13256
13923
|
}
|
|
13257
|
-
constructor(apiKey, ingestionUrl) {
|
|
13924
|
+
constructor(apiKey, ingestionUrl, options) {
|
|
13258
13925
|
this.eventIngestionQueue = [];
|
|
13259
13926
|
this.userProperties = {};
|
|
13260
13927
|
this.isProcessing = false;
|
|
@@ -13292,6 +13959,11 @@ class HumanBehaviorTracker {
|
|
|
13292
13959
|
});
|
|
13293
13960
|
this.apiKey = apiKey;
|
|
13294
13961
|
this.redactionManager = new RedactionManager();
|
|
13962
|
+
// Initialize property manager
|
|
13963
|
+
this.propertyManager = new PropertyManager({
|
|
13964
|
+
enableAutomaticProperties: (options === null || options === void 0 ? void 0 : options.enableAutomaticProperties) !== false,
|
|
13965
|
+
propertyDenylist: (options === null || options === void 0 ? void 0 : options.propertyDenylist) || []
|
|
13966
|
+
});
|
|
13295
13967
|
// Handle session restoration with improved continuity
|
|
13296
13968
|
if (isBrowser) {
|
|
13297
13969
|
const existingSessionId = localStorage.getItem(`human_behavior_session_id_${this.apiKey}`);
|
|
@@ -13330,7 +14002,28 @@ class HumanBehaviorTracker {
|
|
|
13330
14002
|
try {
|
|
13331
14003
|
const userId = this.getCookie(`human_behavior_end_user_id_${this.apiKey}`);
|
|
13332
14004
|
logDebug(`Initializing with sessionId: ${this.sessionId}, userId: ${userId}`);
|
|
13333
|
-
|
|
14005
|
+
// Get automatic properties for init
|
|
14006
|
+
const automaticProperties = this.propertyManager.getAutomaticProperties();
|
|
14007
|
+
// Create a custom init request with automatic properties
|
|
14008
|
+
const initResponse = yield fetch(`${this.api['baseUrl']}/api/ingestion/init`, {
|
|
14009
|
+
method: 'POST',
|
|
14010
|
+
headers: {
|
|
14011
|
+
'Content-Type': 'application/json',
|
|
14012
|
+
'Authorization': `Bearer ${this.apiKey}`,
|
|
14013
|
+
'Referer': document.referrer || ''
|
|
14014
|
+
},
|
|
14015
|
+
body: JSON.stringify({
|
|
14016
|
+
sessionId: this.sessionId,
|
|
14017
|
+
endUserId: userId,
|
|
14018
|
+
entryURL: window.location.href,
|
|
14019
|
+
referrer: document.referrer,
|
|
14020
|
+
automaticProperties: automaticProperties
|
|
14021
|
+
})
|
|
14022
|
+
});
|
|
14023
|
+
if (!initResponse.ok) {
|
|
14024
|
+
throw new Error(`Failed to initialize: ${initResponse.statusText}`);
|
|
14025
|
+
}
|
|
14026
|
+
const { sessionId, endUserId } = yield initResponse.json();
|
|
13334
14027
|
// Check if server returned a different session ID (for session continuity)
|
|
13335
14028
|
if (sessionId !== this.sessionId) {
|
|
13336
14029
|
logDebug(`Server returned different sessionId: ${sessionId} (client had: ${this.sessionId})`);
|
|
@@ -13342,6 +14035,10 @@ class HumanBehaviorTracker {
|
|
|
13342
14035
|
}
|
|
13343
14036
|
this.endUserId = endUserId;
|
|
13344
14037
|
this.setCookie(`human_behavior_end_user_id_${this.apiKey}`, endUserId, 365);
|
|
14038
|
+
// Send IP information after successful initialization
|
|
14039
|
+
this.api.sendIPInfo(this.sessionId).catch(error => {
|
|
14040
|
+
logWarn('Failed to send IP info:', error);
|
|
14041
|
+
});
|
|
13345
14042
|
// Only setup browser-specific handlers when in browser environment
|
|
13346
14043
|
if (isBrowser) {
|
|
13347
14044
|
this.setupPageUnloadHandler();
|
|
@@ -13462,6 +14159,8 @@ class HumanBehaviorTracker {
|
|
|
13462
14159
|
return __awaiter(this, void 0, void 0, function* () {
|
|
13463
14160
|
if (!this.initialized)
|
|
13464
14161
|
return;
|
|
14162
|
+
// Update automatic properties for new page
|
|
14163
|
+
this.propertyManager.updateAutomaticProperties();
|
|
13465
14164
|
try {
|
|
13466
14165
|
const pageViewData = {
|
|
13467
14166
|
url: url || window.location.href,
|
|
@@ -13471,11 +14170,13 @@ class HumanBehaviorTracker {
|
|
|
13471
14170
|
referrer: document.referrer,
|
|
13472
14171
|
timestamp: new Date().toISOString()
|
|
13473
14172
|
};
|
|
14173
|
+
// Get enhanced properties with automatic properties
|
|
14174
|
+
const enhancedProperties = this.propertyManager.getEventProperties(pageViewData);
|
|
13474
14175
|
// Add pageview event to the main event stream
|
|
13475
14176
|
yield this.addEvent({
|
|
13476
14177
|
type: 5, // Custom event type
|
|
13477
14178
|
data: {
|
|
13478
|
-
payload: Object.assign({ eventType: 'pageview' },
|
|
14179
|
+
payload: Object.assign({ eventType: 'pageview' }, enhancedProperties)
|
|
13479
14180
|
},
|
|
13480
14181
|
timestamp: Date.now()
|
|
13481
14182
|
});
|
|
@@ -13491,10 +14192,12 @@ class HumanBehaviorTracker {
|
|
|
13491
14192
|
var _a, _b, _c, _d, _e;
|
|
13492
14193
|
if (!this.initialized)
|
|
13493
14194
|
return;
|
|
14195
|
+
// Get enhanced properties with automatic properties
|
|
14196
|
+
const enhancedProperties = this.propertyManager.getEventProperties(properties);
|
|
13494
14197
|
try {
|
|
13495
14198
|
// Send custom event directly to the API
|
|
13496
|
-
yield this.api.sendCustomEvent(this.sessionId, eventName,
|
|
13497
|
-
logDebug(`Custom event tracked: ${eventName}`,
|
|
14199
|
+
yield this.api.sendCustomEvent(this.sessionId, eventName, enhancedProperties);
|
|
14200
|
+
logDebug(`Custom event tracked: ${eventName}`, enhancedProperties);
|
|
13498
14201
|
}
|
|
13499
14202
|
catch (error) {
|
|
13500
14203
|
logError('Failed to track custom event:', error);
|
|
@@ -13514,7 +14217,7 @@ class HumanBehaviorTracker {
|
|
|
13514
14217
|
try {
|
|
13515
14218
|
const customEventData = {
|
|
13516
14219
|
eventName: eventName,
|
|
13517
|
-
properties:
|
|
14220
|
+
properties: enhancedProperties || {},
|
|
13518
14221
|
timestamp: new Date().toISOString(),
|
|
13519
14222
|
url: window.location.href,
|
|
13520
14223
|
pathname: window.location.pathname
|
|
@@ -13814,8 +14517,25 @@ class HumanBehaviorTracker {
|
|
|
13814
14517
|
// Store user properties
|
|
13815
14518
|
this.userProperties = userProperties;
|
|
13816
14519
|
logDebug('Identifying user:', { userProperties, originalEndUserId, sessionId: this.sessionId });
|
|
13817
|
-
//
|
|
13818
|
-
|
|
14520
|
+
// Get automatic properties and send with user data
|
|
14521
|
+
const automaticProperties = this.propertyManager.getAutomaticProperties();
|
|
14522
|
+
// Create a custom user request with automatic properties
|
|
14523
|
+
const userResponse = yield fetch(`${this.api['baseUrl']}/api/ingestion/user`, {
|
|
14524
|
+
method: 'POST',
|
|
14525
|
+
headers: {
|
|
14526
|
+
'Content-Type': 'application/json',
|
|
14527
|
+
'Authorization': `Bearer ${this.apiKey}`
|
|
14528
|
+
},
|
|
14529
|
+
body: JSON.stringify({
|
|
14530
|
+
userId: originalEndUserId,
|
|
14531
|
+
userAttributes: userProperties,
|
|
14532
|
+
sessionId: this.sessionId,
|
|
14533
|
+
automaticProperties: automaticProperties
|
|
14534
|
+
})
|
|
14535
|
+
});
|
|
14536
|
+
if (!userResponse.ok) {
|
|
14537
|
+
throw new Error(`Failed to identify user: ${userResponse.statusText}`);
|
|
14538
|
+
}
|
|
13819
14539
|
// Don't update endUserId - keep it as the original UUID
|
|
13820
14540
|
return originalEndUserId || '';
|
|
13821
14541
|
});
|
|
@@ -13863,7 +14583,7 @@ class HumanBehaviorTracker {
|
|
|
13863
14583
|
collectFonts: false, // Disable font collection to reduce errors
|
|
13864
14584
|
inlineStylesheet: true, // Keep styles for proper session replay
|
|
13865
14585
|
recordCrossOriginIframes: false, // Prevent cross-origin iframe errors
|
|
13866
|
-
// ✅ CANVAS RECORDING -
|
|
14586
|
+
// ✅ CANVAS RECORDING - protection against overwhelm
|
|
13867
14587
|
recordCanvas: this.recordCanvas, // Opt-in only
|
|
13868
14588
|
sampling: this.recordCanvas ? { canvas: 4 } : undefined, // 4 FPS throttle
|
|
13869
14589
|
dataURLOptions: this.recordCanvas ? {
|
|
@@ -14287,6 +15007,79 @@ class HumanBehaviorTracker {
|
|
|
14287
15007
|
initialized: this.initialized
|
|
14288
15008
|
};
|
|
14289
15009
|
}
|
|
15010
|
+
// ===== PROPERTY MANAGEMENT METHODS =====
|
|
15011
|
+
/**
|
|
15012
|
+
* Set a session property that will be included in all events for this session
|
|
15013
|
+
*/
|
|
15014
|
+
setSessionProperty(key, value) {
|
|
15015
|
+
this.propertyManager.setSessionProperty(key, value);
|
|
15016
|
+
}
|
|
15017
|
+
/**
|
|
15018
|
+
* Set multiple session properties
|
|
15019
|
+
*/
|
|
15020
|
+
setSessionProperties(properties) {
|
|
15021
|
+
this.propertyManager.setSessionProperties(properties);
|
|
15022
|
+
}
|
|
15023
|
+
/**
|
|
15024
|
+
* Get a session property
|
|
15025
|
+
*/
|
|
15026
|
+
getSessionProperty(key) {
|
|
15027
|
+
return this.propertyManager.getSessionProperty(key);
|
|
15028
|
+
}
|
|
15029
|
+
/**
|
|
15030
|
+
* Remove a session property
|
|
15031
|
+
*/
|
|
15032
|
+
removeSessionProperty(key) {
|
|
15033
|
+
this.propertyManager.removeSessionProperty(key);
|
|
15034
|
+
}
|
|
15035
|
+
/**
|
|
15036
|
+
* Set a user property that will be included in all events
|
|
15037
|
+
*/
|
|
15038
|
+
setUserProperty(key, value) {
|
|
15039
|
+
this.propertyManager.setUserProperty(key, value);
|
|
15040
|
+
}
|
|
15041
|
+
/**
|
|
15042
|
+
* Set multiple user properties
|
|
15043
|
+
*/
|
|
15044
|
+
setUserProperties(properties) {
|
|
15045
|
+
this.propertyManager.setUserProperties(properties);
|
|
15046
|
+
}
|
|
15047
|
+
/**
|
|
15048
|
+
* Get a user property
|
|
15049
|
+
*/
|
|
15050
|
+
getUserProperty(key) {
|
|
15051
|
+
return this.propertyManager.getUserProperty(key);
|
|
15052
|
+
}
|
|
15053
|
+
/**
|
|
15054
|
+
* Remove a user property
|
|
15055
|
+
*/
|
|
15056
|
+
removeUserProperty(key) {
|
|
15057
|
+
this.propertyManager.removeUserProperty(key);
|
|
15058
|
+
}
|
|
15059
|
+
/**
|
|
15060
|
+
* Set a property only if it hasn't been set before
|
|
15061
|
+
*/
|
|
15062
|
+
setOnce(key, value, scope = 'user') {
|
|
15063
|
+
this.propertyManager.setOnce(key, value, scope);
|
|
15064
|
+
}
|
|
15065
|
+
/**
|
|
15066
|
+
* Clear all session properties
|
|
15067
|
+
*/
|
|
15068
|
+
clearSessionProperties() {
|
|
15069
|
+
this.propertyManager.clearSessionProperties();
|
|
15070
|
+
}
|
|
15071
|
+
/**
|
|
15072
|
+
* Clear all user properties
|
|
15073
|
+
*/
|
|
15074
|
+
clearUserProperties() {
|
|
15075
|
+
this.propertyManager.clearUserProperties();
|
|
15076
|
+
}
|
|
15077
|
+
/**
|
|
15078
|
+
* Get all properties for debugging
|
|
15079
|
+
*/
|
|
15080
|
+
getAllProperties() {
|
|
15081
|
+
return this.propertyManager.getAllProperties();
|
|
15082
|
+
}
|
|
14290
15083
|
}
|
|
14291
15084
|
// Only expose to window object in browser environments
|
|
14292
15085
|
if (isBrowser) {
|
|
@@ -14305,5 +15098,5 @@ if (typeof window !== 'undefined') {
|
|
|
14305
15098
|
window.HumanBehaviorTracker = HumanBehaviorTracker;
|
|
14306
15099
|
}
|
|
14307
15100
|
|
|
14308
|
-
export { HumanBehaviorAPI, HumanBehaviorTracker, LogLevel, MAX_CHUNK_SIZE_BYTES, RedactionManager, isChunkSizeExceeded, logDebug, logError, logInfo, logWarn, logger, redactionManager, splitLargeEvent, validateSingleEventSize };
|
|
15101
|
+
export { HumanBehaviorAPI, HumanBehaviorTracker, LogLevel, MAX_CHUNK_SIZE_BYTES, PropertyManager, RedactionManager, clearIPCache, getAutomaticProperties, getCachedIP, getClientIP, getCurrentPageProperties, getDeviceInfo, getInitialProperties, getLocationInfo, isChunkSizeExceeded, logDebug, logError, logInfo, logWarn, logger, redactionManager, splitLargeEvent, validateSingleEventSize };
|
|
14309
15102
|
//# sourceMappingURL=index.js.map
|