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