@pi-r/aws-v3 0.6.5 → 0.7.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/README.md +3 -6
- package/client/index.js +68 -65
- package/download/index.js +12 -16
- package/package.json +10 -9
- package/types/index.d.ts +41 -0
- package/upload/index.js +122 -91
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,28 +1,26 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
|
|
3
|
-
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;
|
|
4
3
|
const Lib = require("@aws-sdk/lib-dynamodb");
|
|
5
4
|
const Client = require("@aws-sdk/client-dynamodb");
|
|
6
5
|
const Providers = require("@aws-sdk/credential-providers");
|
|
7
|
-
const
|
|
6
|
+
const Cloud = require("@e-mc/cloud");
|
|
8
7
|
const util_1 = require("@e-mc/cloud/util");
|
|
9
8
|
const types_1 = require("@e-mc/types");
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
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) {
|
|
13
11
|
let Policy;
|
|
14
12
|
switch (ACL) {
|
|
15
13
|
case 1:
|
|
16
|
-
Policy = (0,
|
|
14
|
+
Policy = (0, aws_lib_1.getBucketPublicReadPolicy)(Bucket);
|
|
17
15
|
break;
|
|
18
|
-
case
|
|
19
|
-
Policy = (0,
|
|
16
|
+
case "public-read-write":
|
|
17
|
+
Policy = (0, aws_lib_1.getPublicReadPolicy)(Bucket, false, true);
|
|
20
18
|
break;
|
|
21
|
-
case
|
|
22
|
-
Policy = (0,
|
|
19
|
+
case "authenticated-read":
|
|
20
|
+
Policy = (0, aws_lib_1.getPublicReadPolicy)(Bucket, true);
|
|
23
21
|
break;
|
|
24
22
|
default:
|
|
25
|
-
Policy = (0,
|
|
23
|
+
Policy = (0, aws_lib_1.getPrivatePolicy)(Bucket);
|
|
26
24
|
break;
|
|
27
25
|
}
|
|
28
26
|
return client.send(new S3.PutBucketPolicyCommand({ Bucket, Policy }))
|
|
@@ -41,23 +39,6 @@ async function setCannedAcl(S3, client, Bucket, ACL, service = 'aws-v3', recursi
|
|
|
41
39
|
}
|
|
42
40
|
});
|
|
43
41
|
}
|
|
44
|
-
function sanitizeCredentials(credential) {
|
|
45
|
-
const result = credential.credentials || (credential.credentials = {});
|
|
46
|
-
for (const attr in credential) {
|
|
47
|
-
switch (attr) {
|
|
48
|
-
case 'accessKeyId':
|
|
49
|
-
case 'secretAccessKey':
|
|
50
|
-
case 'sessionToken':
|
|
51
|
-
case 'expiration':
|
|
52
|
-
if (typeof result !== 'function') {
|
|
53
|
-
result[attr] = credential[attr];
|
|
54
|
-
}
|
|
55
|
-
delete credential[attr];
|
|
56
|
-
break;
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
return result;
|
|
60
|
-
}
|
|
61
42
|
function fromProvider(credential) {
|
|
62
43
|
const from = credential.provider;
|
|
63
44
|
let credentials = credential.credentials;
|
|
@@ -95,10 +76,10 @@ function fromProvider(credential) {
|
|
|
95
76
|
else if ((0, types_1.isPlainObject)(from.sso)) {
|
|
96
77
|
credentials = Providers.fromSSO(from.sso);
|
|
97
78
|
}
|
|
98
|
-
else if (from.env && (0,
|
|
79
|
+
else if (from.env && (0, aws_lib_1.isEnvDefined)()) {
|
|
99
80
|
credentials = Providers.fromEnv();
|
|
100
81
|
}
|
|
101
|
-
else if (from.ini && (0,
|
|
82
|
+
else if (from.ini && (0, aws_lib_1.isSharedCredentialsDefined)()) {
|
|
102
83
|
credentials = Providers.fromIni();
|
|
103
84
|
}
|
|
104
85
|
if ((0, types_1.isPlainObject)(credentials)) {
|
|
@@ -124,9 +105,8 @@ function fromProvider(credential) {
|
|
|
124
105
|
return credential;
|
|
125
106
|
}
|
|
126
107
|
const isNoSuchBucket = (err) => err instanceof Error && err.name === 'NoSuchBucket';
|
|
127
|
-
function createStorageClient(credential, service =
|
|
108
|
+
function createStorageClient(credential, service = "aws-v3", sdk = "@aws-sdk/client-s3") {
|
|
128
109
|
try {
|
|
129
|
-
sanitizeCredentials(credential);
|
|
130
110
|
const AWS = require(sdk);
|
|
131
111
|
return [new AWS.S3Client(fromProvider(credential)), AWS];
|
|
132
112
|
}
|
|
@@ -141,25 +121,24 @@ function createDatabaseClient(credential) {
|
|
|
141
121
|
}
|
|
142
122
|
exports.createDatabaseClient = createDatabaseClient;
|
|
143
123
|
function validateStorage(credential) {
|
|
144
|
-
const credentials =
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
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();
|
|
148
127
|
return true;
|
|
149
128
|
}
|
|
150
|
-
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)();
|
|
151
130
|
}
|
|
152
131
|
exports.validateStorage = validateStorage;
|
|
153
132
|
function validateDatabase(credential, data) {
|
|
154
|
-
return (0,
|
|
133
|
+
return (0, aws_lib_1.isDatabaseDefined)(credential, data) && validateStorage(credential);
|
|
155
134
|
}
|
|
156
135
|
exports.validateDatabase = validateDatabase;
|
|
157
|
-
async function createBucket(credential, Bucket, publicRead, service =
|
|
158
|
-
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);
|
|
159
138
|
}
|
|
160
139
|
exports.createBucket = createBucket;
|
|
161
|
-
async function createBucketV2(credential, Bucket, ACL, options, service =
|
|
162
|
-
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);
|
|
163
142
|
const [client, AWS] = createStorageClient.call(this, credential, service, sdk);
|
|
164
143
|
return client.send(new AWS.HeadBucketCommand({ Bucket }))
|
|
165
144
|
.then(async () => {
|
|
@@ -171,8 +150,8 @@ async function createBucketV2(credential, Bucket, ACL, options, service = 'aws-v
|
|
|
171
150
|
.catch(async () => {
|
|
172
151
|
const input = { ...options, Bucket };
|
|
173
152
|
const region = credential.region;
|
|
174
|
-
if ((0, types_1.isString)(region) && region !==
|
|
175
|
-
input.CreateBucketConfiguration
|
|
153
|
+
if ((0, types_1.isString)(region) && region !== "us-east-1") {
|
|
154
|
+
input.CreateBucketConfiguration ||= { LocationConstraint: region };
|
|
176
155
|
}
|
|
177
156
|
return client.send(new AWS.CreateBucketCommand(input))
|
|
178
157
|
.then(async () => {
|
|
@@ -198,7 +177,7 @@ async function createBucketV2(credential, Bucket, ACL, options, service = 'aws-v
|
|
|
198
177
|
});
|
|
199
178
|
}
|
|
200
179
|
exports.createBucketV2 = createBucketV2;
|
|
201
|
-
async function setBucketPolicy(credential, Bucket, options, service =
|
|
180
|
+
async function setBucketPolicy(credential, Bucket, options, service = "aws-v3", sdk = "@aws-sdk/client-s3") {
|
|
202
181
|
const [client, AWS] = createStorageClient.call(this, credential, service, sdk);
|
|
203
182
|
const block = 'PublicAccessBlockConfiguration' in options;
|
|
204
183
|
const policy = !block && 'Policy' in options && !('ACL' in options);
|
|
@@ -208,7 +187,7 @@ async function setBucketPolicy(credential, Bucket, options, service = 'aws', sdk
|
|
|
208
187
|
this.formatMessage(64, service, [block ? "Bucket configured" : policy ? "Bucket policy configured" : "Bucket ACL configured", Bucket], '', { ...Cloud.LOG_CLOUD_COMMAND });
|
|
209
188
|
return true;
|
|
210
189
|
})
|
|
211
|
-
.catch(err => {
|
|
190
|
+
.catch((err) => {
|
|
212
191
|
if (!isNoSuchBucket(err)) {
|
|
213
192
|
this.formatFail(64, service, ["Unable to update bucket policy", Bucket], err, { ...Cloud.LOG_CLOUD_FAIL, fatal: false });
|
|
214
193
|
}
|
|
@@ -216,7 +195,30 @@ async function setBucketPolicy(credential, Bucket, options, service = 'aws', sdk
|
|
|
216
195
|
});
|
|
217
196
|
}
|
|
218
197
|
exports.setBucketPolicy = setBucketPolicy;
|
|
219
|
-
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") {
|
|
220
222
|
const [client, AWS] = createStorageClient.call(this, credential, service, sdk);
|
|
221
223
|
const WebsiteConfiguration = {};
|
|
222
224
|
const { indexPage: Suffix, errorPage: Key } = options;
|
|
@@ -228,22 +230,22 @@ async function setBucketWebsite(credential, Bucket, options, service = 'aws', sd
|
|
|
228
230
|
}
|
|
229
231
|
return client.send(new AWS.PutBucketWebsiteCommand({ Bucket, WebsiteConfiguration }))
|
|
230
232
|
.then(() => {
|
|
231
|
-
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 });
|
|
232
234
|
return true;
|
|
233
235
|
})
|
|
234
|
-
.catch(err => {
|
|
236
|
+
.catch((err) => {
|
|
235
237
|
if (!isNoSuchBucket(err)) {
|
|
236
|
-
this.formatFail(64, service, ["Unable to
|
|
238
|
+
this.formatFail(64, service, ["Unable to set bucket website", Bucket], err, { ...Cloud.LOG_CLOUD_FAIL, fatal: false });
|
|
237
239
|
}
|
|
238
240
|
return false;
|
|
239
241
|
});
|
|
240
242
|
}
|
|
241
243
|
exports.setBucketWebsite = setBucketWebsite;
|
|
242
|
-
async function deleteObjects(credential, Bucket, service, sdk) {
|
|
244
|
+
async function deleteObjects(credential, Bucket, service = "aws-v3", sdk = "@aws-sdk/client-s3") {
|
|
243
245
|
return deleteObjectsV2.call(this, credential, Bucket, true, service, sdk);
|
|
244
246
|
}
|
|
245
247
|
exports.deleteObjects = deleteObjects;
|
|
246
|
-
async function deleteObjectsV2(credential, Bucket, recursive = true, service =
|
|
248
|
+
async function deleteObjectsV2(credential, Bucket, recursive = true, service = "aws-v3", sdk = "@aws-sdk/client-s3") {
|
|
247
249
|
const [client, AWS] = createStorageClient.call(this, credential, service, sdk);
|
|
248
250
|
return client.send(new AWS.ListObjectsCommand({ Bucket }))
|
|
249
251
|
.then(async ({ Contents }) => {
|
|
@@ -260,12 +262,12 @@ async function deleteObjectsV2(credential, Bucket, recursive = true, service = '
|
|
|
260
262
|
this.formatMessage(64, service, ["Bucket emptied" + ` (${recursive ? 'recursive' : files})`, Bucket], recursive ? files : '', { ...Cloud.LOG_CLOUD_COMMAND });
|
|
261
263
|
}
|
|
262
264
|
})
|
|
263
|
-
.catch(err => {
|
|
265
|
+
.catch((err) => {
|
|
264
266
|
this.formatFail(64, service, ["Unable to empty bucket", Bucket], err, { ...Cloud.LOG_CLOUD_FAIL, fatal: false });
|
|
265
267
|
});
|
|
266
268
|
}
|
|
267
269
|
})
|
|
268
|
-
.catch(err => {
|
|
270
|
+
.catch((err) => {
|
|
269
271
|
if (!isNoSuchBucket(err)) {
|
|
270
272
|
this.formatFail(64, service, ["Unable to list bucket", Bucket], err, { ...Cloud.LOG_CLOUD_FAIL, fatal: false });
|
|
271
273
|
}
|
|
@@ -277,18 +279,17 @@ async function executeQuery(credential, data, sessionKey) {
|
|
|
277
279
|
}
|
|
278
280
|
exports.executeQuery = executeQuery;
|
|
279
281
|
async function executeBatchQuery(credential, batch, sessionKey) {
|
|
280
|
-
var _a;
|
|
281
282
|
const length = batch.length;
|
|
282
283
|
const result = new Array(length);
|
|
283
284
|
const caching = length > 0 && this.hasCache(batch[0].service, sessionKey);
|
|
284
285
|
const cacheValue = { value: this.valueOfKey(credential, 'cache'), sessionKey };
|
|
285
286
|
let client;
|
|
286
|
-
const createClient = () => client
|
|
287
|
+
const createClient = () => client ||= createDatabaseClient.call(this, credential);
|
|
287
288
|
const closeClient = () => client?.[0].destroy();
|
|
288
|
-
(0,
|
|
289
|
+
(0, aws_lib_1.setDatabaseEndpoint)(credential);
|
|
289
290
|
for (let i = 0; i < length; ++i) {
|
|
290
291
|
const item = batch[i];
|
|
291
|
-
let { service, table: TableName, id, query,
|
|
292
|
+
let { service, table: TableName, id, query, key, limit = 0, update, ignoreCache } = item;
|
|
292
293
|
const useCache = caching && ignoreCache !== true;
|
|
293
294
|
const getCache = (value) => {
|
|
294
295
|
if (ignoreCache !== 1) {
|
|
@@ -304,7 +305,7 @@ async function executeBatchQuery(credential, batch, sessionKey) {
|
|
|
304
305
|
throw (0, util_1.formatError)(item, "Missing database table");
|
|
305
306
|
}
|
|
306
307
|
if (useCache) {
|
|
307
|
-
queryString = TableName + '_' +
|
|
308
|
+
queryString = TableName + '_' + Cloud.asString(key, true) + (id !== undefined ? '_' + Cloud.asString(id, true) : '');
|
|
308
309
|
if (!update && (rows = getCache(queryString))) {
|
|
309
310
|
result[i] = rows;
|
|
310
311
|
continue;
|
|
@@ -332,7 +333,7 @@ async function executeBatchQuery(credential, batch, sessionKey) {
|
|
|
332
333
|
if (limit > 0) {
|
|
333
334
|
query.Limit = limit;
|
|
334
335
|
}
|
|
335
|
-
if (useCache && (rows = getCache(queryString =
|
|
336
|
+
if (useCache && (rows = getCache(queryString = Cloud.asString(query, true)))) {
|
|
336
337
|
result[i] = rows;
|
|
337
338
|
continue;
|
|
338
339
|
}
|
|
@@ -347,14 +348,14 @@ async function executeBatchQuery(credential, batch, sessionKey) {
|
|
|
347
348
|
if (!(0, types_1.isPlainObject)(params.RequestItems)) {
|
|
348
349
|
params.RequestItems = {};
|
|
349
350
|
}
|
|
350
|
-
TableName
|
|
351
|
+
TableName ||= Object.keys(params.RequestItems)[0];
|
|
351
352
|
if (!TableName) {
|
|
352
353
|
throw (0, util_1.formatError)(item, "Missing database table");
|
|
353
354
|
}
|
|
354
|
-
const Item =
|
|
355
|
+
const Item = params.RequestItems[TableName] ||= {};
|
|
355
356
|
Item.Keys = query;
|
|
356
357
|
params = { RequestItems: { [TableName]: Item } };
|
|
357
|
-
if (useCache && (rows = getCache(queryString =
|
|
358
|
+
if (useCache && (rows = getCache(queryString = Cloud.asString(params, true)))) {
|
|
358
359
|
result[i] = rows;
|
|
359
360
|
continue;
|
|
360
361
|
}
|
|
@@ -372,7 +373,7 @@ async function executeBatchQuery(credential, batch, sessionKey) {
|
|
|
372
373
|
else {
|
|
373
374
|
params = { TableName };
|
|
374
375
|
}
|
|
375
|
-
if (useCache && (rows = getCache(queryString =
|
|
376
|
+
if (useCache && (rows = getCache(queryString = Cloud.asString(params, true)))) {
|
|
376
377
|
result[i] = rows;
|
|
377
378
|
continue;
|
|
378
379
|
}
|
|
@@ -392,3 +393,5 @@ async function executeBatchQuery(credential, batch, sessionKey) {
|
|
|
392
393
|
return result;
|
|
393
394
|
}
|
|
394
395
|
exports.executeBatchQuery = executeBatchQuery;
|
|
396
|
+
exports.CLOUD_UPLOAD_STREAM = true;
|
|
397
|
+
exports.CLOUD_UPLOAD_CHUNK = true;
|
package/download/index.js
CHANGED
|
@@ -1,35 +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
|
-
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
|
-
}
|
|
34
|
-
|
|
35
|
-
module.exports = download;
|
|
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.0",
|
|
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.0",
|
|
24
|
+
"@e-mc/module": "^0.9.0",
|
|
25
|
+
"@e-mc/types": "^0.9.0",
|
|
26
|
+
"@pi-r/aws-lib": "^0.7.0",
|
|
27
|
+
"@aws-sdk/client-dynamodb": "^3.563.0",
|
|
28
|
+
"@aws-sdk/client-s3": "^3.563.0",
|
|
29
|
+
"@aws-sdk/credential-providers": "^3.563.0",
|
|
30
|
+
"@aws-sdk/lib-dynamodb": "^3.563.0",
|
|
31
|
+
"@aws-sdk/lib-storage": "^3.563.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
|
-
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 @@ function upload(credential, service = 'aws-v3', sdk = '@aws-sdk/client-s3') {
|
|
|
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 @@ function upload(credential, service = 'aws-v3', sdk = '@aws-sdk/client-s3') {
|
|
|
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 @@ function upload(credential, service = 'aws-v3', sdk = '@aws-sdk/client-s3') {
|
|
|
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 @@ function upload(credential, service = 'aws-v3', sdk = '@aws-sdk/client-s3') {
|
|
|
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
|
}
|
|
@@ -175,6 +208,4 @@ function upload(credential, service = 'aws-v3', sdk = '@aws-sdk/client-s3') {
|
|
|
175
208
|
});
|
|
176
209
|
}
|
|
177
210
|
};
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
module.exports = upload;
|
|
211
|
+
};
|