Vercel/app/api/storage/vercel-blob/route.ts
Sam Becker b8c01492b8
Store optimized assets for all photos (#304)
* Begin storing optimized photo files

* Increase optimized image size to 1080

* Refactor photo/storage modules

* Refine storage file naming api

* Simplify photo storage api

* Finalize photo storage api

* Start storing/serving optimized photos

* Finalize optimized photo asset generation

* Temporarily allow static optimization on PREVIEW branches

* Restore static optimization as production-only

* Remove og image inline-flex class

* Tweak convert upload signature

* Refactor optimized file storage

* Display optimized files when they exist in photo form

* Create small disclosure component

* Report photo storage files more accurately

* Sort optimized files

* Generate optimized storage files when updating/syncing photos

* Include source bucket when copying files with MinIO

* Make deleting files more resilient
2025-09-06 23:20:20 -05:00

50 lines
1.5 KiB
TypeScript

import { auth } from '@/auth/server';
import { revalidateAdminPaths, revalidatePhotosKey } from '@/photo/cache';
import {
ACCEPTED_PHOTO_FILE_TYPES,
MAX_PHOTO_UPLOAD_SIZE_IN_BYTES,
} from '@/photo';
import { handleUpload, type HandleUploadBody } from '@vercel/blob/client';
import { NextResponse } from 'next/server';
import { isUploadPathnameValid } from '@/photo/storage';
export async function POST(request: Request): Promise<NextResponse> {
const body: HandleUploadBody = await request.json();
try {
const jsonResponse = await handleUpload({
body,
request,
onBeforeGenerateToken: async (pathname) => {
const session = await auth();
if (session?.user) {
if (isUploadPathnameValid(pathname)) {
return {
maximumSizeInBytes: MAX_PHOTO_UPLOAD_SIZE_IN_BYTES,
allowedContentTypes: ACCEPTED_PHOTO_FILE_TYPES,
addRandomSuffix: true,
};
} else {
throw new Error('Invalid upload');
}
} else {
throw new Error('Unauthenticated upload');
}
},
// This argument is required, but doesn't seem to fire
onUploadCompleted: async () => {
revalidatePhotosKey();
revalidateAdminPaths();
},
});
revalidatePhotosKey();
revalidateAdminPaths();
return NextResponse.json(jsonResponse);
} catch (error) {
return NextResponse.json(
{ error: (error as Error).message },
{ status: 400 },
);
}
}