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.
- package/dist/cjs/angular/index.cjs +176 -17
- package/dist/cjs/angular/index.cjs.map +1 -1
- package/dist/cjs/index.cjs +176 -17
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/install-wizard.cjs +5 -5
- package/dist/cjs/install-wizard.cjs.map +1 -1
- package/dist/cjs/react/index.cjs +176 -17
- package/dist/cjs/react/index.cjs.map +1 -1
- package/dist/cjs/remix/index.cjs +176 -17
- package/dist/cjs/remix/index.cjs.map +1 -1
- package/dist/cjs/svelte/index.cjs +176 -17
- package/dist/cjs/svelte/index.cjs.map +1 -1
- package/dist/cjs/vue/index.cjs +176 -17
- package/dist/cjs/vue/index.cjs.map +1 -1
- package/dist/cjs/wizard/index.cjs +5 -5
- package/dist/cjs/wizard/index.cjs.map +1 -1
- package/dist/cli/ai-auto-install.js +5 -5
- package/dist/cli/ai-auto-install.js.map +1 -1
- package/dist/cli/auto-install.js +5 -5
- package/dist/cli/auto-install.js.map +1 -1
- package/dist/esm/angular/index.js +176 -17
- package/dist/esm/angular/index.js.map +1 -1
- package/dist/esm/index.js +176 -17
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/install-wizard.js +5 -5
- package/dist/esm/install-wizard.js.map +1 -1
- package/dist/esm/react/index.js +176 -17
- package/dist/esm/react/index.js.map +1 -1
- package/dist/esm/remix/index.js +176 -17
- package/dist/esm/remix/index.js.map +1 -1
- package/dist/esm/svelte/index.js +176 -17
- package/dist/esm/svelte/index.js.map +1 -1
- package/dist/esm/vue/index.js +176 -17
- package/dist/esm/vue/index.js.map +1 -1
- package/dist/esm/wizard/index.js +5 -5
- package/dist/esm/wizard/index.js.map +1 -1
- package/dist/index.min.js +1 -1
- package/dist/index.min.js.map +1 -1
- package/dist/types/angular/index.d.ts +22 -0
- package/dist/types/index.d.ts +40 -2
- package/dist/types/install-wizard.d.ts +1 -1
- package/dist/types/react/index.d.ts +22 -0
- package/dist/types/remix/index.d.ts +22 -0
- package/dist/types/svelte/index.d.ts +22 -0
- package/dist/types/wizard/index.d.ts +1 -1
- package/package.json +1 -1
- package/readme.md +59 -5
- package/src/redact.ts +135 -15
- package/src/tracker.ts +69 -4
- 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.
|
|
12989
|
-
|
|
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
|
-
*
|
|
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
|
-
|
|
12997
|
-
if (this.
|
|
12998
|
-
return
|
|
13061
|
+
applyRedactionClasses() {
|
|
13062
|
+
if (this.redactedFields.size === 0) {
|
|
13063
|
+
return;
|
|
12999
13064
|
}
|
|
13000
|
-
//
|
|
13001
|
-
|
|
13065
|
+
// Add 'rr-mask' class to redacted elements
|
|
13066
|
+
this.redactedFields.forEach(selector => {
|
|
13002
13067
|
try {
|
|
13003
|
-
|
|
13004
|
-
|
|
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:
|
|
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'])
|