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