humanbehavior-js 0.4.19 → 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/install-wizard.cjs +56 -10
- package/dist/cjs/install-wizard.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/cjs/wizard/index.cjs +56 -10
- package/dist/cjs/wizard/index.cjs.map +1 -1
- package/dist/cli/ai-auto-install.js +56 -10
- package/dist/cli/ai-auto-install.js.map +1 -1
- package/dist/cli/auto-install.js +56 -10
- package/dist/cli/auto-install.js.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/install-wizard.js +56 -10
- package/dist/esm/install-wizard.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/esm/wizard/index.js +56 -10
- package/dist/esm/wizard/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/src/wizard/core/install-wizard.ts +60 -10
- package/canvas-recording-demo.html +0 -143
- package/clean-console-demo.html +0 -39
- package/simple-demo.html +0 -26
package/dist/cjs/react/index.cjs
CHANGED
|
@@ -12393,6 +12393,145 @@ const logWarn = (message, ...args) => logger.warn(message, ...args);
|
|
|
12393
12393
|
const logInfo = (message, ...args) => logger.info(message, ...args);
|
|
12394
12394
|
const logDebug = (message, ...args) => logger.debug(message, ...args);
|
|
12395
12395
|
|
|
12396
|
+
/**
|
|
12397
|
+
* IP Address Detection Utility
|
|
12398
|
+
* Attempts to get the client's public IP address using multiple methods
|
|
12399
|
+
*/
|
|
12400
|
+
/**
|
|
12401
|
+
* Get IP address using STUN server (most reliable)
|
|
12402
|
+
*/
|
|
12403
|
+
function getIPFromSTUN() {
|
|
12404
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
12405
|
+
try {
|
|
12406
|
+
const pc = new RTCPeerConnection({
|
|
12407
|
+
iceServers: [
|
|
12408
|
+
{ urls: 'stun:stun.l.google.com:19302' },
|
|
12409
|
+
{ urls: 'stun:stun1.l.google.com:19302' },
|
|
12410
|
+
{ urls: 'stun:stun2.l.google.com:19302' }
|
|
12411
|
+
]
|
|
12412
|
+
});
|
|
12413
|
+
return new Promise((resolve) => {
|
|
12414
|
+
const timeout = setTimeout(() => {
|
|
12415
|
+
pc.close();
|
|
12416
|
+
resolve(null);
|
|
12417
|
+
}, 5000);
|
|
12418
|
+
pc.createDataChannel('');
|
|
12419
|
+
pc.createOffer()
|
|
12420
|
+
.then(offer => pc.setLocalDescription(offer))
|
|
12421
|
+
.catch(() => resolve(null));
|
|
12422
|
+
pc.onicecandidate = (event) => {
|
|
12423
|
+
if (event.candidate) {
|
|
12424
|
+
const candidate = event.candidate.candidate;
|
|
12425
|
+
const match = candidate.match(/([0-9]{1,3}(\.[0-9]{1,3}){3})/);
|
|
12426
|
+
if (match) {
|
|
12427
|
+
clearTimeout(timeout);
|
|
12428
|
+
pc.close();
|
|
12429
|
+
resolve(match[1]);
|
|
12430
|
+
}
|
|
12431
|
+
}
|
|
12432
|
+
};
|
|
12433
|
+
});
|
|
12434
|
+
}
|
|
12435
|
+
catch (error) {
|
|
12436
|
+
return null;
|
|
12437
|
+
}
|
|
12438
|
+
});
|
|
12439
|
+
}
|
|
12440
|
+
/**
|
|
12441
|
+
* Get IP address using public IP service (fallback)
|
|
12442
|
+
*/
|
|
12443
|
+
function getIPFromPublicService() {
|
|
12444
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
12445
|
+
try {
|
|
12446
|
+
const response = yield fetch('https://api.ipify.org?format=json', {
|
|
12447
|
+
method: 'GET'
|
|
12448
|
+
});
|
|
12449
|
+
if (response.ok) {
|
|
12450
|
+
const data = yield response.json();
|
|
12451
|
+
return data.ip;
|
|
12452
|
+
}
|
|
12453
|
+
}
|
|
12454
|
+
catch (error) {
|
|
12455
|
+
// Try alternative service
|
|
12456
|
+
try {
|
|
12457
|
+
const response = yield fetch('https://httpbin.org/ip', {
|
|
12458
|
+
method: 'GET'
|
|
12459
|
+
});
|
|
12460
|
+
if (response.ok) {
|
|
12461
|
+
const data = yield response.json();
|
|
12462
|
+
return data.origin;
|
|
12463
|
+
}
|
|
12464
|
+
}
|
|
12465
|
+
catch (fallbackError) {
|
|
12466
|
+
// Last resort
|
|
12467
|
+
try {
|
|
12468
|
+
const response = yield fetch('https://api.myip.com', {
|
|
12469
|
+
method: 'GET'
|
|
12470
|
+
});
|
|
12471
|
+
if (response.ok) {
|
|
12472
|
+
const data = yield response.json();
|
|
12473
|
+
return data.ip;
|
|
12474
|
+
}
|
|
12475
|
+
}
|
|
12476
|
+
catch (lastError) {
|
|
12477
|
+
return null;
|
|
12478
|
+
}
|
|
12479
|
+
}
|
|
12480
|
+
}
|
|
12481
|
+
return null;
|
|
12482
|
+
});
|
|
12483
|
+
}
|
|
12484
|
+
/**
|
|
12485
|
+
* Get client's public IP address
|
|
12486
|
+
* Tries STUN first (most reliable), then falls back to public services
|
|
12487
|
+
*/
|
|
12488
|
+
function getClientIP() {
|
|
12489
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
12490
|
+
const startTime = Date.now();
|
|
12491
|
+
// Try STUN first (most reliable and privacy-friendly)
|
|
12492
|
+
const stunIP = yield getIPFromSTUN();
|
|
12493
|
+
if (stunIP) {
|
|
12494
|
+
return {
|
|
12495
|
+
ip: stunIP,
|
|
12496
|
+
method: 'stun',
|
|
12497
|
+
timestamp: startTime
|
|
12498
|
+
};
|
|
12499
|
+
}
|
|
12500
|
+
// Fallback to public IP service
|
|
12501
|
+
const publicIP = yield getIPFromPublicService();
|
|
12502
|
+
if (publicIP) {
|
|
12503
|
+
return {
|
|
12504
|
+
ip: publicIP,
|
|
12505
|
+
method: 'public-service',
|
|
12506
|
+
timestamp: startTime
|
|
12507
|
+
};
|
|
12508
|
+
}
|
|
12509
|
+
return null;
|
|
12510
|
+
});
|
|
12511
|
+
}
|
|
12512
|
+
/**
|
|
12513
|
+
* Get IP address with caching to avoid repeated requests
|
|
12514
|
+
*/
|
|
12515
|
+
let cachedIP = null;
|
|
12516
|
+
let cacheTimestamp = 0;
|
|
12517
|
+
const CACHE_DURATION = 5 * 60 * 1000; // 5 minutes
|
|
12518
|
+
function getCachedIP() {
|
|
12519
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
12520
|
+
const now = Date.now();
|
|
12521
|
+
// Return cached IP if still valid
|
|
12522
|
+
if (cachedIP && (now - cacheTimestamp) < CACHE_DURATION) {
|
|
12523
|
+
return cachedIP;
|
|
12524
|
+
}
|
|
12525
|
+
// Get fresh IP
|
|
12526
|
+
const ipInfo = yield getClientIP();
|
|
12527
|
+
if (ipInfo) {
|
|
12528
|
+
cachedIP = ipInfo;
|
|
12529
|
+
cacheTimestamp = now;
|
|
12530
|
+
}
|
|
12531
|
+
return ipInfo;
|
|
12532
|
+
});
|
|
12533
|
+
}
|
|
12534
|
+
|
|
12396
12535
|
const MAX_CHUNK_SIZE_BYTES = 1024 * 1024; // 1MB chunk size - more conservative
|
|
12397
12536
|
function isChunkSizeExceeded(currentChunk, newEvent, sessionId) {
|
|
12398
12537
|
const nextChunkSize = new TextEncoder().encode(JSON.stringify({
|
|
@@ -12486,6 +12625,45 @@ class HumanBehaviorAPI {
|
|
|
12486
12625
|
}
|
|
12487
12626
|
});
|
|
12488
12627
|
}
|
|
12628
|
+
/**
|
|
12629
|
+
* Send IP address information to the server
|
|
12630
|
+
* This is called after successful initialization
|
|
12631
|
+
*/
|
|
12632
|
+
sendIPInfo(sessionId) {
|
|
12633
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
12634
|
+
try {
|
|
12635
|
+
const ipInfo = yield getCachedIP();
|
|
12636
|
+
if (!ipInfo) {
|
|
12637
|
+
logWarn('No IP address available to send');
|
|
12638
|
+
return;
|
|
12639
|
+
}
|
|
12640
|
+
logDebug('Sending IP info:', ipInfo);
|
|
12641
|
+
const response = yield fetch(`${this.baseUrl}/api/ingestion/ip-info`, {
|
|
12642
|
+
method: 'POST',
|
|
12643
|
+
headers: {
|
|
12644
|
+
'Content-Type': 'application/json',
|
|
12645
|
+
'Authorization': `Bearer ${this.apiKey}`
|
|
12646
|
+
},
|
|
12647
|
+
body: JSON.stringify({
|
|
12648
|
+
sessionId: sessionId,
|
|
12649
|
+
clientIP: ipInfo.ip,
|
|
12650
|
+
ipDetectionMethod: ipInfo.method,
|
|
12651
|
+
timestamp: ipInfo.timestamp
|
|
12652
|
+
})
|
|
12653
|
+
});
|
|
12654
|
+
if (!response.ok) {
|
|
12655
|
+
const errorText = yield response.text();
|
|
12656
|
+
logWarn('Failed to send IP info:', response.status, errorText);
|
|
12657
|
+
}
|
|
12658
|
+
else {
|
|
12659
|
+
logDebug('IP info sent successfully');
|
|
12660
|
+
}
|
|
12661
|
+
}
|
|
12662
|
+
catch (error) {
|
|
12663
|
+
logWarn('Error sending IP info:', error);
|
|
12664
|
+
}
|
|
12665
|
+
});
|
|
12666
|
+
}
|
|
12489
12667
|
sendEvents(events, sessionId, userId) {
|
|
12490
12668
|
return __awaiter(this, void 0, void 0, function* () {
|
|
12491
12669
|
// ✅ SIMPLE VALIDATION FOR ALL EVENTS
|
|
@@ -12712,7 +12890,7 @@ class HumanBehaviorAPI {
|
|
|
12712
12890
|
// This module provides methods to configure rrweb's built-in masking
|
|
12713
12891
|
// Uses CSS selectors and classes for reliable redaction without event corruption
|
|
12714
12892
|
// Check if we're in a browser environment
|
|
12715
|
-
const isBrowser$
|
|
12893
|
+
const isBrowser$3 = typeof window !== 'undefined';
|
|
12716
12894
|
class RedactionManager {
|
|
12717
12895
|
constructor(options) {
|
|
12718
12896
|
this.redactedText = '[REDACTED]';
|
|
@@ -12871,7 +13049,7 @@ class RedactionManager {
|
|
|
12871
13049
|
* Check if a DOM change should be redacted based on its ID
|
|
12872
13050
|
*/
|
|
12873
13051
|
shouldRedactDOMChange(changeData) {
|
|
12874
|
-
if (!isBrowser$
|
|
13052
|
+
if (!isBrowser$3)
|
|
12875
13053
|
return false;
|
|
12876
13054
|
try {
|
|
12877
13055
|
// Check if this change has an ID that we can use to find the element
|
|
@@ -13014,7 +13192,7 @@ class RedactionManager {
|
|
|
13014
13192
|
* Check if an event is from a field that should be redacted
|
|
13015
13193
|
*/
|
|
13016
13194
|
isFieldSelected(eventData) {
|
|
13017
|
-
if (!isBrowser$
|
|
13195
|
+
if (!isBrowser$3)
|
|
13018
13196
|
return false;
|
|
13019
13197
|
try {
|
|
13020
13198
|
// For input events (source 5), we need to determine if this is a sensitive field
|
|
@@ -13165,6 +13343,485 @@ class RedactionManager {
|
|
|
13165
13343
|
// Export a default instance
|
|
13166
13344
|
new RedactionManager();
|
|
13167
13345
|
|
|
13346
|
+
/**
|
|
13347
|
+
* Automatic Property Detection for HumanBehavior SDK
|
|
13348
|
+
* Captures device type, location, and initial referrer information
|
|
13349
|
+
*/
|
|
13350
|
+
// Check if we're in a browser environment
|
|
13351
|
+
const isBrowser$2 = typeof window !== 'undefined';
|
|
13352
|
+
/**
|
|
13353
|
+
* Detect device type based on user agent and screen size
|
|
13354
|
+
*/
|
|
13355
|
+
function detectDeviceType() {
|
|
13356
|
+
if (!isBrowser$2)
|
|
13357
|
+
return 'unknown';
|
|
13358
|
+
const userAgent = navigator.userAgent.toLowerCase();
|
|
13359
|
+
const screenWidth = window.screen.width;
|
|
13360
|
+
const screenHeight = window.screen.height;
|
|
13361
|
+
// Mobile detection
|
|
13362
|
+
if (/mobile|android|iphone|ipad|ipod|blackberry|windows phone/i.test(userAgent)) {
|
|
13363
|
+
if (/ipad/i.test(userAgent) || (screenWidth >= 768 && screenHeight >= 1024)) {
|
|
13364
|
+
return 'tablet';
|
|
13365
|
+
}
|
|
13366
|
+
return 'mobile';
|
|
13367
|
+
}
|
|
13368
|
+
// Desktop detection
|
|
13369
|
+
if (/windows|macintosh|linux/i.test(userAgent)) {
|
|
13370
|
+
return 'desktop';
|
|
13371
|
+
}
|
|
13372
|
+
return 'unknown';
|
|
13373
|
+
}
|
|
13374
|
+
/**
|
|
13375
|
+
* Extract browser information from user agent
|
|
13376
|
+
*/
|
|
13377
|
+
function detectBrowser() {
|
|
13378
|
+
if (!isBrowser$2)
|
|
13379
|
+
return { browser: 'unknown', browser_version: 'unknown' };
|
|
13380
|
+
const userAgent = navigator.userAgent;
|
|
13381
|
+
// Chrome
|
|
13382
|
+
if (/chrome/i.test(userAgent) && !/edge/i.test(userAgent)) {
|
|
13383
|
+
const match = userAgent.match(/chrome\/(\d+)/i);
|
|
13384
|
+
return {
|
|
13385
|
+
browser: 'chrome',
|
|
13386
|
+
browser_version: match ? match[1] : 'unknown'
|
|
13387
|
+
};
|
|
13388
|
+
}
|
|
13389
|
+
// Firefox
|
|
13390
|
+
if (/firefox/i.test(userAgent)) {
|
|
13391
|
+
const match = userAgent.match(/firefox\/(\d+)/i);
|
|
13392
|
+
return {
|
|
13393
|
+
browser: 'firefox',
|
|
13394
|
+
browser_version: match ? match[1] : 'unknown'
|
|
13395
|
+
};
|
|
13396
|
+
}
|
|
13397
|
+
// Safari
|
|
13398
|
+
if (/safari/i.test(userAgent) && !/chrome/i.test(userAgent)) {
|
|
13399
|
+
const match = userAgent.match(/version\/(\d+)/i);
|
|
13400
|
+
return {
|
|
13401
|
+
browser: 'safari',
|
|
13402
|
+
browser_version: match ? match[1] : 'unknown'
|
|
13403
|
+
};
|
|
13404
|
+
}
|
|
13405
|
+
// Edge
|
|
13406
|
+
if (/edge/i.test(userAgent)) {
|
|
13407
|
+
const match = userAgent.match(/edge\/(\d+)/i);
|
|
13408
|
+
return {
|
|
13409
|
+
browser: 'edge',
|
|
13410
|
+
browser_version: match ? match[1] : 'unknown'
|
|
13411
|
+
};
|
|
13412
|
+
}
|
|
13413
|
+
// Internet Explorer
|
|
13414
|
+
if (/msie|trident/i.test(userAgent)) {
|
|
13415
|
+
const match = userAgent.match(/msie (\d+)/i) || userAgent.match(/rv:(\d+)/i);
|
|
13416
|
+
return {
|
|
13417
|
+
browser: 'ie',
|
|
13418
|
+
browser_version: match ? match[1] : 'unknown'
|
|
13419
|
+
};
|
|
13420
|
+
}
|
|
13421
|
+
return { browser: 'unknown', browser_version: 'unknown' };
|
|
13422
|
+
}
|
|
13423
|
+
/**
|
|
13424
|
+
* Extract operating system information from user agent
|
|
13425
|
+
*/
|
|
13426
|
+
function detectOS() {
|
|
13427
|
+
if (!isBrowser$2)
|
|
13428
|
+
return { os: 'unknown', os_version: 'unknown' };
|
|
13429
|
+
const userAgent = navigator.userAgent;
|
|
13430
|
+
// Windows
|
|
13431
|
+
if (/windows/i.test(userAgent)) {
|
|
13432
|
+
const match = userAgent.match(/windows nt (\d+\.\d+)/i);
|
|
13433
|
+
let version = 'unknown';
|
|
13434
|
+
if (match) {
|
|
13435
|
+
const versionNum = parseFloat(match[1]);
|
|
13436
|
+
if (versionNum === 10.0)
|
|
13437
|
+
version = '10';
|
|
13438
|
+
else if (versionNum === 6.3)
|
|
13439
|
+
version = '8.1';
|
|
13440
|
+
else if (versionNum === 6.2)
|
|
13441
|
+
version = '8';
|
|
13442
|
+
else if (versionNum === 6.1)
|
|
13443
|
+
version = '7';
|
|
13444
|
+
else
|
|
13445
|
+
version = match[1];
|
|
13446
|
+
}
|
|
13447
|
+
return { os: 'windows', os_version: version };
|
|
13448
|
+
}
|
|
13449
|
+
// macOS
|
|
13450
|
+
if (/macintosh|mac os x/i.test(userAgent)) {
|
|
13451
|
+
const match = userAgent.match(/mac os x (\d+[._]\d+)/i);
|
|
13452
|
+
return {
|
|
13453
|
+
os: 'macos',
|
|
13454
|
+
os_version: match ? match[1].replace('_', '.') : 'unknown'
|
|
13455
|
+
};
|
|
13456
|
+
}
|
|
13457
|
+
// iOS
|
|
13458
|
+
if (/iphone|ipad|ipod/i.test(userAgent)) {
|
|
13459
|
+
const match = userAgent.match(/os (\d+[._]\d+)/i);
|
|
13460
|
+
return {
|
|
13461
|
+
os: 'ios',
|
|
13462
|
+
os_version: match ? match[1].replace('_', '.') : 'unknown'
|
|
13463
|
+
};
|
|
13464
|
+
}
|
|
13465
|
+
// Android
|
|
13466
|
+
if (/android/i.test(userAgent)) {
|
|
13467
|
+
const match = userAgent.match(/android (\d+\.\d+)/i);
|
|
13468
|
+
return {
|
|
13469
|
+
os: 'android',
|
|
13470
|
+
os_version: match ? match[1] : 'unknown'
|
|
13471
|
+
};
|
|
13472
|
+
}
|
|
13473
|
+
// Linux
|
|
13474
|
+
if (/linux/i.test(userAgent)) {
|
|
13475
|
+
return { os: 'linux', os_version: 'unknown' };
|
|
13476
|
+
}
|
|
13477
|
+
return { os: 'unknown', os_version: 'unknown' };
|
|
13478
|
+
}
|
|
13479
|
+
/**
|
|
13480
|
+
* Extract UTM parameters from URL
|
|
13481
|
+
*/
|
|
13482
|
+
function extractUTMParams(url) {
|
|
13483
|
+
const urlObj = new URL(url);
|
|
13484
|
+
const utmParams = {};
|
|
13485
|
+
const utmKeys = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content'];
|
|
13486
|
+
utmKeys.forEach(key => {
|
|
13487
|
+
const value = urlObj.searchParams.get(key);
|
|
13488
|
+
if (value) {
|
|
13489
|
+
utmParams[key] = value;
|
|
13490
|
+
}
|
|
13491
|
+
});
|
|
13492
|
+
return utmParams;
|
|
13493
|
+
}
|
|
13494
|
+
/**
|
|
13495
|
+
* Extract domain from URL
|
|
13496
|
+
*/
|
|
13497
|
+
function extractDomain(url) {
|
|
13498
|
+
try {
|
|
13499
|
+
const urlObj = new URL(url);
|
|
13500
|
+
return urlObj.hostname;
|
|
13501
|
+
}
|
|
13502
|
+
catch (_a) {
|
|
13503
|
+
return '';
|
|
13504
|
+
}
|
|
13505
|
+
}
|
|
13506
|
+
/**
|
|
13507
|
+
* Get device information
|
|
13508
|
+
*/
|
|
13509
|
+
function getDeviceInfo() {
|
|
13510
|
+
if (!isBrowser$2) {
|
|
13511
|
+
return {
|
|
13512
|
+
device_type: 'unknown',
|
|
13513
|
+
browser: 'unknown',
|
|
13514
|
+
browser_version: 'unknown',
|
|
13515
|
+
os: 'unknown',
|
|
13516
|
+
os_version: 'unknown',
|
|
13517
|
+
screen_resolution: 'unknown',
|
|
13518
|
+
viewport_size: 'unknown',
|
|
13519
|
+
color_depth: 0,
|
|
13520
|
+
timezone: 'unknown',
|
|
13521
|
+
language: 'unknown',
|
|
13522
|
+
languages: []
|
|
13523
|
+
};
|
|
13524
|
+
}
|
|
13525
|
+
const { browser, browser_version } = detectBrowser();
|
|
13526
|
+
const { os, os_version } = detectOS();
|
|
13527
|
+
return {
|
|
13528
|
+
device_type: detectDeviceType(),
|
|
13529
|
+
browser,
|
|
13530
|
+
browser_version,
|
|
13531
|
+
os,
|
|
13532
|
+
os_version,
|
|
13533
|
+
screen_resolution: `${window.screen.width}x${window.screen.height}`,
|
|
13534
|
+
viewport_size: `${window.innerWidth}x${window.innerHeight}`,
|
|
13535
|
+
color_depth: window.screen.colorDepth,
|
|
13536
|
+
timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
|
|
13537
|
+
language: navigator.language,
|
|
13538
|
+
languages: [...(navigator.languages || [navigator.language])],
|
|
13539
|
+
raw_user_agent: navigator.userAgent
|
|
13540
|
+
};
|
|
13541
|
+
}
|
|
13542
|
+
/**
|
|
13543
|
+
* Get location information
|
|
13544
|
+
*/
|
|
13545
|
+
function getLocationInfo() {
|
|
13546
|
+
if (!isBrowser$2) {
|
|
13547
|
+
return {
|
|
13548
|
+
current_url: '',
|
|
13549
|
+
pathname: '',
|
|
13550
|
+
search: '',
|
|
13551
|
+
hash: '',
|
|
13552
|
+
title: '',
|
|
13553
|
+
referrer: '',
|
|
13554
|
+
referrer_domain: '',
|
|
13555
|
+
initial_referrer: '',
|
|
13556
|
+
initial_referrer_domain: ''
|
|
13557
|
+
};
|
|
13558
|
+
}
|
|
13559
|
+
const currentUrl = window.location.href;
|
|
13560
|
+
const referrer = document.referrer;
|
|
13561
|
+
const utmParams = extractUTMParams(currentUrl);
|
|
13562
|
+
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);
|
|
13563
|
+
}
|
|
13564
|
+
/**
|
|
13565
|
+
* Get all automatic properties
|
|
13566
|
+
*/
|
|
13567
|
+
function getAutomaticProperties() {
|
|
13568
|
+
return Object.assign(Object.assign({}, getDeviceInfo()), getLocationInfo());
|
|
13569
|
+
}
|
|
13570
|
+
/**
|
|
13571
|
+
* Get initial properties that should be captured once per session
|
|
13572
|
+
*/
|
|
13573
|
+
function getInitialProperties() {
|
|
13574
|
+
if (!isBrowser$2)
|
|
13575
|
+
return {};
|
|
13576
|
+
const locationInfo = getLocationInfo();
|
|
13577
|
+
return {
|
|
13578
|
+
initial_referrer: locationInfo.initial_referrer,
|
|
13579
|
+
initial_referrer_domain: locationInfo.initial_referrer_domain,
|
|
13580
|
+
initial_url: locationInfo.current_url,
|
|
13581
|
+
initial_pathname: locationInfo.pathname,
|
|
13582
|
+
initial_utm_source: locationInfo.utm_source,
|
|
13583
|
+
initial_utm_medium: locationInfo.utm_medium,
|
|
13584
|
+
initial_utm_campaign: locationInfo.utm_campaign,
|
|
13585
|
+
initial_utm_term: locationInfo.utm_term,
|
|
13586
|
+
initial_utm_content: locationInfo.utm_content
|
|
13587
|
+
};
|
|
13588
|
+
}
|
|
13589
|
+
/**
|
|
13590
|
+
* Get current page properties (changes with navigation)
|
|
13591
|
+
*/
|
|
13592
|
+
function getCurrentPageProperties() {
|
|
13593
|
+
if (!isBrowser$2)
|
|
13594
|
+
return {};
|
|
13595
|
+
const locationInfo = getLocationInfo();
|
|
13596
|
+
return {
|
|
13597
|
+
current_url: locationInfo.current_url,
|
|
13598
|
+
pathname: locationInfo.pathname,
|
|
13599
|
+
search: locationInfo.search,
|
|
13600
|
+
hash: locationInfo.hash,
|
|
13601
|
+
title: locationInfo.title,
|
|
13602
|
+
referrer: locationInfo.referrer,
|
|
13603
|
+
referrer_domain: locationInfo.referrer_domain,
|
|
13604
|
+
utm_source: locationInfo.utm_source,
|
|
13605
|
+
utm_medium: locationInfo.utm_medium,
|
|
13606
|
+
utm_campaign: locationInfo.utm_campaign,
|
|
13607
|
+
utm_term: locationInfo.utm_term,
|
|
13608
|
+
utm_content: locationInfo.utm_content
|
|
13609
|
+
};
|
|
13610
|
+
}
|
|
13611
|
+
|
|
13612
|
+
/**
|
|
13613
|
+
* Property Manager for HumanBehavior SDK
|
|
13614
|
+
* Handles automatic properties, session properties, and user properties
|
|
13615
|
+
*/
|
|
13616
|
+
class PropertyManager {
|
|
13617
|
+
constructor(config = {}) {
|
|
13618
|
+
this.sessionProperties = {};
|
|
13619
|
+
this.userProperties = {};
|
|
13620
|
+
this.initialProperties = {};
|
|
13621
|
+
this.isInitialized = false;
|
|
13622
|
+
this.config = Object.assign({ enableAutomaticProperties: true, enableSessionProperties: true, enableUserProperties: true, propertyDenylist: [] }, config);
|
|
13623
|
+
this.automaticProperties = getAutomaticProperties();
|
|
13624
|
+
this.initialize();
|
|
13625
|
+
}
|
|
13626
|
+
/**
|
|
13627
|
+
* Initialize the property manager
|
|
13628
|
+
*/
|
|
13629
|
+
initialize() {
|
|
13630
|
+
if (this.isInitialized)
|
|
13631
|
+
return;
|
|
13632
|
+
// Capture initial properties once
|
|
13633
|
+
this.initialProperties = getInitialProperties();
|
|
13634
|
+
// Load session properties from sessionStorage
|
|
13635
|
+
this.loadSessionProperties();
|
|
13636
|
+
this.isInitialized = true;
|
|
13637
|
+
}
|
|
13638
|
+
/**
|
|
13639
|
+
* Get all properties for an event
|
|
13640
|
+
*/
|
|
13641
|
+
getEventProperties(eventProperties = {}) {
|
|
13642
|
+
const properties = Object.assign({}, eventProperties);
|
|
13643
|
+
// Add automatic properties
|
|
13644
|
+
if (this.config.enableAutomaticProperties) {
|
|
13645
|
+
Object.assign(properties, this.getAutomaticProperties());
|
|
13646
|
+
}
|
|
13647
|
+
// Add session properties
|
|
13648
|
+
if (this.config.enableSessionProperties) {
|
|
13649
|
+
Object.assign(properties, this.sessionProperties);
|
|
13650
|
+
}
|
|
13651
|
+
// Add user properties
|
|
13652
|
+
if (this.config.enableUserProperties) {
|
|
13653
|
+
Object.assign(properties, this.userProperties);
|
|
13654
|
+
}
|
|
13655
|
+
// Add initial properties (only once per session)
|
|
13656
|
+
if (!this.sessionProperties['$initial_properties_captured']) {
|
|
13657
|
+
Object.assign(properties, this.initialProperties);
|
|
13658
|
+
this.setSessionProperty('$initial_properties_captured', true);
|
|
13659
|
+
}
|
|
13660
|
+
// Apply denylist
|
|
13661
|
+
this.applyDenylist(properties);
|
|
13662
|
+
return properties;
|
|
13663
|
+
}
|
|
13664
|
+
/**
|
|
13665
|
+
* Get automatic properties
|
|
13666
|
+
*/
|
|
13667
|
+
getAutomaticProperties() {
|
|
13668
|
+
return Object.assign(Object.assign({}, this.automaticProperties), getCurrentPageProperties() // Always get fresh page properties
|
|
13669
|
+
);
|
|
13670
|
+
}
|
|
13671
|
+
/**
|
|
13672
|
+
* Get automatic properties with GeoIP data merged in
|
|
13673
|
+
*/
|
|
13674
|
+
getAutomaticPropertiesWithGeoIP(geoIPProperties = {}) {
|
|
13675
|
+
return Object.assign(Object.assign(Object.assign({}, this.automaticProperties), getCurrentPageProperties()), geoIPProperties);
|
|
13676
|
+
}
|
|
13677
|
+
/**
|
|
13678
|
+
* Set a session property
|
|
13679
|
+
*/
|
|
13680
|
+
setSessionProperty(key, value) {
|
|
13681
|
+
this.sessionProperties[key] = value;
|
|
13682
|
+
this.saveSessionProperties();
|
|
13683
|
+
}
|
|
13684
|
+
/**
|
|
13685
|
+
* Set multiple session properties
|
|
13686
|
+
*/
|
|
13687
|
+
setSessionProperties(properties) {
|
|
13688
|
+
Object.assign(this.sessionProperties, properties);
|
|
13689
|
+
this.saveSessionProperties();
|
|
13690
|
+
}
|
|
13691
|
+
/**
|
|
13692
|
+
* Get a session property
|
|
13693
|
+
*/
|
|
13694
|
+
getSessionProperty(key) {
|
|
13695
|
+
return this.sessionProperties[key];
|
|
13696
|
+
}
|
|
13697
|
+
/**
|
|
13698
|
+
* Remove a session property
|
|
13699
|
+
*/
|
|
13700
|
+
removeSessionProperty(key) {
|
|
13701
|
+
delete this.sessionProperties[key];
|
|
13702
|
+
this.saveSessionProperties();
|
|
13703
|
+
}
|
|
13704
|
+
/**
|
|
13705
|
+
* Set a user property
|
|
13706
|
+
*/
|
|
13707
|
+
setUserProperty(key, value) {
|
|
13708
|
+
this.userProperties[key] = value;
|
|
13709
|
+
}
|
|
13710
|
+
/**
|
|
13711
|
+
* Set multiple user properties
|
|
13712
|
+
*/
|
|
13713
|
+
setUserProperties(properties) {
|
|
13714
|
+
Object.assign(this.userProperties, properties);
|
|
13715
|
+
}
|
|
13716
|
+
/**
|
|
13717
|
+
* Get a user property
|
|
13718
|
+
*/
|
|
13719
|
+
getUserProperty(key) {
|
|
13720
|
+
return this.userProperties[key];
|
|
13721
|
+
}
|
|
13722
|
+
/**
|
|
13723
|
+
* Remove a user property
|
|
13724
|
+
*/
|
|
13725
|
+
removeUserProperty(key) {
|
|
13726
|
+
delete this.userProperties[key];
|
|
13727
|
+
}
|
|
13728
|
+
/**
|
|
13729
|
+
* Set a property only if it hasn't been set before
|
|
13730
|
+
*/
|
|
13731
|
+
setOnce(key, value, scope = 'user') {
|
|
13732
|
+
if (scope === 'session') {
|
|
13733
|
+
if (!(key in this.sessionProperties)) {
|
|
13734
|
+
this.setSessionProperty(key, value);
|
|
13735
|
+
}
|
|
13736
|
+
}
|
|
13737
|
+
else {
|
|
13738
|
+
if (!(key in this.userProperties)) {
|
|
13739
|
+
this.setUserProperty(key, value);
|
|
13740
|
+
}
|
|
13741
|
+
}
|
|
13742
|
+
}
|
|
13743
|
+
/**
|
|
13744
|
+
* Clear all session properties
|
|
13745
|
+
*/
|
|
13746
|
+
clearSessionProperties() {
|
|
13747
|
+
this.sessionProperties = {};
|
|
13748
|
+
this.saveSessionProperties();
|
|
13749
|
+
}
|
|
13750
|
+
/**
|
|
13751
|
+
* Clear all user properties
|
|
13752
|
+
*/
|
|
13753
|
+
clearUserProperties() {
|
|
13754
|
+
this.userProperties = {};
|
|
13755
|
+
}
|
|
13756
|
+
/**
|
|
13757
|
+
* Reset all properties
|
|
13758
|
+
*/
|
|
13759
|
+
reset() {
|
|
13760
|
+
this.clearSessionProperties();
|
|
13761
|
+
this.clearUserProperties();
|
|
13762
|
+
this.initialProperties = {};
|
|
13763
|
+
this.isInitialized = false;
|
|
13764
|
+
this.initialize();
|
|
13765
|
+
}
|
|
13766
|
+
/**
|
|
13767
|
+
* Load session properties from sessionStorage
|
|
13768
|
+
*/
|
|
13769
|
+
loadSessionProperties() {
|
|
13770
|
+
if (typeof sessionStorage === 'undefined')
|
|
13771
|
+
return;
|
|
13772
|
+
try {
|
|
13773
|
+
const stored = sessionStorage.getItem('hb_session_properties');
|
|
13774
|
+
if (stored) {
|
|
13775
|
+
this.sessionProperties = JSON.parse(stored);
|
|
13776
|
+
}
|
|
13777
|
+
}
|
|
13778
|
+
catch (error) {
|
|
13779
|
+
console.warn('Failed to load session properties:', error);
|
|
13780
|
+
}
|
|
13781
|
+
}
|
|
13782
|
+
/**
|
|
13783
|
+
* Save session properties to sessionStorage
|
|
13784
|
+
*/
|
|
13785
|
+
saveSessionProperties() {
|
|
13786
|
+
if (typeof sessionStorage === 'undefined')
|
|
13787
|
+
return;
|
|
13788
|
+
try {
|
|
13789
|
+
sessionStorage.setItem('hb_session_properties', JSON.stringify(this.sessionProperties));
|
|
13790
|
+
}
|
|
13791
|
+
catch (error) {
|
|
13792
|
+
console.warn('Failed to save session properties:', error);
|
|
13793
|
+
}
|
|
13794
|
+
}
|
|
13795
|
+
/**
|
|
13796
|
+
* Apply property denylist
|
|
13797
|
+
*/
|
|
13798
|
+
applyDenylist(properties) {
|
|
13799
|
+
if (!this.config.propertyDenylist || this.config.propertyDenylist.length === 0) {
|
|
13800
|
+
return;
|
|
13801
|
+
}
|
|
13802
|
+
this.config.propertyDenylist.forEach(deniedKey => {
|
|
13803
|
+
delete properties[deniedKey];
|
|
13804
|
+
});
|
|
13805
|
+
}
|
|
13806
|
+
/**
|
|
13807
|
+
* Update automatic properties (call when page changes)
|
|
13808
|
+
*/
|
|
13809
|
+
updateAutomaticProperties() {
|
|
13810
|
+
this.automaticProperties = getAutomaticProperties();
|
|
13811
|
+
}
|
|
13812
|
+
/**
|
|
13813
|
+
* Get all properties for debugging
|
|
13814
|
+
*/
|
|
13815
|
+
getAllProperties() {
|
|
13816
|
+
return {
|
|
13817
|
+
automatic: this.getAutomaticProperties(),
|
|
13818
|
+
session: Object.assign({}, this.sessionProperties),
|
|
13819
|
+
user: Object.assign({}, this.userProperties),
|
|
13820
|
+
initial: Object.assign({}, this.initialProperties)
|
|
13821
|
+
};
|
|
13822
|
+
}
|
|
13823
|
+
}
|
|
13824
|
+
|
|
13168
13825
|
// Check if we're in a browser environment
|
|
13169
13826
|
const isBrowser$1 = typeof window !== 'undefined';
|
|
13170
13827
|
class HumanBehaviorTracker {
|
|
@@ -13231,7 +13888,10 @@ class HumanBehaviorTracker {
|
|
|
13231
13888
|
this.configureLogging({ level: options.logLevel });
|
|
13232
13889
|
}
|
|
13233
13890
|
// Create new tracker instance
|
|
13234
|
-
const tracker = new HumanBehaviorTracker(apiKey, options === null || options === void 0 ? void 0 : options.ingestionUrl
|
|
13891
|
+
const tracker = new HumanBehaviorTracker(apiKey, options === null || options === void 0 ? void 0 : options.ingestionUrl, {
|
|
13892
|
+
enableAutomaticProperties: options === null || options === void 0 ? void 0 : options.enableAutomaticProperties,
|
|
13893
|
+
propertyDenylist: options === null || options === void 0 ? void 0 : options.propertyDenylist
|
|
13894
|
+
});
|
|
13235
13895
|
// Store canvas recording preference
|
|
13236
13896
|
tracker.recordCanvas = (_a = options === null || options === void 0 ? void 0 : options.recordCanvas) !== null && _a !== void 0 ? _a : false;
|
|
13237
13897
|
// Set redacted fields if specified
|
|
@@ -13248,7 +13908,7 @@ class HumanBehaviorTracker {
|
|
|
13248
13908
|
tracker.start();
|
|
13249
13909
|
return tracker;
|
|
13250
13910
|
}
|
|
13251
|
-
constructor(apiKey, ingestionUrl) {
|
|
13911
|
+
constructor(apiKey, ingestionUrl, options) {
|
|
13252
13912
|
this.eventIngestionQueue = [];
|
|
13253
13913
|
this.userProperties = {};
|
|
13254
13914
|
this.isProcessing = false;
|
|
@@ -13286,6 +13946,11 @@ class HumanBehaviorTracker {
|
|
|
13286
13946
|
});
|
|
13287
13947
|
this.apiKey = apiKey;
|
|
13288
13948
|
this.redactionManager = new RedactionManager();
|
|
13949
|
+
// Initialize property manager
|
|
13950
|
+
this.propertyManager = new PropertyManager({
|
|
13951
|
+
enableAutomaticProperties: (options === null || options === void 0 ? void 0 : options.enableAutomaticProperties) !== false,
|
|
13952
|
+
propertyDenylist: (options === null || options === void 0 ? void 0 : options.propertyDenylist) || []
|
|
13953
|
+
});
|
|
13289
13954
|
// Handle session restoration with improved continuity
|
|
13290
13955
|
if (isBrowser$1) {
|
|
13291
13956
|
const existingSessionId = localStorage.getItem(`human_behavior_session_id_${this.apiKey}`);
|
|
@@ -13324,7 +13989,28 @@ class HumanBehaviorTracker {
|
|
|
13324
13989
|
try {
|
|
13325
13990
|
const userId = this.getCookie(`human_behavior_end_user_id_${this.apiKey}`);
|
|
13326
13991
|
logDebug(`Initializing with sessionId: ${this.sessionId}, userId: ${userId}`);
|
|
13327
|
-
|
|
13992
|
+
// Get automatic properties for init
|
|
13993
|
+
const automaticProperties = this.propertyManager.getAutomaticProperties();
|
|
13994
|
+
// Create a custom init request with automatic properties
|
|
13995
|
+
const initResponse = yield fetch(`${this.api['baseUrl']}/api/ingestion/init`, {
|
|
13996
|
+
method: 'POST',
|
|
13997
|
+
headers: {
|
|
13998
|
+
'Content-Type': 'application/json',
|
|
13999
|
+
'Authorization': `Bearer ${this.apiKey}`,
|
|
14000
|
+
'Referer': document.referrer || ''
|
|
14001
|
+
},
|
|
14002
|
+
body: JSON.stringify({
|
|
14003
|
+
sessionId: this.sessionId,
|
|
14004
|
+
endUserId: userId,
|
|
14005
|
+
entryURL: window.location.href,
|
|
14006
|
+
referrer: document.referrer,
|
|
14007
|
+
automaticProperties: automaticProperties
|
|
14008
|
+
})
|
|
14009
|
+
});
|
|
14010
|
+
if (!initResponse.ok) {
|
|
14011
|
+
throw new Error(`Failed to initialize: ${initResponse.statusText}`);
|
|
14012
|
+
}
|
|
14013
|
+
const { sessionId, endUserId } = yield initResponse.json();
|
|
13328
14014
|
// Check if server returned a different session ID (for session continuity)
|
|
13329
14015
|
if (sessionId !== this.sessionId) {
|
|
13330
14016
|
logDebug(`Server returned different sessionId: ${sessionId} (client had: ${this.sessionId})`);
|
|
@@ -13336,6 +14022,10 @@ class HumanBehaviorTracker {
|
|
|
13336
14022
|
}
|
|
13337
14023
|
this.endUserId = endUserId;
|
|
13338
14024
|
this.setCookie(`human_behavior_end_user_id_${this.apiKey}`, endUserId, 365);
|
|
14025
|
+
// Send IP information after successful initialization
|
|
14026
|
+
this.api.sendIPInfo(this.sessionId).catch(error => {
|
|
14027
|
+
logWarn('Failed to send IP info:', error);
|
|
14028
|
+
});
|
|
13339
14029
|
// Only setup browser-specific handlers when in browser environment
|
|
13340
14030
|
if (isBrowser$1) {
|
|
13341
14031
|
this.setupPageUnloadHandler();
|
|
@@ -13456,6 +14146,8 @@ class HumanBehaviorTracker {
|
|
|
13456
14146
|
return __awaiter(this, void 0, void 0, function* () {
|
|
13457
14147
|
if (!this.initialized)
|
|
13458
14148
|
return;
|
|
14149
|
+
// Update automatic properties for new page
|
|
14150
|
+
this.propertyManager.updateAutomaticProperties();
|
|
13459
14151
|
try {
|
|
13460
14152
|
const pageViewData = {
|
|
13461
14153
|
url: url || window.location.href,
|
|
@@ -13465,11 +14157,13 @@ class HumanBehaviorTracker {
|
|
|
13465
14157
|
referrer: document.referrer,
|
|
13466
14158
|
timestamp: new Date().toISOString()
|
|
13467
14159
|
};
|
|
14160
|
+
// Get enhanced properties with automatic properties
|
|
14161
|
+
const enhancedProperties = this.propertyManager.getEventProperties(pageViewData);
|
|
13468
14162
|
// Add pageview event to the main event stream
|
|
13469
14163
|
yield this.addEvent({
|
|
13470
14164
|
type: 5, // Custom event type
|
|
13471
14165
|
data: {
|
|
13472
|
-
payload: Object.assign({ eventType: 'pageview' },
|
|
14166
|
+
payload: Object.assign({ eventType: 'pageview' }, enhancedProperties)
|
|
13473
14167
|
},
|
|
13474
14168
|
timestamp: Date.now()
|
|
13475
14169
|
});
|
|
@@ -13485,10 +14179,12 @@ class HumanBehaviorTracker {
|
|
|
13485
14179
|
var _a, _b, _c, _d, _e;
|
|
13486
14180
|
if (!this.initialized)
|
|
13487
14181
|
return;
|
|
14182
|
+
// Get enhanced properties with automatic properties
|
|
14183
|
+
const enhancedProperties = this.propertyManager.getEventProperties(properties);
|
|
13488
14184
|
try {
|
|
13489
14185
|
// Send custom event directly to the API
|
|
13490
|
-
yield this.api.sendCustomEvent(this.sessionId, eventName,
|
|
13491
|
-
logDebug(`Custom event tracked: ${eventName}`,
|
|
14186
|
+
yield this.api.sendCustomEvent(this.sessionId, eventName, enhancedProperties);
|
|
14187
|
+
logDebug(`Custom event tracked: ${eventName}`, enhancedProperties);
|
|
13492
14188
|
}
|
|
13493
14189
|
catch (error) {
|
|
13494
14190
|
logError('Failed to track custom event:', error);
|
|
@@ -13508,7 +14204,7 @@ class HumanBehaviorTracker {
|
|
|
13508
14204
|
try {
|
|
13509
14205
|
const customEventData = {
|
|
13510
14206
|
eventName: eventName,
|
|
13511
|
-
properties:
|
|
14207
|
+
properties: enhancedProperties || {},
|
|
13512
14208
|
timestamp: new Date().toISOString(),
|
|
13513
14209
|
url: window.location.href,
|
|
13514
14210
|
pathname: window.location.pathname
|
|
@@ -13808,8 +14504,25 @@ class HumanBehaviorTracker {
|
|
|
13808
14504
|
// Store user properties
|
|
13809
14505
|
this.userProperties = userProperties;
|
|
13810
14506
|
logDebug('Identifying user:', { userProperties, originalEndUserId, sessionId: this.sessionId });
|
|
13811
|
-
//
|
|
13812
|
-
|
|
14507
|
+
// Get automatic properties and send with user data
|
|
14508
|
+
const automaticProperties = this.propertyManager.getAutomaticProperties();
|
|
14509
|
+
// Create a custom user request with automatic properties
|
|
14510
|
+
const userResponse = yield fetch(`${this.api['baseUrl']}/api/ingestion/user`, {
|
|
14511
|
+
method: 'POST',
|
|
14512
|
+
headers: {
|
|
14513
|
+
'Content-Type': 'application/json',
|
|
14514
|
+
'Authorization': `Bearer ${this.apiKey}`
|
|
14515
|
+
},
|
|
14516
|
+
body: JSON.stringify({
|
|
14517
|
+
userId: originalEndUserId,
|
|
14518
|
+
userAttributes: userProperties,
|
|
14519
|
+
sessionId: this.sessionId,
|
|
14520
|
+
automaticProperties: automaticProperties
|
|
14521
|
+
})
|
|
14522
|
+
});
|
|
14523
|
+
if (!userResponse.ok) {
|
|
14524
|
+
throw new Error(`Failed to identify user: ${userResponse.statusText}`);
|
|
14525
|
+
}
|
|
13813
14526
|
// Don't update endUserId - keep it as the original UUID
|
|
13814
14527
|
return originalEndUserId || '';
|
|
13815
14528
|
});
|
|
@@ -13857,7 +14570,7 @@ class HumanBehaviorTracker {
|
|
|
13857
14570
|
collectFonts: false, // Disable font collection to reduce errors
|
|
13858
14571
|
inlineStylesheet: true, // Keep styles for proper session replay
|
|
13859
14572
|
recordCrossOriginIframes: false, // Prevent cross-origin iframe errors
|
|
13860
|
-
// ✅ CANVAS RECORDING -
|
|
14573
|
+
// ✅ CANVAS RECORDING - protection against overwhelm
|
|
13861
14574
|
recordCanvas: this.recordCanvas, // Opt-in only
|
|
13862
14575
|
sampling: this.recordCanvas ? { canvas: 4 } : undefined, // 4 FPS throttle
|
|
13863
14576
|
dataURLOptions: this.recordCanvas ? {
|
|
@@ -14281,6 +14994,79 @@ class HumanBehaviorTracker {
|
|
|
14281
14994
|
initialized: this.initialized
|
|
14282
14995
|
};
|
|
14283
14996
|
}
|
|
14997
|
+
// ===== PROPERTY MANAGEMENT METHODS =====
|
|
14998
|
+
/**
|
|
14999
|
+
* Set a session property that will be included in all events for this session
|
|
15000
|
+
*/
|
|
15001
|
+
setSessionProperty(key, value) {
|
|
15002
|
+
this.propertyManager.setSessionProperty(key, value);
|
|
15003
|
+
}
|
|
15004
|
+
/**
|
|
15005
|
+
* Set multiple session properties
|
|
15006
|
+
*/
|
|
15007
|
+
setSessionProperties(properties) {
|
|
15008
|
+
this.propertyManager.setSessionProperties(properties);
|
|
15009
|
+
}
|
|
15010
|
+
/**
|
|
15011
|
+
* Get a session property
|
|
15012
|
+
*/
|
|
15013
|
+
getSessionProperty(key) {
|
|
15014
|
+
return this.propertyManager.getSessionProperty(key);
|
|
15015
|
+
}
|
|
15016
|
+
/**
|
|
15017
|
+
* Remove a session property
|
|
15018
|
+
*/
|
|
15019
|
+
removeSessionProperty(key) {
|
|
15020
|
+
this.propertyManager.removeSessionProperty(key);
|
|
15021
|
+
}
|
|
15022
|
+
/**
|
|
15023
|
+
* Set a user property that will be included in all events
|
|
15024
|
+
*/
|
|
15025
|
+
setUserProperty(key, value) {
|
|
15026
|
+
this.propertyManager.setUserProperty(key, value);
|
|
15027
|
+
}
|
|
15028
|
+
/**
|
|
15029
|
+
* Set multiple user properties
|
|
15030
|
+
*/
|
|
15031
|
+
setUserProperties(properties) {
|
|
15032
|
+
this.propertyManager.setUserProperties(properties);
|
|
15033
|
+
}
|
|
15034
|
+
/**
|
|
15035
|
+
* Get a user property
|
|
15036
|
+
*/
|
|
15037
|
+
getUserProperty(key) {
|
|
15038
|
+
return this.propertyManager.getUserProperty(key);
|
|
15039
|
+
}
|
|
15040
|
+
/**
|
|
15041
|
+
* Remove a user property
|
|
15042
|
+
*/
|
|
15043
|
+
removeUserProperty(key) {
|
|
15044
|
+
this.propertyManager.removeUserProperty(key);
|
|
15045
|
+
}
|
|
15046
|
+
/**
|
|
15047
|
+
* Set a property only if it hasn't been set before
|
|
15048
|
+
*/
|
|
15049
|
+
setOnce(key, value, scope = 'user') {
|
|
15050
|
+
this.propertyManager.setOnce(key, value, scope);
|
|
15051
|
+
}
|
|
15052
|
+
/**
|
|
15053
|
+
* Clear all session properties
|
|
15054
|
+
*/
|
|
15055
|
+
clearSessionProperties() {
|
|
15056
|
+
this.propertyManager.clearSessionProperties();
|
|
15057
|
+
}
|
|
15058
|
+
/**
|
|
15059
|
+
* Clear all user properties
|
|
15060
|
+
*/
|
|
15061
|
+
clearUserProperties() {
|
|
15062
|
+
this.propertyManager.clearUserProperties();
|
|
15063
|
+
}
|
|
15064
|
+
/**
|
|
15065
|
+
* Get all properties for debugging
|
|
15066
|
+
*/
|
|
15067
|
+
getAllProperties() {
|
|
15068
|
+
return this.propertyManager.getAllProperties();
|
|
15069
|
+
}
|
|
14284
15070
|
}
|
|
14285
15071
|
// Only expose to window object in browser environments
|
|
14286
15072
|
if (isBrowser$1) {
|
|
@@ -14436,7 +15222,7 @@ const useUserTracking = () => {
|
|
|
14436
15222
|
identifyUser
|
|
14437
15223
|
};
|
|
14438
15224
|
};
|
|
14439
|
-
// Automatic page tracking component
|
|
15225
|
+
// Automatic page tracking component
|
|
14440
15226
|
function HumanBehaviorPageView() {
|
|
14441
15227
|
const tracker = React.useContext(HumanBehaviorContext);
|
|
14442
15228
|
React.useEffect(() => {
|