@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 CHANGED
@@ -1,10 +1,7 @@
1
- # @pi-r/aws-v3
1
+ ### @pi-r/aws-v3
2
2
 
3
- ## Documentation
3
+ https://e-mc.readthedocs.io/en/latest/cloud/aws-v3.html
4
4
 
5
- - [E-mc](https://e-mc.readthedocs.io/en/latest/cloud/aws-v3.html)
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
- Object.defineProperty(exports, "__esModule", { value: true });
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 aws_1 = require("@pi-r/aws");
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 Module = require("@e-mc/module");
11
- const Cloud = require("@e-mc/cloud");
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, aws_1.getBucketPublicReadPolicy)(Bucket);
14
+ Policy = (0, aws_lib_1.getBucketPublicReadPolicy)(Bucket);
17
15
  break;
18
- case 'public-read-write':
19
- Policy = (0, aws_1.getPublicReadPolicy)(Bucket, false, true);
16
+ case "public-read-write":
17
+ Policy = (0, aws_lib_1.getPublicReadPolicy)(Bucket, false, true);
20
18
  break;
21
- case 'authenticated-read':
22
- Policy = (0, aws_1.getPublicReadPolicy)(Bucket, true);
19
+ case "authenticated-read":
20
+ Policy = (0, aws_lib_1.getPublicReadPolicy)(Bucket, true);
23
21
  break;
24
22
  default:
25
- Policy = (0, aws_1.getPrivatePolicy)(Bucket);
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, aws_1.isEnvDefined)()) {
79
+ else if (from.env && (0, aws_lib_1.isEnvDefined)()) {
99
80
  credentials = Providers.fromEnv();
100
81
  }
101
- else if (from.ini && (0, aws_1.isSharedCredentialsDefined)()) {
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 = 'aws-v3', sdk = '@aws-sdk/client-s3') {
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 = sanitizeCredentials(credential);
145
- const profile = credential.profile;
146
- if (profile || !credentials && !credential.provider && (0, aws_1.isSharedCredentialsDefined)()) {
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 && (typeof credentials === 'function' || (0, aws_1.isAccessDefined)(credentials)) || (0, types_1.isPlainObject)(credential.provider) || (0, aws_1.isEnvDefined)();
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, aws_1.isDatabaseDefined)(credential, data) && validateStorage(credential);
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 = 'aws-v3', sdk = '@aws-sdk/client-s3') {
158
- return createBucketV2.call(this, credential, Bucket, publicRead ? 'public-read' : undefined, undefined, service, sdk);
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 = 'aws-v3', sdk = '@aws-sdk/client-s3') {
162
- ACL = ACL === 1 ? 1 : (0, aws_1.checkBucketCannedACL)(ACL);
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 !== 'us-east-1') {
175
- input.CreateBucketConfiguration || (input.CreateBucketConfiguration = { LocationConstraint: region });
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 = 'aws', sdk = 'aws-sdk/clients/s3') {
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 setBucketWebsite(credential, Bucket, options, service = 'aws', sdk = 'aws-sdk/clients/s3') {
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 configure bucket", Bucket], err, { ...Cloud.LOG_CLOUD_FAIL, fatal: false });
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 = 'aws-v3', sdk = '@aws-sdk/client-s3') {
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 || (client = createDatabaseClient.call(this, credential));
287
+ const createClient = () => client ||= createDatabaseClient.call(this, credential);
287
288
  const closeClient = () => client?.[0].destroy();
288
- (0, aws_1.setDatabaseEndpoint)(credential);
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, partitionKey, key = partitionKey, limit = 0, update, ignoreCache } = item;
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 + '_' + Module.asString(key, true) + (id !== undefined ? '_' + Module.asString(id, true) : '');
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 = Module.asString(query, true)))) {
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 || (TableName = Object.keys(params.RequestItems)[0]);
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 = (_a = params.RequestItems)[TableName] || (_a[TableName] = {});
355
+ const Item = params.RequestItems[TableName] ||= {};
355
356
  Item.Keys = query;
356
357
  params = { RequestItems: { [TableName]: Item } };
357
- if (useCache && (rows = getCache(queryString = Module.asString(params, true)))) {
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 = Module.asString(params, true)))) {
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 = 'aws-v3', sdk = '@aws-sdk/client-s3') {
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 = Module.joinPath(Bucket, Key);
17
- let input = { Bucket, Key, VersionId: target.versionId };
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
- const deleteObject = target.deleteObject;
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
- input = Object.assign(deleteObject, input);
21
+ if (!(0, types_1.isPlainObject)(deleteObject)) {
22
+ deleteObject = undefined;
25
23
  }
26
- client.send(new AWS.DeleteObjectCommand(input))
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.6.5",
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.8.6",
24
- "@e-mc/module": "^0.8.6",
25
- "@e-mc/types": "^0.8.6",
26
- "@pi-r/aws": "^0.6.5",
27
- "@aws-sdk/client-dynamodb": "^3.525.0",
28
- "@aws-sdk/client-s3": "^3.525.0",
29
- "@aws-sdk/credential-providers": "^3.525.0",
30
- "@aws-sdk/lib-dynamodb": "^3.525.0"
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
  }
@@ -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 Module = require("@e-mc/module");
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 = 'aws-v3', sdk = '@aws-sdk/client-s3') {
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 && bucketKey in BUCKET_RESPONSE) {
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 ? 'public-read' : admin.acl;
34
- const response = BUCKET_RESPONSE[_a = bucketKey = (0, aws_1.getBucketKey)(credential, Bucket, bucketAcl, service, sdk)] || (BUCKET_RESPONSE[_a] = client_1.createBucketV2.call(this, credential, Bucket, bucketAcl, configBucket?.create, service, sdk));
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
- const DefaultRetention = configBucket?.retentionPolicy;
42
- if ((0, types_1.isPlainObject)(DefaultRetention)) {
43
- client.send(new AWS.PutObjectLockConfigurationCommand({ Bucket, ObjectLockConfiguration: { ObjectLockEnabled: 'Enabled', Rule: { DefaultRetention } }, ExpectedBucketOwner: options?.ExpectedBucketOwner, RequestPayer: options?.RequestPayer }))
44
- .then(() => {
45
- aws_1.writeMessageDefaultRetention.call(this, Bucket, DefaultRetention, service);
46
- })
47
- .catch(err => addLog(err));
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 ? Module.joinPath(pathname, filename) : filename }))
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 = [data.buffer];
106
+ const Body = [];
107
+ const Stream = [];
79
108
  const ContentType = [contentType];
80
- if (fileGroup) {
81
- const [key, body, type] = (0, util_1.createKeyAndBody)(filename, fileGroup, addLog);
82
- Key.push(...key);
83
- Body.push(...body);
84
- ContentType.push(...type);
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 = Module.joinPath(pathname, Key[i]);
95
- let params;
96
- try {
97
- params = { ...options, Bucket, Key: pathname + Key[i], Body: stream.Readable.from(Body[i]) };
98
- const readable = publicRead || active && publicRead !== false && !acl;
99
- if (first) {
100
- params.ContentType || (params.ContentType = ContentType[i]);
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 = 'public-read';
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
- client.send(new AWS.PutObjectCommand(params), { abortSignal: this.signal })
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 ? Module.joinPath(endpoint, objectKey) : Module.joinPath(`https://${Bucket}.s3.${!credential.region || credential.region === 'us-east-1' ? 'us-east-1.' : ''}amazonaws.com`, objectKey);
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 (!first) {
138
- return;
139
- }
140
- let length = -1;
141
- if ((0, types_1.isPlainObject)(tags) && (length = Object.keys(tags).length) > 0) {
142
- const TagSet = [];
143
- for (const name in tags) {
144
- TagSet.push({ Key: name, Value: tags[name] });
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
- client.send(new AWS.PutObjectTaggingCommand({ Bucket, Key: params.Key, ExpectedBucketOwner: params.ExpectedBucketOwner, Tagging: { TagSet }, RequestPayer: params.RequestPayer }), error => {
147
- if (!error) {
148
- this.formatMessage(64, service, ["Tags created", Bucket], params.Key, { ...Cloud.LOG_CLOUD_COMMAND });
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
+ };