import { AuditEvent, AuditEventExport } from '../types'; export class AuditExporter { static async exportToCSV(events: AuditEvent[], options?: Partial): Promise { const fields = options?.fields || [ 'id', 'timestamp', 'actor.id', 'actor.type', 'action', 'resource.type', 'resource.id', 'result', ]; // Create header row const header = fields.join(','); // Create data rows const rows = events.map(event => { return fields.map(field => { const value = this.getNestedValue(event, field); // Escape values containing commas or quotes if (typeof value === 'string' && (value.includes(',') || value.includes('"'))) { return `"${value.replace(/"/g, '""')}"`; } return value?.toString() || ''; }).join(','); }); return [header, ...rows].join('\n'); } static async exportToJSON(events: AuditEvent[], options?: Partial): Promise { const fields = options?.fields; if (fields) { // Export only specified fields const filtered = events.map(event => { const result: any = {}; fields.forEach(field => { result[field] = this.getNestedValue(event, field); }); return result; }); return JSON.stringify(filtered, null, 2); } return JSON.stringify(events, null, 2); } static async export(events: AuditEvent[], options: AuditEventExport): Promise { let content: string; let mimeType: string; switch (options.format) { case 'csv': content = await this.exportToCSV(events, options); mimeType = 'text/csv'; break; case 'json': content = await this.exportToJSON(events, options); mimeType = 'application/json'; break; default: throw new Error(`Unsupported export format: ${options.format}`); } return new Blob([content], { type: mimeType }); } static download(blob: Blob, filename: string): void { const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = filename; document.body.appendChild(a); a.click(); document.body.removeChild(a); URL.revokeObjectURL(url); } private static getNestedValue(obj: any, path: string): any { return path.split('.').reduce((current, key) => current?.[key], obj); } }