@aws-amplify/storage
Version:
Storage category of aws-amplify
152 lines (149 loc) • 7.86 kB
JavaScript
import { StorageAction } from '@aws-amplify/core/internals/utils';
import '@smithy/md5-js';
import '@aws-amplify/core/internals/aws-client-utils';
import '../../utils/client/runtime/s3TransferHandler/fetch.mjs';
import 'fast-xml-parser';
import '../../utils/client/runtime/s3TransferHandler/xhr.mjs';
import 'buffer';
import { resolveS3ConfigAndInput } from '../../utils/resolveS3ConfigAndInput.mjs';
import { assertValidationError } from '../../../../errors/utils/assertValidationError.mjs';
import { StorageValidationErrorCode } from '../../../../errors/types/validation.mjs';
import { logger } from '../../../../utils/logger.mjs';
import { validateBucketOwnerID } from '../../utils/validateBucketOwnerID.mjs';
import { validateStorageOperationInput } from '../../utils/validateStorageOperationInput.mjs';
import { isInputWithPath } from '../../utils/isInputWithPath.mjs';
import '../../utils/client/s3data/base.mjs';
import '../../utils/client/s3data/getObject.mjs';
import '../../utils/client/s3data/listObjectsV2.mjs';
import '../../utils/client/s3data/putObject.mjs';
import '../../utils/client/s3data/createMultipartUpload.mjs';
import '../../utils/client/s3data/uploadPart.mjs';
import '../../utils/client/s3data/completeMultipartUpload.mjs';
import '../../utils/client/s3data/listParts.mjs';
import '../../utils/client/s3data/abortMultipartUpload.mjs';
import { copyObject } from '../../utils/client/s3data/copyObject.mjs';
import '../../utils/client/s3data/headObject.mjs';
import '../../utils/client/s3data/deleteObject.mjs';
import { getStorageUserAgentValue } from '../../utils/userAgent.mjs';
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
const isCopyInputWithPath = (input) => isInputWithPath(input.source);
const storageBucketAssertion = (sourceBucket, destBucket) => {
/** For multi-bucket, both source and destination bucket needs to be passed in
* or both can be undefined and we fallback to singleton's default value
*/
assertValidationError(
// Both src & dest bucket option is present is acceptable
(sourceBucket !== undefined && destBucket !== undefined) ||
// or both are undefined is also acceptable
(!destBucket && !sourceBucket), StorageValidationErrorCode.InvalidCopyOperationStorageBucket);
};
const copy = async (amplify, input) => {
return isCopyInputWithPath(input)
? copyWithPath(amplify, input)
: copyWithKey(amplify, input);
};
const copyWithPath = async (amplify, input) => {
const { source, destination } = input;
storageBucketAssertion(source.bucket, destination.bucket);
const { bucket: sourceBucket } = await resolveS3ConfigAndInput(amplify, {
path: input.source.path,
options: {
locationCredentialsProvider: input.options?.locationCredentialsProvider,
...input.source,
},
});
// The bucket, region, credentials of s3 client are resolved from destination.
// Whereas the source bucket and path are a input parameter of S3 copy operation.
const { s3Config, bucket: destBucket, identityId, } = await resolveS3ConfigAndInput(amplify, {
path: input.destination.path,
options: {
locationCredentialsProvider: input.options?.locationCredentialsProvider,
customEndpoint: input.options?.customEndpoint,
...input.destination,
},
}); // resolveS3ConfigAndInput does not make extra API calls or storage access if called repeatedly.
assertValidationError(!!source.path, StorageValidationErrorCode.NoSourcePath);
assertValidationError(!!destination.path, StorageValidationErrorCode.NoDestinationPath);
const { objectKey: sourcePath } = validateStorageOperationInput(source, identityId);
const { objectKey: destinationPath } = validateStorageOperationInput(destination, identityId);
validateBucketOwnerID(source.expectedBucketOwner);
validateBucketOwnerID(destination.expectedBucketOwner);
const finalCopySource = `${sourceBucket}/${sourcePath}`;
const finalCopyDestination = destinationPath;
logger.debug(`copying "${finalCopySource}" to "${finalCopyDestination}".`);
await serviceCopy({
source: finalCopySource,
destination: finalCopyDestination,
bucket: destBucket,
s3Config,
notModifiedSince: input.source.notModifiedSince,
eTag: input.source.eTag,
expectedSourceBucketOwner: input.source?.expectedBucketOwner,
expectedBucketOwner: input.destination?.expectedBucketOwner,
});
return { path: finalCopyDestination };
};
/** @deprecated Use {@link copyWithPath} instead. */
const copyWithKey = async (amplify, input) => {
const { source, destination } = input;
storageBucketAssertion(source.bucket, destination.bucket);
assertValidationError(!!source.key, StorageValidationErrorCode.NoSourceKey);
assertValidationError(!!destination.key, StorageValidationErrorCode.NoDestinationKey);
validateBucketOwnerID(source.expectedBucketOwner);
validateBucketOwnerID(destination.expectedBucketOwner);
const { bucket: sourceBucket, keyPrefix: sourceKeyPrefix } = await resolveS3ConfigAndInput(amplify, {
...input,
options: {
// @ts-expect-error: 'options' does not exist on type 'CopyInput'. In case of JS users set the location
// credentials provider option, resolveS3ConfigAndInput will throw validation error.
locationCredentialsProvider: input.options?.locationCredentialsProvider,
...input.source,
},
});
// The bucket, region, credentials of s3 client are resolved from destination.
// Whereas the source bucket and path are a input parameter of S3 copy operation.
const { s3Config, bucket: destBucket, keyPrefix: destinationKeyPrefix, } = await resolveS3ConfigAndInput(amplify, {
...input,
options: {
// @ts-expect-error: 'options' does not exist on type 'CopyInput'. In case of JS users set the location
// credentials provider option, resolveS3ConfigAndInput will throw validation error.
locationCredentialsProvider: input.options?.locationCredentialsProvider,
...input.destination,
},
}); // resolveS3ConfigAndInput does not make extra API calls or storage access if called repeatedly.
// TODO(ashwinkumar6) V6-logger: warn `You may copy files from another user if the source level is "protected", currently it's ${srcLevel}`
const finalCopySource = `${sourceBucket}/${sourceKeyPrefix}${source.key}`;
const finalCopyDestination = `${destinationKeyPrefix}${destination.key}`;
logger.debug(`copying "${finalCopySource}" to "${finalCopyDestination}".`);
await serviceCopy({
source: finalCopySource,
destination: finalCopyDestination,
bucket: destBucket,
s3Config,
notModifiedSince: input.source.notModifiedSince,
eTag: input.source.eTag,
expectedSourceBucketOwner: input.source?.expectedBucketOwner,
expectedBucketOwner: input.destination?.expectedBucketOwner,
});
return {
key: destination.key,
};
};
const serviceCopy = async ({ source, destination, bucket, s3Config, notModifiedSince, eTag, expectedSourceBucketOwner, expectedBucketOwner, }) => {
await copyObject({
...s3Config,
userAgentValue: getStorageUserAgentValue(StorageAction.Copy),
}, {
Bucket: bucket,
CopySource: source,
Key: destination,
MetadataDirective: 'COPY',
CopySourceIfMatch: eTag,
CopySourceIfUnmodifiedSince: notModifiedSince,
ExpectedSourceBucketOwner: expectedSourceBucketOwner,
ExpectedBucketOwner: expectedBucketOwner,
});
};
export { copy, copyWithKey };
//# sourceMappingURL=copy.mjs.map