humanbehavior-js 0.4.23 → 0.4.24

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.
Files changed (50) hide show
  1. package/dist/cjs/angular/index.cjs +176 -17
  2. package/dist/cjs/angular/index.cjs.map +1 -1
  3. package/dist/cjs/index.cjs +176 -17
  4. package/dist/cjs/index.cjs.map +1 -1
  5. package/dist/cjs/install-wizard.cjs +5 -5
  6. package/dist/cjs/install-wizard.cjs.map +1 -1
  7. package/dist/cjs/react/index.cjs +176 -17
  8. package/dist/cjs/react/index.cjs.map +1 -1
  9. package/dist/cjs/remix/index.cjs +176 -17
  10. package/dist/cjs/remix/index.cjs.map +1 -1
  11. package/dist/cjs/svelte/index.cjs +176 -17
  12. package/dist/cjs/svelte/index.cjs.map +1 -1
  13. package/dist/cjs/vue/index.cjs +176 -17
  14. package/dist/cjs/vue/index.cjs.map +1 -1
  15. package/dist/cjs/wizard/index.cjs +5 -5
  16. package/dist/cjs/wizard/index.cjs.map +1 -1
  17. package/dist/cli/ai-auto-install.js +5 -5
  18. package/dist/cli/ai-auto-install.js.map +1 -1
  19. package/dist/cli/auto-install.js +5 -5
  20. package/dist/cli/auto-install.js.map +1 -1
  21. package/dist/esm/angular/index.js +176 -17
  22. package/dist/esm/angular/index.js.map +1 -1
  23. package/dist/esm/index.js +176 -17
  24. package/dist/esm/index.js.map +1 -1
  25. package/dist/esm/install-wizard.js +5 -5
  26. package/dist/esm/install-wizard.js.map +1 -1
  27. package/dist/esm/react/index.js +176 -17
  28. package/dist/esm/react/index.js.map +1 -1
  29. package/dist/esm/remix/index.js +176 -17
  30. package/dist/esm/remix/index.js.map +1 -1
  31. package/dist/esm/svelte/index.js +176 -17
  32. package/dist/esm/svelte/index.js.map +1 -1
  33. package/dist/esm/vue/index.js +176 -17
  34. package/dist/esm/vue/index.js.map +1 -1
  35. package/dist/esm/wizard/index.js +5 -5
  36. package/dist/esm/wizard/index.js.map +1 -1
  37. package/dist/index.min.js +1 -1
  38. package/dist/index.min.js.map +1 -1
  39. package/dist/types/angular/index.d.ts +22 -0
  40. package/dist/types/index.d.ts +40 -2
  41. package/dist/types/install-wizard.d.ts +1 -1
  42. package/dist/types/react/index.d.ts +22 -0
  43. package/dist/types/remix/index.d.ts +22 -0
  44. package/dist/types/svelte/index.d.ts +22 -0
  45. package/dist/types/wizard/index.d.ts +1 -1
  46. package/package.json +1 -1
  47. package/readme.md +59 -5
  48. package/src/redact.ts +135 -15
  49. package/src/tracker.ts +69 -4
  50. package/src/wizard/core/install-wizard.ts +5 -5
package/dist/esm/index.js CHANGED
@@ -12906,6 +12906,8 @@ class RedactionManager {
12906
12906
  constructor(options) {
12907
12907
  this.redactedText = '[REDACTED]';
12908
12908
  this.unredactedFields = new Set(); // Fields that user wants to unredact
12909
+ this.redactedFields = new Set(); // Fields that user wants to redact
12910
+ this.redactionMode = 'privacy-first';
12909
12911
  this.excludeSelectors = [
12910
12912
  '[data-no-redact="true"]',
12911
12913
  '.human-behavior-no-redact'
@@ -12916,10 +12918,56 @@ class RedactionManager {
12916
12918
  if (options === null || options === void 0 ? void 0 : options.excludeSelectors) {
12917
12919
  this.excludeSelectors = [...this.excludeSelectors, ...options.excludeSelectors];
12918
12920
  }
12921
+ // Handle new redaction strategy
12922
+ if (options === null || options === void 0 ? void 0 : options.redactionStrategy) {
12923
+ this.redactionMode = options.redactionStrategy.mode;
12924
+ if (this.redactionMode === 'privacy-first') {
12925
+ // Privacy-first: everything redacted by default, unredact specific fields
12926
+ if (options.redactionStrategy.unredactFields) {
12927
+ this.setFieldsToUnredact(options.redactionStrategy.unredactFields);
12928
+ }
12929
+ }
12930
+ else {
12931
+ // Visibility-first: everything visible by default, redact specific fields
12932
+ if (options.redactionStrategy.redactFields) {
12933
+ this.setFieldsToRedact(options.redactionStrategy.redactFields);
12934
+ }
12935
+ }
12936
+ }
12937
+ // Handle legacy redactFields (backward compatibility)
12938
+ if (options === null || options === void 0 ? void 0 : options.legacyRedactFields) {
12939
+ this.setFieldsToUnredact(options.legacyRedactFields);
12940
+ }
12941
+ // Handle legacy userFields
12919
12942
  if (options === null || options === void 0 ? void 0 : options.userFields) {
12920
12943
  this.setFieldsToUnredact(options.userFields);
12921
12944
  }
12922
12945
  }
12946
+ /**
12947
+ * Set specific fields to be redacted (for visibility-first mode)
12948
+ * @param fields Array of CSS selectors for fields to redact
12949
+ */
12950
+ setFieldsToRedact(fields) {
12951
+ this.redactedFields.clear();
12952
+ // Always include password fields in redacted list
12953
+ const passwordFields = [
12954
+ 'input[type="password"]',
12955
+ 'input[type="password" i]',
12956
+ '[type="password"]',
12957
+ '[type="password" i]'
12958
+ ];
12959
+ // Add password fields and user-specified fields
12960
+ [...passwordFields, ...fields].forEach(field => {
12961
+ this.redactedFields.add(field);
12962
+ });
12963
+ if (this.redactedFields.size > 0) {
12964
+ logDebug(`Redaction: Active for ${this.redactedFields.size} field(s):`, Array.from(this.redactedFields));
12965
+ }
12966
+ else {
12967
+ logDebug('Redaction: No fields to redact');
12968
+ }
12969
+ this.applyRedactionClasses();
12970
+ }
12923
12971
  /**
12924
12972
  * Set specific fields to be unredacted (everything else stays redacted by rrweb)
12925
12973
  * @param fields Array of CSS selectors for fields to unredact
@@ -12974,6 +13022,12 @@ class RedactionManager {
12974
13022
  hasUnredactedFields() {
12975
13023
  return this.unredactedFields.size > 0;
12976
13024
  }
13025
+ /**
13026
+ * Get the current redaction mode
13027
+ */
13028
+ getRedactionMode() {
13029
+ return this.redactionMode;
13030
+ }
12977
13031
  /**
12978
13032
  * Get the currently unredacted fields
12979
13033
  */
@@ -12985,30 +13039,42 @@ class RedactionManager {
12985
13039
  * Returns null if no fields are unredacted (everything stays redacted)
12986
13040
  */
12987
13041
  getMaskTextSelector() {
12988
- if (this.unredactedFields.size === 0) {
12989
- return null; // Everything stays redacted
13042
+ if (this.redactionMode === 'privacy-first') {
13043
+ // Privacy-first: mask everything except unredacted fields
13044
+ if (this.unredactedFields.size === 0) {
13045
+ return null; // Everything stays redacted
13046
+ }
13047
+ return Array.from(this.unredactedFields).join(',');
13048
+ }
13049
+ else {
13050
+ // Visibility-first: mask only redacted fields
13051
+ if (this.redactedFields.size === 0) {
13052
+ return null; // Nothing to redact
13053
+ }
13054
+ return Array.from(this.redactedFields).join(',');
12990
13055
  }
12991
- return Array.from(this.unredactedFields).join(',');
12992
13056
  }
12993
13057
  /**
12994
- * Check if an element should be unredacted
13058
+ * Apply redaction classes to DOM elements (for visibility-first mode)
13059
+ * Adds 'rr-mask' class to elements that should be redacted
12995
13060
  */
12996
- shouldUnredactElement(element) {
12997
- if (this.unredactedFields.size === 0) {
12998
- return false; // Nothing unredacted
13061
+ applyRedactionClasses() {
13062
+ if (this.redactedFields.size === 0) {
13063
+ return;
12999
13064
  }
13000
- // Check if any selector matches this element
13001
- for (const selector of this.unredactedFields) {
13065
+ // Add 'rr-mask' class to redacted elements
13066
+ this.redactedFields.forEach(selector => {
13002
13067
  try {
13003
- if (element.matches(selector)) {
13004
- return true;
13005
- }
13068
+ const elements = document.querySelectorAll(selector);
13069
+ elements.forEach(element => {
13070
+ element.classList.add('rr-mask');
13071
+ });
13072
+ logDebug(`Added rr-mask class to ${elements.length} element(s) for selector: ${selector}`);
13006
13073
  }
13007
13074
  catch (e) {
13008
13075
  logWarn(`Invalid selector: ${selector}`);
13009
13076
  }
13010
- }
13011
- return false;
13077
+ });
13012
13078
  }
13013
13079
  /**
13014
13080
  * Apply unredaction classes to DOM elements
@@ -13066,6 +13132,47 @@ class RedactionManager {
13066
13132
  isElementUnredacted(element) {
13067
13133
  return this.shouldUnredactElement(element);
13068
13134
  }
13135
+ /**
13136
+ * Check if an element should be unredacted
13137
+ */
13138
+ shouldUnredactElement(element) {
13139
+ if (this.redactionMode === 'privacy-first') {
13140
+ // Privacy-first: check if element is in unredacted fields
13141
+ if (this.unredactedFields.size === 0) {
13142
+ return false; // Nothing unredacted
13143
+ }
13144
+ // Check if any selector matches this element
13145
+ for (const selector of this.unredactedFields) {
13146
+ try {
13147
+ if (element.matches(selector)) {
13148
+ return true;
13149
+ }
13150
+ }
13151
+ catch (e) {
13152
+ logWarn(`Invalid selector: ${selector}`);
13153
+ }
13154
+ }
13155
+ return false;
13156
+ }
13157
+ else {
13158
+ // Visibility-first: check if element is NOT in redacted fields
13159
+ if (this.redactedFields.size === 0) {
13160
+ return true; // Nothing redacted, everything visible
13161
+ }
13162
+ // Check if any selector matches this element
13163
+ for (const selector of this.redactedFields) {
13164
+ try {
13165
+ if (element.matches(selector)) {
13166
+ return false; // Element is redacted
13167
+ }
13168
+ }
13169
+ catch (e) {
13170
+ logWarn(`Invalid selector: ${selector}`);
13171
+ }
13172
+ }
13173
+ return true; // Element is not redacted
13174
+ }
13175
+ }
13069
13176
  }
13070
13177
  // Export a default instance
13071
13178
  const redactionManager = new RedactionManager();
@@ -13633,10 +13740,23 @@ class HumanBehaviorTracker {
13633
13740
  });
13634
13741
  // Store canvas recording preference
13635
13742
  tracker.recordCanvas = (_a = options === null || options === void 0 ? void 0 : options.recordCanvas) !== null && _a !== void 0 ? _a : false;
13636
- // Set unredacted fields if specified
13743
+ // Set unredacted fields if specified (legacy support)
13637
13744
  if (options === null || options === void 0 ? void 0 : options.redactFields) {
13638
13745
  tracker.setUnredactedFields(options.redactFields);
13639
13746
  }
13747
+ // Handle new redaction strategy
13748
+ if (options === null || options === void 0 ? void 0 : options.redactionStrategy) {
13749
+ if (options.redactionStrategy.mode === 'privacy-first') {
13750
+ if (options.redactionStrategy.unredactFields) {
13751
+ tracker.setUnredactedFields(options.redactionStrategy.unredactFields);
13752
+ }
13753
+ }
13754
+ else {
13755
+ if (options.redactionStrategy.redactFields) {
13756
+ tracker.setRedactedFields(options.redactionStrategy.redactFields);
13757
+ }
13758
+ }
13759
+ }
13640
13760
  // Setup automatic tracking if enabled
13641
13761
  if ((options === null || options === void 0 ? void 0 : options.enableAutomaticTracking) !== false) {
13642
13762
  tracker.setupAutomaticTracking(options === null || options === void 0 ? void 0 : options.automaticTrackingOptions);
@@ -13682,7 +13802,10 @@ class HumanBehaviorTracker {
13682
13802
  ingestionUrl: ingestionUrl || defaultIngestionUrl
13683
13803
  });
13684
13804
  this.apiKey = apiKey;
13685
- this.redactionManager = new RedactionManager();
13805
+ this.redactionManager = new RedactionManager({
13806
+ redactionStrategy: options === null || options === void 0 ? void 0 : options.redactionStrategy,
13807
+ legacyRedactFields: options === null || options === void 0 ? void 0 : options.redactFields // For backward compatibility
13808
+ });
13686
13809
  // Initialize property manager
13687
13810
  this.propertyManager = new PropertyManager({
13688
13811
  enableAutomaticProperties: (options === null || options === void 0 ? void 0 : options.enableAutomaticProperties) !== false,
@@ -14260,6 +14383,31 @@ class HumanBehaviorTracker {
14260
14383
  if (!userResponse.ok) {
14261
14384
  throw new Error(`Failed to identify user: ${userResponse.statusText}`);
14262
14385
  }
14386
+ // Get IP info and GeoIP data
14387
+ try {
14388
+ const ipResponse = yield fetch(`${this.api['baseUrl']}/api/ingestion/ip-info`, {
14389
+ method: 'POST',
14390
+ headers: {
14391
+ 'Content-Type': 'application/json',
14392
+ 'Authorization': `Bearer ${this.apiKey}`
14393
+ },
14394
+ body: JSON.stringify({
14395
+ sessionId: this.sessionId,
14396
+ clientIP: null, // Let server detect from headers
14397
+ ipDetectionMethod: 'headers',
14398
+ timestamp: new Date().toISOString()
14399
+ })
14400
+ });
14401
+ if (ipResponse.ok) {
14402
+ logDebug('✅ IP info and GeoIP data retrieved successfully');
14403
+ }
14404
+ else {
14405
+ logDebug(`⚠️ IP info request failed: ${ipResponse.statusText}`);
14406
+ }
14407
+ }
14408
+ catch (error) {
14409
+ logDebug(`⚠️ IP info request error: ${error}`);
14410
+ }
14263
14411
  // Don't update endUserId - keep it as the original UUID
14264
14412
  return originalEndUserId || '';
14265
14413
  });
@@ -14299,7 +14447,7 @@ class HumanBehaviorTracker {
14299
14447
  // ✅ HUMANBEHAVIOR'S CUSTOM SETTINGS
14300
14448
  maskTextSelector: this.redactionManager.getMaskTextSelector() || undefined,
14301
14449
  maskTextFn: undefined,
14302
- maskAllInputs: true, // HumanBehavior default
14450
+ maskAllInputs: this.redactionManager.getRedactionMode() === 'privacy-first', // Configurable based on strategy
14303
14451
  maskInputOptions: { password: true }, // HumanBehavior default
14304
14452
  maskInputFn: undefined,
14305
14453
  slimDOMOptions: {},
@@ -14608,6 +14756,17 @@ class HumanBehaviorTracker {
14608
14756
  this.redactionManager = new RedactionManager(options);
14609
14757
  });
14610
14758
  }
14759
+ /**
14760
+ * Set specific fields to be redacted (for visibility-first mode)
14761
+ * @param fields Array of CSS selectors for fields to redact
14762
+ */
14763
+ setRedactedFields(fields) {
14764
+ this.redactionManager.setFieldsToRedact(fields);
14765
+ // ✅ RESTART RECORDING WITH NEW SETTINGS - Ensures redaction is applied
14766
+ if (this.recordInstance) {
14767
+ this.restartWithNewRedaction();
14768
+ }
14769
+ }
14611
14770
  /**
14612
14771
  * Set specific fields to be unredacted (everything else stays redacted by rrweb)
14613
14772
  * @param fields Array of CSS selectors for fields to unredact (e.g., ['#username', '#comment'])