| 188 | } |
| 189 | |
| 190 | private sanitizeProperties(properties: Record<string, any>): Record<string, any> { |
| 191 | const sanitized: Record<string, any> = {}; |
| 192 | |
| 193 | for (const [key, value] of Object.entries(properties)) { |
| 194 | // Skip null/undefined values |
| 195 | if (value == null) continue; |
| 196 | |
| 197 | // Apply specific sanitizers based on key |
| 198 | if (key.includes('path') || key.includes('file')) { |
| 199 | sanitized[key] = typeof value === 'string' ? sanitizers.sanitizeFilePath(value) : value; |
| 200 | } else if (key.includes('project')) { |
| 201 | sanitized[key] = typeof value === 'string' ? sanitizers.sanitizeProjectPath(value) : value; |
| 202 | } else if (key.includes('error') || key.includes('message')) { |
| 203 | sanitized[key] = typeof value === 'string' ? sanitizers.sanitizeErrorMessage(value) : value; |
| 204 | } else if (key.includes('agent_name')) { |
| 205 | sanitized[key] = typeof value === 'string' ? sanitizers.sanitizeAgentName(value) : value; |
| 206 | } else { |
| 207 | // For other properties, ensure no PII |
| 208 | if (typeof value === 'string') { |
| 209 | // Remove potential file paths |
| 210 | let cleanValue = value.replace(/\/[\w\-\/\.]+/g, '/***'); |
| 211 | // Remove potential API keys |
| 212 | cleanValue = cleanValue.replace(/[a-zA-Z0-9]{32,}/g, '***'); |
| 213 | // Remove emails |
| 214 | cleanValue = cleanValue.replace(/[\w\.-]+@[\w\.-]+\.\w+/g, '***@***.***'); |
| 215 | sanitized[key] = cleanValue; |
| 216 | } else { |
| 217 | sanitized[key] = value; |
| 218 | } |
| 219 | } |
| 220 | } |
| 221 | |
| 222 | return sanitized; |
| 223 | } |
| 224 | |
| 225 | private flushEvents(): void { |
| 226 | if (this.eventQueue.length === 0) return; |