@cumulus/aws-client 11.1.4 → 11.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -5
- package/S3.d.ts +2 -0
- package/S3.js +34 -10
- package/S3ObjectStore.d.ts +7 -4
- package/S3ObjectStore.js +9 -6
- package/package.json +5 -5
- package/test-utils.d.ts +2 -0
- package/test-utils.js +10 -1
package/README.md
CHANGED
|
@@ -855,7 +855,9 @@ Copy an S3 object to another location in S3 using a multipart copy
|
|
|
855
855
|
|
|
856
856
|
**Kind**: inner method of [<code>S3</code>](#module_S3)
|
|
857
857
|
**Returns**: <code>Promise.<{etag: string}></code> - object containing the ETag of the
|
|
858
|
-
destination object
|
|
858
|
+
destination object
|
|
859
|
+
|
|
860
|
+
note: this method may error if used with zero byte files. see CUMULUS-2557 and https://github.com/nasa/cumulus/pull/2117.
|
|
859
861
|
|
|
860
862
|
| Param | Type | Default | Description |
|
|
861
863
|
| --- | --- | --- | --- |
|
|
@@ -1163,12 +1165,12 @@ Class to use when interacting with S3
|
|
|
1163
1165
|
**Kind**: global class
|
|
1164
1166
|
|
|
1165
1167
|
* [S3ObjectStore](#S3ObjectStore)
|
|
1166
|
-
* [.signGetObject(objectUrl, [options], [queryParams])](#S3ObjectStore+signGetObject) ⇒ <code>Promise.<string></code>
|
|
1167
|
-
* [.signHeadObject(objectUrl, [options], [queryParams])](#S3ObjectStore+signHeadObject) ⇒ <code>Promise.<string></code>
|
|
1168
|
+
* [.signGetObject(objectUrl, [options], [queryParams], presignOptions)](#S3ObjectStore+signGetObject) ⇒ <code>Promise.<string></code>
|
|
1169
|
+
* [.signHeadObject(objectUrl, [options], [queryParams], presignOptions)](#S3ObjectStore+signHeadObject) ⇒ <code>Promise.<string></code>
|
|
1168
1170
|
|
|
1169
1171
|
<a name="S3ObjectStore+signGetObject"></a>
|
|
1170
1172
|
|
|
1171
|
-
### s3ObjectStore.signGetObject(objectUrl, [options], [queryParams]) ⇒ <code>Promise.<string></code>
|
|
1173
|
+
### s3ObjectStore.signGetObject(objectUrl, [options], [queryParams], presignOptions) ⇒ <code>Promise.<string></code>
|
|
1172
1174
|
Returns an HTTPS URL that can be used to perform a GET on the given object
|
|
1173
1175
|
store URL
|
|
1174
1176
|
|
|
@@ -1184,10 +1186,11 @@ store URL
|
|
|
1184
1186
|
| objectUrl | <code>string</code> | the URL of the object to sign |
|
|
1185
1187
|
| [options] | <code>string</code> | options to pass to S3.getObject |
|
|
1186
1188
|
| [queryParams] | <code>string</code> | a mapping of parameter key/values to put in the URL |
|
|
1189
|
+
| presignOptions | <code>RequestPresigningArguments</code> | presignOptions |
|
|
1187
1190
|
|
|
1188
1191
|
<a name="S3ObjectStore+signHeadObject"></a>
|
|
1189
1192
|
|
|
1190
|
-
### s3ObjectStore.signHeadObject(objectUrl, [options], [queryParams]) ⇒ <code>Promise.<string></code>
|
|
1193
|
+
### s3ObjectStore.signHeadObject(objectUrl, [options], [queryParams], presignOptions) ⇒ <code>Promise.<string></code>
|
|
1191
1194
|
Returns an HTTPS URL that can be used to perform a HEAD on the given object
|
|
1192
1195
|
store URL
|
|
1193
1196
|
|
|
@@ -1203,6 +1206,7 @@ store URL
|
|
|
1203
1206
|
| objectUrl | <code>string</code> | the URL of the object to sign |
|
|
1204
1207
|
| [options] | <code>string</code> | options to pass to S3.getObject |
|
|
1205
1208
|
| [queryParams] | <code>string</code> | a mapping of parameter key/values to put in the URL |
|
|
1209
|
+
| presignOptions | <code>RequestPresigningArguments</code> | presignOptions |
|
|
1206
1210
|
|
|
1207
1211
|
|
|
1208
1212
|
## About Cumulus
|
package/S3.d.ts
CHANGED
|
@@ -409,6 +409,8 @@ export declare const createS3Buckets: (buckets: Array<string>) => Promise<any>;
|
|
|
409
409
|
* @param {number} [params.chunkSize] - chunk size of the S3 multipart uploads
|
|
410
410
|
* @returns {Promise.<{ etag: string }>} object containing the ETag of the
|
|
411
411
|
* destination object
|
|
412
|
+
*
|
|
413
|
+
* note: this method may error if used with zero byte files. see CUMULUS-2557 and https://github.com/nasa/cumulus/pull/2117.
|
|
412
414
|
*/
|
|
413
415
|
export declare const multipartCopyObject: (params: {
|
|
414
416
|
sourceBucket: string;
|
package/S3.js
CHANGED
|
@@ -800,6 +800,8 @@ const uploadPartCopy = async (params) => {
|
|
|
800
800
|
* @param {number} [params.chunkSize] - chunk size of the S3 multipart uploads
|
|
801
801
|
* @returns {Promise.<{ etag: string }>} object containing the ETag of the
|
|
802
802
|
* destination object
|
|
803
|
+
*
|
|
804
|
+
* note: this method may error if used with zero byte files. see CUMULUS-2557 and https://github.com/nasa/cumulus/pull/2117.
|
|
803
805
|
*/
|
|
804
806
|
const multipartCopyObject = async (params) => {
|
|
805
807
|
var _a;
|
|
@@ -870,16 +872,38 @@ exports.multipartCopyObject = multipartCopyObject;
|
|
|
870
872
|
* @returns {Promise<undefined>}
|
|
871
873
|
*/
|
|
872
874
|
const moveObject = async (params) => {
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
875
|
+
const { sourceBucket, sourceKey, destinationBucket, destinationKey, ACL, copyTags, chunkSize, } = params;
|
|
876
|
+
const sourceObject = await (0, exports.headObject)(sourceBucket, sourceKey);
|
|
877
|
+
if (sourceObject.ContentLength === 0) {
|
|
878
|
+
// 0 byte files cannot be copied with multipart upload,
|
|
879
|
+
// so use a regular S3 PUT
|
|
880
|
+
const s3uri = (0, exports.buildS3Uri)(destinationBucket, destinationKey);
|
|
881
|
+
const { CopyObjectResult } = await (0, exports.s3CopyObject)({
|
|
882
|
+
CopySource: path_1.default.join(sourceBucket, sourceKey),
|
|
883
|
+
Bucket: destinationBucket,
|
|
884
|
+
Key: destinationKey,
|
|
885
|
+
});
|
|
886
|
+
// This error should never actually be reached in practice. It's a
|
|
887
|
+
// necessary workaround for bad typings in the AWS SDK.
|
|
888
|
+
// https://github.com/aws/aws-sdk-js/issues/1719
|
|
889
|
+
if (!CopyObjectResult || !CopyObjectResult.ETag) {
|
|
890
|
+
throw new Error(`ETag could not be determined for copy of ${(0, exports.buildS3Uri)(sourceBucket, sourceKey)} to ${s3uri}`);
|
|
891
|
+
}
|
|
892
|
+
}
|
|
893
|
+
else {
|
|
894
|
+
await (0, exports.multipartCopyObject)({
|
|
895
|
+
sourceBucket: sourceBucket,
|
|
896
|
+
sourceKey: sourceKey,
|
|
897
|
+
destinationBucket: destinationBucket,
|
|
898
|
+
destinationKey: destinationKey,
|
|
899
|
+
sourceObject: sourceObject,
|
|
900
|
+
ACL: ACL,
|
|
901
|
+
copyTags: (0, isBoolean_1.default)(copyTags) ? copyTags : true,
|
|
902
|
+
chunkSize: chunkSize,
|
|
903
|
+
});
|
|
904
|
+
}
|
|
905
|
+
const deleteS3ObjRes = await (0, exports.deleteS3Object)(sourceBucket, sourceKey);
|
|
906
|
+
return deleteS3ObjRes;
|
|
883
907
|
};
|
|
884
908
|
exports.moveObject = moveObject;
|
|
885
909
|
//# sourceMappingURL=S3.js.map
|
package/S3ObjectStore.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { GetObjectCommand, HeadObjectCommand, GetObjectCommandInput, S3ClientConfig } from '@aws-sdk/client-s3';
|
|
2
|
+
import { RequestPresigningArguments } from '@aws-sdk/types';
|
|
2
3
|
declare type QueryParams = {
|
|
3
|
-
[key: string]:
|
|
4
|
+
[key: string]: string;
|
|
4
5
|
};
|
|
5
6
|
/**
|
|
6
7
|
* Class to use when interacting with S3
|
|
@@ -13,7 +14,7 @@ declare class S3ObjectStore {
|
|
|
13
14
|
constructor(config?: Partial<S3ClientConfig>);
|
|
14
15
|
getQueryParams(): QueryParams;
|
|
15
16
|
setQueryParams(queryParams: QueryParams): void;
|
|
16
|
-
getS3SignedUrlWithCustomQueryParams(command: GetObjectCommand | HeadObjectCommand): Promise<string>;
|
|
17
|
+
getS3SignedUrlWithCustomQueryParams(command: GetObjectCommand | HeadObjectCommand, presignOptions?: RequestPresigningArguments): Promise<string>;
|
|
17
18
|
/**
|
|
18
19
|
* Returns an HTTPS URL that can be used to perform a GET on the given object
|
|
19
20
|
* store URL
|
|
@@ -21,10 +22,11 @@ declare class S3ObjectStore {
|
|
|
21
22
|
* @param {string} objectUrl - the URL of the object to sign
|
|
22
23
|
* @param {string} [options] - options to pass to S3.getObject
|
|
23
24
|
* @param {string} [queryParams] - a mapping of parameter key/values to put in the URL
|
|
25
|
+
* @param {RequestPresigningArguments} presignOptions - presignOptions
|
|
24
26
|
* @returns {Promise<string>} a signed URL
|
|
25
27
|
* @throws TypeError - if the URL is not a recognized protocol or cannot be parsed
|
|
26
28
|
*/
|
|
27
|
-
signGetObject(objectUrl: string, options?: Partial<GetObjectCommandInput>, queryParams?: QueryParams): Promise<string>;
|
|
29
|
+
signGetObject(objectUrl: string, options?: Partial<GetObjectCommandInput>, queryParams?: QueryParams, presignOptions?: RequestPresigningArguments): Promise<string>;
|
|
28
30
|
/**
|
|
29
31
|
* Returns an HTTPS URL that can be used to perform a HEAD on the given object
|
|
30
32
|
* store URL
|
|
@@ -32,12 +34,13 @@ declare class S3ObjectStore {
|
|
|
32
34
|
* @param {string} objectUrl - the URL of the object to sign
|
|
33
35
|
* @param {string} [options] - options to pass to S3.getObject
|
|
34
36
|
* @param {string} [queryParams] - a mapping of parameter key/values to put in the URL
|
|
37
|
+
* @param {RequestPresigningArguments} presignOptions - presignOptions
|
|
35
38
|
* @returns {Promise<string>} a signed URL
|
|
36
39
|
* @throws TypeError - if the URL is not a recognized protocol or cannot be parsed
|
|
37
40
|
*/
|
|
38
41
|
signHeadObject(objectUrl: string, options: {
|
|
39
42
|
[key: string]: string;
|
|
40
|
-
} | undefined, queryParams: QueryParams): Promise<string>;
|
|
43
|
+
} | undefined, queryParams: QueryParams, presignOptions?: RequestPresigningArguments): Promise<string>;
|
|
41
44
|
}
|
|
42
45
|
export = S3ObjectStore;
|
|
43
46
|
//# sourceMappingURL=S3ObjectStore.d.ts.map
|
package/S3ObjectStore.js
CHANGED
|
@@ -11,6 +11,7 @@ const S3_1 = require("./S3");
|
|
|
11
11
|
const client_1 = __importDefault(require("./client"));
|
|
12
12
|
// Code modified from https://github.com/nasa/harmony/blob/main/app/util/object-store.ts
|
|
13
13
|
const log = new logger_1.default({ sender: '@cumulus/aws-client/S3ObjectStore' });
|
|
14
|
+
const S3_LINK_EXPIRY_SECONDS_DEFAULT = 3600;
|
|
14
15
|
/**
|
|
15
16
|
* Class to use when interacting with S3
|
|
16
17
|
*
|
|
@@ -29,7 +30,7 @@ class S3ObjectStore {
|
|
|
29
30
|
setQueryParams(queryParams) {
|
|
30
31
|
this.queryParams = queryParams;
|
|
31
32
|
}
|
|
32
|
-
async getS3SignedUrlWithCustomQueryParams(command) {
|
|
33
|
+
async getS3SignedUrlWithCustomQueryParams(command, presignOptions = {}) {
|
|
33
34
|
this.s3.middlewareStack.addRelativeTo((next) => (args) => {
|
|
34
35
|
const { request } = args;
|
|
35
36
|
request.query = {
|
|
@@ -42,7 +43,7 @@ class S3ObjectStore {
|
|
|
42
43
|
relation: 'before',
|
|
43
44
|
toMiddleware: 'presignInterceptMiddleware',
|
|
44
45
|
});
|
|
45
|
-
const signedUrl = await (0, s3_request_presigner_1.getSignedUrl)(this.s3, command);
|
|
46
|
+
const signedUrl = await (0, s3_request_presigner_1.getSignedUrl)(this.s3, command, { expiresIn: S3_LINK_EXPIRY_SECONDS_DEFAULT, ...presignOptions });
|
|
46
47
|
this.s3.middlewareStack.remove(this.middlewareName);
|
|
47
48
|
return signedUrl;
|
|
48
49
|
}
|
|
@@ -53,10 +54,11 @@ class S3ObjectStore {
|
|
|
53
54
|
* @param {string} objectUrl - the URL of the object to sign
|
|
54
55
|
* @param {string} [options] - options to pass to S3.getObject
|
|
55
56
|
* @param {string} [queryParams] - a mapping of parameter key/values to put in the URL
|
|
57
|
+
* @param {RequestPresigningArguments} presignOptions - presignOptions
|
|
56
58
|
* @returns {Promise<string>} a signed URL
|
|
57
59
|
* @throws TypeError - if the URL is not a recognized protocol or cannot be parsed
|
|
58
60
|
*/
|
|
59
|
-
async signGetObject(objectUrl, options = {}, queryParams = {}) {
|
|
61
|
+
async signGetObject(objectUrl, options = {}, queryParams = {}, presignOptions = {}) {
|
|
60
62
|
log.info(`Executing signGetObject with objectUrl: ${objectUrl}, options: ${JSON.stringify(options)}, queryParams: ${JSON.stringify(queryParams)}`);
|
|
61
63
|
const url = new url_1.URL(objectUrl);
|
|
62
64
|
if (url.protocol.toLowerCase() !== 's3:') {
|
|
@@ -66,7 +68,7 @@ class S3ObjectStore {
|
|
|
66
68
|
await (0, S3_1.headObject)(Bucket, Key);
|
|
67
69
|
const command = new client_s3_1.GetObjectCommand({ Bucket, Key, ...options });
|
|
68
70
|
this.setQueryParams(queryParams);
|
|
69
|
-
const signedUrl = await this.getS3SignedUrlWithCustomQueryParams(command);
|
|
71
|
+
const signedUrl = await this.getS3SignedUrlWithCustomQueryParams(command, presignOptions);
|
|
70
72
|
log.debug(`Signed GetObject request URL: ${signedUrl}`);
|
|
71
73
|
return signedUrl;
|
|
72
74
|
}
|
|
@@ -77,10 +79,11 @@ class S3ObjectStore {
|
|
|
77
79
|
* @param {string} objectUrl - the URL of the object to sign
|
|
78
80
|
* @param {string} [options] - options to pass to S3.getObject
|
|
79
81
|
* @param {string} [queryParams] - a mapping of parameter key/values to put in the URL
|
|
82
|
+
* @param {RequestPresigningArguments} presignOptions - presignOptions
|
|
80
83
|
* @returns {Promise<string>} a signed URL
|
|
81
84
|
* @throws TypeError - if the URL is not a recognized protocol or cannot be parsed
|
|
82
85
|
*/
|
|
83
|
-
async signHeadObject(objectUrl, options = {}, queryParams) {
|
|
86
|
+
async signHeadObject(objectUrl, options = {}, queryParams, presignOptions = {}) {
|
|
84
87
|
log.info(`Executing signHeadObject with objectUrl: ${objectUrl}, options: ${JSON.stringify(options)}, queryParams: ${JSON.stringify(queryParams)}`);
|
|
85
88
|
const url = new url_1.URL(objectUrl);
|
|
86
89
|
if (url.protocol.toLowerCase() !== 's3:') {
|
|
@@ -89,7 +92,7 @@ class S3ObjectStore {
|
|
|
89
92
|
const { Bucket, Key } = (0, S3_1.parseS3Uri)(objectUrl);
|
|
90
93
|
const command = new client_s3_1.HeadObjectCommand({ Bucket, Key, ...options });
|
|
91
94
|
this.setQueryParams(queryParams);
|
|
92
|
-
const signedUrl = await this.getS3SignedUrlWithCustomQueryParams(command);
|
|
95
|
+
const signedUrl = await this.getS3SignedUrlWithCustomQueryParams(command, presignOptions);
|
|
93
96
|
log.debug(`Signed HeadObject request URL: ${signedUrl}`);
|
|
94
97
|
return signedUrl;
|
|
95
98
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cumulus/aws-client",
|
|
3
|
-
"version": "11.1.
|
|
3
|
+
"version": "11.1.6",
|
|
4
4
|
"description": "Utilities for working with AWS",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"GIBS",
|
|
@@ -51,9 +51,9 @@
|
|
|
51
51
|
"@aws-sdk/s3-request-presigner": "^3.53.0",
|
|
52
52
|
"@aws-sdk/signature-v4-crt": "^3.53.0",
|
|
53
53
|
"@aws-sdk/types": "^3.53.0",
|
|
54
|
-
"@cumulus/checksum": "11.1.
|
|
55
|
-
"@cumulus/errors": "11.1.
|
|
56
|
-
"@cumulus/logger": "11.1.
|
|
54
|
+
"@cumulus/checksum": "11.1.6",
|
|
55
|
+
"@cumulus/errors": "11.1.6",
|
|
56
|
+
"@cumulus/logger": "11.1.6",
|
|
57
57
|
"aws-sdk": "^2.585.0",
|
|
58
58
|
"jsonpath-plus": "^1.1.0",
|
|
59
59
|
"lodash": "~4.17.21",
|
|
@@ -68,5 +68,5 @@
|
|
|
68
68
|
"devDependencies": {
|
|
69
69
|
"@types/uuid": "^8.0.0"
|
|
70
70
|
},
|
|
71
|
-
"gitHead": "
|
|
71
|
+
"gitHead": "cc17225ec1ded9cc2d2b1decc952da97ce0df072"
|
|
72
72
|
}
|
package/test-utils.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { Readable } from 'stream';
|
|
1
2
|
import { AWSClientTypes } from './types';
|
|
2
3
|
export declare const inTestMode: () => boolean;
|
|
3
4
|
declare const localStackPorts: {
|
|
@@ -75,5 +76,6 @@ export declare function getLocalstackAwsClientOptions<T extends AWSClientTypes>(
|
|
|
75
76
|
* @private
|
|
76
77
|
*/
|
|
77
78
|
export declare const throttleOnce: (fn: (...args: unknown[]) => unknown) => (...args: unknown[]) => unknown;
|
|
79
|
+
export declare const streamToString: (stream: Readable) => Promise<unknown>;
|
|
78
80
|
export {};
|
|
79
81
|
//# sourceMappingURL=test-utils.d.ts.map
|
package/test-utils.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.throttleOnce = exports.getLocalstackAwsClientOptions = exports.localStackAwsClientOptions = exports.getLocalstackEndpoint = exports.inTestMode = void 0;
|
|
3
|
+
exports.streamToString = exports.throttleOnce = exports.getLocalstackAwsClientOptions = exports.localStackAwsClientOptions = exports.getLocalstackEndpoint = exports.inTestMode = void 0;
|
|
4
4
|
const errors_1 = require("@cumulus/errors");
|
|
5
5
|
const utils_1 = require("./utils");
|
|
6
6
|
const inTestMode = () => process.env.NODE_ENV === 'test';
|
|
@@ -130,4 +130,13 @@ const throttleOnce = (fn) => {
|
|
|
130
130
|
};
|
|
131
131
|
};
|
|
132
132
|
exports.throttleOnce = throttleOnce;
|
|
133
|
+
const streamToString = (stream) => {
|
|
134
|
+
let result = '';
|
|
135
|
+
// eslint-disable-next-line no-return-assign
|
|
136
|
+
stream.on('data', (chunk) => result += chunk.toString());
|
|
137
|
+
return new Promise((resolve) => {
|
|
138
|
+
stream.on('end', () => resolve(result));
|
|
139
|
+
});
|
|
140
|
+
};
|
|
141
|
+
exports.streamToString = streamToString;
|
|
133
142
|
//# sourceMappingURL=test-utils.js.map
|