Preview
Recipes
Practical patterns for wiring <FilePreview> into real apps.
Auth — custom fetcher with Authorization header
Pre-signed URLs are the cleanest way to ship private files (no auth header needed), but when an API gateway in front of S3 demands a Bearer token, pass a fetcher that injects it:
import { FilePreview } from '@vuer-ai/vuer-m3u/preview'
function authFetcher(url: string, init?: RequestInit) {
return fetch(url, {
...init,
headers: {
...(init?.headers ?? {}),
Authorization: `Bearer ${getToken()}`,
},
})
}
<FilePreview url={url} fetcher={authFetcher} />The fetcher is called for every request the previewer makes — text fetches, NPY two-stage Range, MCAP footer reads, the lot. It does not wrap native <img> / <video> requests; for those, use a service worker or pre-signed URLs.
DreamLake metadata pass-through — skip the probe
DreamLake's listing API already returns size and contentType for every file in an episode. Pass these through directly instead of forcing a HEAD round-trip:
import { FilePreview } from '@vuer-ai/vuer-m3u/preview'
function FileCard({ file }: { file: EpisodeFile }) {
return (
<FilePreview
url={file.url}
filename={file.name}
size={file.size}
contentType={file.contentType}
/>
)
}With size set, the image hard-limit check runs before any fetch. With contentType set, kind resolution falls through to MIME if the extension is ambiguous (e.g. .dat). The default probe='never' means no HEAD request fires.
If you have a mixed source where some files come with metadata and others don't, opt into auto-probe:
<FilePreview url={url} probe="auto" />probe="auto" only fires HEAD when both size and contentType are missing — this preserves the metadata-fast-path while gracefully handling unknown URLs.
File switcher in a panel
A common shape: list of files on the left, preview pane on the right, click a row to swap the URL. The switcher below stages this pattern with a <select> for compactness.
import { useState } from 'react'
import { FilePreview } from '@vuer-ai/vuer-m3u/preview'
export function MyComponent() {
const [url, setUrl] = useState('/files/README.md')
return (
<>
<select value={url} onChange={(e) => setUrl(e.target.value)}>
<option value="/files/README.md">README.md</option>
<option value="/files/data.csv">data.csv</option>
</select>
<FilePreview url={url} />
</>
)
}A few things worth calling out:
<FilePreview>is keyed byurl— whenurlchanges, internal state resets. There is no need to remount manually.- Lazy chunks load on first use, then cache — flipping from CSV → JSONL → CSV downloads each previewer once.
- Errors are isolated per preview — a 404 on one URL does not poison the next one.
- The header bar persists for every kind, including unsupported and error states, so the download button is always available.