humanbehavior-js 0.0.9 → 0.1.0

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 CHANGED
@@ -4359,129 +4359,16 @@ class HumanBehaviorAPI {
4359
4359
  }
4360
4360
  });
4361
4361
  }
4362
- sendSessionComplete(sessionId) {
4363
- return __awaiter$1(this, void 0, void 0, function* () {
4364
- const response = yield fetch(`${this.baseUrl}/api/ingestion/sessionComplete`, {
4365
- method: 'POST',
4366
- headers: {
4367
- 'Content-Type': 'application/json',
4368
- 'Authorization': `Bearer ${this.apiKey}`
4369
- },
4370
- body: JSON.stringify({ sessionId })
4371
- });
4372
- if (!response.ok) {
4373
- throw new Error(`Failed to send session complete: ${response.statusText}`);
4374
- }
4375
- });
4376
- }
4377
- sendCustomEvent(eventName, eventProperties, sessionId) {
4378
- return __awaiter$1(this, void 0, void 0, function* () {
4379
- const maxRetries = 3;
4380
- let retryCount = 0;
4381
- while (retryCount < maxRetries) {
4382
- try {
4383
- const response = yield fetch(`${this.baseUrl}/api/ingestion/customEvent`, {
4384
- method: 'POST',
4385
- headers: {
4386
- 'Content-Type': 'application/json',
4387
- 'Authorization': `Bearer ${this.apiKey}`
4388
- },
4389
- body: JSON.stringify({
4390
- name: eventName,
4391
- properties: eventProperties,
4392
- sessionId: sessionId,
4393
- timestamp: new Date().toISOString()
4394
- })
4395
- });
4396
- if (!response.ok) {
4397
- throw new Error(`Failed to send custom event: ${response.statusText}`);
4398
- }
4399
- return yield response.json();
4400
- }
4401
- catch (error) {
4402
- retryCount++;
4403
- if (retryCount === maxRetries) {
4404
- logError('Error sending custom event after max retries:', error);
4405
- throw error;
4406
- }
4407
- // Exponential backoff
4408
- yield new Promise(resolve => setTimeout(resolve, Math.pow(2, retryCount) * 1000));
4409
- }
4410
- }
4411
- });
4412
- }
4413
- sendCustomEvents(events, sessionId) {
4414
- return __awaiter$1(this, void 0, void 0, function* () {
4415
- const maxRetries = 3;
4416
- let retryCount = 0;
4417
- while (retryCount < maxRetries) {
4418
- try {
4419
- const response = yield fetch(`${this.baseUrl}/api/ingestion/customEvent/batch`, {
4420
- method: 'POST',
4421
- headers: {
4422
- 'Content-Type': 'application/json',
4423
- 'Authorization': `Bearer ${this.apiKey}`
4424
- },
4425
- body: JSON.stringify({
4426
- events: events.map(event => (Object.assign(Object.assign({}, event), { sessionId: sessionId })))
4427
- })
4428
- });
4429
- if (!response.ok) {
4430
- throw new Error(`Failed to send custom events: ${response.statusText}`);
4431
- }
4432
- return yield response.json();
4433
- }
4434
- catch (error) {
4435
- retryCount++;
4436
- if (retryCount === maxRetries) {
4437
- logError('Error sending custom events after max retries:', error);
4438
- throw error;
4439
- }
4440
- // Exponential backoff
4441
- yield new Promise(resolve => setTimeout(resolve, Math.pow(2, retryCount) * 1000));
4442
- }
4443
- }
4444
- });
4445
- }
4446
- sendBeaconEvents(events, sessionId, isSessionComplete = false) {
4362
+ sendBeaconEvents(events, sessionId) {
4447
4363
  const data = new URLSearchParams();
4448
4364
  data.append('events', encodeURIComponent(JSON.stringify(events)));
4449
4365
  data.append('sessionId', encodeURIComponent(sessionId));
4450
4366
  data.append('timestamp', encodeURIComponent(Date.now().toString()));
4451
4367
  data.append('apiKey', encodeURIComponent(this.apiKey));
4452
- if (isSessionComplete) {
4453
- logInfo('Session complete beacon sending');
4454
- localStorage.setItem('koalaware_session_complete', Date.now().toString());
4455
- data.append('sessionComplete', encodeURIComponent('true'));
4456
- }
4457
4368
  navigator.sendBeacon(`${this.baseUrl}/api/ingestion/events`, data);
4458
4369
  // KoalawareTracker.logToStorage(`Sending events beacon: ${this.baseUrl}/api/ingestion/events`);
4459
4370
  // KoalawareTracker.logToStorage(`Events beacon success: ${success}`);
4460
4371
  }
4461
- sendBeaconSessionComplete(sessionId) {
4462
- const data = new URLSearchParams();
4463
- data.append('sessionId', sessionId);
4464
- data.append('apiKey', this.apiKey);
4465
- data.append('sessionComplete', 'true');
4466
- navigator.sendBeacon(`${this.baseUrl}/api/ingestion/sessionComplete`, data);
4467
- // KoalawareTracker.logToStorage(`Sending completion beacon: ${this.baseUrl}/api/ingestion/sessionComplete`);
4468
- // KoalawareTracker.logToStorage(`Complete beacon success: ${success}`);
4469
- }
4470
- sendBeaconCustomEvent(eventName, eventProperties, sessionId) {
4471
- const data = new URLSearchParams();
4472
- data.append('name', encodeURIComponent(eventName));
4473
- data.append('properties', encodeURIComponent(JSON.stringify(eventProperties)));
4474
- data.append('sessionId', encodeURIComponent(sessionId));
4475
- data.append('timestamp', encodeURIComponent(new Date().toISOString()));
4476
- data.append('apiKey', encodeURIComponent(this.apiKey));
4477
- return navigator.sendBeacon(`${this.baseUrl}/api/ingestion/customEvent`, data);
4478
- }
4479
- sendBeaconCustomEvents(events, sessionId) {
4480
- const data = new URLSearchParams();
4481
- data.append('events', encodeURIComponent(JSON.stringify(events.map(event => (Object.assign(Object.assign({}, event), { sessionId: sessionId }))))));
4482
- data.append('apiKey', encodeURIComponent(this.apiKey));
4483
- return navigator.sendBeacon(`${this.baseUrl}/api/ingestion/customEvent/batch`, data);
4484
- }
4485
4372
  }
4486
4373
 
4487
4374
  // Redaction functionality for sensitive input fields
@@ -4900,6 +4787,40 @@ const redactionManager = new RedactionManager();
4900
4787
  // Check if we're in a browser environment
4901
4788
  const isBrowser = typeof window !== 'undefined';
4902
4789
  class HumanBehaviorTracker {
4790
+ /**
4791
+ * Initialize the HumanBehavior tracker
4792
+ * This is the main entry point - call this once per page
4793
+ */
4794
+ static init(apiKey, options) {
4795
+ // Return existing instance if already initialized
4796
+ if (isBrowser && window.__humanBehaviorGlobalTracker) {
4797
+ logDebug('Tracker already initialized, returning existing instance');
4798
+ return window.__humanBehaviorGlobalTracker;
4799
+ }
4800
+ // Configure logging if specified
4801
+ if (options === null || options === void 0 ? void 0 : options.logLevel) {
4802
+ this.configureLogging({ level: options.logLevel });
4803
+ }
4804
+ // Create new tracker instance
4805
+ const tracker = new HumanBehaviorTracker(apiKey, options === null || options === void 0 ? void 0 : options.ingestionUrl);
4806
+ // Set redacted fields if specified
4807
+ if (options === null || options === void 0 ? void 0 : options.redactFields) {
4808
+ tracker.setRedactedFields(options.redactFields);
4809
+ }
4810
+ // Test connection (non-blocking)
4811
+ if (isBrowser) {
4812
+ const testUrl = tracker.api['baseUrl'] + '/api/ingestion/health';
4813
+ fetch(testUrl, { method: 'HEAD' })
4814
+ .then(() => logDebug('Connection test successful'))
4815
+ .catch((error) => {
4816
+ logWarn('Connection test failed - ad blocker may be active:', error.message);
4817
+ tracker._connectionBlocked = true;
4818
+ });
4819
+ }
4820
+ // Start tracking
4821
+ tracker.start();
4822
+ return tracker;
4823
+ }
4903
4824
  constructor(apiKey, ingestionUrl) {
4904
4825
  this.eventIngestionQueue = [];
4905
4826
  this.queueSizeBytes = 0;
@@ -4914,60 +4835,77 @@ class HumanBehaviorTracker {
4914
4835
  this.initializationPromise = null;
4915
4836
  // Console tracking properties
4916
4837
  this.originalConsole = null;
4917
- this.originalLogger = null;
4918
4838
  this.consoleTrackingEnabled = false;
4839
+ // Navigation tracking properties
4840
+ this.navigationTrackingEnabled = false;
4841
+ this.currentUrl = '';
4842
+ this.previousUrl = '';
4843
+ this.originalPushState = null;
4844
+ this.originalReplaceState = null;
4845
+ this.navigationListeners = [];
4846
+ this._connectionBlocked = false;
4919
4847
  if (!apiKey) {
4920
4848
  throw new Error('Human Behavior API Key is required');
4921
4849
  }
4922
- // ========================================
4923
- // DEVELOPER: Choose your ingestion server
4924
- // ========================================
4925
- // Uncomment ONE of the following lines to select your server:
4926
- // AWS Development Server
4927
- const defaultIngestionUrl = 'http://3.137.217.33:3000';
4928
- // Vercel Production Server
4929
- // const defaultIngestionUrl = 'https://ingestion-server.vercel.app';
4930
- // Local Development Server
4931
- // const defaultIngestionUrl = 'http://localhost:3000';
4850
+ // Initialize API
4851
+ const defaultIngestionUrl = 'http://3.137.217.33:3000'; // AWS Development Server
4932
4852
  this.api = new HumanBehaviorAPI({
4933
4853
  apiKey: apiKey,
4934
4854
  ingestionUrl: ingestionUrl || defaultIngestionUrl
4935
4855
  });
4936
4856
  this.apiKey = apiKey;
4937
4857
  this.redactionManager = new RedactionManager();
4938
- // Check for existing session ID and last activity time in localStorage
4939
- const existingSessionId = isBrowser ? localStorage.getItem('human_behavior_session_id') : null;
4940
- const lastActivity = isBrowser ? localStorage.getItem('human_behavior_last_activity') : null;
4941
- // If we have a last activity time, check if it's within 30 minutes
4942
- const thirtyMinutesAgo = Date.now() - (30 * 60 * 1000);
4943
- const shouldUseExistingSession = lastActivity && parseInt(lastActivity) > thirtyMinutesAgo;
4944
- this.sessionId = (existingSessionId && shouldUseExistingSession) ? existingSessionId : v1();
4945
- // Store the session ID if it's new
4946
- if ((!existingSessionId || !shouldUseExistingSession) && isBrowser) {
4947
- localStorage.setItem('human_behavior_session_id', this.sessionId);
4858
+ // Handle session restoration
4859
+ if (isBrowser) {
4860
+ const existingSessionId = localStorage.getItem('human_behavior_session_id');
4861
+ const lastActivity = localStorage.getItem('human_behavior_last_activity');
4862
+ const thirtyMinutesAgo = Date.now() - (30 * 60 * 1000);
4863
+ if (existingSessionId && lastActivity && parseInt(lastActivity) > thirtyMinutesAgo) {
4864
+ this.sessionId = existingSessionId;
4865
+ logDebug(`Reusing existing session: ${this.sessionId}`);
4866
+ }
4867
+ else {
4868
+ this.sessionId = v1();
4869
+ logDebug(`Creating new session: ${this.sessionId}`);
4870
+ localStorage.setItem('human_behavior_session_id', this.sessionId);
4871
+ }
4872
+ this.currentUrl = window.location.href;
4873
+ window.__humanBehaviorGlobalTracker = this;
4874
+ }
4875
+ else {
4876
+ this.sessionId = v1();
4948
4877
  }
4949
- // Start initialization immediately
4878
+ // Start initialization
4950
4879
  this.initializationPromise = this.init();
4951
4880
  }
4952
4881
  init() {
4953
4882
  return __awaiter$1(this, void 0, void 0, function* () {
4954
4883
  try {
4955
4884
  const userId = this.getCookie(`human_behavior_end_user_id_${this.apiKey}`);
4885
+ logDebug(`Initializing with sessionId: ${this.sessionId}, userId: ${userId}`);
4956
4886
  const { sessionId, endUserId } = yield this.api.init(this.sessionId, userId);
4957
- this.sessionId = sessionId;
4887
+ // Check if server returned a different session ID
4888
+ if (sessionId !== this.sessionId) {
4889
+ logDebug(`Server returned different sessionId: ${sessionId} (client had: ${this.sessionId})`);
4890
+ this.sessionId = sessionId;
4891
+ // Update localStorage with server's session ID
4892
+ if (isBrowser) {
4893
+ localStorage.setItem('human_behavior_session_id', this.sessionId);
4894
+ }
4895
+ }
4958
4896
  this.endUserId = endUserId;
4959
4897
  this.setCookie(`human_behavior_end_user_id_${this.apiKey}`, endUserId, 365);
4960
4898
  // Only setup browser-specific handlers when in browser environment
4961
4899
  if (isBrowser) {
4962
4900
  this.setupPageUnloadHandler();
4963
- this.start();
4901
+ this.setupNavigationTracking();
4964
4902
  this.processRejectedEvents();
4965
4903
  }
4966
4904
  else {
4967
4905
  logWarn('HumanBehaviorTracker initialized in a non-browser environment. Session tracking is disabled.');
4968
4906
  }
4969
4907
  this.initialized = true;
4970
- logInfo('HumanBehaviorTracker initialized');
4908
+ logInfo(`HumanBehaviorTracker initialized with sessionId: ${this.sessionId}, endUserId: ${endUserId}`);
4971
4909
  }
4972
4910
  catch (error) {
4973
4911
  logError('Failed to initialize HumanBehaviorTracker:', error);
@@ -4983,6 +4921,171 @@ class HumanBehaviorTracker {
4983
4921
  yield this.initializationPromise;
4984
4922
  });
4985
4923
  }
4924
+ /**
4925
+ * Setup navigation event tracking for SPA navigation
4926
+ */
4927
+ setupNavigationTracking() {
4928
+ if (!isBrowser || this.navigationTrackingEnabled)
4929
+ return;
4930
+ this.navigationTrackingEnabled = true;
4931
+ logDebug('Setting up navigation tracking');
4932
+ // Store original history methods
4933
+ this.originalPushState = history.pushState;
4934
+ this.originalReplaceState = history.replaceState;
4935
+ // Override pushState to capture programmatic navigation
4936
+ history.pushState = (...args) => {
4937
+ this.previousUrl = this.currentUrl;
4938
+ this.currentUrl = window.location.href;
4939
+ // Call original method
4940
+ this.originalPushState.apply(history, args);
4941
+ // Track navigation event
4942
+ this.trackNavigationEvent('pushState', this.previousUrl, this.currentUrl);
4943
+ };
4944
+ // Override replaceState to capture programmatic navigation
4945
+ history.replaceState = (...args) => {
4946
+ this.previousUrl = this.currentUrl;
4947
+ this.currentUrl = window.location.href;
4948
+ // Call original method
4949
+ this.originalReplaceState.apply(history, args);
4950
+ // Track navigation event
4951
+ this.trackNavigationEvent('replaceState', this.previousUrl, this.currentUrl);
4952
+ };
4953
+ // Listen for popstate events (back/forward navigation)
4954
+ const popstateListener = () => {
4955
+ this.previousUrl = this.currentUrl;
4956
+ this.currentUrl = window.location.href;
4957
+ this.trackNavigationEvent('popstate', this.previousUrl, this.currentUrl);
4958
+ };
4959
+ window.addEventListener('popstate', popstateListener);
4960
+ this.navigationListeners.push(() => {
4961
+ window.removeEventListener('popstate', popstateListener);
4962
+ });
4963
+ // Listen for hashchange events
4964
+ const hashchangeListener = () => {
4965
+ this.previousUrl = this.currentUrl;
4966
+ this.currentUrl = window.location.href;
4967
+ this.trackNavigationEvent('hashchange', this.previousUrl, this.currentUrl);
4968
+ };
4969
+ window.addEventListener('hashchange', hashchangeListener);
4970
+ this.navigationListeners.push(() => {
4971
+ window.removeEventListener('hashchange', hashchangeListener);
4972
+ });
4973
+ // Track initial page load
4974
+ this.trackNavigationEvent('pageLoad', '', this.currentUrl);
4975
+ }
4976
+ /**
4977
+ * Track navigation events and send custom events
4978
+ */
4979
+ trackNavigationEvent(type, fromUrl, toUrl) {
4980
+ return __awaiter$1(this, void 0, void 0, function* () {
4981
+ if (!this.initialized)
4982
+ return;
4983
+ try {
4984
+ const navigationData = {
4985
+ type: type,
4986
+ from: fromUrl,
4987
+ to: toUrl,
4988
+ timestamp: new Date().toISOString(),
4989
+ pathname: window.location.pathname,
4990
+ search: window.location.search,
4991
+ hash: window.location.hash,
4992
+ referrer: document.referrer
4993
+ };
4994
+ // Add navigation event to the main event stream
4995
+ yield this.addEvent({
4996
+ type: 5, // Custom event type
4997
+ data: {
4998
+ payload: Object.assign({ eventType: 'navigation' }, navigationData)
4999
+ },
5000
+ timestamp: Date.now()
5001
+ });
5002
+ logDebug(`Navigation tracked: ${type} from ${fromUrl} to ${toUrl}`);
5003
+ }
5004
+ catch (error) {
5005
+ logError('Failed to track navigation event:', error);
5006
+ }
5007
+ });
5008
+ }
5009
+ /**
5010
+ * Track a page view event (PostHog-style)
5011
+ */
5012
+ trackPageView(url) {
5013
+ return __awaiter$1(this, void 0, void 0, function* () {
5014
+ if (!this.initialized)
5015
+ return;
5016
+ try {
5017
+ const pageViewData = {
5018
+ url: url || window.location.href,
5019
+ pathname: window.location.pathname,
5020
+ search: window.location.search,
5021
+ hash: window.location.hash,
5022
+ referrer: document.referrer,
5023
+ timestamp: new Date().toISOString()
5024
+ };
5025
+ // Add pageview event to the main event stream
5026
+ yield this.addEvent({
5027
+ type: 5, // Custom event type
5028
+ data: {
5029
+ payload: Object.assign({ eventType: 'pageview' }, pageViewData)
5030
+ },
5031
+ timestamp: Date.now()
5032
+ });
5033
+ logDebug(`Pageview tracked: ${pageViewData.url}`);
5034
+ }
5035
+ catch (error) {
5036
+ logError('Failed to track pageview event:', error);
5037
+ }
5038
+ });
5039
+ }
5040
+ /**
5041
+ * Track a custom event (PostHog-style)
5042
+ */
5043
+ customEvent(eventName, properties) {
5044
+ return __awaiter$1(this, void 0, void 0, function* () {
5045
+ if (!this.initialized)
5046
+ return;
5047
+ try {
5048
+ const customEventData = {
5049
+ eventName: eventName,
5050
+ properties: properties || {},
5051
+ timestamp: new Date().toISOString(),
5052
+ url: window.location.href,
5053
+ pathname: window.location.pathname
5054
+ };
5055
+ // Add custom event to the main event stream
5056
+ yield this.addEvent({
5057
+ type: 5, // Custom event type
5058
+ data: {
5059
+ payload: Object.assign({ eventType: 'custom' }, customEventData)
5060
+ },
5061
+ timestamp: Date.now()
5062
+ });
5063
+ logDebug(`Custom event tracked: ${eventName}`, properties);
5064
+ }
5065
+ catch (error) {
5066
+ logError('Failed to track custom event:', error);
5067
+ }
5068
+ });
5069
+ }
5070
+ /**
5071
+ * Cleanup navigation tracking
5072
+ */
5073
+ cleanupNavigationTracking() {
5074
+ if (!this.navigationTrackingEnabled)
5075
+ return;
5076
+ // Restore original history methods
5077
+ if (this.originalPushState) {
5078
+ history.pushState = this.originalPushState;
5079
+ }
5080
+ if (this.originalReplaceState) {
5081
+ history.replaceState = this.originalReplaceState;
5082
+ }
5083
+ // Remove event listeners
5084
+ this.navigationListeners.forEach(cleanup => cleanup());
5085
+ this.navigationListeners = [];
5086
+ this.navigationTrackingEnabled = false;
5087
+ logDebug('Navigation tracking cleaned up');
5088
+ }
4986
5089
  static logToStorage(message) {
4987
5090
  logInfo(message);
4988
5091
  }
@@ -5016,13 +5119,6 @@ class HumanBehaviorTracker {
5016
5119
  warn: console.warn,
5017
5120
  error: console.error
5018
5121
  };
5019
- // Store original logger methods
5020
- this.originalLogger = {
5021
- error: logError,
5022
- warn: logWarn,
5023
- info: logInfo,
5024
- debug: logDebug
5025
- };
5026
5122
  // Override console methods to capture ALL console output (including logger output)
5027
5123
  console.log = (...args) => {
5028
5124
  this.trackConsoleEvent('log', args);
@@ -5037,44 +5133,47 @@ class HumanBehaviorTracker {
5037
5133
  this.originalConsole.error(...args);
5038
5134
  };
5039
5135
  this.consoleTrackingEnabled = true;
5040
- this.originalLogger.debug('Console tracking enabled');
5136
+ logDebug('Console tracking enabled');
5041
5137
  }
5042
5138
  /**
5043
5139
  * Disable console event tracking
5044
5140
  */
5045
5141
  disableConsoleTracking() {
5046
- if (!isBrowser || !this.consoleTrackingEnabled || !this.originalConsole)
5142
+ if (!isBrowser || !this.consoleTrackingEnabled)
5047
5143
  return;
5048
5144
  // Restore original console methods
5049
- console.log = this.originalConsole.log;
5050
- console.warn = this.originalConsole.warn;
5051
- console.error = this.originalConsole.error;
5145
+ if (this.originalConsole) {
5146
+ console.log = this.originalConsole.log;
5147
+ console.warn = this.originalConsole.warn;
5148
+ console.error = this.originalConsole.error;
5149
+ }
5052
5150
  this.consoleTrackingEnabled = false;
5053
- this.originalConsole = null;
5054
- this.originalLogger = null;
5151
+ logDebug('Console tracking disabled');
5055
5152
  }
5056
- /**
5057
- * Track console events
5058
- */
5059
5153
  trackConsoleEvent(level, args) {
5060
5154
  if (!this.initialized)
5061
5155
  return;
5062
- const consoleEvent = {
5063
- type: 5, // Custom event type
5064
- data: {
5065
- payload: {
5066
- type: 'console',
5067
- level: level,
5068
- message: args.map(arg => typeof arg === 'string' ? arg :
5069
- typeof arg === 'object' ? JSON.stringify(arg) :
5070
- String(arg)).join(' '),
5071
- timestamp: Date.now(),
5072
- url: window.location.href
5073
- }
5074
- },
5075
- timestamp: Date.now()
5076
- };
5077
- this.addEvent(consoleEvent);
5156
+ try {
5157
+ const consoleData = {
5158
+ level: level,
5159
+ message: args.map(arg => typeof arg === 'object' ? JSON.stringify(arg) : String(arg)).join(' '),
5160
+ timestamp: new Date().toISOString(),
5161
+ url: window.location.href
5162
+ };
5163
+ // Add console event to the main event stream
5164
+ this.addEvent({
5165
+ type: 5, // Custom event type
5166
+ data: {
5167
+ payload: Object.assign({ eventType: 'console' }, consoleData)
5168
+ },
5169
+ timestamp: Date.now()
5170
+ }).catch(error => {
5171
+ logError('Failed to track console event:', error);
5172
+ });
5173
+ }
5174
+ catch (error) {
5175
+ logError('Error in trackConsoleEvent:', error);
5176
+ }
5078
5177
  }
5079
5178
  setupPageUnloadHandler() {
5080
5179
  if (!isBrowser)
@@ -5090,15 +5189,18 @@ class HumanBehaviorTracker {
5090
5189
  });
5091
5190
  // Handle actual page unload/close
5092
5191
  window.addEventListener('beforeunload', () => {
5093
- // Update last activity time
5094
- localStorage.setItem('human_behavior_last_activity', Date.now().toString());
5095
5192
  // Send final events
5096
5193
  this.api.sendBeaconEvents(this.eventIngestionQueue, this.sessionId);
5097
5194
  });
5098
- // Update activity timestamp periodically
5099
- setInterval(() => {
5195
+ // Update activity timestamp on user interaction (not on page load)
5196
+ const updateActivity = () => {
5100
5197
  localStorage.setItem('human_behavior_last_activity', Date.now().toString());
5101
- }, 60000); // Update every minute
5198
+ };
5199
+ // Listen for user interactions to update activity timestamp
5200
+ window.addEventListener('click', updateActivity);
5201
+ window.addEventListener('keydown', updateActivity);
5202
+ window.addEventListener('scroll', updateActivity);
5203
+ window.addEventListener('mousemove', updateActivity);
5102
5204
  }
5103
5205
  viewLogs() {
5104
5206
  try {
@@ -5136,12 +5238,6 @@ class HumanBehaviorTracker {
5136
5238
  yield this.api.sendUserAuth(this.endUserId, this.userProperties, this.sessionId, authFields);
5137
5239
  });
5138
5240
  }
5139
- customEvent(eventName_1) {
5140
- return __awaiter$1(this, arguments, void 0, function* (eventName, eventProperties = {}) {
5141
- yield this.ensureInitialized();
5142
- this.api.sendBeaconCustomEvent(eventName, eventProperties, this.sessionId);
5143
- });
5144
- }
5145
5241
  start() {
5146
5242
  return __awaiter$1(this, void 0, void 0, function* () {
5147
5243
  yield this.ensureInitialized();
@@ -5178,6 +5274,8 @@ class HumanBehaviorTracker {
5178
5274
  }
5179
5275
  // Disable console tracking
5180
5276
  this.disableConsoleTracking();
5277
+ // Cleanup navigation tracking
5278
+ this.cleanupNavigationTracking();
5181
5279
  });
5182
5280
  }
5183
5281
  addEvent(event) {
@@ -5220,7 +5318,7 @@ class HumanBehaviorTracker {
5220
5318
  }
5221
5319
  flush() {
5222
5320
  return __awaiter$1(this, void 0, void 0, function* () {
5223
- var _a;
5321
+ var _a, _b, _c, _d;
5224
5322
  // Prevent concurrent flushes
5225
5323
  if (this.isProcessing || !this.initialized) {
5226
5324
  return;
@@ -5243,6 +5341,14 @@ class HumanBehaviorTracker {
5243
5341
  this.rejectedEvents.push(...eventsToProcess);
5244
5342
  this.processRejectedEvents();
5245
5343
  }
5344
+ else if (((_b = error.message) === null || _b === void 0 ? void 0 : _b.includes('ERR_BLOCKED_BY_CLIENT')) ||
5345
+ ((_c = error.message) === null || _c === void 0 ? void 0 : _c.includes('Failed to fetch')) ||
5346
+ ((_d = error.message) === null || _d === void 0 ? void 0 : _d.includes('NetworkError'))) {
5347
+ // Handle ad blocker or network issues gracefully
5348
+ logWarn('Request blocked by ad blocker or network issue, storing events for retry');
5349
+ this.rejectedEvents.push(...eventsToProcess);
5350
+ // Don't process rejected events immediately to avoid spam
5351
+ }
5246
5352
  else {
5247
5353
  throw error;
5248
5354
  }
@@ -5315,6 +5421,61 @@ class HumanBehaviorTracker {
5315
5421
  getRedactedFields() {
5316
5422
  return this.redactionManager.getSelectedFields();
5317
5423
  }
5424
+ /**
5425
+ * Get the current session ID
5426
+ */
5427
+ getSessionId() {
5428
+ return this.sessionId;
5429
+ }
5430
+ /**
5431
+ * Get the current URL being tracked
5432
+ */
5433
+ getCurrentUrl() {
5434
+ return this.currentUrl;
5435
+ }
5436
+ /**
5437
+ * Test if the tracker can reach the ingestion server
5438
+ */
5439
+ testConnection() {
5440
+ return __awaiter$1(this, void 0, void 0, function* () {
5441
+ try {
5442
+ yield this.api.init(this.sessionId, this.endUserId);
5443
+ return { success: true };
5444
+ }
5445
+ catch (error) {
5446
+ return {
5447
+ success: false,
5448
+ error: error.message || 'Unknown error'
5449
+ };
5450
+ }
5451
+ });
5452
+ }
5453
+ /**
5454
+ * Get connection status and recommendations
5455
+ */
5456
+ getConnectionStatus() {
5457
+ const recommendations = [];
5458
+ let blocked = false;
5459
+ // Check if we have rejected events (might indicate blocking)
5460
+ if (this.rejectedEvents.length > 0) {
5461
+ blocked = true;
5462
+ recommendations.push('Some requests may be blocked by ad blockers');
5463
+ }
5464
+ // Check if connection was blocked during initialization
5465
+ if (this._connectionBlocked) {
5466
+ blocked = true;
5467
+ recommendations.push('Initial connection test failed - ad blocker may be active');
5468
+ }
5469
+ // Check if we're in a browser environment
5470
+ if (typeof window === 'undefined') {
5471
+ recommendations.push('Not running in browser environment');
5472
+ }
5473
+ // Check if navigator.sendBeacon is available
5474
+ if (typeof navigator.sendBeacon === 'undefined') {
5475
+ recommendations.push('sendBeacon not available, using fetch fallback');
5476
+ }
5477
+ return { blocked, recommendations };
5478
+ }
5318
5479
  }
5319
5480
  // Only expose to window object in browser environments
5320
5481
  if (isBrowser) {