import { Download, File, FileAudio, FileImage, FileText, FileVideo } from 'lucide-react'; import * as mime from 'mime-types'; interface FileIconProps { /** The MIME type, e.g. `application/pdf`. */ mediaType: string; /** Optional CSS classes forwarded to the icon. */ className?: string; } /** * Render a representative icon for a file based on its MIME type. * * @param root0 - The component props. * @param root0.mediaType - The MIME type of the file. * @param root0.className - CSS classes forwarded to the icon. * @returns A lucide icon element appropriate for the file kind. */ function FileIcon({ mediaType, className }: FileIconProps) { switch (mediaType.split('/')[0]) { case 'image': return ; case 'audio': return ; case 'video': return ; case 'text': return ; default: return mediaType === 'application/pdf' ? ( ) : ( ); } } /** * Classify a file href for safe, correct linking. * * - `safe`: only `http`/`https`/`data`/`blob` schemes become a clickable * link, so a malicious model-supplied URL (e.g. `javascript:`) can't turn * the card into a click-to-execute vector. * - `downloadable`: the HTML `download` attribute is only honoured for * same-origin, `blob:`, and `data:` URLs; cross-origin remote URLs ignore * it and just open. We only set `download` when it will actually work, and * open remote URLs in a new tab instead. * * @param href - The candidate href (remote URL or `data:` URL). * @returns Whether the href is safe to link and whether `download` applies. */ function classifyHref(href: string): { safe: boolean; downloadable: boolean } { let url: URL; try { url = new URL(href, window.location.origin); } catch { return { safe: false, downloadable: false }; } const safe = ['http:', 'https:', 'data:', 'blob:'].includes(url.protocol); const downloadable = url.protocol === 'data:' || url.protocol === 'blob:' || url.origin === window.location.origin; return { safe, downloadable }; } interface FileAttachmentProps { /** Display name of the file (falls back to a name generated from the extension). */ name?: string; /** Resolved href — a remote URL or a `data:` URL — used for download. */ href: string; /** MIME type of the file, e.g. `application/pdf`. */ mediaType: string; } /** * A compact, downloadable card for a non-previewable file attachment * (PDF, Word, Excel, plain-text blobs, …). * * Image / audio / video data blocks are rendered inline by the caller; * every other MIME type falls back to this card instead of rendering * nothing at all. * * @param root0 - The component props. * @param root0.name - Display name of the file. * @param root0.href - Download href (remote URL or `data:` URL). * @param root0.mediaType - MIME type of the file. * @returns A downloadable file-attachment card. */ export function FileAttachment({ name, href, mediaType }: FileAttachmentProps) { const ext = (mime.extension(mediaType) || '').toUpperCase(); const displayName = name || (ext ? `file.${ext.toLowerCase()}` : 'file'); const { safe, downloadable } = classifyHref(href); // Only safe schemes become a real link. Downloadable hrefs (data:/blob:/ // same-origin) get `download`; remote URLs open in a new tab, where the // `download` attribute would be ignored anyway. const linkProps = !safe ? {} : downloadable ? { href, download: displayName } : { href, target: '_blank' as const, rel: 'noopener noreferrer' }; return ( {displayName} {ext && {ext}} ); }