From f641d5e8cabab49f05511578122120cf1ef77d8a Mon Sep 17 00:00:00 2001 From: Fabrizio Date: Thu, 2 May 2024 16:08:26 +0100 Subject: [PATCH] feat: signed upload URL upsert (#199) --- infra/storage/Dockerfile | 2 +- src/packages/StorageFileApi.ts | 12 ++++++++++-- test/storageFileApi.test.ts | 21 +++++++++++++++++++++ 3 files changed, 32 insertions(+), 3 deletions(-) diff --git a/infra/storage/Dockerfile b/infra/storage/Dockerfile index 3ab158e..ed3db4f 100644 --- a/infra/storage/Dockerfile +++ b/infra/storage/Dockerfile @@ -1,3 +1,3 @@ -FROM supabase/storage-api:v1.0.10 +FROM supabase/storage-api:v1.2.1 RUN apk add curl --no-cache \ No newline at end of file diff --git a/src/packages/StorageFileApi.ts b/src/packages/StorageFileApi.ts index 7b0913b..1f9417e 100644 --- a/src/packages/StorageFileApi.ts +++ b/src/packages/StorageFileApi.ts @@ -220,9 +220,11 @@ export default class StorageFileApi { * Signed upload URLs can be used to upload files to the bucket without further authentication. * They are valid for 2 hours. * @param path The file path, including the current file name. For example `folder/image.png`. + * @param options.upsert If set to true, allows the file to be overwritten if it already exists. */ async createSignedUploadUrl( - path: string + path: string, + options?: { upsert: boolean } ): Promise< | { data: { signedUrl: string; token: string; path: string } @@ -236,11 +238,17 @@ export default class StorageFileApi { try { let _path = this._getFinalPath(path) + const headers = { ...this.headers } + + if (options?.upsert) { + headers['x-upsert'] = 'true' + } + const data = await post( this.fetch, `${this.url}/object/upload/sign/${_path}`, {}, - { headers: this.headers } + { headers } ) const url = new URL(this.url + data.url) diff --git a/test/storageFileApi.test.ts b/test/storageFileApi.test.ts index 58a2703..78da022 100644 --- a/test/storageFileApi.test.ts +++ b/test/storageFileApi.test.ts @@ -242,6 +242,26 @@ describe('Object API', () => { expect(uploadRes.data?.path).toEqual(uploadPath) }) + test('can upload overwriting files with a signed url', async () => { + const { error: uploadErr } = await storage.from(bucketName).upload(uploadPath, file) + + expect(uploadErr).toBeNull() + + const { data, error } = await storage.from(bucketName).createSignedUploadUrl(uploadPath, { + upsert: true, + }) + + expect(error).toBeNull() + assert(data?.path) + + const uploadRes = await storage + .from(bucketName) + .uploadToSignedUrl(data.path, data.token, file) + + expect(uploadRes.error).toBeNull() + expect(uploadRes.data?.path).toEqual(uploadPath) + }) + test('cannot upload to a signed url twice', async () => { const { data, error } = await storage.from(bucketName).createSignedUploadUrl(uploadPath) @@ -258,6 +278,7 @@ describe('Object API', () => { const uploadRes2 = await storage .from(bucketName) .uploadToSignedUrl(data.path, data.token, file) + expect(uploadRes2.error).toEqual({ error: 'Duplicate', message: 'The resource already exists',