humanbehavior-js 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -176,7 +176,7 @@ declare class HumanBehaviorTracker {
176
176
  private processRejectedEvents;
177
177
  private flush;
178
178
  private setCookie;
179
- private getCookie;
179
+ getCookie(name: string): string | null;
180
180
  /**
181
181
  * Start redaction functionality for sensitive input fields
182
182
  * @param options Optional configuration for redaction behavior
@@ -217,6 +217,20 @@ declare class HumanBehaviorTracker {
217
217
  blocked: boolean;
218
218
  recommendations: string[];
219
219
  };
220
+ /**
221
+ * Check if the current user is a preexisting user
222
+ * Returns true if the user has an existing endUserId cookie from a previous session
223
+ */
224
+ isPreexistingUser(): boolean;
225
+ /**
226
+ * Get user information including whether they are preexisting
227
+ */
228
+ getUserInfo(): {
229
+ endUserId: string | null;
230
+ sessionId: string;
231
+ isPreexistingUser: boolean;
232
+ initialized: boolean;
233
+ };
220
234
  }
221
235
 
222
236
  declare const MAX_CHUNK_SIZE_BYTES: number;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "humanbehavior-js",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "SDK for HumanBehavior session and event recording",
5
5
  "type": "module",
6
6
  "main": "./dist/cjs/index.js",
package/simple-spa.html CHANGED
@@ -160,6 +160,7 @@
160
160
  <strong>Session Info:</strong><br>
161
161
  Session ID: <span id="sessionId">Loading...</span><br>
162
162
  End User ID: <span id="endUserId">Loading...</span><br>
163
+ User Type: <span id="userType">Loading...</span><br>
163
164
  Current URL: <span id="currentUrl">Loading...</span>
164
165
  </div>
165
166
 
@@ -197,12 +198,16 @@
197
198
  <div class="status">
198
199
  <strong>Current Session:</strong><br>
199
200
  Session ID: <span id="sessionId-about">Loading...</span><br>
201
+ User Type: <span id="userType-about">Loading...</span><br>
200
202
  Page Load Time: <span id="pageLoadTime">Loading...</span>
201
203
  </div>
202
204
 
203
205
  <button class="button" onclick="trackCustomEvent('about_page_viewed', {section: 'about'})">
204
206
  Track About Page View
205
207
  </button>
208
+ <button class="button secondary" onclick="showUserInfo()">
209
+ Show Detailed User Info
210
+ </button>
206
211
  `
207
212
  },
208
213
 
@@ -239,6 +244,7 @@
239
244
  Initialized: <span id="trackerInitialized">Loading...</span><br>
240
245
  Session ID: <span id="sessionId-status">Loading...</span><br>
241
246
  End User ID: <span id="endUserId-status">Loading...</span><br>
247
+ User Type: <span id="userType-status">Loading...</span><br>
242
248
  Current URL: <span id="currentUrl-status">Loading...</span><br>
243
249
  Connection Status: <span id="connectionStatus">Loading...</span>
244
250
  </div>
@@ -418,6 +424,17 @@
418
424
  el.textContent = endUserId;
419
425
  });
420
426
 
427
+ // Update user type (preexisting vs new)
428
+ const userTypeElements = document.querySelectorAll('#userType, #userType-about, #userType-status');
429
+ let userType = 'Unknown';
430
+ if (tracker.isPreexistingUser) {
431
+ const isPreexisting = tracker.isPreexistingUser();
432
+ userType = isPreexisting ? '🔄 Preexisting User' : '🆕 New User';
433
+ }
434
+ userTypeElements.forEach(el => {
435
+ el.textContent = userType;
436
+ });
437
+
421
438
  const currentUrlElements = document.querySelectorAll('#currentUrl, #currentUrl-status');
422
439
  const currentUrl = window.location.href;
423
440
  currentUrlElements.forEach(el => {
@@ -522,6 +539,39 @@
522
539
  });
523
540
  }
524
541
 
542
+ // Show detailed user information
543
+ function showUserInfo() {
544
+ if (!tracker) {
545
+ addLog('Tracker not available');
546
+ return;
547
+ }
548
+
549
+ try {
550
+ const userInfo = tracker.getUserInfo ? tracker.getUserInfo() : null;
551
+ if (userInfo) {
552
+ const infoText = `
553
+ <strong>Detailed User Information:</strong><br>
554
+ End User ID: ${userInfo.endUserId || 'Not set'}<br>
555
+ Session ID: ${userInfo.sessionId}<br>
556
+ Is Preexisting User: ${userInfo.isPreexistingUser ? 'Yes' : 'No'}<br>
557
+ Initialized: ${userInfo.initialized ? 'Yes' : 'No'}<br>
558
+ <br>
559
+ <strong>Cookie Check:</strong><br>
560
+ End User Cookie: ${tracker.getCookie ? tracker.getCookie(`human_behavior_end_user_id_13c3e029-ca45-4a3c-a33b-f5dcb297e31c`) : 'Method not available'}<br>
561
+ Session Cookie: ${tracker.getCookie ? tracker.getCookie('human_behavior_session_id') : 'Method not available'}
562
+ `;
563
+
564
+ // Show in an alert or add to logs
565
+ addLog('Detailed user info displayed', userInfo);
566
+ alert(infoText);
567
+ } else {
568
+ addLog('getUserInfo method not available');
569
+ }
570
+ } catch (error) {
571
+ addLog(`Error getting user info: ${error.message}`);
572
+ }
573
+ }
574
+
525
575
  // Add log message
526
576
  function addLog(message, data = null) {
527
577
  const logElements = document.querySelectorAll('.logs');
package/src/api.ts CHANGED
@@ -199,7 +199,7 @@ export class HumanBehaviorAPI {
199
199
  if (!response.ok) {
200
200
  throw new Error(`Failed to authenticate user: ${response.statusText} with API key: ${this.apiKey}`);
201
201
  }
202
-
202
+ // Returns: { success: true, message: '...', userId: '...' }
203
203
  return await response.json();
204
204
  } catch (error) {
205
205
  logError('Error authenticating user:', error);
@@ -207,10 +207,6 @@ export class HumanBehaviorAPI {
207
207
  }
208
208
  }
209
209
 
210
-
211
-
212
-
213
-
214
210
  public sendBeaconEvents(events: any[], sessionId: string) {
215
211
  const data = new URLSearchParams()
216
212
  data.append('events', encodeURIComponent(JSON.stringify(events)))
@@ -218,15 +214,9 @@ export class HumanBehaviorAPI {
218
214
  data.append('timestamp', encodeURIComponent(Date.now().toString()))
219
215
  data.append('apiKey', encodeURIComponent(this.apiKey))
220
216
 
221
-
222
217
  const success = navigator.sendBeacon(
223
218
  `${this.baseUrl}/api/ingestion/events`,
224
219
  data
225
220
  );
226
-
227
- // KoalawareTracker.logToStorage(`Sending events beacon: ${this.baseUrl}/api/ingestion/events`);
228
- // KoalawareTracker.logToStorage(`Events beacon success: ${success}`);
229
221
  }
230
-
231
-
232
222
  }
package/src/tracker.ts CHANGED
@@ -80,7 +80,7 @@ export class HumanBehaviorTracker {
80
80
 
81
81
  // Test connection (non-blocking)
82
82
  if (isBrowser) {
83
- const testUrl = tracker.api['baseUrl'] + '/api/ingestion/health';
83
+ const testUrl = tracker.api['baseUrl'] + '/api/health';
84
84
  fetch(testUrl, { method: 'HEAD' })
85
85
  .then(() => logDebug('Connection test successful'))
86
86
  .catch((error) => {
@@ -109,19 +109,29 @@ export class HumanBehaviorTracker {
109
109
  this.apiKey = apiKey;
110
110
  this.redactionManager = new RedactionManager();
111
111
 
112
- // Handle session restoration
112
+ // Handle session restoration with improved continuity
113
113
  if (isBrowser) {
114
114
  const existingSessionId = localStorage.getItem('human_behavior_session_id');
115
115
  const lastActivity = localStorage.getItem('human_behavior_last_activity');
116
116
  const thirtyMinutesAgo = Date.now() - (30 * 60 * 1000);
117
117
 
118
+ // Check if we have an existing session that's still within the activity window
118
119
  if (existingSessionId && lastActivity && parseInt(lastActivity) > thirtyMinutesAgo) {
119
120
  this.sessionId = existingSessionId;
120
121
  logDebug(`Reusing existing session: ${this.sessionId}`);
122
+ // Update activity timestamp to extend the session window
123
+ localStorage.setItem('human_behavior_last_activity', Date.now().toString());
121
124
  } else {
125
+ // Clear old session data if it's expired
126
+ if (existingSessionId) {
127
+ logDebug(`Session expired, clearing old session: ${existingSessionId}`);
128
+ localStorage.removeItem('human_behavior_session_id');
129
+ localStorage.removeItem('human_behavior_last_activity');
130
+ }
122
131
  this.sessionId = uuidv1();
123
132
  logDebug(`Creating new session: ${this.sessionId}`);
124
133
  localStorage.setItem('human_behavior_session_id', this.sessionId);
134
+ localStorage.setItem('human_behavior_last_activity', Date.now().toString());
125
135
  }
126
136
 
127
137
  this.currentUrl = window.location.href;
@@ -141,11 +151,11 @@ export class HumanBehaviorTracker {
141
151
 
142
152
  const { sessionId, endUserId } = await this.api.init(this.sessionId, userId);
143
153
 
144
- // Check if server returned a different session ID
154
+ // Check if server returned a different session ID (for session continuity)
145
155
  if (sessionId !== this.sessionId) {
146
156
  logDebug(`Server returned different sessionId: ${sessionId} (client had: ${this.sessionId})`);
147
157
  this.sessionId = sessionId;
148
- // Update localStorage with server's session ID
158
+ // Update localStorage with server's session ID for continuity
149
159
  if (isBrowser) {
150
160
  localStorage.setItem('human_behavior_session_id', this.sessionId);
151
161
  }
@@ -405,8 +415,6 @@ export class HumanBehaviorTracker {
405
415
  error: console.error
406
416
  };
407
417
 
408
-
409
-
410
418
  // Override console methods to capture ALL console output (including logger output)
411
419
  console.log = (...args) => {
412
420
  this.trackConsoleEvent('log', args);
@@ -538,7 +546,12 @@ export class HumanBehaviorTracker {
538
546
  if (!this.userProperties || Object.keys(this.userProperties).length === 0) {
539
547
  throw new Error('No user info available. Call addUserInfo() first.');
540
548
  }
541
- await this.api.sendUserAuth(this.endUserId, this.userProperties, this.sessionId, authFields);
549
+ const response = await this.api.sendUserAuth(this.endUserId, this.userProperties, this.sessionId, authFields);
550
+ if (response && response.userId && response.userId !== this.endUserId) {
551
+ // Update endUserId and cookie if backend returns a new userId
552
+ this.endUserId = response.userId;
553
+ this.setCookie(`human_behavior_end_user_id_${this.apiKey}`, response.userId, 365);
554
+ }
542
555
  }
543
556
 
544
557
  public async start() {
@@ -661,25 +674,69 @@ export class HumanBehaviorTracker {
661
674
  }
662
675
  }
663
676
 
664
- // Add helper methods for cookie management
677
+ // Add helper methods for cookie management with localStorage fallback
665
678
  private setCookie(name: string, value: string, daysToExpire: number) {
666
679
  if (!isBrowser) return;
667
- const date = new Date();
668
- date.setTime(date.getTime() + (daysToExpire * 24 * 60 * 60 * 1000));
669
- const expires = `expires=${date.toUTCString()}`;
670
- document.cookie = `${name}=${value};${expires};path=/;SameSite=Lax`;
680
+
681
+ try {
682
+ // Try to set cookie first
683
+ const date = new Date();
684
+ date.setTime(date.getTime() + (daysToExpire * 24 * 60 * 60 * 1000));
685
+ const expires = `expires=${date.toUTCString()}`;
686
+ document.cookie = `${name}=${value};${expires};path=/;SameSite=Lax`;
687
+
688
+ // Also store in localStorage as backup
689
+ localStorage.setItem(name, value);
690
+ logDebug(`Set cookie and localStorage: ${name}`);
691
+ } catch (error) {
692
+ // If cookie fails, use localStorage only
693
+ try {
694
+ localStorage.setItem(name, value);
695
+ logDebug(`Cookie blocked, using localStorage: ${name}`);
696
+ } catch (localStorageError) {
697
+ logError('Failed to store user ID in both cookie and localStorage:', localStorageError);
698
+ }
699
+ }
671
700
  }
672
701
 
673
- private getCookie(name: string): string | null {
702
+ public getCookie(name: string): string | null {
674
703
  if (!isBrowser) return null;
675
- const nameEQ = name + "=";
676
- const ca = document.cookie.split(';');
677
- for (let i = 0; i < ca.length; i++) {
678
- let c = ca[i];
679
- while (c.charAt(0) === ' ') c = c.substring(1, c.length);
680
- if (c.indexOf(nameEQ) === 0) return c.substring(nameEQ.length, c.length);
704
+
705
+ try {
706
+ // Try to get from cookie first
707
+ const nameEQ = name + "=";
708
+ const ca = document.cookie.split(';');
709
+ for (let i = 0; i < ca.length; i++) {
710
+ let c = ca[i];
711
+ while (c.charAt(0) === ' ') c = c.substring(1, c.length);
712
+ if (c.indexOf(nameEQ) === 0) {
713
+ const cookieValue = c.substring(nameEQ.length, c.length);
714
+ logDebug(`Found cookie: ${name}`);
715
+ return cookieValue;
716
+ }
717
+ }
718
+
719
+ // If cookie not found, try localStorage
720
+ const localStorageValue = localStorage.getItem(name);
721
+ if (localStorageValue) {
722
+ logDebug(`Cookie not found, using localStorage: ${name}`);
723
+ return localStorageValue;
724
+ }
725
+
726
+ return null;
727
+ } catch (error) {
728
+ // If cookie access fails, try localStorage
729
+ try {
730
+ const localStorageValue = localStorage.getItem(name);
731
+ if (localStorageValue) {
732
+ logDebug(`Cookie access failed, using localStorage: ${name}`);
733
+ return localStorageValue;
734
+ }
735
+ } catch (localStorageError) {
736
+ logError('Failed to access both cookie and localStorage:', localStorageError);
737
+ }
738
+ return null;
681
739
  }
682
- return null;
683
740
  }
684
741
 
685
742
  /**
@@ -787,6 +844,37 @@ export class HumanBehaviorTracker {
787
844
 
788
845
  return { blocked, recommendations };
789
846
  }
847
+
848
+ /**
849
+ * Check if the current user is a preexisting user
850
+ * Returns true if the user has an existing endUserId cookie from a previous session
851
+ */
852
+ public isPreexistingUser(): boolean {
853
+ if (!isBrowser) {
854
+ return false;
855
+ }
856
+
857
+ // Check if there's an existing endUserId cookie for this API key
858
+ const existingEndUserId = this.getCookie(`human_behavior_end_user_id_${this.apiKey}`);
859
+ return existingEndUserId !== null && existingEndUserId !== this.endUserId;
860
+ }
861
+
862
+ /**
863
+ * Get user information including whether they are preexisting
864
+ */
865
+ public getUserInfo(): {
866
+ endUserId: string | null;
867
+ sessionId: string;
868
+ isPreexistingUser: boolean;
869
+ initialized: boolean;
870
+ } {
871
+ return {
872
+ endUserId: this.endUserId,
873
+ sessionId: this.sessionId,
874
+ isPreexistingUser: this.isPreexistingUser(),
875
+ initialized: this.initialized
876
+ };
877
+ }
790
878
  }
791
879
 
792
880
  // Only expose to window object in browser environments