humanbehavior-js 0.3.6 → 0.3.7
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/index.js +12155 -3893
- package/dist/cjs/index.js.map +1 -1
- package/dist/esm/index.js +12155 -3893
- package/dist/esm/index.js.map +1 -1
- package/dist/index.min.js +1 -15
- package/dist/index.min.js.map +1 -1
- package/dist/types/index.d.ts +1 -1
- package/package.json +2 -3
- package/readme.md +2 -2
- package/src/api.ts +19 -2
- package/src/tracker.ts +54 -24
package/dist/types/index.d.ts
CHANGED
|
@@ -261,7 +261,7 @@ declare class HumanBehaviorTracker {
|
|
|
261
261
|
getCurrentUrl(): string;
|
|
262
262
|
/**
|
|
263
263
|
* Get current snapshot frequency info
|
|
264
|
-
* Uses configured values (5 minutes, 1000 events)
|
|
264
|
+
* Uses configured values (5 minutes, 1000 events)
|
|
265
265
|
*/
|
|
266
266
|
getSnapshotFrequencyInfo(): {
|
|
267
267
|
sessionDuration: number;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "humanbehavior-js",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.7",
|
|
4
4
|
"description": "SDK for HumanBehavior session and event recording",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/cjs/index.js",
|
|
@@ -30,8 +30,7 @@
|
|
|
30
30
|
"license": "ISC",
|
|
31
31
|
"dependencies": {
|
|
32
32
|
"@types/react": "^19.0.12",
|
|
33
|
-
"
|
|
34
|
-
"rrweb": "^2.0.0-alpha.4",
|
|
33
|
+
"@rrweb/record": "^2.0.0-alpha.17",
|
|
35
34
|
"uuid": "^11.1.0"
|
|
36
35
|
},
|
|
37
36
|
"peerDependencies": {
|
package/readme.md
CHANGED
|
@@ -119,7 +119,7 @@ const status = tracker.getConnectionStatus();
|
|
|
119
119
|
|
|
120
120
|
The SDK automatically handles session continuity:
|
|
121
121
|
|
|
122
|
-
1. **Session Restoration**: Automatically restores sessions within
|
|
122
|
+
1. **Session Restoration**: Automatically restores sessions within 15 minutes
|
|
123
123
|
2. **Activity Tracking**: Updates activity timestamp on user interactions
|
|
124
124
|
3. **Cross-Page Persistence**: Session persists across page navigations
|
|
125
125
|
|
|
@@ -144,7 +144,7 @@ If you see `net::ERR_BLOCKED_BY_CLIENT` errors:
|
|
|
144
144
|
|
|
145
145
|
### Session Issues
|
|
146
146
|
|
|
147
|
-
- Sessions automatically expire after
|
|
147
|
+
- Sessions automatically expire after 15 minutes of inactivity
|
|
148
148
|
- Each page load calls `/init` but reuses existing sessions when possible
|
|
149
149
|
- Check browser console for session restoration logs
|
|
150
150
|
|
package/src/api.ts
CHANGED
|
@@ -23,7 +23,16 @@ export function validateSingleEventSize(event: any, sessionId: string): void {
|
|
|
23
23
|
}
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
|
|
26
30
|
export function splitLargeEvent(event: any, sessionId: string): any[] {
|
|
31
|
+
// ✅ SIMPLE VALIDATION
|
|
32
|
+
if (!event || typeof event !== 'object') {
|
|
33
|
+
return [];
|
|
34
|
+
}
|
|
35
|
+
|
|
27
36
|
const eventSize = new TextEncoder().encode(JSON.stringify({
|
|
28
37
|
sessionId,
|
|
29
38
|
events: [event]
|
|
@@ -132,6 +141,9 @@ export class HumanBehaviorAPI {
|
|
|
132
141
|
}
|
|
133
142
|
|
|
134
143
|
async sendEvents(events: any[], sessionId: string, userId: string) {
|
|
144
|
+
// ✅ SIMPLE VALIDATION FOR ALL EVENTS
|
|
145
|
+
const validEvents = events.filter(event => event && typeof event === 'object');
|
|
146
|
+
|
|
135
147
|
const response = await fetch(`${this.baseUrl}/api/ingestion/events`, {
|
|
136
148
|
method: 'POST',
|
|
137
149
|
headers: {
|
|
@@ -140,7 +152,7 @@ export class HumanBehaviorAPI {
|
|
|
140
152
|
},
|
|
141
153
|
body: JSON.stringify({
|
|
142
154
|
sessionId,
|
|
143
|
-
events:
|
|
155
|
+
events: validEvents,
|
|
144
156
|
endUserId: userId
|
|
145
157
|
})
|
|
146
158
|
});
|
|
@@ -156,6 +168,11 @@ export class HumanBehaviorAPI {
|
|
|
156
168
|
let currentChunk: any[] = [];
|
|
157
169
|
|
|
158
170
|
for (const event of events) {
|
|
171
|
+
// ✅ SIMPLE VALIDATION FOR ALL EVENTS
|
|
172
|
+
if (!event || typeof event !== 'object') {
|
|
173
|
+
continue;
|
|
174
|
+
}
|
|
175
|
+
|
|
159
176
|
if (isChunkSizeExceeded(currentChunk, event, sessionId)) {
|
|
160
177
|
// If current chunk is not empty, send it first
|
|
161
178
|
if (currentChunk.length > 0) {
|
|
@@ -226,7 +243,7 @@ export class HumanBehaviorAPI {
|
|
|
226
243
|
userId: userId,
|
|
227
244
|
userAttributes: userData,
|
|
228
245
|
sessionId: sessionId,
|
|
229
|
-
posthogName: userData.email || userData.name || null // Update
|
|
246
|
+
posthogName: userData.email || userData.name || null // Update user name with email
|
|
230
247
|
};
|
|
231
248
|
|
|
232
249
|
console.log('Sending user data to server:', payload);
|
package/src/tracker.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { record } from '@rrweb/record';
|
|
2
2
|
import { v1 as uuidv1 } from 'uuid';
|
|
3
3
|
import { HumanBehaviorAPI } from './api';
|
|
4
4
|
import { RedactionManager, RedactionOptions } from './redact';
|
|
@@ -128,10 +128,10 @@ export class HumanBehaviorTracker {
|
|
|
128
128
|
if (isBrowser) {
|
|
129
129
|
const existingSessionId = localStorage.getItem('human_behavior_session_id');
|
|
130
130
|
const lastActivity = localStorage.getItem('human_behavior_last_activity');
|
|
131
|
-
const
|
|
131
|
+
const fifteenMinutesAgo = Date.now() - (15 * 60 * 1000);
|
|
132
132
|
|
|
133
133
|
// Check if we have an existing session that's still within the activity window
|
|
134
|
-
if (existingSessionId && lastActivity && parseInt(lastActivity) >
|
|
134
|
+
if (existingSessionId && lastActivity && parseInt(lastActivity) > fifteenMinutesAgo) {
|
|
135
135
|
this.sessionId = existingSessionId;
|
|
136
136
|
logDebug(`Reusing existing session: ${this.sessionId}`);
|
|
137
137
|
// Update activity timestamp to extend the session window
|
|
@@ -754,9 +754,13 @@ export class HumanBehaviorTracker {
|
|
|
754
754
|
// Enable console tracking
|
|
755
755
|
this.enableConsoleTracking();
|
|
756
756
|
|
|
757
|
-
// ✅
|
|
758
|
-
//
|
|
759
|
-
const
|
|
757
|
+
// ✅ DOM READY DETECTION
|
|
758
|
+
// Wait for DOM to be ready before starting recording
|
|
759
|
+
const startRecording = () => {
|
|
760
|
+
logDebug('🎯 DOM ready, starting session recording');
|
|
761
|
+
|
|
762
|
+
// ✅ HUMANBEHAVIOR RRWEB CONFIGURATION
|
|
763
|
+
const recordInstance = record({
|
|
760
764
|
emit: (event) => {
|
|
761
765
|
// ✅ DIRECT EVENT HANDLING - Let rrweb handle events natively
|
|
762
766
|
this.addEvent(event);
|
|
@@ -766,28 +770,43 @@ export class HumanBehaviorTracker {
|
|
|
766
770
|
logDebug(`🎯 FullSnapshot generated at ${new Date().toISOString()}`);
|
|
767
771
|
}
|
|
768
772
|
},
|
|
769
|
-
|
|
770
|
-
recordCanvas: true,
|
|
771
|
-
collectFonts: true,
|
|
772
|
-
inlineImages: true,
|
|
773
|
-
blockClass: 'rr-block',
|
|
774
|
-
ignoreClass: 'rr-ignore',
|
|
775
|
-
maskTextClass: 'rr-mask',
|
|
776
|
-
|
|
777
|
-
// ✅ RRWEB BUILT-IN MASKING - More reliable than custom redaction
|
|
778
|
-
maskAllInputs: false, // Let users control this via selectors
|
|
773
|
+
// ✅ HUMANBEHAVIOR'S CUSTOM SETTINGS
|
|
779
774
|
maskTextSelector: this.redactionManager.getMaskTextSelector() || undefined,
|
|
775
|
+
maskTextFn: undefined,
|
|
776
|
+
maskAllInputs: true, // HumanBehavior default
|
|
777
|
+
maskInputOptions: { password: true }, // HumanBehavior default
|
|
778
|
+
maskInputFn: undefined,
|
|
779
|
+
slimDOMOptions: {},
|
|
780
|
+
collectFonts: false, // HumanBehavior default
|
|
781
|
+
inlineStylesheet: true, // HumanBehavior default
|
|
782
|
+
recordCrossOriginIframes: false, // HumanBehavior default
|
|
780
783
|
|
|
781
|
-
// ✅
|
|
782
|
-
|
|
783
|
-
checkoutEveryNth: 1000, // Take FullSnapshot every 1000 events
|
|
784
|
+
// ✅ CANVAS RECORDING - Disabled to prevent large data URIs
|
|
785
|
+
recordCanvas: false, // Disabled to prevent large data URIs
|
|
784
786
|
|
|
785
|
-
// ✅
|
|
786
|
-
|
|
787
|
+
// ✅ FULLSNAPSHOT GENERATION - Use reasonable intervals
|
|
788
|
+
checkoutEveryNms: 300000, // Take FullSnapshot every 5 minutes
|
|
789
|
+
checkoutEveryNth: 1000, // Take FullSnapshot every 1000 events
|
|
787
790
|
});
|
|
788
791
|
|
|
789
792
|
// Store the record instance for cleanup
|
|
790
793
|
this.recordInstance = recordInstance;
|
|
794
|
+
};
|
|
795
|
+
|
|
796
|
+
// ✅ DOM READY DETECTION
|
|
797
|
+
logDebug(`🎯 DOM ready state: ${document.readyState}`);
|
|
798
|
+
if (document.readyState === 'complete') {
|
|
799
|
+
// DOM already ready, start immediately
|
|
800
|
+
logDebug('🎯 DOM already complete, starting recording immediately');
|
|
801
|
+
startRecording();
|
|
802
|
+
} else {
|
|
803
|
+
// Wait for DOM to be ready
|
|
804
|
+
logDebug('🎯 DOM not ready, waiting for DOMContentLoaded event');
|
|
805
|
+
document.addEventListener('DOMContentLoaded', () => {
|
|
806
|
+
logDebug('🎯 DOMContentLoaded fired, starting recording');
|
|
807
|
+
startRecording();
|
|
808
|
+
}, { once: true });
|
|
809
|
+
}
|
|
791
810
|
}
|
|
792
811
|
|
|
793
812
|
public async stop() {
|
|
@@ -822,11 +841,22 @@ export class HumanBehaviorTracker {
|
|
|
822
841
|
// ✅ DIRECT EVENT HANDLING - No custom processing to avoid corruption
|
|
823
842
|
// Events flow directly from rrweb to ingestion server
|
|
824
843
|
|
|
844
|
+
// ✅ EVENT VALIDATION
|
|
845
|
+
if (!event || typeof event !== 'object') {
|
|
846
|
+
logDebug('⚠️ Skipping invalid event:', event);
|
|
847
|
+
return;
|
|
848
|
+
}
|
|
849
|
+
|
|
825
850
|
// ✅ LOG FULLSNAPSHOT STATUS FOR DEBUGGING
|
|
826
851
|
if (event.type === 2) { // FullSnapshot
|
|
827
852
|
const hasData = !!event.data;
|
|
828
853
|
const hasNode = !!(event.data && event.data.node);
|
|
829
|
-
|
|
854
|
+
|
|
855
|
+
if (!hasData || !hasNode) {
|
|
856
|
+
logDebug(`⚠️ Empty FullSnapshot detected: hasData=${hasData}, hasNode=${hasNode} - continuing session`);
|
|
857
|
+
} else {
|
|
858
|
+
logDebug(`✅ Valid FullSnapshot: hasData=${hasData}, hasNode=${hasNode}, dataType=${event.data?.node?.type}`);
|
|
859
|
+
}
|
|
830
860
|
}
|
|
831
861
|
|
|
832
862
|
this.eventIngestionQueue.push(event); // Direct event handling
|
|
@@ -1072,7 +1102,7 @@ export class HumanBehaviorTracker {
|
|
|
1072
1102
|
|
|
1073
1103
|
/**
|
|
1074
1104
|
* Get current snapshot frequency info
|
|
1075
|
-
* Uses configured values (5 minutes, 1000 events)
|
|
1105
|
+
* Uses configured values (5 minutes, 1000 events)
|
|
1076
1106
|
*/
|
|
1077
1107
|
public getSnapshotFrequencyInfo(): {
|
|
1078
1108
|
sessionDuration: number;
|
|
@@ -1084,7 +1114,7 @@ export class HumanBehaviorTracker {
|
|
|
1084
1114
|
|
|
1085
1115
|
return {
|
|
1086
1116
|
sessionDuration,
|
|
1087
|
-
currentInterval: 300000, // Configured - 5 minutes
|
|
1117
|
+
currentInterval: 300000, // Configured - 5 minutes
|
|
1088
1118
|
currentThreshold: 1000, // Configured - 1000 events
|
|
1089
1119
|
phase: 'configured' // Using explicit configuration
|
|
1090
1120
|
};
|