@pi-r/aws-v3 0.6.7 → 0.7.1
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 +3 -6
- package/client/index.js +70 -66
- package/download/index.js +11 -13
- package/package.json +10 -9
- package/types/index.d.ts +41 -0
- package/upload/index.js +121 -88
package/README.md
CHANGED
|
@@ -1,10 +1,7 @@
|
|
|
1
|
-
|
|
1
|
+
### @pi-r/aws-v3
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
https://e-mc.readthedocs.io/en/latest/cloud/aws-v3.html
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
- [squared](https://squared.readthedocs.io)
|
|
7
|
-
|
|
8
|
-
## LICENSE
|
|
5
|
+
### LICENSE
|
|
9
6
|
|
|
10
7
|
MIT
|
package/client/index.js
CHANGED
|
@@ -1,27 +1,26 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
exports.executeBatchQuery = exports.executeQuery = exports.deleteObjectsV2 = exports.deleteObjects = exports.setBucketWebsite = exports.setBucketPolicy = exports.createBucketV2 = exports.createBucket = exports.validateDatabase = exports.validateStorage = exports.createDatabaseClient = exports.createStorageClient = void 0;
|
|
2
|
+
exports.CLOUD_UPLOAD_CHUNK = exports.CLOUD_UPLOAD_STREAM = exports.executeBatchQuery = exports.executeQuery = exports.deleteObjectsV2 = exports.deleteObjects = exports.setBucketWebsite = exports.setBucketTagging = exports.setBucketPolicy = exports.createBucketV2 = exports.createBucket = exports.validateDatabase = exports.validateStorage = exports.createDatabaseClient = exports.createStorageClient = void 0;
|
|
3
3
|
const Lib = require("@aws-sdk/lib-dynamodb");
|
|
4
4
|
const Client = require("@aws-sdk/client-dynamodb");
|
|
5
5
|
const Providers = require("@aws-sdk/credential-providers");
|
|
6
|
-
const
|
|
6
|
+
const Cloud = require("@e-mc/cloud");
|
|
7
7
|
const util_1 = require("@e-mc/cloud/util");
|
|
8
8
|
const types_1 = require("@e-mc/types");
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
async function setCannedAcl(S3, client, Bucket, ACL, service = 'aws-v3', recursive) {
|
|
9
|
+
const aws_lib_1 = require("@pi-r/aws-lib");
|
|
10
|
+
async function setCannedAcl(S3, client, Bucket, ACL, service = "aws-v3", recursive) {
|
|
12
11
|
let Policy;
|
|
13
12
|
switch (ACL) {
|
|
14
13
|
case 1:
|
|
15
|
-
Policy = (0,
|
|
14
|
+
Policy = (0, aws_lib_1.getBucketPublicReadPolicy)(Bucket);
|
|
16
15
|
break;
|
|
17
|
-
case
|
|
18
|
-
Policy = (0,
|
|
16
|
+
case "public-read-write":
|
|
17
|
+
Policy = (0, aws_lib_1.getPublicReadPolicy)(Bucket, false, true);
|
|
19
18
|
break;
|
|
20
|
-
case
|
|
21
|
-
Policy = (0,
|
|
19
|
+
case "authenticated-read":
|
|
20
|
+
Policy = (0, aws_lib_1.getPublicReadPolicy)(Bucket, true);
|
|
22
21
|
break;
|
|
23
22
|
default:
|
|
24
|
-
Policy = (0,
|
|
23
|
+
Policy = (0, aws_lib_1.getPrivatePolicy)(Bucket);
|
|
25
24
|
break;
|
|
26
25
|
}
|
|
27
26
|
return client.send(new S3.PutBucketPolicyCommand({ Bucket, Policy }))
|
|
@@ -40,23 +39,6 @@ async function setCannedAcl(S3, client, Bucket, ACL, service = 'aws-v3', recursi
|
|
|
40
39
|
}
|
|
41
40
|
});
|
|
42
41
|
}
|
|
43
|
-
function sanitizeCredentials(credential) {
|
|
44
|
-
const result = credential.credentials || (credential.credentials = {});
|
|
45
|
-
for (const attr in credential) {
|
|
46
|
-
switch (attr) {
|
|
47
|
-
case 'accessKeyId':
|
|
48
|
-
case 'secretAccessKey':
|
|
49
|
-
case 'sessionToken':
|
|
50
|
-
case 'expiration':
|
|
51
|
-
if (typeof result !== 'function') {
|
|
52
|
-
result[attr] = credential[attr];
|
|
53
|
-
}
|
|
54
|
-
delete credential[attr];
|
|
55
|
-
break;
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
return result;
|
|
59
|
-
}
|
|
60
42
|
function fromProvider(credential) {
|
|
61
43
|
const from = credential.provider;
|
|
62
44
|
let credentials = credential.credentials;
|
|
@@ -94,10 +76,10 @@ function fromProvider(credential) {
|
|
|
94
76
|
else if ((0, types_1.isPlainObject)(from.sso)) {
|
|
95
77
|
credentials = Providers.fromSSO(from.sso);
|
|
96
78
|
}
|
|
97
|
-
else if (from.env && (0,
|
|
79
|
+
else if (from.env && (0, aws_lib_1.isEnvDefined)()) {
|
|
98
80
|
credentials = Providers.fromEnv();
|
|
99
81
|
}
|
|
100
|
-
else if (from.ini && (0,
|
|
82
|
+
else if (from.ini && (0, aws_lib_1.isSharedCredentialsDefined)()) {
|
|
101
83
|
credentials = Providers.fromIni();
|
|
102
84
|
}
|
|
103
85
|
if ((0, types_1.isPlainObject)(credentials)) {
|
|
@@ -123,9 +105,8 @@ function fromProvider(credential) {
|
|
|
123
105
|
return credential;
|
|
124
106
|
}
|
|
125
107
|
const isNoSuchBucket = (err) => err instanceof Error && err.name === 'NoSuchBucket';
|
|
126
|
-
function createStorageClient(credential, service =
|
|
108
|
+
function createStorageClient(credential, service = "aws-v3", sdk = "@aws-sdk/client-s3") {
|
|
127
109
|
try {
|
|
128
|
-
sanitizeCredentials(credential);
|
|
129
110
|
const AWS = require(sdk);
|
|
130
111
|
return [new AWS.S3Client(fromProvider(credential)), AWS];
|
|
131
112
|
}
|
|
@@ -140,25 +121,24 @@ function createDatabaseClient(credential) {
|
|
|
140
121
|
}
|
|
141
122
|
exports.createDatabaseClient = createDatabaseClient;
|
|
142
123
|
function validateStorage(credential) {
|
|
143
|
-
const credentials =
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
credential.credentials = Providers.fromIni({ profile });
|
|
124
|
+
const credentials = credential.credentials;
|
|
125
|
+
if (!credentials && !credential.provider && (0, aws_lib_1.isSharedCredentialsDefined)()) {
|
|
126
|
+
credential.credentials = Providers.fromIni();
|
|
147
127
|
return true;
|
|
148
128
|
}
|
|
149
|
-
return !!credentials && (
|
|
129
|
+
return !!credentials && ((0, aws_lib_1.isAccessDefined)(credentials) || typeof credentials === 'function') || (0, types_1.isPlainObject)(credential.provider) || (0, aws_lib_1.isEnvDefined)();
|
|
150
130
|
}
|
|
151
131
|
exports.validateStorage = validateStorage;
|
|
152
132
|
function validateDatabase(credential, data) {
|
|
153
|
-
return (0,
|
|
133
|
+
return (0, aws_lib_1.isDatabaseDefined)(credential, data) && validateStorage(credential);
|
|
154
134
|
}
|
|
155
135
|
exports.validateDatabase = validateDatabase;
|
|
156
|
-
async function createBucket(credential, Bucket, publicRead, service =
|
|
157
|
-
return createBucketV2.call(this, credential, Bucket, publicRead ?
|
|
136
|
+
async function createBucket(credential, Bucket, publicRead, service = "aws-v3", sdk = "@aws-sdk/client-s3") {
|
|
137
|
+
return createBucketV2.call(this, credential, Bucket, publicRead ? "public-read" : undefined, undefined, service, sdk);
|
|
158
138
|
}
|
|
159
139
|
exports.createBucket = createBucket;
|
|
160
|
-
async function createBucketV2(credential, Bucket, ACL, options, service =
|
|
161
|
-
ACL = ACL === 1 ? 1 : (0,
|
|
140
|
+
async function createBucketV2(credential, Bucket, ACL, options, service = "aws-v3", sdk = "@aws-sdk/client-s3") {
|
|
141
|
+
ACL = ACL === 1 ? 1 : (0, aws_lib_1.checkBucketCannedACL)(ACL);
|
|
162
142
|
const [client, AWS] = createStorageClient.call(this, credential, service, sdk);
|
|
163
143
|
return client.send(new AWS.HeadBucketCommand({ Bucket }))
|
|
164
144
|
.then(async () => {
|
|
@@ -170,8 +150,8 @@ async function createBucketV2(credential, Bucket, ACL, options, service = 'aws-v
|
|
|
170
150
|
.catch(async () => {
|
|
171
151
|
const input = { ...options, Bucket };
|
|
172
152
|
const region = credential.region;
|
|
173
|
-
if ((0, types_1.isString)(region) && region !==
|
|
174
|
-
input.CreateBucketConfiguration
|
|
153
|
+
if ((0, types_1.isString)(region) && region !== "us-east-1") {
|
|
154
|
+
input.CreateBucketConfiguration ||= { LocationConstraint: region };
|
|
175
155
|
}
|
|
176
156
|
return client.send(new AWS.CreateBucketCommand(input))
|
|
177
157
|
.then(async () => {
|
|
@@ -197,7 +177,7 @@ async function createBucketV2(credential, Bucket, ACL, options, service = 'aws-v
|
|
|
197
177
|
});
|
|
198
178
|
}
|
|
199
179
|
exports.createBucketV2 = createBucketV2;
|
|
200
|
-
async function setBucketPolicy(credential, Bucket, options, service =
|
|
180
|
+
async function setBucketPolicy(credential, Bucket, options, service = "aws-v3", sdk = "@aws-sdk/client-s3") {
|
|
201
181
|
const [client, AWS] = createStorageClient.call(this, credential, service, sdk);
|
|
202
182
|
const block = 'PublicAccessBlockConfiguration' in options;
|
|
203
183
|
const policy = !block && 'Policy' in options && !('ACL' in options);
|
|
@@ -207,7 +187,7 @@ async function setBucketPolicy(credential, Bucket, options, service = 'aws', sdk
|
|
|
207
187
|
this.formatMessage(64, service, [block ? "Bucket configured" : policy ? "Bucket policy configured" : "Bucket ACL configured", Bucket], '', { ...Cloud.LOG_CLOUD_COMMAND });
|
|
208
188
|
return true;
|
|
209
189
|
})
|
|
210
|
-
.catch(err => {
|
|
190
|
+
.catch((err) => {
|
|
211
191
|
if (!isNoSuchBucket(err)) {
|
|
212
192
|
this.formatFail(64, service, ["Unable to update bucket policy", Bucket], err, { ...Cloud.LOG_CLOUD_FAIL, fatal: false });
|
|
213
193
|
}
|
|
@@ -215,7 +195,30 @@ async function setBucketPolicy(credential, Bucket, options, service = 'aws', sdk
|
|
|
215
195
|
});
|
|
216
196
|
}
|
|
217
197
|
exports.setBucketPolicy = setBucketPolicy;
|
|
218
|
-
async function
|
|
198
|
+
async function setBucketTagging(credential, Bucket, options, service = "aws-v3", sdk = "@aws-sdk/client-s3") {
|
|
199
|
+
if (!(0, types_1.isPlainObject)(options) || !Array.isArray(options.Tagging?.TagSet)) {
|
|
200
|
+
return false;
|
|
201
|
+
}
|
|
202
|
+
const [client, AWS] = createStorageClient.call(this, credential, service, sdk);
|
|
203
|
+
const deleting = options.Tagging.TagSet.length === 0;
|
|
204
|
+
const command = () => {
|
|
205
|
+
this.formatMessage(64, service, [deleting ? "Tags deleted" : "Tags created", Bucket], null, { ...Cloud.LOG_CLOUD_COMMAND });
|
|
206
|
+
return true;
|
|
207
|
+
};
|
|
208
|
+
const error = (err) => {
|
|
209
|
+
if (!isNoSuchBucket(err)) {
|
|
210
|
+
this.formatFail(64, service, ["Unable to update bucket tagging", Bucket], err, { ...Cloud.LOG_CLOUD_FAIL, fatal: false });
|
|
211
|
+
}
|
|
212
|
+
return false;
|
|
213
|
+
};
|
|
214
|
+
if (deleting) {
|
|
215
|
+
return client.send(new AWS.DeleteBucketTaggingCommand({ Bucket, ExpectedBucketOwner: options.ExpectedBucketOwner })).then(command).catch((err) => error(err));
|
|
216
|
+
}
|
|
217
|
+
options.Bucket = Bucket;
|
|
218
|
+
return client.send(new AWS.PutBucketTaggingCommand(options)).then(command).catch((err) => error(err));
|
|
219
|
+
}
|
|
220
|
+
exports.setBucketTagging = setBucketTagging;
|
|
221
|
+
async function setBucketWebsite(credential, Bucket, options, service = "aws-v3", sdk = "@aws-sdk/client-s3") {
|
|
219
222
|
const [client, AWS] = createStorageClient.call(this, credential, service, sdk);
|
|
220
223
|
const WebsiteConfiguration = {};
|
|
221
224
|
const { indexPage: Suffix, errorPage: Key } = options;
|
|
@@ -227,26 +230,26 @@ async function setBucketWebsite(credential, Bucket, options, service = 'aws', sd
|
|
|
227
230
|
}
|
|
228
231
|
return client.send(new AWS.PutBucketWebsiteCommand({ Bucket, WebsiteConfiguration }))
|
|
229
232
|
.then(() => {
|
|
230
|
-
this.formatMessage(64, service, ["Bucket configured", Bucket], WebsiteConfiguration, { ...Cloud.LOG_CLOUD_COMMAND });
|
|
233
|
+
this.formatMessage(64, service, ["Bucket website configured", Bucket], WebsiteConfiguration, { ...Cloud.LOG_CLOUD_COMMAND });
|
|
231
234
|
return true;
|
|
232
235
|
})
|
|
233
|
-
.catch(err => {
|
|
236
|
+
.catch((err) => {
|
|
234
237
|
if (!isNoSuchBucket(err)) {
|
|
235
|
-
this.formatFail(64, service, ["Unable to
|
|
238
|
+
this.formatFail(64, service, ["Unable to set bucket website", Bucket], err, { ...Cloud.LOG_CLOUD_FAIL, fatal: false });
|
|
236
239
|
}
|
|
237
240
|
return false;
|
|
238
241
|
});
|
|
239
242
|
}
|
|
240
243
|
exports.setBucketWebsite = setBucketWebsite;
|
|
241
|
-
async function deleteObjects(credential, Bucket, service, sdk) {
|
|
244
|
+
async function deleteObjects(credential, Bucket, service = "aws-v3", sdk = "@aws-sdk/client-s3") {
|
|
242
245
|
return deleteObjectsV2.call(this, credential, Bucket, true, service, sdk);
|
|
243
246
|
}
|
|
244
247
|
exports.deleteObjects = deleteObjects;
|
|
245
|
-
async function deleteObjectsV2(credential, Bucket, recursive = true, service =
|
|
248
|
+
async function deleteObjectsV2(credential, Bucket, recursive = true, service = "aws-v3", sdk = "@aws-sdk/client-s3") {
|
|
246
249
|
const [client, AWS] = createStorageClient.call(this, credential, service, sdk);
|
|
247
250
|
return client.send(new AWS.ListObjectsCommand({ Bucket }))
|
|
248
251
|
.then(async ({ Contents }) => {
|
|
249
|
-
if (Contents
|
|
252
|
+
if (Contents?.length) {
|
|
250
253
|
let Objects = Contents.map(data => ({ Key: data.Key }));
|
|
251
254
|
if (!recursive) {
|
|
252
255
|
Objects = Objects.filter(value => !value.Key.includes('/'));
|
|
@@ -259,12 +262,12 @@ async function deleteObjectsV2(credential, Bucket, recursive = true, service = '
|
|
|
259
262
|
this.formatMessage(64, service, ["Bucket emptied" + ` (${recursive ? 'recursive' : files})`, Bucket], recursive ? files : '', { ...Cloud.LOG_CLOUD_COMMAND });
|
|
260
263
|
}
|
|
261
264
|
})
|
|
262
|
-
.catch(err => {
|
|
265
|
+
.catch((err) => {
|
|
263
266
|
this.formatFail(64, service, ["Unable to empty bucket", Bucket], err, { ...Cloud.LOG_CLOUD_FAIL, fatal: false });
|
|
264
267
|
});
|
|
265
268
|
}
|
|
266
269
|
})
|
|
267
|
-
.catch(err => {
|
|
270
|
+
.catch((err) => {
|
|
268
271
|
if (!isNoSuchBucket(err)) {
|
|
269
272
|
this.formatFail(64, service, ["Unable to list bucket", Bucket], err, { ...Cloud.LOG_CLOUD_FAIL, fatal: false });
|
|
270
273
|
}
|
|
@@ -276,18 +279,17 @@ async function executeQuery(credential, data, sessionKey) {
|
|
|
276
279
|
}
|
|
277
280
|
exports.executeQuery = executeQuery;
|
|
278
281
|
async function executeBatchQuery(credential, batch, sessionKey) {
|
|
279
|
-
var _a;
|
|
280
282
|
const length = batch.length;
|
|
281
283
|
const result = new Array(length);
|
|
282
284
|
const caching = length > 0 && this.hasCache(batch[0].service, sessionKey);
|
|
283
285
|
const cacheValue = { value: this.valueOfKey(credential, 'cache'), sessionKey };
|
|
284
286
|
let client;
|
|
285
|
-
const createClient = () => client
|
|
286
|
-
const closeClient = () => client
|
|
287
|
-
(0,
|
|
287
|
+
const createClient = () => client ||= createDatabaseClient.call(this, credential);
|
|
288
|
+
const closeClient = () => client?.[0].destroy();
|
|
289
|
+
(0, aws_lib_1.setDatabaseEndpoint)(credential);
|
|
288
290
|
for (let i = 0; i < length; ++i) {
|
|
289
291
|
const item = batch[i];
|
|
290
|
-
let { service, table: TableName, id, query,
|
|
292
|
+
let { service, table: TableName, id, query, key, limit = 0, update, ignoreCache } = item;
|
|
291
293
|
const useCache = caching && ignoreCache !== true;
|
|
292
294
|
const getCache = (value) => {
|
|
293
295
|
if (ignoreCache !== 1) {
|
|
@@ -303,7 +305,7 @@ async function executeBatchQuery(credential, batch, sessionKey) {
|
|
|
303
305
|
throw (0, util_1.formatError)(item, "Missing database table");
|
|
304
306
|
}
|
|
305
307
|
if (useCache) {
|
|
306
|
-
queryString = TableName + '_' +
|
|
308
|
+
queryString = TableName + '_' + Cloud.asString(key, true) + (id !== undefined ? '_' + Cloud.asString(id, true) : '');
|
|
307
309
|
if (!update && (rows = getCache(queryString))) {
|
|
308
310
|
result[i] = rows;
|
|
309
311
|
continue;
|
|
@@ -331,7 +333,7 @@ async function executeBatchQuery(credential, batch, sessionKey) {
|
|
|
331
333
|
if (limit > 0) {
|
|
332
334
|
query.Limit = limit;
|
|
333
335
|
}
|
|
334
|
-
if (useCache && (rows = getCache(queryString =
|
|
336
|
+
if (useCache && (rows = getCache(queryString = Cloud.asString(query, true)))) {
|
|
335
337
|
result[i] = rows;
|
|
336
338
|
continue;
|
|
337
339
|
}
|
|
@@ -346,14 +348,14 @@ async function executeBatchQuery(credential, batch, sessionKey) {
|
|
|
346
348
|
if (!(0, types_1.isPlainObject)(params.RequestItems)) {
|
|
347
349
|
params.RequestItems = {};
|
|
348
350
|
}
|
|
349
|
-
TableName
|
|
351
|
+
TableName ||= Object.keys(params.RequestItems)[0];
|
|
350
352
|
if (!TableName) {
|
|
351
353
|
throw (0, util_1.formatError)(item, "Missing database table");
|
|
352
354
|
}
|
|
353
|
-
const Item =
|
|
355
|
+
const Item = params.RequestItems[TableName] ||= {};
|
|
354
356
|
Item.Keys = query;
|
|
355
357
|
params = { RequestItems: { [TableName]: Item } };
|
|
356
|
-
if (useCache && (rows = getCache(queryString =
|
|
358
|
+
if (useCache && (rows = getCache(queryString = Cloud.asString(params, true)))) {
|
|
357
359
|
result[i] = rows;
|
|
358
360
|
continue;
|
|
359
361
|
}
|
|
@@ -371,7 +373,7 @@ async function executeBatchQuery(credential, batch, sessionKey) {
|
|
|
371
373
|
else {
|
|
372
374
|
params = { TableName };
|
|
373
375
|
}
|
|
374
|
-
if (useCache && (rows = getCache(queryString =
|
|
376
|
+
if (useCache && (rows = getCache(queryString = Cloud.asString(params, true)))) {
|
|
375
377
|
result[i] = rows;
|
|
376
378
|
continue;
|
|
377
379
|
}
|
|
@@ -391,3 +393,5 @@ async function executeBatchQuery(credential, batch, sessionKey) {
|
|
|
391
393
|
return result;
|
|
392
394
|
}
|
|
393
395
|
exports.executeBatchQuery = executeBatchQuery;
|
|
396
|
+
exports.CLOUD_UPLOAD_STREAM = true;
|
|
397
|
+
exports.CLOUD_UPLOAD_CHUNK = true;
|
package/download/index.js
CHANGED
|
@@ -1,33 +1,31 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
const util_1 = require("@e-mc/cloud/util");
|
|
3
3
|
const types_1 = require("@e-mc/types");
|
|
4
|
-
const Module = require("@e-mc/module");
|
|
5
4
|
const Cloud = require("@e-mc/cloud");
|
|
6
5
|
const client_1 = require("@pi-r/aws-v3");
|
|
7
|
-
module.exports = function download(config, service =
|
|
6
|
+
module.exports = function download(config, service = "aws-v3", sdk = "@aws-sdk/client-s3") {
|
|
8
7
|
const [client, AWS] = client_1.createStorageClient.call(this, config, service, sdk);
|
|
9
8
|
return (data, callback) => {
|
|
10
9
|
const { bucket: Bucket, download: target } = data;
|
|
11
|
-
const Key = target.filename;
|
|
10
|
+
const Key = target.keyname || target.filename;
|
|
12
11
|
if (!Bucket || !Key) {
|
|
13
12
|
callback((0, types_1.errorValue)('Missing property', !Bucket ? 'Bucket' : 'Key'));
|
|
14
13
|
return;
|
|
15
14
|
}
|
|
16
|
-
const location =
|
|
17
|
-
|
|
18
|
-
client.send(new AWS.GetObjectCommand(input), { abortSignal: this.signal })
|
|
15
|
+
const location = Cloud.joinPath(Bucket, Key);
|
|
16
|
+
client.send(new AWS.GetObjectCommand({ ...target.options, Bucket, Key, VersionId: target.versionId }), { abortSignal: this.signal })
|
|
19
17
|
.then(result => {
|
|
20
|
-
(0, util_1.readableAsBuffer)(result.Body).then(buffer => callback(null, buffer)).catch(err => callback(err));
|
|
21
|
-
|
|
18
|
+
(0, util_1.readableAsBuffer)(result.Body).then(buffer => callback(null, buffer)).catch((err) => callback(err));
|
|
19
|
+
let deleteObject = target.deleteObject;
|
|
22
20
|
if (deleteObject) {
|
|
23
|
-
if ((0, types_1.isPlainObject)(deleteObject)) {
|
|
24
|
-
|
|
21
|
+
if (!(0, types_1.isPlainObject)(deleteObject)) {
|
|
22
|
+
deleteObject = undefined;
|
|
25
23
|
}
|
|
26
|
-
client.send(new AWS.DeleteObjectCommand(
|
|
24
|
+
client.send(new AWS.DeleteObjectCommand({ ...deleteObject, Bucket, Key, VersionId: target.versionId }))
|
|
27
25
|
.then(() => this.formatMessage(64, service, "Delete success", location, { ...Cloud.LOG_CLOUD_DELETE }))
|
|
28
|
-
.catch(err => this.formatFail(64, service, ["Delete failed", location], err, { ...Cloud.LOG_CLOUD_FAIL, fatal: !!target.active }));
|
|
26
|
+
.catch((err) => this.formatFail(64, service, ["Delete failed", location], err, { ...Cloud.LOG_CLOUD_FAIL, fatal: !!target.active }));
|
|
29
27
|
}
|
|
30
28
|
})
|
|
31
|
-
.catch(err => callback(err));
|
|
29
|
+
.catch((err) => callback(err));
|
|
32
30
|
};
|
|
33
31
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pi-r/aws-v3",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.1",
|
|
4
4
|
"description": "AWS V3 cloud functions for E-mc.",
|
|
5
5
|
"main": "client/index.js",
|
|
6
6
|
"publishConfig": {
|
|
@@ -20,13 +20,14 @@
|
|
|
20
20
|
"license": "MIT",
|
|
21
21
|
"homepage": "https://github.com/anpham6/pi-r#readme",
|
|
22
22
|
"dependencies": {
|
|
23
|
-
"@e-mc/cloud": "^0.
|
|
24
|
-
"@e-mc/module": "^0.
|
|
25
|
-
"@e-mc/types": "^0.
|
|
26
|
-
"@pi-r/aws": "^0.
|
|
27
|
-
"@aws-sdk/client-dynamodb": "^3.
|
|
28
|
-
"@aws-sdk/client-s3": "^3.
|
|
29
|
-
"@aws-sdk/credential-providers": "^3.
|
|
30
|
-
"@aws-sdk/lib-dynamodb": "^3.
|
|
23
|
+
"@e-mc/cloud": "^0.9.2",
|
|
24
|
+
"@e-mc/module": "^0.9.2",
|
|
25
|
+
"@e-mc/types": "^0.9.2",
|
|
26
|
+
"@pi-r/aws-lib": "^0.7.1",
|
|
27
|
+
"@aws-sdk/client-dynamodb": "^3.584.0",
|
|
28
|
+
"@aws-sdk/client-s3": "^3.583.0",
|
|
29
|
+
"@aws-sdk/credential-providers": "^3.583.0",
|
|
30
|
+
"@aws-sdk/lib-dynamodb": "^3.584.0",
|
|
31
|
+
"@aws-sdk/lib-storage": "^3.583.0"
|
|
31
32
|
}
|
|
32
33
|
}
|
package/types/index.d.ts
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { CloudDatabase, CloudStorage } from '@e-mc/types/lib/cloud';
|
|
2
|
+
|
|
3
|
+
import type { AwsAuthInputConfig } from '@aws-sdk/middleware-signing';
|
|
4
|
+
import type { DynamoDBClientConfig, QueryCommandInput, ScanCommandInput } from '@aws-sdk/client-dynamodb';
|
|
5
|
+
import type { BatchGetCommandInput, TranslateConfig, UpdateCommandInput } from '@aws-sdk/lib-dynamodb';
|
|
6
|
+
import type { NativeAttributeValue } from "@aws-sdk/util-dynamodb";
|
|
7
|
+
import type { S3ClientConfig } from '@aws-sdk/client-s3';
|
|
8
|
+
|
|
9
|
+
export interface AWSBaseCredential extends AwsAuthInputConfig {
|
|
10
|
+
provider?: {
|
|
11
|
+
http?: unknown;
|
|
12
|
+
ini?: unknown;
|
|
13
|
+
cognitoIdentity?: unknown;
|
|
14
|
+
cognitoIdentityPool?: unknown;
|
|
15
|
+
temporaryCredentials?: unknown;
|
|
16
|
+
webToken?: unknown;
|
|
17
|
+
containerMetadata?: unknown;
|
|
18
|
+
instanceMetadata?: unknown;
|
|
19
|
+
process?: unknown;
|
|
20
|
+
tokenFile?: unknown;
|
|
21
|
+
sso?: unknown;
|
|
22
|
+
env?: unknown;
|
|
23
|
+
nodeProviderChain?: unknown;
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export type AWSStorage = CloudStorage<AWSStorageCredential, "aws-v3">;
|
|
28
|
+
|
|
29
|
+
export interface AWSStorageCredential extends S3ClientConfig, AWSBaseCredential {}
|
|
30
|
+
|
|
31
|
+
export interface AWSDatabaseQuery extends CloudDatabase<QueryCommandInput | ObjectMap<NativeAttributeValue>[], PlainObject, UpdateCommandInput, BatchGetCommandInput | ScanCommandInput> {
|
|
32
|
+
source: "cloud";
|
|
33
|
+
service: "aws-v3";
|
|
34
|
+
key?: string | AttributeKey;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export interface AWSDatabaseCredential extends Omit<DynamoDBClientConfig, "credentials">, AWSBaseCredential {
|
|
38
|
+
translateConfig?: TranslateConfig;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export type AttributeKey = Record<string, NativeAttributeValue>;
|
package/upload/index.js
CHANGED
|
@@ -1,24 +1,24 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
const path = require("path");
|
|
3
|
+
const fs = require("fs");
|
|
3
4
|
const stream = require("stream");
|
|
5
|
+
const lib_storage_1 = require("@aws-sdk/lib-storage");
|
|
6
|
+
const Cloud = require("@e-mc/cloud");
|
|
4
7
|
const util_1 = require("@e-mc/cloud/util");
|
|
5
|
-
const aws_1 = require("@pi-r/aws");
|
|
6
8
|
const types_1 = require("@e-mc/types");
|
|
7
|
-
const
|
|
8
|
-
const Cloud = require("@e-mc/cloud");
|
|
9
|
+
const aws_lib_1 = require("@pi-r/aws-lib");
|
|
9
10
|
const client_1 = require("@pi-r/aws-v3");
|
|
10
11
|
const BUCKET_SESSION = new Set();
|
|
11
12
|
const BUCKET_RESPONSE = {};
|
|
12
|
-
module.exports = function upload(credential, service =
|
|
13
|
+
module.exports = function upload(credential, service = "aws-v3", sdk = "@aws-sdk/client-s3") {
|
|
13
14
|
const [client, AWS] = client_1.createStorageClient.call(this, credential, service, sdk);
|
|
14
15
|
return async (data, callback) => {
|
|
15
|
-
var _a;
|
|
16
16
|
const { bucket: Bucket, localUri } = data;
|
|
17
|
-
const { pathname = '', fileGroup, contentType, metadata, tags, endpoint, active, publicRead, acl, admin = {}, overwrite, options } = data.upload;
|
|
17
|
+
const { pathname = '', flags = 0, fileGroup, contentType, metadata, tags: Tags, endpoint, active, publicRead, acl, admin = {}, overwrite, options } = data.upload;
|
|
18
18
|
let filename = data.upload.filename || path.basename(localUri), bucketKey;
|
|
19
19
|
const cleanup = () => {
|
|
20
20
|
BUCKET_SESSION.delete(service + Bucket);
|
|
21
|
-
if (bucketKey
|
|
21
|
+
if (bucketKey) {
|
|
22
22
|
delete BUCKET_RESPONSE[bucketKey];
|
|
23
23
|
}
|
|
24
24
|
};
|
|
@@ -30,21 +30,49 @@ module.exports = function upload(credential, service = 'aws-v3', sdk = '@aws-sdk
|
|
|
30
30
|
const addLog = (err) => err instanceof Error && this.addLog(this.statusType.WARN, err, service, Bucket);
|
|
31
31
|
const configBucket = admin.configBucket;
|
|
32
32
|
if (!BUCKET_SESSION.has(service + Bucket)) {
|
|
33
|
-
const bucketAcl = admin.publicRead ?
|
|
34
|
-
const response = BUCKET_RESPONSE[
|
|
33
|
+
const bucketAcl = admin.publicRead ? "public-read" : admin.acl;
|
|
34
|
+
const response = BUCKET_RESPONSE[bucketKey = (0, aws_lib_1.getBucketKey)(credential, Bucket, bucketAcl, service, sdk)] ||= client_1.createBucketV2.call(this, credential, Bucket, bucketAcl, configBucket?.create, service, sdk);
|
|
35
35
|
if (!await response) {
|
|
36
36
|
errorResponse(null);
|
|
37
37
|
return;
|
|
38
38
|
}
|
|
39
39
|
BUCKET_SESSION.add(service + Bucket);
|
|
40
40
|
}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
41
|
+
if (configBucket) {
|
|
42
|
+
const { cors: CORSConfiguration, lifecycle: LifecycleConfiguration, retentionPolicy: DefaultRetention } = configBucket;
|
|
43
|
+
const ExpectedBucketOwner = options?.ExpectedBucketOwner;
|
|
44
|
+
const commandMessage = (feature, message) => this.formatMessage(64, service, ["Bucket configured" + ` (${feature})`, message || Bucket], ExpectedBucketOwner, { ...Cloud[message === 'delete' ? 'LOG_CLOUD_WARN' : 'LOG_CLOUD_COMMAND'] });
|
|
45
|
+
if ((0, types_1.isPlainObject)(DefaultRetention)) {
|
|
46
|
+
client.send(new AWS.PutObjectLockConfigurationCommand({ Bucket, ObjectLockConfiguration: { ObjectLockEnabled: 'Enabled', Rule: { DefaultRetention } }, ExpectedBucketOwner, RequestPayer: options?.RequestPayer }))
|
|
47
|
+
.then(() => {
|
|
48
|
+
this.formatMessage(64, service, ["Bucket configured" + ' (Retention Policy)', Bucket], (0, aws_lib_1.formatDefaultRetention)(DefaultRetention), { ...Cloud.LOG_CLOUD_COMMAND });
|
|
49
|
+
})
|
|
50
|
+
.catch((err) => addLog(err));
|
|
51
|
+
}
|
|
52
|
+
if (CORSConfiguration && Array.isArray(CORSConfiguration.CORSRules)) {
|
|
53
|
+
if (CORSConfiguration.CORSRules.length === 0) {
|
|
54
|
+
client.send(new AWS.DeleteBucketCorsCommand({ Bucket, ExpectedBucketOwner }))
|
|
55
|
+
.then(() => commandMessage('CORS', 'delete'))
|
|
56
|
+
.catch((err) => addLog(err));
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
client.send(new AWS.PutBucketCorsCommand({ Bucket, CORSConfiguration, ExpectedBucketOwner }))
|
|
60
|
+
.then(() => commandMessage('CORS'))
|
|
61
|
+
.catch((err) => addLog(err));
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
if (LifecycleConfiguration && Array.isArray(LifecycleConfiguration.Rules)) {
|
|
65
|
+
if (LifecycleConfiguration.Rules.length === 0) {
|
|
66
|
+
client.send(new AWS.DeleteBucketLifecycleCommand({ Bucket, ExpectedBucketOwner }))
|
|
67
|
+
.then(() => commandMessage('Lifecycle', 'delete'))
|
|
68
|
+
.catch((err) => addLog(err));
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
client.send(new AWS.PutBucketLifecycleConfigurationCommand({ Bucket, LifecycleConfiguration, ExpectedBucketOwner }))
|
|
72
|
+
.then(() => commandMessage('Lifecycle'))
|
|
73
|
+
.catch((err) => addLog(err));
|
|
74
|
+
}
|
|
75
|
+
}
|
|
48
76
|
}
|
|
49
77
|
if (!overwrite) {
|
|
50
78
|
const current = filename;
|
|
@@ -57,9 +85,9 @@ module.exports = function upload(credential, service = 'aws-v3', sdk = '@aws-sdk
|
|
|
57
85
|
break;
|
|
58
86
|
}
|
|
59
87
|
}
|
|
60
|
-
exists = await client.send(new AWS.HeadObjectCommand({ Bucket, Key: pathname ?
|
|
88
|
+
exists = await client.send(new AWS.HeadObjectCommand({ Bucket, Key: pathname ? Cloud.joinPath(pathname, filename) : filename }))
|
|
61
89
|
.then(() => true)
|
|
62
|
-
.catch(err => {
|
|
90
|
+
.catch((err) => {
|
|
63
91
|
if (err instanceof Error && err.name !== 'NotFound') {
|
|
64
92
|
filename = (0, types_1.generateUUID)() + path.extname(current);
|
|
65
93
|
return true;
|
|
@@ -75,13 +103,37 @@ module.exports = function upload(credential, service = 'aws-v3', sdk = '@aws-sdk
|
|
|
75
103
|
await client.send(new AWS.PutObjectCommand({ Bucket, Key: pathname, Body: Buffer.from(''), ContentLength: 0 })).catch(() => { });
|
|
76
104
|
}
|
|
77
105
|
const Key = [filename];
|
|
78
|
-
const Body = [
|
|
106
|
+
const Body = [];
|
|
107
|
+
const Stream = [];
|
|
79
108
|
const ContentType = [contentType];
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
109
|
+
let partSize = 0;
|
|
110
|
+
const getPartSize = () => partSize > 0 ? Math.max(partSize, 5242880) : undefined;
|
|
111
|
+
if (flags & 2) {
|
|
112
|
+
if (flags & 4) {
|
|
113
|
+
partSize = (0, types_1.alignSize)(data.upload.chunkSize, 1024);
|
|
114
|
+
}
|
|
115
|
+
try {
|
|
116
|
+
Stream.push(data.buffer.length ? stream.Readable.from(data.buffer, { highWaterMark: getPartSize() }) : fs.createReadStream(localUri, { highWaterMark: getPartSize(), signal: this.signal }));
|
|
117
|
+
if (fileGroup) {
|
|
118
|
+
const [key, body, type] = (0, util_1.createKeyAndBody)(filename, fileGroup, 0, addLog, 2);
|
|
119
|
+
Key.push(...key);
|
|
120
|
+
Stream.push(...body);
|
|
121
|
+
ContentType.push(...type);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
catch (err) {
|
|
125
|
+
errorResponse(err);
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
else {
|
|
130
|
+
Body.push(data.buffer);
|
|
131
|
+
if (fileGroup) {
|
|
132
|
+
const [key, body, type] = (0, util_1.createKeyAndBody)(filename, fileGroup, 0, addLog);
|
|
133
|
+
Key.push(...key);
|
|
134
|
+
Body.push(...body);
|
|
135
|
+
ContentType.push(...type);
|
|
136
|
+
}
|
|
85
137
|
}
|
|
86
138
|
for (let i = 0; i < Key.length; ++i) {
|
|
87
139
|
const first = i === 0;
|
|
@@ -91,81 +143,62 @@ module.exports = function upload(credential, service = 'aws-v3', sdk = '@aws-sdk
|
|
|
91
143
|
}
|
|
92
144
|
return;
|
|
93
145
|
}
|
|
94
|
-
const objectKey =
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
146
|
+
const objectKey = Cloud.joinPath(pathname, Key[i]);
|
|
147
|
+
const params = { ...options, Bucket, Key: pathname + Key[i], Body: Stream[i] || stream.Readable.from(Body[i]) };
|
|
148
|
+
const readable = publicRead || active && publicRead !== false && !acl;
|
|
149
|
+
let tags, length = -1;
|
|
150
|
+
if (first) {
|
|
151
|
+
params.ContentType ||= ContentType[i];
|
|
152
|
+
if (readable) {
|
|
153
|
+
params.ACL = "public-read";
|
|
154
|
+
}
|
|
155
|
+
else if (acl) {
|
|
156
|
+
params.ACL = acl;
|
|
157
|
+
}
|
|
158
|
+
if (metadata) {
|
|
159
|
+
params.Metadata = metadata;
|
|
160
|
+
}
|
|
161
|
+
if ((0, types_1.isPlainObject)(Tags) && (length = Object.keys(Tags).length) > 0) {
|
|
162
|
+
tags = [];
|
|
163
|
+
for (const name in Tags) {
|
|
164
|
+
tags.push({ Key: name, Value: Tags[name] });
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
else if (Tags === false) {
|
|
168
|
+
length = 0;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
else {
|
|
172
|
+
params.ContentType = ContentType[i];
|
|
173
|
+
if (!params.ACL) {
|
|
101
174
|
if (readable) {
|
|
102
|
-
params.ACL =
|
|
175
|
+
params.ACL = "public-read";
|
|
103
176
|
}
|
|
104
177
|
else if (acl) {
|
|
105
178
|
params.ACL = acl;
|
|
106
179
|
}
|
|
107
|
-
if (metadata) {
|
|
108
|
-
params.Metadata = metadata;
|
|
109
|
-
}
|
|
110
180
|
}
|
|
111
|
-
else {
|
|
112
|
-
params.ContentType = ContentType[i];
|
|
113
|
-
if (!params.ACL) {
|
|
114
|
-
if (readable) {
|
|
115
|
-
params.ACL = 'public-read';
|
|
116
|
-
}
|
|
117
|
-
else if (acl) {
|
|
118
|
-
params.ACL = acl;
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
catch (err) {
|
|
124
|
-
if (first) {
|
|
125
|
-
errorResponse(err);
|
|
126
|
-
return;
|
|
127
|
-
}
|
|
128
|
-
if (err instanceof Error) {
|
|
129
|
-
this.addLog(this.statusType.WARN, err.message, service + ': ' + Bucket);
|
|
130
|
-
}
|
|
131
|
-
continue;
|
|
132
181
|
}
|
|
133
|
-
|
|
182
|
+
new lib_storage_1.Upload({ client, params, tags, partSize: getPartSize(), queueSize: partSize > 0 ? data.upload.chunkLimit : undefined }).done()
|
|
134
183
|
.then(() => {
|
|
135
|
-
const url = endpoint ?
|
|
184
|
+
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);
|
|
136
185
|
this.formatMessage(64, service, "Upload success", url, { ...Cloud.LOG_CLOUD_UPLOAD });
|
|
137
|
-
if (
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
186
|
+
if (first) {
|
|
187
|
+
if (length === 0) {
|
|
188
|
+
client.send(new AWS.DeleteObjectTaggingCommand({ Bucket, Key: params.Key, ExpectedBucketOwner: params.ExpectedBucketOwner }), error => {
|
|
189
|
+
if (!error) {
|
|
190
|
+
this.formatMessage(64, service, ["Tags deleted", Bucket], params.Key, { ...Cloud.LOG_CLOUD_COMMAND });
|
|
191
|
+
}
|
|
192
|
+
else {
|
|
193
|
+
addLog(error);
|
|
194
|
+
}
|
|
195
|
+
});
|
|
145
196
|
}
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
}
|
|
150
|
-
else {
|
|
151
|
-
addLog(error);
|
|
152
|
-
}
|
|
153
|
-
});
|
|
154
|
-
}
|
|
155
|
-
else if (tags === false || length === 0) {
|
|
156
|
-
client.send(new AWS.DeleteObjectTaggingCommand({ Bucket, Key: params.Key, ExpectedBucketOwner: params.ExpectedBucketOwner }), error => {
|
|
157
|
-
if (!error) {
|
|
158
|
-
this.formatMessage(64, service, ["Tags deleted", Bucket], params.Key, { ...Cloud.LOG_CLOUD_COMMAND });
|
|
159
|
-
}
|
|
160
|
-
else {
|
|
161
|
-
addLog(error);
|
|
162
|
-
}
|
|
163
|
-
});
|
|
164
|
-
}
|
|
165
|
-
cleanup();
|
|
166
|
-
callback(null, url);
|
|
197
|
+
cleanup();
|
|
198
|
+
callback(null, url);
|
|
199
|
+
}
|
|
167
200
|
})
|
|
168
|
-
.catch(err => {
|
|
201
|
+
.catch((err) => {
|
|
169
202
|
if (first) {
|
|
170
203
|
errorResponse(err);
|
|
171
204
|
}
|