Files
livedash-node/lib/csvFetcher.ts
Kaj Kowalski 93fbb44eec feat: comprehensive Biome linting fixes and code quality improvements
Major code quality overhaul addressing 58% of all linting issues:

• Type Safety Improvements:
  - Replace all any types with proper TypeScript interfaces
  - Fix Map component shadowing (renamed to CountryMap)
  - Add comprehensive custom error classes system
  - Enhance API route type safety

• Accessibility Enhancements:
  - Add explicit button types to all interactive elements
  - Implement useId() hooks for form element accessibility
  - Add SVG title attributes for screen readers
  - Fix static element interactions with keyboard handlers

• React Best Practices:
  - Resolve exhaustive dependencies warnings with useCallback
  - Extract nested component definitions to top level
  - Fix array index keys with proper unique identifiers
  - Improve component organization and prop typing

• Code Organization:
  - Automatic import organization and type import optimization
  - Fix unused function parameters and variables
  - Enhanced error handling with structured error responses
  - Improve component reusability and maintainability

Results: 248 → 104 total issues (58% reduction)
- Fixed all critical type safety and security issues
- Enhanced accessibility compliance significantly
- Improved code maintainability and performance
2025-06-29 07:35:45 +02:00

84 lines
2.5 KiB
TypeScript

// Simplified CSV fetcher - fetches and parses CSV data without any processing
// Maps directly to SessionImport table fields
import { parse } from "csv-parse/sync";
import fetch from "node-fetch";
// Raw CSV data interface matching SessionImport schema
interface RawSessionImport {
externalSessionId: string;
startTimeRaw: string;
endTimeRaw: string;
ipAddress: string | null;
countryCode: string | null;
language: string | null;
messagesSent: number | null;
sentimentRaw: string | null;
escalatedRaw: string | null;
forwardedHrRaw: string | null;
fullTranscriptUrl: string | null;
avgResponseTimeSeconds: number | null;
tokens: number | null;
tokensEur: number | null;
category: string | null;
initialMessage: string | null;
}
/**
* Fetches and parses CSV data from a URL without any processing
* Maps CSV columns by position to SessionImport fields
* @param url The CSV URL
* @param username Optional username for authentication
* @param password Optional password for authentication
* @returns Array of raw session import data
*/
export async function fetchAndParseCsv(
url: string,
username?: string,
password?: string
): Promise<RawSessionImport[]> {
const authHeader =
username && password
? `Basic ${Buffer.from(`${username}:${password}`).toString("base64")}`
: undefined;
const res = await fetch(url, {
headers: authHeader ? { Authorization: authHeader } : {},
});
if (!res.ok) {
throw new Error(`Failed to fetch CSV: ${res.status} ${res.statusText}`);
}
const text = await res.text();
// Parse CSV without headers, using positional column mapping
const records: string[][] = parse(text, {
delimiter: ",",
from_line: 1, // Start from first line (no headers)
relax_column_count: true,
skip_empty_lines: true,
trim: true,
});
// Map CSV columns by position to SessionImport fields
return records.map((row) => ({
externalSessionId: row[0] || "",
startTimeRaw: row[1] || "",
endTimeRaw: row[2] || "",
ipAddress: row[3] || null,
countryCode: row[4] || null,
language: row[5] || null,
messagesSent: row[6] ? parseInt(row[6], 10) || null : null,
sentimentRaw: row[7] || null,
escalatedRaw: row[8] || null,
forwardedHrRaw: row[9] || null,
fullTranscriptUrl: row[10] || null,
avgResponseTimeSeconds: row[11] ? parseFloat(row[11]) || null : null,
tokens: row[12] ? parseInt(row[12], 10) || null : null,
tokensEur: row[13] ? parseFloat(row[13]) || null : null,
category: row[14] || null,
initialMessage: row[15] || null,
}));
}