Upload Hooks
Presign, authorize, confirm, and persist verified upload metadata.
Enable upload operations on a named route with upload: true or an UploadConfig object.
import { S3Client } from "@aws-sdk/client-s3";
import { dimahS3, errors, route } from "@dimah-s3/server";
export const awsS3 = new S3Client({/* env */});
export const s3 = dimahS3({
client: awsS3,
bucket: process.env.S3_BUCKET!,
routes: {
avatar: route({
upload: {
fileTypes: ["image/*"],
maxFileSize: 2 * 1024 * 1024,
guard: async ({ request }) => {
const session = await getSession(request);
if (!session) throw errors.unauthorized();
},
onConfirmed: async ({ key, contentLength, request }) => {
const session = await getSession(request);
await db.user.update({
where: { id: session.userId },
data: { avatarKey: key, avatarSize: contentLength },
});
},
},
}),
},
});Upload lifecycle flow
- route.guardhook
- objecthook
- upload.guardhook
- onPresignedhook
- Upload to S3S3
- confirmGuardhook
- HeadObjectserver
- onConfirmedhook
guard: Evaluates session and permissions before key generation.object: Computes destination folder, key, metadata, ACL, storage class, cache control, or tags.onPresigned: Fires after the presigned URL is created.confirmGuard: Authorizes the confirmation request after bytes land in S3.onConfirmed: Reads verified metadata fromHeadObjectand persists the record.
Type reference
import type {
UploadGuardContext,
UploadOnConfirmedContext,
UploadConfirmGuardContext,
UploadObjectContext,
UploadObjectInfo,
UploadOnPresignedContext,
} from "@dimah-s3/server";UploadGuardContext
Runs after upload.object assigns the key (and after global / route guards).
Prop
Type
UploadOnConfirmedContext
Runs after HeadObject validates the uploaded file size and content type.
Prop
Type
UploadConfirmGuardContext
Runs before HeadObject when confirming single-shot uploads or completing multipart uploads.
Prop
Type
UploadObjectContext
Input passed to upload.object to generate custom destination keys and metadata.
Prop
Type
Frequently asked questions
Presign payloads represent client-declared values, which can be spoofed. In onConfirmed, the server queries S3 with HeadObject to obtain the actual byte length and content type.
If onConfirmed throws an error, dimah-s3 automatically performs a best-effort DeleteObject to prevent orphaned files in your S3 bucket.
Return metadata from upload.object:
avatar: route({
upload: {
object: async ({ request, file }) => ({
folder: "avatars",
metadata: {
originalName: file.name,
},
}),
},
});