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
@@ -12891,6 +12891,8 @@ class RedactionManager {
12891
12891
  constructor(options) {
12892
12892
  this.redactedText = '[REDACTED]';
12893
12893
  this.unredactedFields = new Set(); // Fields that user wants to unredact
12894
+ this.redactedFields = new Set(); // Fields that user wants to redact
12895
+ this.redactionMode = 'privacy-first';
12894
12896
  this.excludeSelectors = [
12895
12897
  '[data-no-redact="true"]',
12896
12898
  '.human-behavior-no-redact'
@@ -12901,10 +12903,56 @@ class RedactionManager {
12901
12903
  if (options === null || options === void 0 ? void 0 : options.excludeSelectors) {
12902
12904
  this.excludeSelectors = [...this.excludeSelectors, ...options.excludeSelectors];
12903
12905
  }
12906
+ // Handle new redaction strategy
12907
+ if (options === null || options === void 0 ? void 0 : options.redactionStrategy) {
12908
+ this.redactionMode = options.redactionStrategy.mode;
12909
+ if (this.redactionMode === 'privacy-first') {
12910
+ // Privacy-first: everything redacted by default, unredact specific fields
12911
+ if (options.redactionStrategy.unredactFields) {
12912
+ this.setFieldsToUnredact(options.redactionStrategy.unredactFields);
12913
+ }
12914
+ }
12915
+ else {
12916
+ // Visibility-first: everything visible by default, redact specific fields
12917
+ if (options.redactionStrategy.redactFields) {
12918
+ this.setFieldsToRedact(options.redactionStrategy.redactFields);
12919
+ }
12920
+ }
12921
+ }
12922
+ // Handle legacy redactFields (backward compatibility)
12923
+ if (options === null || options === void 0 ? void 0 : options.legacyRedactFields) {
12924
+ this.setFieldsToUnredact(options.legacyRedactFields);
12925
+ }
12926
+ // Handle legacy userFields
12904
12927
  if (options === null || options === void 0 ? void 0 : options.userFields) {
12905
12928
  this.setFieldsToUnredact(options.userFields);
12906
12929
  }
12907
12930
  }
12931
+ /**
12932
+ * Set specific fields to be redacted (for visibility-first mode)
12933
+ * @param fields Array of CSS selectors for fields to redact
12934
+ */
12935
+ setFieldsToRedact(fields) {
12936
+ this.redactedFields.clear();
12937
+ // Always include password fields in redacted list
12938
+ const passwordFields = [
12939
+ 'input[type="password"]',
12940
+ 'input[type="password" i]',
12941
+ '[type="password"]',
12942
+ '[type="password" i]'
12943
+ ];
12944
+ // Add password fields and user-specified fields
12945
+ [...passwordFields, ...fields].forEach(field => {
12946
+ this.redactedFields.add(field);
12947
+ });
12948
+ if (this.redactedFields.size > 0) {
12949
+ logDebug(`Redaction: Active for ${this.redactedFields.size} field(s):`, Array.from(this.redactedFields));
12950
+ }
12951
+ else {
12952
+ logDebug('Redaction: No fields to redact');
12953
+ }
12954
+ this.applyRedactionClasses();
12955
+ }
12908
12956
  /**
12909
12957
  * Set specific fields to be unredacted (everything else stays redacted by rrweb)
12910
12958
  * @param fields Array of CSS selectors for fields to unredact
@@ -12959,6 +13007,12 @@ class RedactionManager {
12959
13007
  hasUnredactedFields() {
12960
13008
  return this.unredactedFields.size > 0;
12961
13009
  }
13010
+ /**
13011
+ * Get the current redaction mode
13012
+ */
13013
+ getRedactionMode() {
13014
+ return this.redactionMode;
13015
+ }
12962
13016
  /**
12963
13017
  * Get the currently unredacted fields
12964
13018
  */
@@ -12970,30 +13024,42 @@ class RedactionManager {
12970
13024
  * Returns null if no fields are unredacted (everything stays redacted)
12971
13025
  */
12972
13026
  getMaskTextSelector() {
12973
- if (this.unredactedFields.size === 0) {
12974
- return null; // Everything stays redacted
13027
+ if (this.redactionMode === 'privacy-first') {
13028
+ // Privacy-first: mask everything except unredacted fields
13029
+ if (this.unredactedFields.size === 0) {
13030
+ return null; // Everything stays redacted
13031
+ }
13032
+ return Array.from(this.unredactedFields).join(',');
13033
+ }
13034
+ else {
13035
+ // Visibility-first: mask only redacted fields
13036
+ if (this.redactedFields.size === 0) {
13037
+ return null; // Nothing to redact
13038
+ }
13039
+ return Array.from(this.redactedFields).join(',');
12975
13040
  }
12976
- return Array.from(this.unredactedFields).join(',');
12977
13041
  }
12978
13042
  /**
12979
- * Check if an element should be unredacted
13043
+ * Apply redaction classes to DOM elements (for visibility-first mode)
13044
+ * Adds 'rr-mask' class to elements that should be redacted
12980
13045
  */
12981
- shouldUnredactElement(element) {
12982
- if (this.unredactedFields.size === 0) {
12983
- return false; // Nothing unredacted
13046
+ applyRedactionClasses() {
13047
+ if (this.redactedFields.size === 0) {
13048
+ return;
12984
13049
  }
12985
- // Check if any selector matches this element
12986
- for (const selector of this.unredactedFields) {
13050
+ // Add 'rr-mask' class to redacted elements
13051
+ this.redactedFields.forEach(selector => {
12987
13052
  try {
12988
- if (element.matches(selector)) {
12989
- return true;
12990
- }
13053
+ const elements = document.querySelectorAll(selector);
13054
+ elements.forEach(element => {
13055
+ element.classList.add('rr-mask');
13056
+ });
13057
+ logDebug(`Added rr-mask class to ${elements.length} element(s) for selector: ${selector}`);
12991
13058
  }
12992
13059
  catch (e) {
12993
13060
  logWarn(`Invalid selector: ${selector}`);
12994
13061
  }
12995
- }
12996
- return false;
13062
+ });
12997
13063
  }
12998
13064
  /**
12999
13065
  * Apply unredaction classes to DOM elements
@@ -13051,6 +13117,47 @@ class RedactionManager {
13051
13117
  isElementUnredacted(element) {
13052
13118
  return this.shouldUnredactElement(element);
13053
13119
  }
13120
+ /**
13121
+ * Check if an element should be unredacted
13122
+ */
13123
+ shouldUnredactElement(element) {
13124
+ if (this.redactionMode === 'privacy-first') {
13125
+ // Privacy-first: check if element is in unredacted fields
13126
+ if (this.unredactedFields.size === 0) {
13127
+ return false; // Nothing unredacted
13128
+ }
13129
+ // Check if any selector matches this element
13130
+ for (const selector of this.unredactedFields) {
13131
+ try {
13132
+ if (element.matches(selector)) {
13133
+ return true;
13134
+ }
13135
+ }
13136
+ catch (e) {
13137
+ logWarn(`Invalid selector: ${selector}`);
13138
+ }
13139
+ }
13140
+ return false;
13141
+ }
13142
+ else {
13143
+ // Visibility-first: check if element is NOT in redacted fields
13144
+ if (this.redactedFields.size === 0) {
13145
+ return true; // Nothing redacted, everything visible
13146
+ }
13147
+ // Check if any selector matches this element
13148
+ for (const selector of this.redactedFields) {
13149
+ try {
13150
+ if (element.matches(selector)) {
13151
+ return false; // Element is redacted
13152
+ }
13153
+ }
13154
+ catch (e) {
13155
+ logWarn(`Invalid selector: ${selector}`);
13156
+ }
13157
+ }
13158
+ return true; // Element is not redacted
13159
+ }
13160
+ }
13054
13161
  }
13055
13162
  // Export a default instance
13056
13163
  new RedactionManager();
@@ -13618,10 +13725,23 @@ class HumanBehaviorTracker {
13618
13725
  });
13619
13726
  // Store canvas recording preference
13620
13727
  tracker.recordCanvas = (_a = options === null || options === void 0 ? void 0 : options.recordCanvas) !== null && _a !== void 0 ? _a : false;
13621
- // Set unredacted fields if specified
13728
+ // Set unredacted fields if specified (legacy support)
13622
13729
  if (options === null || options === void 0 ? void 0 : options.redactFields) {
13623
13730
  tracker.setUnredactedFields(options.redactFields);
13624
13731
  }
13732
+ // Handle new redaction strategy
13733
+ if (options === null || options === void 0 ? void 0 : options.redactionStrategy) {
13734
+ if (options.redactionStrategy.mode === 'privacy-first') {
13735
+ if (options.redactionStrategy.unredactFields) {
13736
+ tracker.setUnredactedFields(options.redactionStrategy.unredactFields);
13737
+ }
13738
+ }
13739
+ else {
13740
+ if (options.redactionStrategy.redactFields) {
13741
+ tracker.setRedactedFields(options.redactionStrategy.redactFields);
13742
+ }
13743
+ }
13744
+ }
13625
13745
  // Setup automatic tracking if enabled
13626
13746
  if ((options === null || options === void 0 ? void 0 : options.enableAutomaticTracking) !== false) {
13627
13747
  tracker.setupAutomaticTracking(options === null || options === void 0 ? void 0 : options.automaticTrackingOptions);
@@ -13667,7 +13787,10 @@ class HumanBehaviorTracker {
13667
13787
  ingestionUrl: ingestionUrl || defaultIngestionUrl
13668
13788
  });
13669
13789
  this.apiKey = apiKey;
13670
- this.redactionManager = new RedactionManager();
13790
+ this.redactionManager = new RedactionManager({
13791
+ redactionStrategy: options === null || options === void 0 ? void 0 : options.redactionStrategy,
13792
+ legacyRedactFields: options === null || options === void 0 ? void 0 : options.redactFields // For backward compatibility
13793
+ });
13671
13794
  // Initialize property manager
13672
13795
  this.propertyManager = new PropertyManager({
13673
13796
  enableAutomaticProperties: (options === null || options === void 0 ? void 0 : options.enableAutomaticProperties) !== false,
@@ -14245,6 +14368,31 @@ class HumanBehaviorTracker {
14245
14368
  if (!userResponse.ok) {
14246
14369
  throw new Error(`Failed to identify user: ${userResponse.statusText}`);
14247
14370
  }
14371
+ // Get IP info and GeoIP data
14372
+ try {
14373
+ const ipResponse = yield fetch(`${this.api['baseUrl']}/api/ingestion/ip-info`, {
14374
+ method: 'POST',
14375
+ headers: {
14376
+ 'Content-Type': 'application/json',
14377
+ 'Authorization': `Bearer ${this.apiKey}`
14378
+ },
14379
+ body: JSON.stringify({
14380
+ sessionId: this.sessionId,
14381
+ clientIP: null, // Let server detect from headers
14382
+ ipDetectionMethod: 'headers',
14383
+ timestamp: new Date().toISOString()
14384
+ })
14385
+ });
14386
+ if (ipResponse.ok) {
14387
+ logDebug('✅ IP info and GeoIP data retrieved successfully');
14388
+ }
14389
+ else {
14390
+ logDebug(`⚠️ IP info request failed: ${ipResponse.statusText}`);
14391
+ }
14392
+ }
14393
+ catch (error) {
14394
+ logDebug(`⚠️ IP info request error: ${error}`);
14395
+ }
14248
14396
  // Don't update endUserId - keep it as the original UUID
14249
14397
  return originalEndUserId || '';
14250
14398
  });
@@ -14284,7 +14432,7 @@ class HumanBehaviorTracker {
14284
14432
  // ✅ HUMANBEHAVIOR'S CUSTOM SETTINGS
14285
14433
  maskTextSelector: this.redactionManager.getMaskTextSelector() || undefined,
14286
14434
  maskTextFn: undefined,
14287
- maskAllInputs: true, // HumanBehavior default
14435
+ maskAllInputs: this.redactionManager.getRedactionMode() === 'privacy-first', // Configurable based on strategy
14288
14436
  maskInputOptions: { password: true }, // HumanBehavior default
14289
14437
  maskInputFn: undefined,
14290
14438
  slimDOMOptions: {},
@@ -14593,6 +14741,17 @@ class HumanBehaviorTracker {
14593
14741
  this.redactionManager = new RedactionManager(options);
14594
14742
  });
14595
14743
  }
14744
+ /**
14745
+ * Set specific fields to be redacted (for visibility-first mode)
14746
+ * @param fields Array of CSS selectors for fields to redact
14747
+ */
14748
+ setRedactedFields(fields) {
14749
+ this.redactionManager.setFieldsToRedact(fields);
14750
+ // ✅ RESTART RECORDING WITH NEW SETTINGS - Ensures redaction is applied
14751
+ if (this.recordInstance) {
14752
+ this.restartWithNewRedaction();
14753
+ }
14754
+ }
14596
14755
  /**
14597
14756
  * Set specific fields to be unredacted (everything else stays redacted by rrweb)
14598
14757
  * @param fields Array of CSS selectors for fields to unredact (e.g., ['#username', '#comment'])