From f143d25728daeb4ffccc606e7c0be3da2f16f3af Mon Sep 17 00:00:00 2001 From: Sasha <64744993+r1tsuu@users.noreply.github.com> Date: Tue, 4 Mar 2025 16:57:30 +0200 Subject: [PATCH] fix(storage-uploadthing): files are duplicated to the storage via client uploads (#11518) When uploading file via client side upload we invalidate it then on the server side with re-uploading. This works fine with most adapters since they just replace the old file under the same key. UploadThing works differently and generates a new key every time. Example of the issue: image Now, we clear the old file before doing re-upload. --- packages/payload/src/types/index.ts | 4 ++++ .../payload/src/utilities/addDataAndFileToRequest.ts | 1 + .../plugin-cloud-storage/src/hooks/beforeChange.ts | 8 +++++++- packages/plugin-cloud-storage/src/types.ts | 2 ++ .../src/utilities/getIncomingFiles.ts | 1 + packages/storage-uploadthing/src/handleUpload.ts | 12 +++++++++++- 6 files changed, 26 insertions(+), 2 deletions(-) diff --git a/packages/payload/src/types/index.ts b/packages/payload/src/types/index.ts index 3c3496f10..b1793e9c5 100644 --- a/packages/payload/src/types/index.ts +++ b/packages/payload/src/types/index.ts @@ -90,6 +90,10 @@ type PayloadRequestData = { data?: JsonObject /** The file on the request, same rules apply as the `data` property */ file?: { + /** + * Context of the file when it was uploaded via client side. + */ + clientUploadContext?: unknown data: Buffer mimetype: string name: string diff --git a/packages/payload/src/utilities/addDataAndFileToRequest.ts b/packages/payload/src/utilities/addDataAndFileToRequest.ts index b08954ccc..4e24fe4ee 100644 --- a/packages/payload/src/utilities/addDataAndFileToRequest.ts +++ b/packages/payload/src/utilities/addDataAndFileToRequest.ts @@ -87,6 +87,7 @@ export const addDataAndFileToRequest: AddDataAndFileToRequest = async (req) => { req.file = { name: filename, + clientUploadContext, data: Buffer.from(await response.arrayBuffer()), mimetype: response.headers.get('Content-Type') || mimeType, size, diff --git a/packages/plugin-cloud-storage/src/hooks/beforeChange.ts b/packages/plugin-cloud-storage/src/hooks/beforeChange.ts index 5450683a8..0503ba5b0 100644 --- a/packages/plugin-cloud-storage/src/hooks/beforeChange.ts +++ b/packages/plugin-cloud-storage/src/hooks/beforeChange.ts @@ -44,7 +44,13 @@ export const getBeforeChangeHook = } const promises = files.map(async (file) => { - await adapter.handleUpload({ collection, data, file, req }) + await adapter.handleUpload({ + clientUploadContext: file.clientUploadContext, + collection, + data, + file, + req, + }) }) await Promise.all(promises) diff --git a/packages/plugin-cloud-storage/src/types.ts b/packages/plugin-cloud-storage/src/types.ts index ca27701e1..a46de6c53 100644 --- a/packages/plugin-cloud-storage/src/types.ts +++ b/packages/plugin-cloud-storage/src/types.ts @@ -10,6 +10,7 @@ import type { export interface File { buffer: Buffer + clientUploadContext?: unknown filename: string filesize: number mimeType: string @@ -28,6 +29,7 @@ export type ClientUploadsConfig = | boolean export type HandleUpload = (args: { + clientUploadContext: unknown collection: CollectionConfig data: any file: File diff --git a/packages/plugin-cloud-storage/src/utilities/getIncomingFiles.ts b/packages/plugin-cloud-storage/src/utilities/getIncomingFiles.ts index 7fa8b8557..282bc55ec 100644 --- a/packages/plugin-cloud-storage/src/utilities/getIncomingFiles.ts +++ b/packages/plugin-cloud-storage/src/utilities/getIncomingFiles.ts @@ -16,6 +16,7 @@ export function getIncomingFiles({ if (file && data.filename && data.mimeType) { const mainFile: File = { buffer: file.data, + clientUploadContext: file.clientUploadContext, filename: data.filename, filesize: file.size, mimeType: data.mimeType, diff --git a/packages/storage-uploadthing/src/handleUpload.ts b/packages/storage-uploadthing/src/handleUpload.ts index a20f59058..738751116 100644 --- a/packages/storage-uploadthing/src/handleUpload.ts +++ b/packages/storage-uploadthing/src/handleUpload.ts @@ -12,8 +12,18 @@ type HandleUploadArgs = { } export const getHandleUpload = ({ acl, utApi }: HandleUploadArgs): HandleUpload => { - return async ({ data, file }) => { + return async ({ clientUploadContext, data, file }) => { try { + if ( + clientUploadContext && + typeof clientUploadContext === 'object' && + 'key' in clientUploadContext && + typeof clientUploadContext.key === 'string' + ) { + // Clear the old file + await utApi.deleteFiles(clientUploadContext.key) + } + const { buffer, filename, mimeType } = file const blob = new Blob([buffer], { type: mimeType })