humanbehavior-js 0.0.8 → 0.0.9

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
@@ -4053,6 +4053,123 @@ function v1Bytes(rnds, msecs, nsecs, clockseq, node, buf, offset = 0) {
4053
4053
  return buf;
4054
4054
  }
4055
4055
 
4056
+ exports.LogLevel = void 0;
4057
+ (function (LogLevel) {
4058
+ LogLevel[LogLevel["NONE"] = 0] = "NONE";
4059
+ LogLevel[LogLevel["ERROR"] = 1] = "ERROR";
4060
+ LogLevel[LogLevel["WARN"] = 2] = "WARN";
4061
+ LogLevel[LogLevel["INFO"] = 3] = "INFO";
4062
+ LogLevel[LogLevel["DEBUG"] = 4] = "DEBUG";
4063
+ })(exports.LogLevel || (exports.LogLevel = {}));
4064
+ class Logger {
4065
+ constructor(config) {
4066
+ this.config = {
4067
+ level: exports.LogLevel.ERROR, // Default to only errors in production
4068
+ enableConsole: true,
4069
+ enableStorage: false
4070
+ };
4071
+ this.isBrowser = typeof window !== 'undefined';
4072
+ if (config) {
4073
+ this.config = Object.assign(Object.assign({}, this.config), config);
4074
+ }
4075
+ }
4076
+ setConfig(config) {
4077
+ this.config = Object.assign(Object.assign({}, this.config), config);
4078
+ }
4079
+ shouldLog(level) {
4080
+ return level <= this.config.level;
4081
+ }
4082
+ formatMessage(level, message, ...args) {
4083
+ const timestamp = new Date().toISOString();
4084
+ return `[HumanBehavior ${level}] ${timestamp}: ${message}`;
4085
+ }
4086
+ error(message, ...args) {
4087
+ if (!this.shouldLog(exports.LogLevel.ERROR))
4088
+ return;
4089
+ const formattedMessage = this.formatMessage('ERROR', message);
4090
+ if (this.config.enableConsole) {
4091
+ console.error(formattedMessage, ...args);
4092
+ }
4093
+ if (this.config.enableStorage && this.isBrowser) {
4094
+ this.logToStorage(formattedMessage, args);
4095
+ }
4096
+ }
4097
+ warn(message, ...args) {
4098
+ if (!this.shouldLog(exports.LogLevel.WARN))
4099
+ return;
4100
+ const formattedMessage = this.formatMessage('WARN', message);
4101
+ if (this.config.enableConsole) {
4102
+ console.warn(formattedMessage, ...args);
4103
+ }
4104
+ if (this.config.enableStorage && this.isBrowser) {
4105
+ this.logToStorage(formattedMessage, args);
4106
+ }
4107
+ }
4108
+ info(message, ...args) {
4109
+ if (!this.shouldLog(exports.LogLevel.INFO))
4110
+ return;
4111
+ const formattedMessage = this.formatMessage('INFO', message);
4112
+ if (this.config.enableConsole) {
4113
+ console.log(formattedMessage, ...args);
4114
+ }
4115
+ if (this.config.enableStorage && this.isBrowser) {
4116
+ this.logToStorage(formattedMessage, args);
4117
+ }
4118
+ }
4119
+ debug(message, ...args) {
4120
+ if (!this.shouldLog(exports.LogLevel.DEBUG))
4121
+ return;
4122
+ const formattedMessage = this.formatMessage('DEBUG', message);
4123
+ if (this.config.enableConsole) {
4124
+ console.log(formattedMessage, ...args);
4125
+ }
4126
+ if (this.config.enableStorage && this.isBrowser) {
4127
+ this.logToStorage(formattedMessage, args);
4128
+ }
4129
+ }
4130
+ logToStorage(message, args) {
4131
+ try {
4132
+ const logs = JSON.parse(localStorage.getItem('human_behavior_logs') || '[]');
4133
+ const logEntry = {
4134
+ message,
4135
+ args: args.length > 0 ? args : undefined,
4136
+ timestamp: Date.now()
4137
+ };
4138
+ logs.push(logEntry);
4139
+ // Keep only last 1000 logs to prevent storage bloat
4140
+ if (logs.length > 1000) {
4141
+ logs.splice(0, logs.length - 1000);
4142
+ }
4143
+ localStorage.setItem('human_behavior_logs', JSON.stringify(logs));
4144
+ }
4145
+ catch (e) {
4146
+ // Silently fail if storage is not available
4147
+ }
4148
+ }
4149
+ getLogs() {
4150
+ if (!this.isBrowser)
4151
+ return [];
4152
+ try {
4153
+ return JSON.parse(localStorage.getItem('human_behavior_logs') || '[]');
4154
+ }
4155
+ catch (e) {
4156
+ return [];
4157
+ }
4158
+ }
4159
+ clearLogs() {
4160
+ if (this.isBrowser) {
4161
+ localStorage.removeItem('human_behavior_logs');
4162
+ }
4163
+ }
4164
+ }
4165
+ // Create singleton instance
4166
+ const logger = new Logger();
4167
+ // Export convenience methods
4168
+ const logError = (message, ...args) => logger.error(message, ...args);
4169
+ const logWarn = (message, ...args) => logger.warn(message, ...args);
4170
+ const logInfo = (message, ...args) => logger.info(message, ...args);
4171
+ const logDebug = (message, ...args) => logger.debug(message, ...args);
4172
+
4056
4173
  const MAX_CHUNK_SIZE_BYTES = 1024 * 1024 * 10; // 10MB chunk size
4057
4174
  function isChunkSizeExceeded(currentChunk, newEvent, sessionId) {
4058
4175
  const nextChunkSize = new TextEncoder().encode(JSON.stringify({
@@ -4184,7 +4301,7 @@ class HumanBehaviorAPI {
4184
4301
  return results.flat();
4185
4302
  }
4186
4303
  catch (error) {
4187
- console.error('Error sending events:', error);
4304
+ logError('Error sending events:', error);
4188
4305
  throw error;
4189
4306
  }
4190
4307
  });
@@ -4210,7 +4327,7 @@ class HumanBehaviorAPI {
4210
4327
  return yield response.json();
4211
4328
  }
4212
4329
  catch (error) {
4213
- console.error('Error sending user data:', error);
4330
+ logError('Error sending user data:', error);
4214
4331
  throw error;
4215
4332
  }
4216
4333
  });
@@ -4237,7 +4354,7 @@ class HumanBehaviorAPI {
4237
4354
  return yield response.json();
4238
4355
  }
4239
4356
  catch (error) {
4240
- console.error('Error authenticating user:', error);
4357
+ logError('Error authenticating user:', error);
4241
4358
  throw error;
4242
4359
  }
4243
4360
  });
@@ -4284,7 +4401,7 @@ class HumanBehaviorAPI {
4284
4401
  catch (error) {
4285
4402
  retryCount++;
4286
4403
  if (retryCount === maxRetries) {
4287
- console.error('Error sending custom event after max retries:', error);
4404
+ logError('Error sending custom event after max retries:', error);
4288
4405
  throw error;
4289
4406
  }
4290
4407
  // Exponential backoff
@@ -4317,7 +4434,7 @@ class HumanBehaviorAPI {
4317
4434
  catch (error) {
4318
4435
  retryCount++;
4319
4436
  if (retryCount === maxRetries) {
4320
- console.error('Error sending custom events after max retries:', error);
4437
+ logError('Error sending custom events after max retries:', error);
4321
4438
  throw error;
4322
4439
  }
4323
4440
  // Exponential backoff
@@ -4333,7 +4450,7 @@ class HumanBehaviorAPI {
4333
4450
  data.append('timestamp', encodeURIComponent(Date.now().toString()));
4334
4451
  data.append('apiKey', encodeURIComponent(this.apiKey));
4335
4452
  if (isSessionComplete) {
4336
- console.log('Session complete beacon sending');
4453
+ logInfo('Session complete beacon sending');
4337
4454
  localStorage.setItem('koalaware_session_complete', Date.now().toString());
4338
4455
  data.append('sessionComplete', encodeURIComponent('true'));
4339
4456
  }
@@ -4397,18 +4514,18 @@ class RedactionManager {
4397
4514
  this.userSelectedFields.clear();
4398
4515
  fields.forEach(field => this.userSelectedFields.add(field));
4399
4516
  if (fields.length > 0) {
4400
- console.log(`Redaction: Active for ${fields.length} field(s):`, fields);
4517
+ logDebug(`Redaction: Active for ${fields.length} field(s):`, fields);
4401
4518
  // Debug: Check if elements exist
4402
4519
  fields.forEach(selector => {
4403
4520
  const elements = document.querySelectorAll(selector);
4404
- console.log(`Redaction: Found ${elements.length} element(s) for selector '${selector}'`);
4521
+ logDebug(`Redaction: Found ${elements.length} element(s) for selector '${selector}'`);
4405
4522
  elements.forEach((el, index) => {
4406
- console.log(`Redaction: Element ${index} for '${selector}':`, el);
4523
+ logDebug(`Redaction: Element ${index} for '${selector}':`, el);
4407
4524
  });
4408
4525
  });
4409
4526
  }
4410
4527
  else {
4411
- console.log('Redaction: Disabled - no fields selected');
4528
+ logDebug('Redaction: Disabled - no fields selected');
4412
4529
  }
4413
4530
  }
4414
4531
  /**
@@ -4438,7 +4555,7 @@ class RedactionManager {
4438
4555
  if (processedEvent.data.source === 5) { // Input event
4439
4556
  const shouldRedact = this.isFieldSelected(processedEvent.data);
4440
4557
  if (shouldRedact) {
4441
- console.log('Redaction: Processing input event for redaction');
4558
+ logDebug('Redaction: Processing input event for redaction');
4442
4559
  this.redactInputEvent(processedEvent.data);
4443
4560
  }
4444
4561
  }
@@ -4464,30 +4581,30 @@ class RedactionManager {
4464
4581
  if (!this.isFieldSelected(inputData)) {
4465
4582
  return;
4466
4583
  }
4467
- console.log('Redaction: Redacting input event with text:', inputData.text);
4584
+ logDebug('Redaction: Redacting input event with text:', inputData.text);
4468
4585
  // Redact all text-related properties that could contain input data
4469
4586
  const textProperties = ['text', 'value', 'content', 'data', 'input', 'textContent'];
4470
4587
  textProperties.forEach(prop => {
4471
4588
  if (inputData[prop] !== undefined && typeof inputData[prop] === 'string') {
4472
4589
  inputData[prop] = this.redactedText;
4473
- console.log(`Redaction: Redacted property '${prop}'`);
4590
+ logDebug(`Redaction: Redacted property '${prop}'`);
4474
4591
  }
4475
4592
  });
4476
4593
  // Also check for any other string properties that might contain input data
4477
4594
  Object.keys(inputData).forEach(key => {
4478
4595
  if (typeof inputData[key] === 'string' && inputData[key].length > 0) {
4479
4596
  inputData[key] = this.redactedText;
4480
- console.log(`Redaction: Redacted additional property '${key}'`);
4597
+ logDebug(`Redaction: Redacted additional property '${key}'`);
4481
4598
  }
4482
4599
  });
4483
4600
  // Handle nested objects that might contain text data
4484
4601
  if (inputData.attributes && typeof inputData.attributes === 'object') {
4485
4602
  if (inputData.attributes.value && typeof inputData.attributes.value === 'string') {
4486
4603
  inputData.attributes.value = this.redactedText;
4487
- console.log('Redaction: Redacted nested value attribute');
4604
+ logDebug('Redaction: Redacted nested value attribute');
4488
4605
  }
4489
4606
  }
4490
- console.log('Redaction: Input event redaction complete');
4607
+ logDebug('Redaction: Input event redaction complete');
4491
4608
  }
4492
4609
  /**
4493
4610
  * Redact sensitive data in DOM mutation events
@@ -4549,7 +4666,7 @@ class RedactionManager {
4549
4666
  return false;
4550
4667
  }
4551
4668
  catch (e) {
4552
- console.warn('Error checking if DOM change should be redacted:', e);
4669
+ logWarn('Error checking if DOM change should be redacted:', e);
4553
4670
  return false;
4554
4671
  }
4555
4672
  }
@@ -4696,7 +4813,7 @@ class RedactionManager {
4696
4813
  // Check if any of these elements are currently focused
4697
4814
  for (const el of matchingElements) {
4698
4815
  if (el === document.activeElement) {
4699
- console.log('Redaction: Found focused element matching selector:', selector);
4816
+ logDebug('Redaction: Found focused element matching selector:', selector);
4700
4817
  return true;
4701
4818
  }
4702
4819
  }
@@ -4706,7 +4823,7 @@ class RedactionManager {
4706
4823
  // Look for any input element that might be the active one
4707
4824
  const activeElement = document.activeElement;
4708
4825
  if (activeElement && this.shouldRedactElement(activeElement)) {
4709
- console.log('Redaction: Active element should be redacted');
4826
+ logDebug('Redaction: Active element should be redacted');
4710
4827
  return true;
4711
4828
  }
4712
4829
  return false;
@@ -4739,7 +4856,7 @@ class RedactionManager {
4739
4856
  return false;
4740
4857
  }
4741
4858
  catch (e) {
4742
- console.warn('Error checking if field should be redacted:', e);
4859
+ logWarn('Error checking if field should be redacted:', e);
4743
4860
  return false;
4744
4861
  }
4745
4862
  }
@@ -4795,6 +4912,10 @@ class HumanBehaviorTracker {
4795
4912
  this.endUserId = null;
4796
4913
  this.initialized = false;
4797
4914
  this.initializationPromise = null;
4915
+ // Console tracking properties
4916
+ this.originalConsole = null;
4917
+ this.originalLogger = null;
4918
+ this.consoleTrackingEnabled = false;
4798
4919
  if (!apiKey) {
4799
4920
  throw new Error('Human Behavior API Key is required');
4800
4921
  }
@@ -4843,13 +4964,13 @@ class HumanBehaviorTracker {
4843
4964
  this.processRejectedEvents();
4844
4965
  }
4845
4966
  else {
4846
- console.warn('HumanBehaviorTracker initialized in a non-browser environment. Session tracking is disabled.');
4967
+ logWarn('HumanBehaviorTracker initialized in a non-browser environment. Session tracking is disabled.');
4847
4968
  }
4848
4969
  this.initialized = true;
4849
- console.log('HumanBehaviorTracker initialized');
4970
+ logInfo('HumanBehaviorTracker initialized');
4850
4971
  }
4851
4972
  catch (error) {
4852
- console.error('Failed to initialize HumanBehaviorTracker:', error);
4973
+ logError('Failed to initialize HumanBehaviorTracker:', error);
4853
4974
  throw error;
4854
4975
  }
4855
4976
  });
@@ -4863,24 +4984,107 @@ class HumanBehaviorTracker {
4863
4984
  });
4864
4985
  }
4865
4986
  static logToStorage(message) {
4866
- try {
4867
- const logs = JSON.parse(localStorage.getItem('human_behavior_logs') || '[]');
4868
- logs.push(`${new Date().toISOString()}: ${message}`);
4869
- localStorage.setItem('human_behavior_logs', JSON.stringify(logs));
4870
- }
4871
- catch (e) {
4872
- console.error('Failed to log to storage:', e);
4873
- }
4987
+ logInfo(message);
4988
+ }
4989
+ /**
4990
+ * Configure logging behavior for the SDK
4991
+ * @param config Logger configuration options
4992
+ */
4993
+ static configureLogging(config) {
4994
+ const levelMap = {
4995
+ 'none': 0,
4996
+ 'error': 1,
4997
+ 'warn': 2,
4998
+ 'info': 3,
4999
+ 'debug': 4
5000
+ };
5001
+ logger.setConfig({
5002
+ level: levelMap[config.level || 'error'],
5003
+ enableConsole: config.enableConsole !== false,
5004
+ enableStorage: config.enableStorage || false
5005
+ });
5006
+ }
5007
+ /**
5008
+ * Enable console event tracking
5009
+ */
5010
+ enableConsoleTracking() {
5011
+ if (!isBrowser || this.consoleTrackingEnabled)
5012
+ return;
5013
+ // Store original console methods
5014
+ this.originalConsole = {
5015
+ log: console.log,
5016
+ warn: console.warn,
5017
+ error: console.error
5018
+ };
5019
+ // Store original logger methods
5020
+ this.originalLogger = {
5021
+ error: logError,
5022
+ warn: logWarn,
5023
+ info: logInfo,
5024
+ debug: logDebug
5025
+ };
5026
+ // Override console methods to capture ALL console output (including logger output)
5027
+ console.log = (...args) => {
5028
+ this.trackConsoleEvent('log', args);
5029
+ this.originalConsole.log(...args);
5030
+ };
5031
+ console.warn = (...args) => {
5032
+ this.trackConsoleEvent('warn', args);
5033
+ this.originalConsole.warn(...args);
5034
+ };
5035
+ console.error = (...args) => {
5036
+ this.trackConsoleEvent('error', args);
5037
+ this.originalConsole.error(...args);
5038
+ };
5039
+ this.consoleTrackingEnabled = true;
5040
+ this.originalLogger.debug('Console tracking enabled');
5041
+ }
5042
+ /**
5043
+ * Disable console event tracking
5044
+ */
5045
+ disableConsoleTracking() {
5046
+ if (!isBrowser || !this.consoleTrackingEnabled || !this.originalConsole)
5047
+ return;
5048
+ // Restore original console methods
5049
+ console.log = this.originalConsole.log;
5050
+ console.warn = this.originalConsole.warn;
5051
+ console.error = this.originalConsole.error;
5052
+ this.consoleTrackingEnabled = false;
5053
+ this.originalConsole = null;
5054
+ this.originalLogger = null;
5055
+ }
5056
+ /**
5057
+ * Track console events
5058
+ */
5059
+ trackConsoleEvent(level, args) {
5060
+ if (!this.initialized)
5061
+ 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);
4874
5078
  }
4875
5079
  setupPageUnloadHandler() {
4876
5080
  if (!isBrowser)
4877
5081
  return;
4878
- console.log('Setting up page unload handler');
5082
+ logDebug('Setting up page unload handler');
4879
5083
  // Handle visibility changes for sending events
4880
5084
  window.addEventListener('visibilitychange', () => {
4881
5085
  // Only send events when page becomes hidden
4882
5086
  if (document.visibilityState === 'hidden') {
4883
- console.log('Page hidden - sending pending events');
5087
+ logDebug('Page hidden - sending pending events');
4884
5088
  this.api.sendBeaconEvents(this.eventIngestionQueue, this.sessionId);
4885
5089
  }
4886
5090
  });
@@ -4898,12 +5102,12 @@ class HumanBehaviorTracker {
4898
5102
  }
4899
5103
  viewLogs() {
4900
5104
  try {
4901
- const logs = JSON.parse(localStorage.getItem('human_behavior_logs') || '[]');
5105
+ const logs = logger.getLogs();
4902
5106
  console.log('HumanBehavior Logs:', logs);
4903
- localStorage.removeItem('human_behavior_logs'); // Clear logs after viewing
5107
+ logger.clearLogs(); // Clear logs after viewing
4904
5108
  }
4905
5109
  catch (e) {
4906
- console.error('Failed to read logs:', e);
5110
+ logError('Failed to read logs:', e);
4907
5111
  }
4908
5112
  }
4909
5113
  addUserInfo(userProperties) {
@@ -4947,6 +5151,8 @@ class HumanBehaviorTracker {
4947
5151
  this.flushInterval = window.setInterval(() => {
4948
5152
  this.flush();
4949
5153
  }, this.FLUSH_INTERVAL_MS);
5154
+ // Enable console tracking
5155
+ this.enableConsoleTracking();
4950
5156
  // Start recording with redaction enabled
4951
5157
  record({
4952
5158
  emit: (event) => {
@@ -4970,6 +5176,8 @@ class HumanBehaviorTracker {
4970
5176
  clearInterval(this.flushInterval);
4971
5177
  this.flushInterval = null;
4972
5178
  }
5179
+ // Disable console tracking
5180
+ this.disableConsoleTracking();
4973
5181
  });
4974
5182
  }
4975
5183
  addEvent(event) {
@@ -5003,7 +5211,7 @@ class HumanBehaviorTracker {
5003
5211
  this.sessionId = newSessionId;
5004
5212
  }
5005
5213
  catch (error) {
5006
- console.error('Failed to process rejected events:', error);
5214
+ logError('Failed to process rejected events:', error);
5007
5215
  }
5008
5216
  finally {
5009
5217
  this.isProcessingRejectedEvents = false;
@@ -5024,14 +5232,14 @@ class HumanBehaviorTracker {
5024
5232
  this.eventIngestionQueue = [];
5025
5233
  this.queueSizeBytes = 0;
5026
5234
  if (eventsToProcess.length > 0) {
5027
- console.log('Flushing events:', eventsToProcess);
5235
+ logDebug('Flushing events:', eventsToProcess);
5028
5236
  try {
5029
5237
  yield this.api.sendEvents(eventsToProcess, this.sessionId, this.endUserId);
5030
5238
  }
5031
5239
  catch (error) {
5032
5240
  // If we get a 400 error, store events for retry
5033
5241
  if ((_a = error.message) === null || _a === void 0 ? void 0 : _a.includes('ERROR: Session already completed')) {
5034
- console.log('Session expired, storing events for retry');
5242
+ logInfo('Session expired, storing events for retry');
5035
5243
  this.rejectedEvents.push(...eventsToProcess);
5036
5244
  this.processRejectedEvents();
5037
5245
  }
@@ -5077,7 +5285,7 @@ class HumanBehaviorTracker {
5077
5285
  return __awaiter$1(this, void 0, void 0, function* () {
5078
5286
  yield this.ensureInitialized();
5079
5287
  if (!isBrowser) {
5080
- console.warn('Redaction is only available in browser environments');
5288
+ logWarn('Redaction is only available in browser environments');
5081
5289
  return;
5082
5290
  }
5083
5291
  // Create a new redaction manager with the provided options
@@ -5090,7 +5298,7 @@ class HumanBehaviorTracker {
5090
5298
  */
5091
5299
  setRedactedFields(fields) {
5092
5300
  if (!isBrowser) {
5093
- console.warn('Redaction is only available in browser environments');
5301
+ logWarn('Redaction is only available in browser environments');
5094
5302
  return;
5095
5303
  }
5096
5304
  this.redactionManager.setFieldsToRedact(fields);
@@ -5127,6 +5335,11 @@ exports.MAX_CHUNK_SIZE_BYTES = MAX_CHUNK_SIZE_BYTES;
5127
5335
  exports.RedactionManager = RedactionManager;
5128
5336
  exports.default = HumanBehaviorTracker;
5129
5337
  exports.isChunkSizeExceeded = isChunkSizeExceeded;
5338
+ exports.logDebug = logDebug;
5339
+ exports.logError = logError;
5340
+ exports.logInfo = logInfo;
5341
+ exports.logWarn = logWarn;
5342
+ exports.logger = logger;
5130
5343
  exports.redactionManager = redactionManager;
5131
5344
  exports.validateSingleEventSize = validateSingleEventSize;
5132
5345
  //# sourceMappingURL=index.js.map