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/esm/index.js CHANGED
@@ -4049,6 +4049,123 @@ function v1Bytes(rnds, msecs, nsecs, clockseq, node, buf, offset = 0) {
4049
4049
  return buf;
4050
4050
  }
4051
4051
 
4052
+ var LogLevel;
4053
+ (function (LogLevel) {
4054
+ LogLevel[LogLevel["NONE"] = 0] = "NONE";
4055
+ LogLevel[LogLevel["ERROR"] = 1] = "ERROR";
4056
+ LogLevel[LogLevel["WARN"] = 2] = "WARN";
4057
+ LogLevel[LogLevel["INFO"] = 3] = "INFO";
4058
+ LogLevel[LogLevel["DEBUG"] = 4] = "DEBUG";
4059
+ })(LogLevel || (LogLevel = {}));
4060
+ class Logger {
4061
+ constructor(config) {
4062
+ this.config = {
4063
+ level: LogLevel.ERROR, // Default to only errors in production
4064
+ enableConsole: true,
4065
+ enableStorage: false
4066
+ };
4067
+ this.isBrowser = typeof window !== 'undefined';
4068
+ if (config) {
4069
+ this.config = Object.assign(Object.assign({}, this.config), config);
4070
+ }
4071
+ }
4072
+ setConfig(config) {
4073
+ this.config = Object.assign(Object.assign({}, this.config), config);
4074
+ }
4075
+ shouldLog(level) {
4076
+ return level <= this.config.level;
4077
+ }
4078
+ formatMessage(level, message, ...args) {
4079
+ const timestamp = new Date().toISOString();
4080
+ return `[HumanBehavior ${level}] ${timestamp}: ${message}`;
4081
+ }
4082
+ error(message, ...args) {
4083
+ if (!this.shouldLog(LogLevel.ERROR))
4084
+ return;
4085
+ const formattedMessage = this.formatMessage('ERROR', message);
4086
+ if (this.config.enableConsole) {
4087
+ console.error(formattedMessage, ...args);
4088
+ }
4089
+ if (this.config.enableStorage && this.isBrowser) {
4090
+ this.logToStorage(formattedMessage, args);
4091
+ }
4092
+ }
4093
+ warn(message, ...args) {
4094
+ if (!this.shouldLog(LogLevel.WARN))
4095
+ return;
4096
+ const formattedMessage = this.formatMessage('WARN', message);
4097
+ if (this.config.enableConsole) {
4098
+ console.warn(formattedMessage, ...args);
4099
+ }
4100
+ if (this.config.enableStorage && this.isBrowser) {
4101
+ this.logToStorage(formattedMessage, args);
4102
+ }
4103
+ }
4104
+ info(message, ...args) {
4105
+ if (!this.shouldLog(LogLevel.INFO))
4106
+ return;
4107
+ const formattedMessage = this.formatMessage('INFO', message);
4108
+ if (this.config.enableConsole) {
4109
+ console.log(formattedMessage, ...args);
4110
+ }
4111
+ if (this.config.enableStorage && this.isBrowser) {
4112
+ this.logToStorage(formattedMessage, args);
4113
+ }
4114
+ }
4115
+ debug(message, ...args) {
4116
+ if (!this.shouldLog(LogLevel.DEBUG))
4117
+ return;
4118
+ const formattedMessage = this.formatMessage('DEBUG', message);
4119
+ if (this.config.enableConsole) {
4120
+ console.log(formattedMessage, ...args);
4121
+ }
4122
+ if (this.config.enableStorage && this.isBrowser) {
4123
+ this.logToStorage(formattedMessage, args);
4124
+ }
4125
+ }
4126
+ logToStorage(message, args) {
4127
+ try {
4128
+ const logs = JSON.parse(localStorage.getItem('human_behavior_logs') || '[]');
4129
+ const logEntry = {
4130
+ message,
4131
+ args: args.length > 0 ? args : undefined,
4132
+ timestamp: Date.now()
4133
+ };
4134
+ logs.push(logEntry);
4135
+ // Keep only last 1000 logs to prevent storage bloat
4136
+ if (logs.length > 1000) {
4137
+ logs.splice(0, logs.length - 1000);
4138
+ }
4139
+ localStorage.setItem('human_behavior_logs', JSON.stringify(logs));
4140
+ }
4141
+ catch (e) {
4142
+ // Silently fail if storage is not available
4143
+ }
4144
+ }
4145
+ getLogs() {
4146
+ if (!this.isBrowser)
4147
+ return [];
4148
+ try {
4149
+ return JSON.parse(localStorage.getItem('human_behavior_logs') || '[]');
4150
+ }
4151
+ catch (e) {
4152
+ return [];
4153
+ }
4154
+ }
4155
+ clearLogs() {
4156
+ if (this.isBrowser) {
4157
+ localStorage.removeItem('human_behavior_logs');
4158
+ }
4159
+ }
4160
+ }
4161
+ // Create singleton instance
4162
+ const logger = new Logger();
4163
+ // Export convenience methods
4164
+ const logError = (message, ...args) => logger.error(message, ...args);
4165
+ const logWarn = (message, ...args) => logger.warn(message, ...args);
4166
+ const logInfo = (message, ...args) => logger.info(message, ...args);
4167
+ const logDebug = (message, ...args) => logger.debug(message, ...args);
4168
+
4052
4169
  const MAX_CHUNK_SIZE_BYTES = 1024 * 1024 * 10; // 10MB chunk size
4053
4170
  function isChunkSizeExceeded(currentChunk, newEvent, sessionId) {
4054
4171
  const nextChunkSize = new TextEncoder().encode(JSON.stringify({
@@ -4180,7 +4297,7 @@ class HumanBehaviorAPI {
4180
4297
  return results.flat();
4181
4298
  }
4182
4299
  catch (error) {
4183
- console.error('Error sending events:', error);
4300
+ logError('Error sending events:', error);
4184
4301
  throw error;
4185
4302
  }
4186
4303
  });
@@ -4206,7 +4323,7 @@ class HumanBehaviorAPI {
4206
4323
  return yield response.json();
4207
4324
  }
4208
4325
  catch (error) {
4209
- console.error('Error sending user data:', error);
4326
+ logError('Error sending user data:', error);
4210
4327
  throw error;
4211
4328
  }
4212
4329
  });
@@ -4233,7 +4350,7 @@ class HumanBehaviorAPI {
4233
4350
  return yield response.json();
4234
4351
  }
4235
4352
  catch (error) {
4236
- console.error('Error authenticating user:', error);
4353
+ logError('Error authenticating user:', error);
4237
4354
  throw error;
4238
4355
  }
4239
4356
  });
@@ -4280,7 +4397,7 @@ class HumanBehaviorAPI {
4280
4397
  catch (error) {
4281
4398
  retryCount++;
4282
4399
  if (retryCount === maxRetries) {
4283
- console.error('Error sending custom event after max retries:', error);
4400
+ logError('Error sending custom event after max retries:', error);
4284
4401
  throw error;
4285
4402
  }
4286
4403
  // Exponential backoff
@@ -4313,7 +4430,7 @@ class HumanBehaviorAPI {
4313
4430
  catch (error) {
4314
4431
  retryCount++;
4315
4432
  if (retryCount === maxRetries) {
4316
- console.error('Error sending custom events after max retries:', error);
4433
+ logError('Error sending custom events after max retries:', error);
4317
4434
  throw error;
4318
4435
  }
4319
4436
  // Exponential backoff
@@ -4329,7 +4446,7 @@ class HumanBehaviorAPI {
4329
4446
  data.append('timestamp', encodeURIComponent(Date.now().toString()));
4330
4447
  data.append('apiKey', encodeURIComponent(this.apiKey));
4331
4448
  if (isSessionComplete) {
4332
- console.log('Session complete beacon sending');
4449
+ logInfo('Session complete beacon sending');
4333
4450
  localStorage.setItem('koalaware_session_complete', Date.now().toString());
4334
4451
  data.append('sessionComplete', encodeURIComponent('true'));
4335
4452
  }
@@ -4393,18 +4510,18 @@ class RedactionManager {
4393
4510
  this.userSelectedFields.clear();
4394
4511
  fields.forEach(field => this.userSelectedFields.add(field));
4395
4512
  if (fields.length > 0) {
4396
- console.log(`Redaction: Active for ${fields.length} field(s):`, fields);
4513
+ logDebug(`Redaction: Active for ${fields.length} field(s):`, fields);
4397
4514
  // Debug: Check if elements exist
4398
4515
  fields.forEach(selector => {
4399
4516
  const elements = document.querySelectorAll(selector);
4400
- console.log(`Redaction: Found ${elements.length} element(s) for selector '${selector}'`);
4517
+ logDebug(`Redaction: Found ${elements.length} element(s) for selector '${selector}'`);
4401
4518
  elements.forEach((el, index) => {
4402
- console.log(`Redaction: Element ${index} for '${selector}':`, el);
4519
+ logDebug(`Redaction: Element ${index} for '${selector}':`, el);
4403
4520
  });
4404
4521
  });
4405
4522
  }
4406
4523
  else {
4407
- console.log('Redaction: Disabled - no fields selected');
4524
+ logDebug('Redaction: Disabled - no fields selected');
4408
4525
  }
4409
4526
  }
4410
4527
  /**
@@ -4434,7 +4551,7 @@ class RedactionManager {
4434
4551
  if (processedEvent.data.source === 5) { // Input event
4435
4552
  const shouldRedact = this.isFieldSelected(processedEvent.data);
4436
4553
  if (shouldRedact) {
4437
- console.log('Redaction: Processing input event for redaction');
4554
+ logDebug('Redaction: Processing input event for redaction');
4438
4555
  this.redactInputEvent(processedEvent.data);
4439
4556
  }
4440
4557
  }
@@ -4460,30 +4577,30 @@ class RedactionManager {
4460
4577
  if (!this.isFieldSelected(inputData)) {
4461
4578
  return;
4462
4579
  }
4463
- console.log('Redaction: Redacting input event with text:', inputData.text);
4580
+ logDebug('Redaction: Redacting input event with text:', inputData.text);
4464
4581
  // Redact all text-related properties that could contain input data
4465
4582
  const textProperties = ['text', 'value', 'content', 'data', 'input', 'textContent'];
4466
4583
  textProperties.forEach(prop => {
4467
4584
  if (inputData[prop] !== undefined && typeof inputData[prop] === 'string') {
4468
4585
  inputData[prop] = this.redactedText;
4469
- console.log(`Redaction: Redacted property '${prop}'`);
4586
+ logDebug(`Redaction: Redacted property '${prop}'`);
4470
4587
  }
4471
4588
  });
4472
4589
  // Also check for any other string properties that might contain input data
4473
4590
  Object.keys(inputData).forEach(key => {
4474
4591
  if (typeof inputData[key] === 'string' && inputData[key].length > 0) {
4475
4592
  inputData[key] = this.redactedText;
4476
- console.log(`Redaction: Redacted additional property '${key}'`);
4593
+ logDebug(`Redaction: Redacted additional property '${key}'`);
4477
4594
  }
4478
4595
  });
4479
4596
  // Handle nested objects that might contain text data
4480
4597
  if (inputData.attributes && typeof inputData.attributes === 'object') {
4481
4598
  if (inputData.attributes.value && typeof inputData.attributes.value === 'string') {
4482
4599
  inputData.attributes.value = this.redactedText;
4483
- console.log('Redaction: Redacted nested value attribute');
4600
+ logDebug('Redaction: Redacted nested value attribute');
4484
4601
  }
4485
4602
  }
4486
- console.log('Redaction: Input event redaction complete');
4603
+ logDebug('Redaction: Input event redaction complete');
4487
4604
  }
4488
4605
  /**
4489
4606
  * Redact sensitive data in DOM mutation events
@@ -4545,7 +4662,7 @@ class RedactionManager {
4545
4662
  return false;
4546
4663
  }
4547
4664
  catch (e) {
4548
- console.warn('Error checking if DOM change should be redacted:', e);
4665
+ logWarn('Error checking if DOM change should be redacted:', e);
4549
4666
  return false;
4550
4667
  }
4551
4668
  }
@@ -4692,7 +4809,7 @@ class RedactionManager {
4692
4809
  // Check if any of these elements are currently focused
4693
4810
  for (const el of matchingElements) {
4694
4811
  if (el === document.activeElement) {
4695
- console.log('Redaction: Found focused element matching selector:', selector);
4812
+ logDebug('Redaction: Found focused element matching selector:', selector);
4696
4813
  return true;
4697
4814
  }
4698
4815
  }
@@ -4702,7 +4819,7 @@ class RedactionManager {
4702
4819
  // Look for any input element that might be the active one
4703
4820
  const activeElement = document.activeElement;
4704
4821
  if (activeElement && this.shouldRedactElement(activeElement)) {
4705
- console.log('Redaction: Active element should be redacted');
4822
+ logDebug('Redaction: Active element should be redacted');
4706
4823
  return true;
4707
4824
  }
4708
4825
  return false;
@@ -4735,7 +4852,7 @@ class RedactionManager {
4735
4852
  return false;
4736
4853
  }
4737
4854
  catch (e) {
4738
- console.warn('Error checking if field should be redacted:', e);
4855
+ logWarn('Error checking if field should be redacted:', e);
4739
4856
  return false;
4740
4857
  }
4741
4858
  }
@@ -4791,6 +4908,10 @@ class HumanBehaviorTracker {
4791
4908
  this.endUserId = null;
4792
4909
  this.initialized = false;
4793
4910
  this.initializationPromise = null;
4911
+ // Console tracking properties
4912
+ this.originalConsole = null;
4913
+ this.originalLogger = null;
4914
+ this.consoleTrackingEnabled = false;
4794
4915
  if (!apiKey) {
4795
4916
  throw new Error('Human Behavior API Key is required');
4796
4917
  }
@@ -4839,13 +4960,13 @@ class HumanBehaviorTracker {
4839
4960
  this.processRejectedEvents();
4840
4961
  }
4841
4962
  else {
4842
- console.warn('HumanBehaviorTracker initialized in a non-browser environment. Session tracking is disabled.');
4963
+ logWarn('HumanBehaviorTracker initialized in a non-browser environment. Session tracking is disabled.');
4843
4964
  }
4844
4965
  this.initialized = true;
4845
- console.log('HumanBehaviorTracker initialized');
4966
+ logInfo('HumanBehaviorTracker initialized');
4846
4967
  }
4847
4968
  catch (error) {
4848
- console.error('Failed to initialize HumanBehaviorTracker:', error);
4969
+ logError('Failed to initialize HumanBehaviorTracker:', error);
4849
4970
  throw error;
4850
4971
  }
4851
4972
  });
@@ -4859,24 +4980,107 @@ class HumanBehaviorTracker {
4859
4980
  });
4860
4981
  }
4861
4982
  static logToStorage(message) {
4862
- try {
4863
- const logs = JSON.parse(localStorage.getItem('human_behavior_logs') || '[]');
4864
- logs.push(`${new Date().toISOString()}: ${message}`);
4865
- localStorage.setItem('human_behavior_logs', JSON.stringify(logs));
4866
- }
4867
- catch (e) {
4868
- console.error('Failed to log to storage:', e);
4869
- }
4983
+ logInfo(message);
4984
+ }
4985
+ /**
4986
+ * Configure logging behavior for the SDK
4987
+ * @param config Logger configuration options
4988
+ */
4989
+ static configureLogging(config) {
4990
+ const levelMap = {
4991
+ 'none': 0,
4992
+ 'error': 1,
4993
+ 'warn': 2,
4994
+ 'info': 3,
4995
+ 'debug': 4
4996
+ };
4997
+ logger.setConfig({
4998
+ level: levelMap[config.level || 'error'],
4999
+ enableConsole: config.enableConsole !== false,
5000
+ enableStorage: config.enableStorage || false
5001
+ });
5002
+ }
5003
+ /**
5004
+ * Enable console event tracking
5005
+ */
5006
+ enableConsoleTracking() {
5007
+ if (!isBrowser || this.consoleTrackingEnabled)
5008
+ return;
5009
+ // Store original console methods
5010
+ this.originalConsole = {
5011
+ log: console.log,
5012
+ warn: console.warn,
5013
+ error: console.error
5014
+ };
5015
+ // Store original logger methods
5016
+ this.originalLogger = {
5017
+ error: logError,
5018
+ warn: logWarn,
5019
+ info: logInfo,
5020
+ debug: logDebug
5021
+ };
5022
+ // Override console methods to capture ALL console output (including logger output)
5023
+ console.log = (...args) => {
5024
+ this.trackConsoleEvent('log', args);
5025
+ this.originalConsole.log(...args);
5026
+ };
5027
+ console.warn = (...args) => {
5028
+ this.trackConsoleEvent('warn', args);
5029
+ this.originalConsole.warn(...args);
5030
+ };
5031
+ console.error = (...args) => {
5032
+ this.trackConsoleEvent('error', args);
5033
+ this.originalConsole.error(...args);
5034
+ };
5035
+ this.consoleTrackingEnabled = true;
5036
+ this.originalLogger.debug('Console tracking enabled');
5037
+ }
5038
+ /**
5039
+ * Disable console event tracking
5040
+ */
5041
+ disableConsoleTracking() {
5042
+ if (!isBrowser || !this.consoleTrackingEnabled || !this.originalConsole)
5043
+ return;
5044
+ // Restore original console methods
5045
+ console.log = this.originalConsole.log;
5046
+ console.warn = this.originalConsole.warn;
5047
+ console.error = this.originalConsole.error;
5048
+ this.consoleTrackingEnabled = false;
5049
+ this.originalConsole = null;
5050
+ this.originalLogger = null;
5051
+ }
5052
+ /**
5053
+ * Track console events
5054
+ */
5055
+ trackConsoleEvent(level, args) {
5056
+ if (!this.initialized)
5057
+ 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);
4870
5074
  }
4871
5075
  setupPageUnloadHandler() {
4872
5076
  if (!isBrowser)
4873
5077
  return;
4874
- console.log('Setting up page unload handler');
5078
+ logDebug('Setting up page unload handler');
4875
5079
  // Handle visibility changes for sending events
4876
5080
  window.addEventListener('visibilitychange', () => {
4877
5081
  // Only send events when page becomes hidden
4878
5082
  if (document.visibilityState === 'hidden') {
4879
- console.log('Page hidden - sending pending events');
5083
+ logDebug('Page hidden - sending pending events');
4880
5084
  this.api.sendBeaconEvents(this.eventIngestionQueue, this.sessionId);
4881
5085
  }
4882
5086
  });
@@ -4894,12 +5098,12 @@ class HumanBehaviorTracker {
4894
5098
  }
4895
5099
  viewLogs() {
4896
5100
  try {
4897
- const logs = JSON.parse(localStorage.getItem('human_behavior_logs') || '[]');
5101
+ const logs = logger.getLogs();
4898
5102
  console.log('HumanBehavior Logs:', logs);
4899
- localStorage.removeItem('human_behavior_logs'); // Clear logs after viewing
5103
+ logger.clearLogs(); // Clear logs after viewing
4900
5104
  }
4901
5105
  catch (e) {
4902
- console.error('Failed to read logs:', e);
5106
+ logError('Failed to read logs:', e);
4903
5107
  }
4904
5108
  }
4905
5109
  addUserInfo(userProperties) {
@@ -4943,6 +5147,8 @@ class HumanBehaviorTracker {
4943
5147
  this.flushInterval = window.setInterval(() => {
4944
5148
  this.flush();
4945
5149
  }, this.FLUSH_INTERVAL_MS);
5150
+ // Enable console tracking
5151
+ this.enableConsoleTracking();
4946
5152
  // Start recording with redaction enabled
4947
5153
  record({
4948
5154
  emit: (event) => {
@@ -4966,6 +5172,8 @@ class HumanBehaviorTracker {
4966
5172
  clearInterval(this.flushInterval);
4967
5173
  this.flushInterval = null;
4968
5174
  }
5175
+ // Disable console tracking
5176
+ this.disableConsoleTracking();
4969
5177
  });
4970
5178
  }
4971
5179
  addEvent(event) {
@@ -4999,7 +5207,7 @@ class HumanBehaviorTracker {
4999
5207
  this.sessionId = newSessionId;
5000
5208
  }
5001
5209
  catch (error) {
5002
- console.error('Failed to process rejected events:', error);
5210
+ logError('Failed to process rejected events:', error);
5003
5211
  }
5004
5212
  finally {
5005
5213
  this.isProcessingRejectedEvents = false;
@@ -5020,14 +5228,14 @@ class HumanBehaviorTracker {
5020
5228
  this.eventIngestionQueue = [];
5021
5229
  this.queueSizeBytes = 0;
5022
5230
  if (eventsToProcess.length > 0) {
5023
- console.log('Flushing events:', eventsToProcess);
5231
+ logDebug('Flushing events:', eventsToProcess);
5024
5232
  try {
5025
5233
  yield this.api.sendEvents(eventsToProcess, this.sessionId, this.endUserId);
5026
5234
  }
5027
5235
  catch (error) {
5028
5236
  // If we get a 400 error, store events for retry
5029
5237
  if ((_a = error.message) === null || _a === void 0 ? void 0 : _a.includes('ERROR: Session already completed')) {
5030
- console.log('Session expired, storing events for retry');
5238
+ logInfo('Session expired, storing events for retry');
5031
5239
  this.rejectedEvents.push(...eventsToProcess);
5032
5240
  this.processRejectedEvents();
5033
5241
  }
@@ -5073,7 +5281,7 @@ class HumanBehaviorTracker {
5073
5281
  return __awaiter$1(this, void 0, void 0, function* () {
5074
5282
  yield this.ensureInitialized();
5075
5283
  if (!isBrowser) {
5076
- console.warn('Redaction is only available in browser environments');
5284
+ logWarn('Redaction is only available in browser environments');
5077
5285
  return;
5078
5286
  }
5079
5287
  // Create a new redaction manager with the provided options
@@ -5086,7 +5294,7 @@ class HumanBehaviorTracker {
5086
5294
  */
5087
5295
  setRedactedFields(fields) {
5088
5296
  if (!isBrowser) {
5089
- console.warn('Redaction is only available in browser environments');
5297
+ logWarn('Redaction is only available in browser environments');
5090
5298
  return;
5091
5299
  }
5092
5300
  this.redactionManager.setFieldsToRedact(fields);
@@ -5117,5 +5325,5 @@ if (typeof window !== 'undefined') {
5117
5325
  window.HumanBehaviorTracker = HumanBehaviorTracker;
5118
5326
  }
5119
5327
 
5120
- export { HumanBehaviorAPI, HumanBehaviorTracker, MAX_CHUNK_SIZE_BYTES, RedactionManager, HumanBehaviorTracker as default, isChunkSizeExceeded, redactionManager, validateSingleEventSize };
5328
+ export { HumanBehaviorAPI, HumanBehaviorTracker, LogLevel, MAX_CHUNK_SIZE_BYTES, RedactionManager, HumanBehaviorTracker as default, isChunkSizeExceeded, logDebug, logError, logInfo, logWarn, logger, redactionManager, validateSingleEventSize };
5121
5329
  //# sourceMappingURL=index.js.map