import { base } from "$app/paths"; export interface AttachmentLoadResult { files: File[]; errors: string[]; } /** * Parse attachment URLs from query parameters * Supports both comma-separated (?attachments=url1,url2) and multiple params (?attachments=url1&attachments=url2) */ function parseAttachmentUrls(searchParams: URLSearchParams): string[] { const urls: string[] = []; // Get all 'attachments' parameters const attachmentParams = searchParams.getAll("attachments"); for (const param of attachmentParams) { // Split by comma in case multiple URLs are in one param const splitUrls = param.split(",").map((url) => url.trim()); urls.push(...splitUrls); } // Filter out empty strings return urls.filter((url) => url.length > 0); } /** * Extract filename from URL or Content-Disposition header */ function extractFilename(url: string, contentDisposition?: string | null): string { // Try to get filename from Content-Disposition header if (contentDisposition) { const match = contentDisposition.match(/filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/); if (match && match[1]) { return match[1].replace(/['"]/g, ""); } } // Fallback: extract from URL try { const urlObj = new URL(url); const pathname = urlObj.pathname; const segments = pathname.split("/"); const lastSegment = segments[segments.length - 1]; if (lastSegment && lastSegment.length > 0) { return decodeURIComponent(lastSegment); } } catch { // Invalid URL, fall through to default } return "attachment"; } /** * Load files from remote URLs via server-side proxy */ export async function loadAttachmentsFromUrls( searchParams: URLSearchParams ): Promise { const urls = parseAttachmentUrls(searchParams); if (urls.length === 0) { return { files: [], errors: [] }; } const files: File[] = []; const errors: string[] = []; await Promise.all( urls.map(async (url) => { try { // Fetch via our proxy endpoint to bypass CORS const proxyUrl = `${base}/api/fetch-url?${new URLSearchParams({ url })}`; const response = await fetch(proxyUrl); if (!response.ok) { const errorText = await response.text(); errors.push(`Failed to fetch ${url}: ${errorText}`); return; } const blob = await response.blob(); const contentDisposition = response.headers.get("content-disposition"); const filename = extractFilename(url, contentDisposition); // Create File object const file = new File([blob], filename, { type: blob.type || "application/octet-stream", }); files.push(file); } catch (err) { const message = err instanceof Error ? err.message : "Unknown error"; errors.push(`Failed to load ${url}: ${message}`); console.error(`Error loading attachment from ${url}:`, err); } }) ); return { files, errors }; }