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