Reflect server-side processing and malware scans in the UI.
"use client"
import {
type ProcessContext,
type UploadItem,
UploadError,
s3Adapter,
} from "@uploadcn/core"
import { demoTransport, simulateBackendStep } from "@/examples/_demo"
import {
Upload,
UploadDropzone,
UploadDropzoneDescription,
UploadDropzoneTitle,
UploadQueue,
} from "@/components/ui/upload"
const adapter = s3Adapter({
endpoint: "/api/upload",
transport: demoTransport, // docs only, see examples/_demo.ts
})
/**
* The browser can't scan files for malware, your backend does. `process`
* runs after the upload and reflects the backend's verdict:
* uploading → processing → scanning → success | rejected.
*/
async function scan(
item: UploadItem,
{ setStatus, signal }: ProcessContext<unknown>
) {
setStatus("scanning")
// Your backend scans the file; here a stand-in answers.
const verdict = await simulateBackendStep(item.name, "scan", signal)
if (verdict === "infected") {
throw new UploadError("Malware detected, the file was quarantined", {
code: "rejected",
})
}
}
export default function ScanStatesExample() {
return (
<Upload adapter={adapter} process={scan}>
<UploadDropzone>
<UploadDropzoneTitle>
Upload, then wait for the scan
</UploadDropzoneTitle>
<UploadDropzoneDescription>
Files named like “eicar.txt” or “virus.pdf” are flagged by the demo
scanner
</UploadDropzoneDescription>
</UploadDropzone>
<UploadQueue />
</Upload>
)
}
A browser can't scan files for malware, and UploadCN doesn't pretend to. What it gives you is states your backend controls.
Looking for built-in scanning?
createUploadRoute can scan every upload with ClamAV, VirusTotal or your own service
before it completes. See Virus scanning. This page covers
driving the states yourself, for background jobs and webhooks. For text recognition, see
OCR.
- Uploading
- Processing
- Scanning
- Success
- ScanningRejected, the scanner found a problem
With process
process runs after the adapter stored the file. Move between states with setStatus;
throw an UploadError with code "rejected" to reject.
import { UploadError } from "@uploadcn/core"
<Upload
adapter={adapter}
process={async (item, { setStatus, signal, result }) => {
setStatus("scanning")
const verdict = await waitForScan(result.key, { signal }) // poll, SSE, or websocket
if (verdict === "infected") {
throw new UploadError("Malware detected", { code: "rejected" })
}
return { ...result, scanned: true } // becomes item.result
}}
/>From outside (webhooks, realtime)
When results arrive through another channel, drive the item directly:
uploader.update(id, { status: "scanning" })
uploader.update(id, { status: "success", result })
uploader.update(id, { status: "rejected", error: "Malware detected" })Server side
For inline scanning, pass scan to createUploadRoute (Virus scanning).
For background scanning, kick it off in onUploadComplete (enqueue a job, or rely on your
storage provider's scanning integration) and expose the verdict to the client. Until a file is
approved, keep it out of public access, for example, upload to a quarantine prefix and
copy approved files to their final location.