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
package/dist/cjs/remix/index.cjs
CHANGED
|
@@ -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.
|
|
12976
|
-
|
|
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
|
-
*
|
|
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
|
-
|
|
12984
|
-
if (this.
|
|
12985
|
-
return
|
|
13048
|
+
applyRedactionClasses() {
|
|
13049
|
+
if (this.redactedFields.size === 0) {
|
|
13050
|
+
return;
|
|
12986
13051
|
}
|
|
12987
|
-
//
|
|
12988
|
-
|
|
13052
|
+
// Add 'rr-mask' class to redacted elements
|
|
13053
|
+
this.redactedFields.forEach(selector => {
|
|
12989
13054
|
try {
|
|
12990
|
-
|
|
12991
|
-
|
|
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:
|
|
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'])
|