Delete Hooks
Authorize deletion and execute cleanup after S3 removes the object.
Enable object deletion with delete: true or a DeleteConfig object on a named route.
Unlike upload and download, object deletion is executed directly on your
server using DeleteObjectCommand after passing guard checks. The client
never deletes from S3 directly.
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({
delete: {
guard: async ({ key, request }) => {
const session = await getSession(request);
if (!session) throw errors.unauthorized();
const isOwner = await checkAvatarOwnership(session.userId, key);
if (!isOwner) throw errors.forbidden();
},
onDeleted: async ({ key, request }) => {
const session = await getSession(request);
await db.user.update({
where: { id: session.userId },
data: { avatarKey: null },
});
},
},
}),
},
});Delete lifecycle flow
Before delete.guard, the server resolves the named route and rejects keys
outside its keyPrefix (INVALID_KEY).
- delete.guardhook
- DeleteObject in S3S3
- onDeletedDatabase cleanup
Type reference
import type {
DeleteGuardContext,
DeleteOnDeletedContext,
} from "@dimah-s3/server";DeleteGuardContext
Prop
Type
DeleteOnDeletedContext
Prop
Type
Frequently asked questions
Use deleteMany on the server API or removeMany in the React client. Batch
deletion runs delete.guard and S3 DeleteObject for each key, then
triggers onDeleted for each successfully removed key:
const { removeMany } = useDelete({ route: "avatar" });
await removeMany([key1, key2]);onDeleted does not run for a failed S3 deletion. The endpoint returns an
error response such as 502 S3_NETWORK_ERROR or INTERNAL_ERROR.