From 53345cc00dd04df83adc040ebf61701aa4a0f97c Mon Sep 17 00:00:00 2001 From: Braden MacDonald Date: Thu, 14 Mar 2024 23:36:17 -0700 Subject: [PATCH] feat: copyObject() can set new metadata --- client.ts | 20 ++++++++++++-------- integration.ts | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 8 deletions(-) diff --git a/client.ts b/client.ts index 04888e6..d012295 100644 --- a/client.ts +++ b/client.ts @@ -819,7 +819,11 @@ export class Client { public async copyObject( source: { sourceBucketName?: string; sourceKey: string; sourceVersionId?: string }, objectName: string, - options?: { bucketName?: string }, + options?: { + bucketName?: string; + /** Metadata for the new object. If not specified, metadata will be copied from the source. */ + metadata?: ObjectMetadata; + }, ): Promise { const bucketName = this.getBucketName(options); const sourceBucketName = source.sourceBucketName ?? bucketName; @@ -832,13 +836,13 @@ export class Client { let xAmzCopySource = `${sourceBucketName}/${source.sourceKey}`; if (source.sourceVersionId) xAmzCopySource += `?versionId=${source.sourceVersionId}`; - const response = await this.makeRequest({ - method: "PUT", - bucketName, - objectName, - headers: new Headers({ "x-amz-copy-source": xAmzCopySource }), - returnBody: true, - }); + const headers = new Headers(options?.metadata); + if (options?.metadata !== undefined) { + headers.set("x-amz-metadata-directive", "REPLACE"); + } + headers.set("x-amz-copy-source", xAmzCopySource); + + const response = await this.makeRequest({ method: "PUT", bucketName, objectName, headers, returnBody: true }); const responseText = await response.text(); // Parse the response XML. diff --git a/integration.ts b/integration.ts index 544a919..d4e9ef0 100644 --- a/integration.ts +++ b/integration.ts @@ -386,6 +386,40 @@ Deno.test({ }, }); +Deno.test({ + name: "copyObject() copies metadata, but we can override it if we want to", + fn: async () => { + const contents = new Uint8Array([1, 2, 3, 4, 5, 6]); + const sourceKey = "test-copy-metadata-source.txt"; + const destKeySame = "test-copy-metadata-same.txt"; + const destKeyNew = "test-copy-metadata-new.txt"; + + // Create the source file: + const metadata = { + "Content-Type": "test/custom", + "x-amz-meta-custom-key": "custom-value", + }; + await client.putObject(sourceKey, contents, { metadata }); + // Make sure the destination doesn't yet exist: + await client.deleteObject(destKeySame); + assertEquals(await client.exists(destKeySame), false); + + // Copy it with the same metadata: + await client.copyObject({ sourceKey }, destKeySame); + const stat = await client.statObject(destKeySame); + assertEquals(stat.metadata, metadata); + + // Copy it with the different metadata: + const newMetadata = { + "Content-Type": "application/javascript", + "x-amz-meta-other": "new", + }; + await client.copyObject({ sourceKey }, destKeyNew, { metadata: newMetadata }); + const statNew = await client.statObject(destKeyNew); + assertEquals(statNew.metadata, newMetadata); + }, +}); + Deno.test({ name: "bucketExists() can check if a bucket exists", fn: async () => {