Skip to main content

Single File

Upload, replace, and edit a single file attached to a record.

Schema

Use zaf to bind FileInput.Root to a file field:

import { FileInput } from '@repo/storage'
import { zaf } from '@repo/form'
import { z } from 'zod'

export const myFormSchema = z.object({
name: z.string(),
file: zaf(z.file(), {
component: FileInput.Root
}),
})

Create

Upload the file and store the returned createdFile.id as a foreign key:

export const createForm = form(myFormSchema, async ({ file, ...data }) => {
await serverFileManager.createBucket('my-bucket')
const { createdFile } = await serverFileManager.sync('my-bucket', { file })
await db.insert(myTable).values({ ...data, fileId: createdFile.id })
})

Update

Pass oldFileId to replace the previous file. The old file is deleted from both S3 and the database:

export const updateForm = form(myFormSchema, async ({ file, ...data }) => {
if (file) {
const oldFileId = await db.select({ fileId }).from(myTable).where(...).then(r => r[0]?.fileId)
const { createdFile } = await serverFileManager.sync('my-bucket', { file, oldFileId })
// createdFile replaces old file
}
})

Editing -- FileInput.Provider

Wrap the form in FileInput.Provider to show the existing file in the input. This enables preview and replacement:

<FileInput.Provider fileMeta={data.existingFile}>
<TypedForm.Remote form={updateForm} enctype='multipart/form-data' />
</FileInput.Provider>

fileMeta expects an object with name, mimeType, size, key, and bucket.