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.
- 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 +2 -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
|
@@ -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.
|
|
12974
|
-
|
|
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
|
-
*
|
|
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
|
-
|
|
12982
|
-
if (this.
|
|
12983
|
-
return
|
|
13046
|
+
applyRedactionClasses() {
|
|
13047
|
+
if (this.redactedFields.size === 0) {
|
|
13048
|
+
return;
|
|
12984
13049
|
}
|
|
12985
|
-
//
|
|
12986
|
-
|
|
13050
|
+
// Add 'rr-mask' class to redacted elements
|
|
13051
|
+
this.redactedFields.forEach(selector => {
|
|
12987
13052
|
try {
|
|
12988
|
-
|
|
12989
|
-
|
|
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:
|
|
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'])
|