Harden client uploads and add storage fallback
Validate presigned upload responses and fall back to Vercel Blob when third-party storage upload fails so photo uploads remain available. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
d5001c9ee5
commit
053a3b4acc
@ -119,11 +119,27 @@ export const uploadFromClientViaPresignedUrl = async (
|
|||||||
file: File | Blob,
|
file: File | Blob,
|
||||||
fileName: string,
|
fileName: string,
|
||||||
) => {
|
) => {
|
||||||
const url = await fetch(`${PATH_API_PRESIGNED_URL}/${fileName}`)
|
const response = await fetch(`${PATH_API_PRESIGNED_URL}/${fileName}`);
|
||||||
.then((response) => response.text());
|
if (!response.ok) {
|
||||||
|
throw new Error(
|
||||||
|
`Failed to get presigned URL: ${response.status} ${response.statusText}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return fetch(url, { method: 'PUT', body: file })
|
const url = (await response.text()).trim();
|
||||||
.then(() => `${baseUrlForStorage(CURRENT_STORAGE)}/${fileName}`);
|
|
||||||
|
if (!/^https?:\/\//i.test(url)) {
|
||||||
|
throw new Error('Invalid presigned URL response');
|
||||||
|
}
|
||||||
|
|
||||||
|
const uploadResponse = await fetch(url, { method: 'PUT', body: file });
|
||||||
|
if (!uploadResponse.ok) {
|
||||||
|
throw new Error(
|
||||||
|
`Failed to upload with presigned URL: ${uploadResponse.status} ${uploadResponse.statusText}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return `${baseUrlForStorage(CURRENT_STORAGE)}/${fileName}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const uploadFileFromClient = async (
|
export const uploadFileFromClient = async (
|
||||||
@ -136,13 +152,24 @@ export const uploadFileFromClient = async (
|
|||||||
? `${_fileName}-${generateStorageId()}.${extension}`
|
? `${_fileName}-${generateStorageId()}.${extension}`
|
||||||
: `${_fileName}.${extension}`;
|
: `${_fileName}.${extension}`;
|
||||||
|
|
||||||
return (
|
if (
|
||||||
CURRENT_STORAGE === 'cloudflare-r2' ||
|
CURRENT_STORAGE === 'cloudflare-r2' ||
|
||||||
CURRENT_STORAGE === 'aws-s3' ||
|
CURRENT_STORAGE === 'aws-s3' ||
|
||||||
CURRENT_STORAGE === 'minio'
|
CURRENT_STORAGE === 'minio'
|
||||||
)
|
) {
|
||||||
? uploadFromClientViaPresignedUrl(file, fileName)
|
try {
|
||||||
: vercelBlobUploadFromClient(file, fileName);
|
return await uploadFromClientViaPresignedUrl(file, fileName);
|
||||||
|
} catch (error) {
|
||||||
|
// Fall back to Vercel Blob when configured, so uploads stay available
|
||||||
|
// even if third-party object storage is temporarily unreachable.
|
||||||
|
if (HAS_VERCEL_BLOB_STORAGE) {
|
||||||
|
return vercelBlobUploadFromClient(file, fileName);
|
||||||
|
}
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return vercelBlobUploadFromClient(file, fileName);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const putFile = (
|
export const putFile = (
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user