UNPKG

@kaifronsdal/transcript-viewer

Version:

A web-based viewer for AI conversation transcripts with rollback support

101 lines (86 loc) 3.05 kB
import { json, error } from '@sveltejs/kit'; import type { RequestHandler } from './$types'; import path from 'path'; import { validateFilePath, normalizeFilePath } from '$lib/server/utils/server-file-utils'; import { getTranscriptCache } from '$lib/server/cache/transcript-cache'; import { TRANSCRIPT_DIR } from '$lib/server/config'; export const GET: RequestHandler = async ({ url }) => { try { // Parse query parameters const filePath = url.searchParams.get('filePath'); const metadataOnly = url.searchParams.get('metadataOnly') === 'true'; // Validate required parameters if (!filePath) { throw error(400, { message: 'Missing required parameter: filePath' }); } // All file paths should now be relative to the transcript directory // Resolve the relative path against the transcript directory const resolvedPath = path.resolve(TRANSCRIPT_DIR, filePath); // Validate the relative file path if (!validateFilePath(filePath)) { throw error(400, { message: `Invalid or unsafe file path: ${filePath}` }); } // Get cache instance const cache = getTranscriptCache(); // Load the requested data through cache if (metadataOnly) { const metadata = await cache.getMetadata(resolvedPath); if (metadata === null) { throw error(404, { message: `Transcript not found: ${filePath}` }); } return json({ success: true, data: metadata }, { headers: { 'Cache-Control': 'public, max-age=300', // 5 minutes browser cache for metadata } }); } else { const transcript = await cache.getFullTranscript(resolvedPath); if (transcript === null) { throw error(404, { message: `Transcript not found: ${filePath}` }); } return json({ success: true, data: transcript }, { headers: { 'Cache-Control': 'public, max-age=60', // 1 minute browser cache for full transcripts } }); } } catch (err: any) { // If it's already a SvelteKit error, re-throw it if (err.status) { throw err; } // Validation failure mapping with details if (err?.code === 'TRANSCRIPT_VALIDATION_FAILED' && err.validation) { const { errors: validationErrors } = err.validation; const details = validationErrors?.map?.((e: any, i: number) => { const path = e.path || 'root'; return `${i + 1}. ${path}: ${e.message}`; })?.join('\n'); console.error('Transcript validation error:', details); throw error(422, { message: 'Transcript schema validation failed', details, } as any); } // Log unexpected errors console.error('Transcript API error:', err); // Return generic 500 error for unexpected issues throw error(500, { message: 'Internal server error while loading transcript' }); } };