Vercel/src/platforms/storage/vercel-blob.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

62 lines
1.7 KiB
TypeScript

import { PATH_API_VERCEL_BLOB_UPLOAD } from '@/app/path';
import { copy, del, list, put } from '@vercel/blob';
import { upload } from '@vercel/blob/client';
import { getFileNamePartsFromStorageUrl, StorageListResponse } from '.';
import { formatBytes } from '@/utility/number';
const VERCEL_BLOB_STORE_ID = process.env.BLOB_READ_WRITE_TOKEN?.match(
/^vercel_blob_rw_([a-z0-9]+)_[a-z0-9]+$/i,
)?.[1].toLowerCase();
export const VERCEL_BLOB_BASE_URL = VERCEL_BLOB_STORE_ID
? `https://${VERCEL_BLOB_STORE_ID}.public.blob.vercel-storage.com`
: undefined;
export const isUrlFromVercelBlob = (url?: string) =>
VERCEL_BLOB_BASE_URL &&
url?.startsWith(VERCEL_BLOB_BASE_URL);
export const vercelBlobUploadFromClient = async (
file: File | Blob,
fileName: string,
): Promise<string> =>
upload(
fileName,
file, {
access: 'public',
handleUploadUrl: PATH_API_VERCEL_BLOB_UPLOAD,
},
)
.then(({ url }) => url);
export const vercelBlobPut = (
file: Buffer,
fileName: string,
): Promise<string> =>
put(fileName, file, { access: 'public' })
.then(({ url }) => url);
export const vercelBlobCopy = (
sourceUrl: string,
destinationFileName: string,
addRandomSuffix?: boolean,
): Promise<string> =>
copy(
sourceUrl,
destinationFileName,
{ access: 'public', addRandomSuffix },
)
.then(({ url }) => url);
export const vercelBlobDelete = (fileName: string) => del(fileName);
export const vercelBlobList = (
prefix: string,
): Promise<StorageListResponse> => list({ prefix })
.then(({ blobs }) => blobs.map(({ url, uploadedAt, size }) => ({
url,
fileName: getFileNamePartsFromStorageUrl(url).fileName,
uploadedAt,
size: formatBytes(size),
})));