@pi-r/aws-v3 0.11.2 → 0.12.0
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/client/index.js +105 -105
- package/download/index.js +13 -11
- package/package.json +9 -9
- package/upload/index.js +29 -28
package/client/index.js
CHANGED
|
@@ -1,42 +1,27 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
exports.setBucketWebsite = setBucketWebsite;
|
|
12
|
-
exports.deleteObjects = deleteObjects;
|
|
13
|
-
exports.deleteObjectsV2 = deleteObjectsV2;
|
|
14
|
-
exports.deleteObjectsV3 = deleteObjectsV3;
|
|
15
|
-
exports.copyObject = copyObject;
|
|
16
|
-
exports.executeQuery = executeQuery;
|
|
17
|
-
exports.executeBatchQuery = executeBatchQuery;
|
|
18
|
-
const S3 = require("@aws-sdk/client-s3");
|
|
19
|
-
const Lib = require("@aws-sdk/lib-dynamodb");
|
|
20
|
-
const Client = require("@aws-sdk/client-dynamodb");
|
|
21
|
-
const Providers = require("@aws-sdk/credential-providers");
|
|
22
|
-
const Cloud = require("@e-mc/cloud");
|
|
23
|
-
const types_1 = require("@e-mc/types");
|
|
24
|
-
const util_1 = require("@e-mc/cloud/util");
|
|
25
|
-
const aws_lib_1 = require("@pi-r/aws-lib");
|
|
2
|
+
|
|
3
|
+
const s3 = require('@aws-sdk/client-s3');
|
|
4
|
+
const dynamo = require('@aws-sdk/lib-dynamodb');
|
|
5
|
+
const { DynamoDBClient } = require('@aws-sdk/client-dynamodb');
|
|
6
|
+
const { fromCognitoIdentity, fromCognitoIdentityPool, fromContainerMetadata, fromEnv, fromHttp, fromIni, fromInstanceMetadata, fromNodeProviderChain, fromProcess, fromSSO, fromTemporaryCredentials, fromTokenFile, fromWebToken } = require('@aws-sdk/credential-providers');
|
|
7
|
+
const Cloud = require('@e-mc/cloud');
|
|
8
|
+
const { isArray, isError, isPlainObject, isString } = require('@e-mc/types');
|
|
9
|
+
const { formatError } = require('@e-mc/cloud/util');
|
|
10
|
+
const { checkBucketCannedACL, getBucketPublicReadPolicy, getPrivatePolicy, getPublicReadPolicy, isAccessDefined, isDatabaseDefined, isEnvDefined, isSharedCredentialsDefined, setDatabaseEndpoint } = require('@pi-r/aws-lib');
|
|
26
11
|
async function setCannedAcl(instance, client, Bucket, ACL, service = "aws-v3", recursive) {
|
|
27
12
|
let Policy;
|
|
28
13
|
switch (ACL) {
|
|
29
14
|
case 1:
|
|
30
|
-
Policy =
|
|
15
|
+
Policy = getBucketPublicReadPolicy(Bucket);
|
|
31
16
|
break;
|
|
32
17
|
case "public-read-write":
|
|
33
|
-
Policy =
|
|
18
|
+
Policy = getPublicReadPolicy(Bucket, false, true);
|
|
34
19
|
break;
|
|
35
20
|
case "authenticated-read":
|
|
36
|
-
Policy =
|
|
21
|
+
Policy = getPublicReadPolicy(Bucket, true);
|
|
37
22
|
break;
|
|
38
23
|
default:
|
|
39
|
-
Policy =
|
|
24
|
+
Policy = getPrivatePolicy(Bucket);
|
|
40
25
|
break;
|
|
41
26
|
}
|
|
42
27
|
return client.send(new instance.PutBucketPolicyCommand({ Bucket, Policy }))
|
|
@@ -44,7 +29,7 @@ async function setCannedAcl(instance, client, Bucket, ACL, service = "aws-v3", r
|
|
|
44
29
|
this.formatMessage(64, service, ['Grant ' + ACL, Bucket], '', Cloud.optionsLogMessage(recursive ? 'DELAYED' : 'COMMAND'));
|
|
45
30
|
})
|
|
46
31
|
.catch((err) => {
|
|
47
|
-
if (!recursive && err
|
|
32
|
+
if (!recursive && isError(err)) {
|
|
48
33
|
if (err.name === 'OperationAborted') {
|
|
49
34
|
setTimeout(async () => setCannedAcl.call(this, instance, client, Bucket, ACL, service, true), 60000);
|
|
50
35
|
this.formatMessage(64, service, [`Grant ${ACL} (delayed)`, err.Endpoint || Bucket], err, Cloud.optionsLogMessage('DELAYED'));
|
|
@@ -58,58 +43,58 @@ async function setCannedAcl(instance, client, Bucket, ACL, service = "aws-v3", r
|
|
|
58
43
|
function fromProvider(credential) {
|
|
59
44
|
const from = credential.provider;
|
|
60
45
|
let credentials = credential.credentials;
|
|
61
|
-
if (
|
|
46
|
+
if (isPlainObject(from)) {
|
|
62
47
|
if (from.http) {
|
|
63
|
-
credentials =
|
|
48
|
+
credentials = fromHttp(isPlainObject(from.http) ? from.http : {});
|
|
64
49
|
}
|
|
65
|
-
else if (
|
|
66
|
-
credentials =
|
|
50
|
+
else if (isPlainObject(from.ini)) {
|
|
51
|
+
credentials = fromIni(from.ini);
|
|
67
52
|
}
|
|
68
|
-
else if (
|
|
69
|
-
credentials =
|
|
53
|
+
else if (isPlainObject(from.cognitoIdentity)) {
|
|
54
|
+
credentials = fromCognitoIdentity(from.cognitoIdentity);
|
|
70
55
|
}
|
|
71
|
-
else if (
|
|
72
|
-
credentials =
|
|
56
|
+
else if (isPlainObject(from.cognitoIdentityPool)) {
|
|
57
|
+
credentials = fromCognitoIdentityPool(from.cognitoIdentityPool);
|
|
73
58
|
}
|
|
74
|
-
else if (
|
|
75
|
-
credentials =
|
|
59
|
+
else if (isPlainObject(from.temporaryCredentials)) {
|
|
60
|
+
credentials = fromTemporaryCredentials(from.temporaryCredentials);
|
|
76
61
|
}
|
|
77
|
-
else if (
|
|
78
|
-
credentials =
|
|
62
|
+
else if (isPlainObject(from.webToken)) {
|
|
63
|
+
credentials = fromWebToken(from.webToken);
|
|
79
64
|
}
|
|
80
|
-
else if (
|
|
81
|
-
credentials =
|
|
65
|
+
else if (isPlainObject(from.containerMetadata)) {
|
|
66
|
+
credentials = fromContainerMetadata(from.containerMetadata);
|
|
82
67
|
}
|
|
83
|
-
else if (
|
|
84
|
-
credentials =
|
|
68
|
+
else if (isPlainObject(from.instanceMetadata)) {
|
|
69
|
+
credentials = fromInstanceMetadata(from.instanceMetadata);
|
|
85
70
|
}
|
|
86
|
-
else if (
|
|
87
|
-
credentials =
|
|
71
|
+
else if (isPlainObject(from.process)) {
|
|
72
|
+
credentials = fromProcess(from.process);
|
|
88
73
|
}
|
|
89
|
-
else if (
|
|
90
|
-
credentials =
|
|
74
|
+
else if (isPlainObject(from.tokenFile)) {
|
|
75
|
+
credentials = fromTokenFile(from.tokenFile);
|
|
91
76
|
}
|
|
92
|
-
else if (
|
|
93
|
-
credentials =
|
|
77
|
+
else if (isPlainObject(from.sso)) {
|
|
78
|
+
credentials = fromSSO(from.sso);
|
|
94
79
|
}
|
|
95
|
-
else if (from.env &&
|
|
96
|
-
credentials =
|
|
80
|
+
else if (from.env && isEnvDefined()) {
|
|
81
|
+
credentials = fromEnv();
|
|
97
82
|
}
|
|
98
|
-
else if (from.ini &&
|
|
99
|
-
credentials =
|
|
83
|
+
else if (from.ini && isSharedCredentialsDefined()) {
|
|
84
|
+
credentials = fromIni();
|
|
100
85
|
}
|
|
101
|
-
if (
|
|
86
|
+
if (isPlainObject(credentials)) {
|
|
102
87
|
if (from.nodeProviderChain) {
|
|
103
|
-
credentials =
|
|
88
|
+
credentials = fromNodeProviderChain(isPlainObject(from.nodeProviderChain) ? { ...credentials, ...from.nodeProviderChain } : credentials);
|
|
104
89
|
}
|
|
105
90
|
credential.credentials = credentials;
|
|
106
91
|
}
|
|
107
92
|
delete credential.provider;
|
|
108
93
|
}
|
|
109
|
-
if (
|
|
94
|
+
if (isPlainObject(credentials)) {
|
|
110
95
|
let expiration = credentials.expiration;
|
|
111
96
|
if (expiration) {
|
|
112
|
-
if (
|
|
97
|
+
if (isString(expiration)) {
|
|
113
98
|
expiration = new Date(expiration);
|
|
114
99
|
credentials.expiration = expiration;
|
|
115
100
|
}
|
|
@@ -120,10 +105,10 @@ function fromProvider(credential) {
|
|
|
120
105
|
}
|
|
121
106
|
return credential;
|
|
122
107
|
}
|
|
123
|
-
const isNoSuchBucket = (err) => err
|
|
108
|
+
const isNoSuchBucket = (err) => isError(err, 'NoSuchBucket');
|
|
124
109
|
function createStorageClient(credential, service = "aws-v3", sdk = "@aws-sdk/client-s3") {
|
|
125
110
|
try {
|
|
126
|
-
const AWS = sdk === "@aws-sdk/client-s3" ?
|
|
111
|
+
const AWS = sdk === "@aws-sdk/client-s3" ? s3 : require(sdk);
|
|
127
112
|
return [new AWS.S3Client(fromProvider(credential)), AWS];
|
|
128
113
|
}
|
|
129
114
|
catch (err) {
|
|
@@ -132,25 +117,25 @@ function createStorageClient(credential, service = "aws-v3", sdk = "@aws-sdk/cli
|
|
|
132
117
|
}
|
|
133
118
|
}
|
|
134
119
|
function createDatabaseClient(credential) {
|
|
135
|
-
return [
|
|
120
|
+
return [dynamo.DynamoDBDocumentClient.from(new DynamoDBClient(fromProvider(credential)), credential.translateConfig), dynamo];
|
|
136
121
|
}
|
|
137
122
|
function validateStorage(credential) {
|
|
138
123
|
const credentials = credential.credentials;
|
|
139
|
-
if (!credentials && !credential.provider &&
|
|
140
|
-
credential.credentials =
|
|
124
|
+
if (!credentials && !credential.provider && isSharedCredentialsDefined()) {
|
|
125
|
+
credential.credentials = fromIni();
|
|
141
126
|
return true;
|
|
142
127
|
}
|
|
143
|
-
return !!credentials && (
|
|
128
|
+
return !!credentials && (isAccessDefined(credentials) || typeof credentials === 'function') || isPlainObject(credential.provider) || isEnvDefined();
|
|
144
129
|
}
|
|
145
130
|
function validateDatabase(credential, data) {
|
|
146
|
-
return
|
|
131
|
+
return isDatabaseDefined(credential, data) && validateStorage(credential);
|
|
147
132
|
}
|
|
148
133
|
async function createBucket(credential, Bucket, publicRead, service = "aws-v3", sdk = "@aws-sdk/client-s3") {
|
|
149
134
|
return createBucketV2.call(this, credential, Bucket, publicRead ? "public-read" : undefined, undefined, service, sdk);
|
|
150
135
|
}
|
|
151
136
|
async function createBucketV2(credential, Bucket, ACL, options, service = "aws-v3", sdk = "@aws-sdk/client-s3") {
|
|
152
137
|
if (ACL !== 1) {
|
|
153
|
-
ACL =
|
|
138
|
+
ACL = checkBucketCannedACL(ACL);
|
|
154
139
|
}
|
|
155
140
|
const [client, AWS] = createStorageClient.call(this, credential, service, sdk);
|
|
156
141
|
return client.send(new AWS.HeadBucketCommand({ Bucket }))
|
|
@@ -172,7 +157,7 @@ async function createBucketV2(credential, Bucket, ACL, options, service = "aws-v
|
|
|
172
157
|
}
|
|
173
158
|
if (!config.LocationConstraint) {
|
|
174
159
|
const region = credential.region;
|
|
175
|
-
if (
|
|
160
|
+
if (isString(region) && region !== "us-east-1") {
|
|
176
161
|
config.LocationConstraint = region;
|
|
177
162
|
}
|
|
178
163
|
}
|
|
@@ -185,17 +170,14 @@ async function createBucketV2(credential, Bucket, ACL, options, service = "aws-v
|
|
|
185
170
|
return true;
|
|
186
171
|
})
|
|
187
172
|
.catch(async (err) => {
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
}
|
|
194
|
-
return true;
|
|
195
|
-
default:
|
|
196
|
-
this.formatFail(64, service, ["Unable to create bucket", Bucket], err, Cloud.optionsLogMessage('FAIL'));
|
|
197
|
-
return false;
|
|
173
|
+
if (isError(err, 'BucketAlreadyExists', 'BucketAlreadyOwnedByYou')) {
|
|
174
|
+
if (ACL) {
|
|
175
|
+
await setCannedAcl.call(this, AWS, client, Bucket, ACL, service);
|
|
176
|
+
}
|
|
177
|
+
return true;
|
|
198
178
|
}
|
|
179
|
+
this.formatFail(64, service, ["Unable to create bucket", Bucket], err, Cloud.optionsLogMessage('FAIL'));
|
|
180
|
+
return false;
|
|
199
181
|
});
|
|
200
182
|
});
|
|
201
183
|
}
|
|
@@ -217,7 +199,7 @@ async function setBucketPolicy(credential, Bucket, options, service = "aws-v3",
|
|
|
217
199
|
});
|
|
218
200
|
}
|
|
219
201
|
async function setBucketTagging(credential, Bucket, options, service = "aws-v3", sdk = "@aws-sdk/client-s3") {
|
|
220
|
-
if (!
|
|
202
|
+
if (!isPlainObject(options) || !Array.isArray(options.Tagging?.TagSet)) {
|
|
221
203
|
return false;
|
|
222
204
|
}
|
|
223
205
|
const [client, AWS] = createStorageClient.call(this, credential, service, sdk);
|
|
@@ -247,10 +229,10 @@ async function setBucketWebsite(credential, Bucket, options, service = "aws-v3",
|
|
|
247
229
|
const [client, AWS] = createStorageClient.call(this, credential, service, sdk);
|
|
248
230
|
const WebsiteConfiguration = {};
|
|
249
231
|
const { indexPage: Suffix, errorPage: Key } = options;
|
|
250
|
-
if (
|
|
232
|
+
if (isString(Suffix)) {
|
|
251
233
|
WebsiteConfiguration.IndexDocument = { Suffix };
|
|
252
234
|
}
|
|
253
|
-
if (
|
|
235
|
+
if (isString(Key)) {
|
|
254
236
|
WebsiteConfiguration.ErrorDocument = { Key };
|
|
255
237
|
}
|
|
256
238
|
return client.send(new AWS.PutBucketWebsiteCommand({ Bucket, WebsiteConfiguration }))
|
|
@@ -265,8 +247,8 @@ async function setBucketWebsite(credential, Bucket, options, service = "aws-v3",
|
|
|
265
247
|
return false;
|
|
266
248
|
});
|
|
267
249
|
}
|
|
268
|
-
async function deleteObjects(credential, Bucket, service, sdk
|
|
269
|
-
return
|
|
250
|
+
async function deleteObjects(credential, Bucket, options, service, sdk) {
|
|
251
|
+
return deleteObjectsV3.call(this, credential, Bucket, options, service, sdk);
|
|
270
252
|
}
|
|
271
253
|
async function deleteObjectsV2(credential, Bucket, recursive = true, service, sdk) {
|
|
272
254
|
return deleteObjectsV3.call(this, credential, Bucket, { recursive, Bucket }, service, sdk);
|
|
@@ -289,7 +271,7 @@ async function deleteObjectsV3(credential, Bucket, options = {}, service = "aws-
|
|
|
289
271
|
}
|
|
290
272
|
return client.send(new AWS.DeleteObjectsCommand({ Bucket, Delete: { Objects } }))
|
|
291
273
|
.then(data => {
|
|
292
|
-
if (
|
|
274
|
+
if (isArray(data.Deleted)) {
|
|
293
275
|
const files = data.Deleted.length + ' files';
|
|
294
276
|
this.formatMessage(64, service, ["Bucket emptied" + ` (${recursive ? 'recursive' : files})`, Bucket], recursive ? files : '', Cloud.optionsLogMessage('COMMAND'));
|
|
295
277
|
}
|
|
@@ -309,7 +291,7 @@ async function copyObject(credential, BucketSource, KeySource, Bucket, Key, opti
|
|
|
309
291
|
const [client, AWS] = createStorageClient.call(this, credential, service, sdk);
|
|
310
292
|
const index = Key.lastIndexOf('/');
|
|
311
293
|
if (index !== -1) {
|
|
312
|
-
await client.send(new AWS.PutObjectCommand({ Bucket, Key: Key.
|
|
294
|
+
await client.send(new AWS.PutObjectCommand({ Bucket, Key: Key.slice(0, index + 1), Body: Buffer.from(''), ContentLength: 0 })).catch(() => { });
|
|
313
295
|
}
|
|
314
296
|
const CopySource = BucketSource + '/' + KeySource;
|
|
315
297
|
return client.send(new AWS.CopyObjectCommand({ ...options, Bucket, Key, CopySource }))
|
|
@@ -331,17 +313,17 @@ async function executeBatchQuery(credential, batch, sessionKey) {
|
|
|
331
313
|
let client;
|
|
332
314
|
const createClient = () => client ||= createDatabaseClient.call(this, credential);
|
|
333
315
|
const closeClient = () => client?.[0].destroy();
|
|
334
|
-
|
|
316
|
+
setDatabaseEndpoint(credential);
|
|
335
317
|
for (let i = 0; i < length; ++i) {
|
|
336
318
|
const item = batch[i];
|
|
337
319
|
let { service, table: TableName, id, query, key, limit = 0, update, ignoreCache } = item;
|
|
338
320
|
const useCache = caching && ignoreCache !== true;
|
|
339
321
|
cacheValue.exclusiveOf = Array.isArray(ignoreCache) ? ignoreCache : undefined;
|
|
340
322
|
let rows, queryString = '';
|
|
341
|
-
if (key && (id ||
|
|
323
|
+
if (key && (id || isPlainObject(key))) {
|
|
342
324
|
if (!TableName) {
|
|
343
325
|
closeClient();
|
|
344
|
-
throw
|
|
326
|
+
throw formatError(item, "Missing database table");
|
|
345
327
|
}
|
|
346
328
|
if (useCache) {
|
|
347
329
|
queryString = TableName + '_' + Cloud.asString(key, true) + (id !== undefined ? '_' + Cloud.asString(id, true) : '');
|
|
@@ -351,9 +333,9 @@ async function executeBatchQuery(credential, batch, sessionKey) {
|
|
|
351
333
|
}
|
|
352
334
|
}
|
|
353
335
|
const [db, AWS] = createClient();
|
|
354
|
-
const Key =
|
|
336
|
+
const Key = isPlainObject(key) ? key : { [key]: id };
|
|
355
337
|
const command = { TableName, Key };
|
|
356
|
-
if (
|
|
338
|
+
if (isPlainObject(update)) {
|
|
357
339
|
await db.send(new AWS.UpdateCommand({ ...command, ...update }));
|
|
358
340
|
}
|
|
359
341
|
const Item = (await db.send(new AWS.GetCommand(command))).Item;
|
|
@@ -361,13 +343,13 @@ async function executeBatchQuery(credential, batch, sessionKey) {
|
|
|
361
343
|
rows = [Item];
|
|
362
344
|
}
|
|
363
345
|
}
|
|
364
|
-
else if (
|
|
346
|
+
else if (isPlainObject(query)) {
|
|
365
347
|
if (TableName) {
|
|
366
348
|
query.TableName = TableName;
|
|
367
349
|
}
|
|
368
350
|
if (!query.TableName) {
|
|
369
351
|
closeClient();
|
|
370
|
-
throw
|
|
352
|
+
throw formatError(item, "Missing database table");
|
|
371
353
|
}
|
|
372
354
|
if (limit > 0) {
|
|
373
355
|
query.Limit = limit;
|
|
@@ -382,15 +364,15 @@ async function executeBatchQuery(credential, batch, sessionKey) {
|
|
|
382
364
|
rows = Items;
|
|
383
365
|
}
|
|
384
366
|
}
|
|
385
|
-
else if (
|
|
367
|
+
else if (isArray(query)) {
|
|
386
368
|
let params = (item.params || {});
|
|
387
|
-
if (!
|
|
369
|
+
if (!isPlainObject(params.RequestItems)) {
|
|
388
370
|
params.RequestItems = {};
|
|
389
371
|
}
|
|
390
372
|
TableName ||= Object.keys(params.RequestItems)[0];
|
|
391
373
|
if (!TableName) {
|
|
392
374
|
closeClient();
|
|
393
|
-
throw
|
|
375
|
+
throw formatError(item, "Missing database table");
|
|
394
376
|
}
|
|
395
377
|
const Item = params.RequestItems[TableName] ||= {};
|
|
396
378
|
Item.Keys = query;
|
|
@@ -405,17 +387,17 @@ async function executeBatchQuery(credential, batch, sessionKey) {
|
|
|
405
387
|
rows = Responses[TableName];
|
|
406
388
|
}
|
|
407
389
|
}
|
|
408
|
-
else if (
|
|
390
|
+
else if (isString(query)) {
|
|
409
391
|
const Statement = query.trim();
|
|
410
|
-
const Parameters =
|
|
392
|
+
const Parameters = isArray(item.params) ? item.params : undefined;
|
|
411
393
|
const Limit = limit > 0 ? limit : undefined;
|
|
412
394
|
if (!/^select\s/i.test(Statement)) {
|
|
413
395
|
closeClient();
|
|
414
|
-
throw
|
|
396
|
+
throw formatError(item, "Missing database query");
|
|
415
397
|
}
|
|
416
398
|
const db = createClient()[0];
|
|
417
|
-
if (
|
|
418
|
-
await db.send(new
|
|
399
|
+
if (isString(update) && /^(?:insert|delete|update)\s/i.test(update) && !update.includes('?')) {
|
|
400
|
+
await db.send(new dynamo.ExecuteStatementCommand({ Statement: update })).catch((err) => {
|
|
419
401
|
this.formatFail(64, service, "Unable to execute query", err, Cloud.optionsLogMessage('FAIL', { fatal: false }));
|
|
420
402
|
});
|
|
421
403
|
}
|
|
@@ -426,7 +408,7 @@ async function executeBatchQuery(credential, batch, sessionKey) {
|
|
|
426
408
|
result[i] = rows;
|
|
427
409
|
continue;
|
|
428
410
|
}
|
|
429
|
-
const { Items } = await db.send(new
|
|
411
|
+
const { Items } = await db.send(new dynamo.ExecuteStatementCommand({ Statement, Parameters, Limit }));
|
|
430
412
|
if (Items) {
|
|
431
413
|
rows = Items;
|
|
432
414
|
if (rows.length === 0) {
|
|
@@ -444,7 +426,7 @@ async function executeBatchQuery(credential, batch, sessionKey) {
|
|
|
444
426
|
params.TableName = TableName;
|
|
445
427
|
}
|
|
446
428
|
else if (params.TableName) {
|
|
447
|
-
throw
|
|
429
|
+
throw formatError(item, "Missing database table");
|
|
448
430
|
}
|
|
449
431
|
}
|
|
450
432
|
if (useCache && (rows = this.getCacheResult(service, credential, queryString = Cloud.asString(params, true), cacheValue, ignoreCache))) {
|
|
@@ -467,12 +449,30 @@ async function executeBatchQuery(credential, batch, sessionKey) {
|
|
|
467
449
|
}
|
|
468
450
|
else {
|
|
469
451
|
closeClient();
|
|
470
|
-
throw
|
|
452
|
+
throw formatError(item, "Missing database query");
|
|
471
453
|
}
|
|
472
454
|
result[i] = this.setQueryResult(service, credential, queryString, rows, cacheValue);
|
|
473
455
|
}
|
|
474
456
|
closeClient();
|
|
475
457
|
return result;
|
|
476
458
|
}
|
|
477
|
-
|
|
478
|
-
|
|
459
|
+
const CLOUD_UPLOAD_STREAM = true;
|
|
460
|
+
const CLOUD_UPLOAD_CHUNK = true;
|
|
461
|
+
|
|
462
|
+
exports.CLOUD_UPLOAD_CHUNK = CLOUD_UPLOAD_CHUNK;
|
|
463
|
+
exports.CLOUD_UPLOAD_STREAM = CLOUD_UPLOAD_STREAM;
|
|
464
|
+
exports.copyObject = copyObject;
|
|
465
|
+
exports.createBucket = createBucket;
|
|
466
|
+
exports.createBucketV2 = createBucketV2;
|
|
467
|
+
exports.createDatabaseClient = createDatabaseClient;
|
|
468
|
+
exports.createStorageClient = createStorageClient;
|
|
469
|
+
exports.deleteObjects = deleteObjects;
|
|
470
|
+
exports.deleteObjectsV2 = deleteObjectsV2;
|
|
471
|
+
exports.deleteObjectsV3 = deleteObjectsV3;
|
|
472
|
+
exports.executeBatchQuery = executeBatchQuery;
|
|
473
|
+
exports.executeQuery = executeQuery;
|
|
474
|
+
exports.setBucketPolicy = setBucketPolicy;
|
|
475
|
+
exports.setBucketTagging = setBucketTagging;
|
|
476
|
+
exports.setBucketWebsite = setBucketWebsite;
|
|
477
|
+
exports.validateDatabase = validateDatabase;
|
|
478
|
+
exports.validateStorage = validateStorage;
|
package/download/index.js
CHANGED
|
@@ -1,36 +1,37 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
|
|
3
|
-
const
|
|
4
|
-
const
|
|
5
|
-
const
|
|
2
|
+
|
|
3
|
+
const Cloud = require('@e-mc/cloud');
|
|
4
|
+
const { errorValue, isPlainObject } = require('@e-mc/types');
|
|
5
|
+
const { createErrorHandler, intoArray, readableAsBuffer } = require('@e-mc/cloud/util');
|
|
6
|
+
const { copyObject, createStorageClient } = require('@pi-r/aws-v3');
|
|
6
7
|
function download(credential, service = "aws-v3", sdk = "@aws-sdk/client-s3") {
|
|
7
|
-
const [client, AWS] =
|
|
8
|
+
const [client, AWS] = createStorageClient.call(this, credential, service, sdk);
|
|
8
9
|
return (data, callback) => {
|
|
9
10
|
const { bucket: Bucket, download: target } = data;
|
|
10
11
|
const Key = target.keyname || target.filename;
|
|
11
12
|
if (!Bucket || !Key) {
|
|
12
|
-
callback(
|
|
13
|
+
callback(errorValue('Missing property', !Bucket ? 'Bucket' : 'Key'));
|
|
13
14
|
return;
|
|
14
15
|
}
|
|
15
16
|
client.send(new AWS.GetObjectCommand({ ...target.options, Bucket, Key, VersionId: target.versionId }), { abortSignal: this.signal })
|
|
16
17
|
.then(result => {
|
|
17
|
-
|
|
18
|
+
readableAsBuffer(result.Body)
|
|
18
19
|
.then(async (buffer) => {
|
|
19
20
|
callback(null, buffer);
|
|
20
|
-
const copyTo =
|
|
21
|
+
const copyTo = intoArray(target.copyObject);
|
|
21
22
|
if (copyTo) {
|
|
22
23
|
const tasks = [];
|
|
23
24
|
for (const { bucket, pathname, filename, options } of copyTo) {
|
|
24
25
|
const keyObject = filename ? Cloud.joinPath(pathname, filename, true) : Key;
|
|
25
|
-
tasks.push(
|
|
26
|
+
tasks.push(copyObject
|
|
26
27
|
.call(this, credential, Bucket, Key, bucket, keyObject, options, service, sdk)
|
|
27
|
-
.catch(
|
|
28
|
+
.catch(createErrorHandler(this, service, Bucket)));
|
|
28
29
|
}
|
|
29
30
|
await Promise.all(tasks);
|
|
30
31
|
}
|
|
31
32
|
const deleteObject = target.deleteObject;
|
|
32
33
|
if (deleteObject) {
|
|
33
|
-
const deleteOptions =
|
|
34
|
+
const deleteOptions = isPlainObject(deleteObject) ? deleteObject : undefined;
|
|
34
35
|
const location = Cloud.joinPath(Bucket, Key);
|
|
35
36
|
client.send(new AWS.DeleteObjectCommand({ ...deleteOptions, Bucket, Key, VersionId: target.versionId }))
|
|
36
37
|
.then(() => {
|
|
@@ -46,4 +47,5 @@ function download(credential, service = "aws-v3", sdk = "@aws-sdk/client-s3") {
|
|
|
46
47
|
.catch(callback);
|
|
47
48
|
};
|
|
48
49
|
}
|
|
50
|
+
|
|
49
51
|
module.exports = download;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pi-r/aws-v3",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.12.0",
|
|
4
4
|
"description": "AWS cloud functions for E-mc.",
|
|
5
5
|
"main": "client/index.js",
|
|
6
6
|
"publishConfig": {
|
|
@@ -19,14 +19,14 @@
|
|
|
19
19
|
"license": "MIT",
|
|
20
20
|
"homepage": "https://github.com/anpham6/pi-r#readme",
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"@e-mc/cloud": "^0.
|
|
23
|
-
"@e-mc/module": "^0.
|
|
24
|
-
"@e-mc/types": "^0.
|
|
25
|
-
"@pi-r/aws-lib": "^0.
|
|
26
|
-
"@aws-sdk/client-dynamodb": "^3.
|
|
27
|
-
"@aws-sdk/client-s3": "^3.
|
|
22
|
+
"@e-mc/cloud": "^0.14.0",
|
|
23
|
+
"@e-mc/module": "^0.14.0",
|
|
24
|
+
"@e-mc/types": "^0.14.0",
|
|
25
|
+
"@pi-r/aws-lib": "^0.12.0",
|
|
26
|
+
"@aws-sdk/client-dynamodb": "^3.1039.0",
|
|
27
|
+
"@aws-sdk/client-s3": "^3.1039.0",
|
|
28
28
|
"@aws-sdk/credential-providers": "*",
|
|
29
|
-
"@aws-sdk/lib-dynamodb": "^3.
|
|
30
|
-
"@aws-sdk/lib-storage": "^3.
|
|
29
|
+
"@aws-sdk/lib-dynamodb": "^3.1039.0",
|
|
30
|
+
"@aws-sdk/lib-storage": "^3.1039.0"
|
|
31
31
|
}
|
|
32
32
|
}
|
package/upload/index.js
CHANGED
|
@@ -1,21 +1,22 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
|
|
3
|
-
const
|
|
4
|
-
const
|
|
5
|
-
const
|
|
6
|
-
const
|
|
7
|
-
const
|
|
8
|
-
const
|
|
9
|
-
const
|
|
10
|
-
const
|
|
11
|
-
const
|
|
2
|
+
|
|
3
|
+
const path = require('node:path');
|
|
4
|
+
const fs = require('node:fs');
|
|
5
|
+
const stream = require('node:stream');
|
|
6
|
+
const { randomUUID } = require('node:crypto');
|
|
7
|
+
const { Upload } = require('@aws-sdk/lib-storage');
|
|
8
|
+
const Cloud = require('@e-mc/cloud');
|
|
9
|
+
const { alignSize, createAbortError, isErrorCode, isPlainObject } = require('@e-mc/types');
|
|
10
|
+
const { createErrorHandler, createKeyAndBody, generateFilename, intoArray } = require('@e-mc/cloud/util');
|
|
11
|
+
const { formatDefaultRetention, getBucketKey } = require('@pi-r/aws-lib');
|
|
12
|
+
const { copyObject, createBucketV2, createStorageClient } = require('@pi-r/aws-v3');
|
|
12
13
|
const BUCKET_SESSION = new Set();
|
|
13
14
|
const BUCKET_RESPONSE = {};
|
|
14
15
|
function upload(credential, service = "aws-v3", sdk = "@aws-sdk/client-s3") {
|
|
15
|
-
const [client, AWS] =
|
|
16
|
+
const [client, AWS] = createStorageClient.call(this, credential, service, sdk);
|
|
16
17
|
return async (data, callback) => {
|
|
17
18
|
const { bucket: Bucket, localUri } = data;
|
|
18
|
-
const { pathname, flags = 0, fileGroup, contentType, metadata, tags: Tags, endpoint, active, publicRead, acl, admin = {}, overwrite, options } = data.upload;
|
|
19
|
+
const { pathname, flags = 0, fileGroup, descendantsGroup, contentType, metadata, tags: Tags, endpoint, active, publicRead, acl, admin = {}, overwrite, options } = data.upload;
|
|
19
20
|
let filename = data.upload.filename || path.basename(localUri), bucketKey;
|
|
20
21
|
const complete = (err, url) => {
|
|
21
22
|
BUCKET_SESSION.delete(service + Bucket);
|
|
@@ -24,11 +25,11 @@ function upload(credential, service = "aws-v3", sdk = "@aws-sdk/client-s3") {
|
|
|
24
25
|
}
|
|
25
26
|
callback(err, url);
|
|
26
27
|
};
|
|
27
|
-
const addLog =
|
|
28
|
+
const addLog = createErrorHandler(this, Bucket, service);
|
|
28
29
|
const configBucket = admin.configBucket;
|
|
29
30
|
if (!BUCKET_SESSION.has(service + Bucket)) {
|
|
30
31
|
const bucketAcl = admin.publicRead ? "public-read" : admin.acl;
|
|
31
|
-
const response = BUCKET_RESPONSE[bucketKey =
|
|
32
|
+
const response = BUCKET_RESPONSE[bucketKey = getBucketKey(credential, Bucket, bucketAcl, service, sdk)] ||= createBucketV2.call(this, credential, Bucket, bucketAcl, configBucket?.create, service, sdk);
|
|
32
33
|
if (!await response) {
|
|
33
34
|
complete(null);
|
|
34
35
|
return;
|
|
@@ -41,10 +42,10 @@ function upload(credential, service = "aws-v3", sdk = "@aws-sdk/client-s3") {
|
|
|
41
42
|
const commandMessage = (feature, message) => {
|
|
42
43
|
this.formatMessage(64, service, ["Bucket configured" + ` (${feature})`, message || Bucket], ExpectedBucketOwner, { ...Cloud[message === 'delete' ? 'LOG_CLOUD_WARN' : 'LOG_CLOUD_COMMAND'] });
|
|
43
44
|
};
|
|
44
|
-
if (
|
|
45
|
+
if (isPlainObject(DefaultRetention)) {
|
|
45
46
|
client.send(new AWS.PutObjectLockConfigurationCommand({ Bucket, ObjectLockConfiguration: { ObjectLockEnabled: 'Enabled', Rule: { DefaultRetention } }, ExpectedBucketOwner, RequestPayer: options?.RequestPayer }))
|
|
46
47
|
.then(() => {
|
|
47
|
-
this.formatMessage(64, service, ["Bucket configured" + ' (Retention Policy)', Bucket],
|
|
48
|
+
this.formatMessage(64, service, ["Bucket configured" + ' (Retention Policy)', Bucket], formatDefaultRetention(DefaultRetention), Cloud.optionsLogMessage('COMMAND'));
|
|
48
49
|
})
|
|
49
50
|
.catch(addLog);
|
|
50
51
|
}
|
|
@@ -85,7 +86,7 @@ function upload(credential, service = "aws-v3", sdk = "@aws-sdk/client-s3") {
|
|
|
85
86
|
}
|
|
86
87
|
if (!overwrite) {
|
|
87
88
|
const current = filename;
|
|
88
|
-
const next =
|
|
89
|
+
const next = generateFilename(filename);
|
|
89
90
|
let i = 0, exists = false;
|
|
90
91
|
do {
|
|
91
92
|
if (i > 0) {
|
|
@@ -97,9 +98,8 @@ function upload(credential, service = "aws-v3", sdk = "@aws-sdk/client-s3") {
|
|
|
97
98
|
exists = await client.send(new AWS.HeadObjectCommand({ Bucket, Key: Cloud.joinPath(pathname, filename, true) }))
|
|
98
99
|
.then(() => true)
|
|
99
100
|
.catch((err) => {
|
|
100
|
-
if (err
|
|
101
|
-
filename =
|
|
102
|
-
return true;
|
|
101
|
+
if (!isErrorCode(err, 'NotFound')) {
|
|
102
|
+
filename = randomUUID() + path.extname(current);
|
|
103
103
|
}
|
|
104
104
|
return false;
|
|
105
105
|
});
|
|
@@ -119,12 +119,12 @@ function upload(credential, service = "aws-v3", sdk = "@aws-sdk/client-s3") {
|
|
|
119
119
|
const getPartSize = () => partSize > 0 ? Math.max(partSize, 5242880) : undefined;
|
|
120
120
|
if (flags & 2) {
|
|
121
121
|
if (flags & 4) {
|
|
122
|
-
partSize =
|
|
122
|
+
partSize = alignSize(data.upload.chunkSize, 1024);
|
|
123
123
|
}
|
|
124
124
|
try {
|
|
125
125
|
Stream.push(data.buffer.length > 0 ? stream.Readable.from(data.buffer, { highWaterMark: getPartSize() }) : fs.createReadStream(localUri, { highWaterMark: getPartSize(), signal: this.signal }));
|
|
126
126
|
if (fileGroup) {
|
|
127
|
-
const [key, body, type] =
|
|
127
|
+
const [key, body, type] = createKeyAndBody(filename, fileGroup, { errorCallback: addLog, descendantsGroup, flags: 2 });
|
|
128
128
|
Key.push(...key);
|
|
129
129
|
Stream.push(...body);
|
|
130
130
|
ContentType.push(...type);
|
|
@@ -138,7 +138,7 @@ function upload(credential, service = "aws-v3", sdk = "@aws-sdk/client-s3") {
|
|
|
138
138
|
else {
|
|
139
139
|
Body.push(data.buffer);
|
|
140
140
|
if (fileGroup) {
|
|
141
|
-
const [key, body, type] =
|
|
141
|
+
const [key, body, type] = createKeyAndBody(filename, fileGroup, { errorCallback: addLog, descendantsGroup });
|
|
142
142
|
Key.push(...key);
|
|
143
143
|
Body.push(...body);
|
|
144
144
|
ContentType.push(...type);
|
|
@@ -148,7 +148,7 @@ function upload(credential, service = "aws-v3", sdk = "@aws-sdk/client-s3") {
|
|
|
148
148
|
const first = i === 0;
|
|
149
149
|
if (this.aborted) {
|
|
150
150
|
if (first) {
|
|
151
|
-
complete(
|
|
151
|
+
complete(createAbortError());
|
|
152
152
|
}
|
|
153
153
|
return;
|
|
154
154
|
}
|
|
@@ -167,7 +167,7 @@ function upload(credential, service = "aws-v3", sdk = "@aws-sdk/client-s3") {
|
|
|
167
167
|
if (metadata) {
|
|
168
168
|
params.Metadata = metadata;
|
|
169
169
|
}
|
|
170
|
-
if (
|
|
170
|
+
if (isPlainObject(Tags) && (length = Object.keys(Tags).length) > 0) {
|
|
171
171
|
tags = [];
|
|
172
172
|
for (const name in Tags) {
|
|
173
173
|
tags.push({ Key: name, Value: Tags[name] });
|
|
@@ -188,7 +188,7 @@ function upload(credential, service = "aws-v3", sdk = "@aws-sdk/client-s3") {
|
|
|
188
188
|
}
|
|
189
189
|
}
|
|
190
190
|
}
|
|
191
|
-
new
|
|
191
|
+
new Upload({ client, params, tags, partSize: getPartSize(), queueSize: partSize > 0 ? data.upload.chunkLimit : undefined }).done()
|
|
192
192
|
.then(() => {
|
|
193
193
|
const url = endpoint ? Cloud.joinPath(endpoint, objectKey) : Cloud.joinPath(`https://${Bucket}.s3.${!credential.region || credential.region === "us-east-1" ? "us-east-1" + '.' : ''}amazonaws.com`, objectKey);
|
|
194
194
|
this.formatMessage(64, service, "Upload success", url, Cloud.optionsLogMessage('UPLOAD'));
|
|
@@ -203,12 +203,12 @@ function upload(credential, service = "aws-v3", sdk = "@aws-sdk/client-s3") {
|
|
|
203
203
|
}
|
|
204
204
|
});
|
|
205
205
|
}
|
|
206
|
-
const copyTo =
|
|
206
|
+
const copyTo = intoArray(data.upload.copyObject);
|
|
207
207
|
if (copyTo) {
|
|
208
208
|
const tasks = [];
|
|
209
209
|
for (const { bucket: bucketName, pathname: pathObject = pathname, filename: fileObject, options: copyOptions } of copyTo) {
|
|
210
210
|
const keyObject = fileObject ? Cloud.joinPath(pathObject, fileObject, true) : objectKey;
|
|
211
|
-
tasks.push(
|
|
211
|
+
tasks.push(copyObject
|
|
212
212
|
.call(this, credential, Bucket, objectKey, bucketName, keyObject, copyOptions, service, sdk)
|
|
213
213
|
.catch(addLog));
|
|
214
214
|
}
|
|
@@ -228,4 +228,5 @@ function upload(credential, service = "aws-v3", sdk = "@aws-sdk/client-s3") {
|
|
|
228
228
|
}
|
|
229
229
|
};
|
|
230
230
|
}
|
|
231
|
+
|
|
231
232
|
module.exports = upload;
|