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.
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 +1 -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
@@ -2,6 +2,12 @@ interface RedactionOptions {
2
2
  redactedText?: string;
3
3
  excludeSelectors?: string[];
4
4
  userFields?: string[];
5
+ redactionStrategy?: {
6
+ mode: 'privacy-first' | 'visibility-first';
7
+ unredactFields?: string[];
8
+ redactFields?: string[];
9
+ };
10
+ legacyRedactFields?: string[];
5
11
  }
6
12
 
7
13
  declare global {
@@ -46,6 +52,11 @@ declare class HumanBehaviorTracker {
46
52
  ingestionUrl?: string;
47
53
  logLevel?: 'none' | 'error' | 'warn' | 'info' | 'debug';
48
54
  redactFields?: string[];
55
+ redactionStrategy?: {
56
+ mode: 'privacy-first' | 'visibility-first';
57
+ unredactFields?: string[];
58
+ redactFields?: string[];
59
+ };
49
60
  enableAutomaticTracking?: boolean;
50
61
  suppressConsoleErrors?: boolean;
51
62
  recordCanvas?: boolean;
@@ -62,6 +73,12 @@ declare class HumanBehaviorTracker {
62
73
  constructor(apiKey: string | undefined, ingestionUrl?: string, options?: {
63
74
  enableAutomaticProperties?: boolean;
64
75
  propertyDenylist?: string[];
76
+ redactionStrategy?: {
77
+ mode: 'privacy-first' | 'visibility-first';
78
+ unredactFields?: string[];
79
+ redactFields?: string[];
80
+ };
81
+ redactFields?: string[];
65
82
  });
66
83
  private init;
67
84
  private ensureInitialized;
@@ -162,6 +179,11 @@ declare class HumanBehaviorTracker {
162
179
  * @param options Optional configuration for redaction behavior
163
180
  */
164
181
  redact(options?: RedactionOptions): Promise<void>;
182
+ /**
183
+ * Set specific fields to be redacted (for visibility-first mode)
184
+ * @param fields Array of CSS selectors for fields to redact
185
+ */
186
+ setRedactedFields(fields: string[]): void;
165
187
  /**
166
188
  * Set specific fields to be unredacted (everything else stays redacted by rrweb)
167
189
  * @param fields Array of CSS selectors for fields to unredact (e.g., ['#username', '#comment'])
@@ -2,12 +2,25 @@ interface RedactionOptions {
2
2
  redactedText?: string;
3
3
  excludeSelectors?: string[];
4
4
  userFields?: string[];
5
+ redactionStrategy?: {
6
+ mode: 'privacy-first' | 'visibility-first';
7
+ unredactFields?: string[];
8
+ redactFields?: string[];
9
+ };
10
+ legacyRedactFields?: string[];
5
11
  }
6
12
  declare class RedactionManager {
7
13
  private redactedText;
8
14
  private unredactedFields;
15
+ private redactedFields;
16
+ private redactionMode;
9
17
  private excludeSelectors;
10
18
  constructor(options?: RedactionOptions);
19
+ /**
20
+ * Set specific fields to be redacted (for visibility-first mode)
21
+ * @param fields Array of CSS selectors for fields to redact
22
+ */
23
+ setFieldsToRedact(fields: string[]): void;
11
24
  /**
12
25
  * Set specific fields to be unredacted (everything else stays redacted by rrweb)
13
26
  * @param fields Array of CSS selectors for fields to unredact
@@ -26,6 +39,10 @@ declare class RedactionManager {
26
39
  * Check if any fields are currently unredacted
27
40
  */
28
41
  hasUnredactedFields(): boolean;
42
+ /**
43
+ * Get the current redaction mode
44
+ */
45
+ getRedactionMode(): 'privacy-first' | 'visibility-first';
29
46
  /**
30
47
  * Get the currently unredacted fields
31
48
  */
@@ -36,9 +53,10 @@ declare class RedactionManager {
36
53
  */
37
54
  getMaskTextSelector(): string | null;
38
55
  /**
39
- * Check if an element should be unredacted
56
+ * Apply redaction classes to DOM elements (for visibility-first mode)
57
+ * Adds 'rr-mask' class to elements that should be redacted
40
58
  */
41
- shouldUnredactElement(element: HTMLElement): boolean;
59
+ applyRedactionClasses(): void;
42
60
  /**
43
61
  * Apply unredaction classes to DOM elements
44
62
  * Removes 'rr-mask' class from elements that should be unredacted
@@ -60,6 +78,10 @@ declare class RedactionManager {
60
78
  * Check if an element is currently unredacted
61
79
  */
62
80
  isElementUnredacted(element: HTMLElement): boolean;
81
+ /**
82
+ * Check if an element should be unredacted
83
+ */
84
+ shouldUnredactElement(element: HTMLElement): boolean;
63
85
  }
64
86
  declare const redactionManager: RedactionManager;
65
87
 
@@ -105,6 +127,11 @@ declare class HumanBehaviorTracker {
105
127
  ingestionUrl?: string;
106
128
  logLevel?: 'none' | 'error' | 'warn' | 'info' | 'debug';
107
129
  redactFields?: string[];
130
+ redactionStrategy?: {
131
+ mode: 'privacy-first' | 'visibility-first';
132
+ unredactFields?: string[];
133
+ redactFields?: string[];
134
+ };
108
135
  enableAutomaticTracking?: boolean;
109
136
  suppressConsoleErrors?: boolean;
110
137
  recordCanvas?: boolean;
@@ -121,6 +148,12 @@ declare class HumanBehaviorTracker {
121
148
  constructor(apiKey: string | undefined, ingestionUrl?: string, options?: {
122
149
  enableAutomaticProperties?: boolean;
123
150
  propertyDenylist?: string[];
151
+ redactionStrategy?: {
152
+ mode: 'privacy-first' | 'visibility-first';
153
+ unredactFields?: string[];
154
+ redactFields?: string[];
155
+ };
156
+ redactFields?: string[];
124
157
  });
125
158
  private init;
126
159
  private ensureInitialized;
@@ -221,6 +254,11 @@ declare class HumanBehaviorTracker {
221
254
  * @param options Optional configuration for redaction behavior
222
255
  */
223
256
  redact(options?: RedactionOptions): Promise<void>;
257
+ /**
258
+ * Set specific fields to be redacted (for visibility-first mode)
259
+ * @param fields Array of CSS selectors for fields to redact
260
+ */
261
+ setRedactedFields(fields: string[]): void;
224
262
  /**
225
263
  * Set specific fields to be unredacted (everything else stays redacted by rrweb)
226
264
  * @param fields Array of CSS selectors for fields to unredact (e.g., ['#username', '#comment'])
@@ -56,7 +56,7 @@ declare class AutoInstallationWizard {
56
56
  */
57
57
  detectFramework(): Promise<FrameworkInfo>;
58
58
  /**
59
- * Install the SDK package
59
+ * Install the SDK package with latest version range
60
60
  */
61
61
  protected installPackage(): Promise<void>;
62
62
  /**
@@ -4,6 +4,12 @@ interface RedactionOptions {
4
4
  redactedText?: string;
5
5
  excludeSelectors?: string[];
6
6
  userFields?: string[];
7
+ redactionStrategy?: {
8
+ mode: 'privacy-first' | 'visibility-first';
9
+ unredactFields?: string[];
10
+ redactFields?: string[];
11
+ };
12
+ legacyRedactFields?: string[];
7
13
  }
8
14
 
9
15
  declare global {
@@ -48,6 +54,11 @@ declare class HumanBehaviorTracker {
48
54
  ingestionUrl?: string;
49
55
  logLevel?: 'none' | 'error' | 'warn' | 'info' | 'debug';
50
56
  redactFields?: string[];
57
+ redactionStrategy?: {
58
+ mode: 'privacy-first' | 'visibility-first';
59
+ unredactFields?: string[];
60
+ redactFields?: string[];
61
+ };
51
62
  enableAutomaticTracking?: boolean;
52
63
  suppressConsoleErrors?: boolean;
53
64
  recordCanvas?: boolean;
@@ -64,6 +75,12 @@ declare class HumanBehaviorTracker {
64
75
  constructor(apiKey: string | undefined, ingestionUrl?: string, options?: {
65
76
  enableAutomaticProperties?: boolean;
66
77
  propertyDenylist?: string[];
78
+ redactionStrategy?: {
79
+ mode: 'privacy-first' | 'visibility-first';
80
+ unredactFields?: string[];
81
+ redactFields?: string[];
82
+ };
83
+ redactFields?: string[];
67
84
  });
68
85
  private init;
69
86
  private ensureInitialized;
@@ -164,6 +181,11 @@ declare class HumanBehaviorTracker {
164
181
  * @param options Optional configuration for redaction behavior
165
182
  */
166
183
  redact(options?: RedactionOptions): Promise<void>;
184
+ /**
185
+ * Set specific fields to be redacted (for visibility-first mode)
186
+ * @param fields Array of CSS selectors for fields to redact
187
+ */
188
+ setRedactedFields(fields: string[]): void;
167
189
  /**
168
190
  * Set specific fields to be unredacted (everything else stays redacted by rrweb)
169
191
  * @param fields Array of CSS selectors for fields to unredact (e.g., ['#username', '#comment'])
@@ -5,6 +5,12 @@ interface RedactionOptions {
5
5
  redactedText?: string;
6
6
  excludeSelectors?: string[];
7
7
  userFields?: string[];
8
+ redactionStrategy?: {
9
+ mode: 'privacy-first' | 'visibility-first';
10
+ unredactFields?: string[];
11
+ redactFields?: string[];
12
+ };
13
+ legacyRedactFields?: string[];
8
14
  }
9
15
 
10
16
  declare global {
@@ -49,6 +55,11 @@ declare class HumanBehaviorTracker {
49
55
  ingestionUrl?: string;
50
56
  logLevel?: 'none' | 'error' | 'warn' | 'info' | 'debug';
51
57
  redactFields?: string[];
58
+ redactionStrategy?: {
59
+ mode: 'privacy-first' | 'visibility-first';
60
+ unredactFields?: string[];
61
+ redactFields?: string[];
62
+ };
52
63
  enableAutomaticTracking?: boolean;
53
64
  suppressConsoleErrors?: boolean;
54
65
  recordCanvas?: boolean;
@@ -65,6 +76,12 @@ declare class HumanBehaviorTracker {
65
76
  constructor(apiKey: string | undefined, ingestionUrl?: string, options?: {
66
77
  enableAutomaticProperties?: boolean;
67
78
  propertyDenylist?: string[];
79
+ redactionStrategy?: {
80
+ mode: 'privacy-first' | 'visibility-first';
81
+ unredactFields?: string[];
82
+ redactFields?: string[];
83
+ };
84
+ redactFields?: string[];
68
85
  });
69
86
  private init;
70
87
  private ensureInitialized;
@@ -165,6 +182,11 @@ declare class HumanBehaviorTracker {
165
182
  * @param options Optional configuration for redaction behavior
166
183
  */
167
184
  redact(options?: RedactionOptions): Promise<void>;
185
+ /**
186
+ * Set specific fields to be redacted (for visibility-first mode)
187
+ * @param fields Array of CSS selectors for fields to redact
188
+ */
189
+ setRedactedFields(fields: string[]): void;
168
190
  /**
169
191
  * Set specific fields to be unredacted (everything else stays redacted by rrweb)
170
192
  * @param fields Array of CSS selectors for fields to unredact (e.g., ['#username', '#comment'])
@@ -2,6 +2,12 @@ interface RedactionOptions {
2
2
  redactedText?: string;
3
3
  excludeSelectors?: string[];
4
4
  userFields?: string[];
5
+ redactionStrategy?: {
6
+ mode: 'privacy-first' | 'visibility-first';
7
+ unredactFields?: string[];
8
+ redactFields?: string[];
9
+ };
10
+ legacyRedactFields?: string[];
5
11
  }
6
12
 
7
13
  declare global {
@@ -46,6 +52,11 @@ declare class HumanBehaviorTracker {
46
52
  ingestionUrl?: string;
47
53
  logLevel?: 'none' | 'error' | 'warn' | 'info' | 'debug';
48
54
  redactFields?: string[];
55
+ redactionStrategy?: {
56
+ mode: 'privacy-first' | 'visibility-first';
57
+ unredactFields?: string[];
58
+ redactFields?: string[];
59
+ };
49
60
  enableAutomaticTracking?: boolean;
50
61
  suppressConsoleErrors?: boolean;
51
62
  recordCanvas?: boolean;
@@ -62,6 +73,12 @@ declare class HumanBehaviorTracker {
62
73
  constructor(apiKey: string | undefined, ingestionUrl?: string, options?: {
63
74
  enableAutomaticProperties?: boolean;
64
75
  propertyDenylist?: string[];
76
+ redactionStrategy?: {
77
+ mode: 'privacy-first' | 'visibility-first';
78
+ unredactFields?: string[];
79
+ redactFields?: string[];
80
+ };
81
+ redactFields?: string[];
65
82
  });
66
83
  private init;
67
84
  private ensureInitialized;
@@ -162,6 +179,11 @@ declare class HumanBehaviorTracker {
162
179
  * @param options Optional configuration for redaction behavior
163
180
  */
164
181
  redact(options?: RedactionOptions): Promise<void>;
182
+ /**
183
+ * Set specific fields to be redacted (for visibility-first mode)
184
+ * @param fields Array of CSS selectors for fields to redact
185
+ */
186
+ setRedactedFields(fields: string[]): void;
165
187
  /**
166
188
  * Set specific fields to be unredacted (everything else stays redacted by rrweb)
167
189
  * @param fields Array of CSS selectors for fields to unredact (e.g., ['#username', '#comment'])
@@ -56,7 +56,7 @@ declare class AutoInstallationWizard {
56
56
  */
57
57
  detectFramework(): Promise<FrameworkInfo$2>;
58
58
  /**
59
- * Install the SDK package
59
+ * Install the SDK package with latest version range
60
60
  */
61
61
  protected installPackage(): Promise<void>;
62
62
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "humanbehavior-js",
3
- "version": "0.4.23",
3
+ "version": "0.4.24",
4
4
  "description": "SDK for HumanBehavior session and event recording",
5
5
  "type": "module",
6
6
  "main": "./dist/cjs/index.js",
package/readme.md CHANGED
@@ -85,7 +85,11 @@ const tracker = HumanBehaviorTracker.init(apiKey, options);
85
85
  **Options:**
86
86
  - `ingestionUrl`: Custom ingestion server URL
87
87
  - `logLevel`: 'none' | 'error' | 'warn' | 'info' | 'debug'
88
- - `redactFields`: Array of CSS selectors to redact
88
+ - `redactFields`: Array of CSS selectors to unredact (DEPRECATED: Use redactionStrategy instead)
89
+ - `redactionStrategy`: Flexible redaction configuration
90
+ - `mode`: 'privacy-first' | 'visibility-first' (default: 'privacy-first')
91
+ - `unredactFields`: Array of CSS selectors to make visible (when mode: 'privacy-first')
92
+ - `redactFields`: Array of CSS selectors to hide (when mode: 'visibility-first')
89
93
  - `suppressConsoleErrors`: Boolean to suppress common rrweb errors (default: true)
90
94
  - `recordCanvas`: Boolean to enable canvas recording with PostHog-style protection (default: false)
91
95
 
@@ -117,14 +121,64 @@ await tracker.trackNavigationEvent('pushState', '/home', '/about');
117
121
 
118
122
  ### Data Redaction
119
123
 
124
+ The SDK supports flexible redaction strategies to protect sensitive data:
125
+
126
+ #### Privacy-First Mode (Default)
127
+ Everything is redacted by default. Specify fields to unredact:
128
+
129
+ ```javascript
130
+ // Privacy-first: everything redacted, unredact specific fields
131
+ const tracker = HumanBehaviorTracker.init('your-api-key', {
132
+ redactionStrategy: {
133
+ mode: 'privacy-first',
134
+ unredactFields: ['#username', '#comment', '.public-field']
135
+ }
136
+ });
137
+ ```
138
+
139
+ #### Visibility-First Mode
140
+ Everything is visible by default. Specify fields to redact:
141
+
142
+ ```javascript
143
+ // Visibility-first: everything visible, redact specific fields
144
+ const tracker = HumanBehaviorTracker.init('your-api-key', {
145
+ redactionStrategy: {
146
+ mode: 'visibility-first',
147
+ redactFields: ['#password', '#credit-card', '.sensitive-data']
148
+ }
149
+ });
150
+ ```
151
+
152
+ #### Legacy Support
153
+ The old `redactFields` option still works (privacy-first mode):
154
+
120
155
  ```javascript
121
- // Redact sensitive fields
122
- tracker.setRedactedFields(['input[type="password"]', '#email']);
156
+ // Legacy: same as privacy-first mode
157
+ const tracker = HumanBehaviorTracker.init('your-api-key', {
158
+ redactFields: ['#username', '#email'] // These fields will be unredacted
159
+ });
160
+ ```
123
161
 
124
- // Check if redaction is active
125
- const isActive = tracker.isRedactedFields();
162
+ #### Dynamic Redaction
163
+ Change redaction settings at runtime:
164
+
165
+ ```javascript
166
+ // Privacy-first: add fields to unredact
167
+ tracker.setUnredactedFields(['#new-field', '.another-field']);
168
+
169
+ // Visibility-first: add fields to redact
170
+ tracker.setRedactedFields(['#sensitive-field', '.private-data']);
171
+
172
+ // Clear all settings
173
+ tracker.clearUnredactedFields(); // Privacy-first
174
+ tracker.clearRedactedFields(); // Visibility-first
126
175
  ```
127
176
 
177
+ #### Security Features
178
+ - **Password fields always protected** (cannot be unredacted in any mode)
179
+ - **CSS selector validation** (prevents invalid selectors)
180
+ - **Runtime safety checks** (handles DOM errors gracefully)
181
+
128
182
  ### Debugging
129
183
 
130
184
  ```javascript
package/src/redact.ts CHANGED
@@ -10,12 +10,20 @@ const isBrowser = typeof window !== 'undefined';
10
10
  export interface RedactionOptions {
11
11
  redactedText?: string;
12
12
  excludeSelectors?: string[];
13
- userFields?: string[]; // Fields that the user wants to unredact
13
+ userFields?: string[]; // Fields that the user wants to unredact (legacy)
14
+ redactionStrategy?: {
15
+ mode: 'privacy-first' | 'visibility-first';
16
+ unredactFields?: string[]; // Fields to make visible (when mode: 'privacy-first')
17
+ redactFields?: string[]; // Fields to hide (when mode: 'visibility-first')
18
+ };
19
+ legacyRedactFields?: string[]; // For backward compatibility
14
20
  }
15
21
 
16
22
  export class RedactionManager {
17
23
  private redactedText: string = '[REDACTED]';
18
24
  private unredactedFields: Set<string> = new Set(); // Fields that user wants to unredact
25
+ private redactedFields: Set<string> = new Set(); // Fields that user wants to redact
26
+ private redactionMode: 'privacy-first' | 'visibility-first' = 'privacy-first';
19
27
  private excludeSelectors: string[] = [
20
28
  '[data-no-redact="true"]',
21
29
  '.human-behavior-no-redact'
@@ -28,11 +36,64 @@ export class RedactionManager {
28
36
  if (options?.excludeSelectors) {
29
37
  this.excludeSelectors = [...this.excludeSelectors, ...options.excludeSelectors];
30
38
  }
39
+
40
+ // Handle new redaction strategy
41
+ if (options?.redactionStrategy) {
42
+ this.redactionMode = options.redactionStrategy.mode;
43
+
44
+ if (this.redactionMode === 'privacy-first') {
45
+ // Privacy-first: everything redacted by default, unredact specific fields
46
+ if (options.redactionStrategy.unredactFields) {
47
+ this.setFieldsToUnredact(options.redactionStrategy.unredactFields);
48
+ }
49
+ } else {
50
+ // Visibility-first: everything visible by default, redact specific fields
51
+ if (options.redactionStrategy.redactFields) {
52
+ this.setFieldsToRedact(options.redactionStrategy.redactFields);
53
+ }
54
+ }
55
+ }
56
+
57
+ // Handle legacy redactFields (backward compatibility)
58
+ if (options?.legacyRedactFields) {
59
+ this.setFieldsToUnredact(options.legacyRedactFields);
60
+ }
61
+
62
+ // Handle legacy userFields
31
63
  if (options?.userFields) {
32
64
  this.setFieldsToUnredact(options.userFields);
33
65
  }
34
66
  }
35
67
 
68
+ /**
69
+ * Set specific fields to be redacted (for visibility-first mode)
70
+ * @param fields Array of CSS selectors for fields to redact
71
+ */
72
+ public setFieldsToRedact(fields: string[]): void {
73
+ this.redactedFields.clear();
74
+
75
+ // Always include password fields in redacted list
76
+ const passwordFields = [
77
+ 'input[type="password"]',
78
+ 'input[type="password" i]',
79
+ '[type="password"]',
80
+ '[type="password" i]'
81
+ ];
82
+
83
+ // Add password fields and user-specified fields
84
+ [...passwordFields, ...fields].forEach(field => {
85
+ this.redactedFields.add(field);
86
+ });
87
+
88
+ if (this.redactedFields.size > 0) {
89
+ logDebug(`Redaction: Active for ${this.redactedFields.size} field(s):`, Array.from(this.redactedFields));
90
+ } else {
91
+ logDebug('Redaction: No fields to redact');
92
+ }
93
+
94
+ this.applyRedactionClasses();
95
+ }
96
+
36
97
  /**
37
98
  * Set specific fields to be unredacted (everything else stays redacted by rrweb)
38
99
  * @param fields Array of CSS selectors for fields to unredact
@@ -96,6 +157,13 @@ export class RedactionManager {
96
157
  return this.unredactedFields.size > 0;
97
158
  }
98
159
 
160
+ /**
161
+ * Get the current redaction mode
162
+ */
163
+ public getRedactionMode(): 'privacy-first' | 'visibility-first' {
164
+ return this.redactionMode;
165
+ }
166
+
99
167
  /**
100
168
  * Get the currently unredacted fields
101
169
  */
@@ -108,31 +176,42 @@ export class RedactionManager {
108
176
  * Returns null if no fields are unredacted (everything stays redacted)
109
177
  */
110
178
  public getMaskTextSelector(): string | null {
111
- if (this.unredactedFields.size === 0) {
112
- return null; // Everything stays redacted
179
+ if (this.redactionMode === 'privacy-first') {
180
+ // Privacy-first: mask everything except unredacted fields
181
+ if (this.unredactedFields.size === 0) {
182
+ return null; // Everything stays redacted
183
+ }
184
+ return Array.from(this.unredactedFields).join(',');
185
+ } else {
186
+ // Visibility-first: mask only redacted fields
187
+ if (this.redactedFields.size === 0) {
188
+ return null; // Nothing to redact
189
+ }
190
+ return Array.from(this.redactedFields).join(',');
113
191
  }
114
- return Array.from(this.unredactedFields).join(',');
115
192
  }
116
193
 
117
194
  /**
118
- * Check if an element should be unredacted
195
+ * Apply redaction classes to DOM elements (for visibility-first mode)
196
+ * Adds 'rr-mask' class to elements that should be redacted
119
197
  */
120
- public shouldUnredactElement(element: HTMLElement): boolean {
121
- if (this.unredactedFields.size === 0) {
122
- return false; // Nothing unredacted
198
+ public applyRedactionClasses(): void {
199
+ if (this.redactedFields.size === 0) {
200
+ return;
123
201
  }
124
202
 
125
- // Check if any selector matches this element
126
- for (const selector of this.unredactedFields) {
203
+ // Add 'rr-mask' class to redacted elements
204
+ this.redactedFields.forEach(selector => {
127
205
  try {
128
- if (element.matches(selector)) {
129
- return true;
130
- }
206
+ const elements = document.querySelectorAll(selector);
207
+ elements.forEach(element => {
208
+ element.classList.add('rr-mask');
209
+ });
210
+ logDebug(`Added rr-mask class to ${elements.length} element(s) for selector: ${selector}`);
131
211
  } catch (e) {
132
212
  logWarn(`Invalid selector: ${selector}`);
133
213
  }
134
- }
135
- return false;
214
+ });
136
215
  }
137
216
 
138
217
  /**
@@ -198,6 +277,47 @@ export class RedactionManager {
198
277
  public isElementUnredacted(element: HTMLElement): boolean {
199
278
  return this.shouldUnredactElement(element);
200
279
  }
280
+
281
+ /**
282
+ * Check if an element should be unredacted
283
+ */
284
+ public shouldUnredactElement(element: HTMLElement): boolean {
285
+ if (this.redactionMode === 'privacy-first') {
286
+ // Privacy-first: check if element is in unredacted fields
287
+ if (this.unredactedFields.size === 0) {
288
+ return false; // Nothing unredacted
289
+ }
290
+
291
+ // Check if any selector matches this element
292
+ for (const selector of this.unredactedFields) {
293
+ try {
294
+ if (element.matches(selector)) {
295
+ return true;
296
+ }
297
+ } catch (e) {
298
+ logWarn(`Invalid selector: ${selector}`);
299
+ }
300
+ }
301
+ return false;
302
+ } else {
303
+ // Visibility-first: check if element is NOT in redacted fields
304
+ if (this.redactedFields.size === 0) {
305
+ return true; // Nothing redacted, everything visible
306
+ }
307
+
308
+ // Check if any selector matches this element
309
+ for (const selector of this.redactedFields) {
310
+ try {
311
+ if (element.matches(selector)) {
312
+ return false; // Element is redacted
313
+ }
314
+ } catch (e) {
315
+ logWarn(`Invalid selector: ${selector}`);
316
+ }
317
+ }
318
+ return true; // Element is not redacted
319
+ }
320
+ }
201
321
  }
202
322
 
203
323
  // Export a default instance