humanbehavior-js 0.4.23 → 0.4.25

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