@pi-r/aws 0.5.0 → 0.6.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/client/index.d.ts CHANGED
@@ -6,7 +6,7 @@ import type { AWSDatabaseCredential, AWSDatabaseQuery, AWSStorageCredential, Buc
6
6
 
7
7
  import type { ConfigurationOptions } from 'aws-sdk/lib/core';
8
8
  import type { ServiceConfigurationOptions } from 'aws-sdk/lib/service';
9
- import type { DocumentClient } from 'aws-sdk/clients/dynamodb';
9
+ import type { AttributeValue, DocumentClient } from 'aws-sdk/clients/dynamodb';
10
10
  import type { DynamoDBClientConfig } from '@aws-sdk/client-dynamodb';
11
11
  import type { CreateBucketRequest } from 'aws-sdk/clients/s3';
12
12
 
@@ -32,6 +32,7 @@ declare namespace AWS {
32
32
  function setDatabaseEndpoint(config: ServiceConfigurationOptions | DynamoDBClientConfig): void;
33
33
  function checkBucketCannedACL(value: unknown): BucketCannedACL | undefined;
34
34
  function writeMessageDefaultRetention(this: IModule, bucket: string, retention: s3.DefaultRetention, service?: string): void;
35
+ function parseAttributeValue(value: unknown): AttributeValue;
35
36
  function getBucketKey(credential: unknown, Bucket: string, acl: string | undefined, service: string, sdk: string): string;
36
37
  function isNoSuchBucket(err: unknown): boolean;
37
38
  }
package/client/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.isNoSuchBucket = exports.getBucketKey = exports.writeMessageDefaultRetention = exports.checkBucketCannedACL = exports.setDatabaseEndpoint = exports.executeBatchQuery = exports.executeQuery = exports.deleteObjectsV2 = exports.deleteObjects = exports.setBucketWebsite = exports.setBucketPolicy = exports.createBucketV2 = exports.createBucket = exports.createDatabaseClient = exports.createStorageClient = exports.validateDatabase = exports.validateStorage = exports.getPrivatePolicy = exports.getBucketPublicReadPolicy = exports.getPublicReadPolicy = exports.isDatabaseDefined = exports.isEnvDefined = exports.isAccessDefined = void 0;
3
+ exports.isNoSuchBucket = exports.getBucketKey = exports.parseAttributeValue = exports.writeMessageDefaultRetention = exports.checkBucketCannedACL = exports.setDatabaseEndpoint = exports.executeBatchQuery = exports.executeQuery = exports.deleteObjectsV2 = exports.deleteObjects = exports.setBucketWebsite = exports.setBucketPolicy = exports.createBucketV2 = exports.createBucket = exports.createDatabaseClient = exports.createStorageClient = exports.validateDatabase = exports.validateStorage = exports.getPrivatePolicy = exports.getBucketPublicReadPolicy = exports.getPublicReadPolicy = exports.isDatabaseDefined = exports.isEnvDefined = exports.isAccessDefined = void 0;
4
4
  const aws = require("aws-sdk");
5
5
  const types_1 = require("@e-mc/types");
6
6
  const util_1 = require("@e-mc/cloud/util");
@@ -22,7 +22,7 @@ async function setCannedAcl(S3, Bucket, ACL, service = 'aws', recursive) {
22
22
  }
23
23
  else if (!recursive) {
24
24
  if (err instanceof Error && err.code === 'OperationAborted') {
25
- setTimeout(() => setCannedAcl.call(this, S3, Bucket, ACL, service, true), 60000 /* TIME.m */);
25
+ setTimeout(async () => setCannedAcl.call(this, S3, Bucket, ACL, service, true), 60000 /* TIME.m */);
26
26
  this.formatMessage(64 /* LOG_TYPE.CLOUD */, service, [`Grant ${ACL} (delayed)`, Bucket], err, { ...Cloud.LOG_CLOUD_DELAYED });
27
27
  }
28
28
  else {
@@ -158,11 +158,11 @@ function createDatabaseClient(credential) {
158
158
  return new aws.DynamoDB.DocumentClient(options);
159
159
  }
160
160
  exports.createDatabaseClient = createDatabaseClient;
161
- function createBucket(credential, Bucket, publicRead, service = 'aws', sdk = 'aws-sdk/clients/s3') {
161
+ async function createBucket(credential, Bucket, publicRead, service = 'aws', sdk = 'aws-sdk/clients/s3') {
162
162
  return createBucketV2.call(this, credential, Bucket, publicRead ? 'public-read' : undefined, undefined, service, sdk);
163
163
  }
164
164
  exports.createBucket = createBucket;
165
- function createBucketV2(credential, Bucket, ACL, options, service = 'aws', sdk = 'aws-sdk/clients/s3') {
165
+ async function createBucketV2(credential, Bucket, ACL, options, service = 'aws', sdk = 'aws-sdk/clients/s3') {
166
166
  ACL = ACL === 1 ? 1 : checkBucketCannedACL(ACL);
167
167
  const S3 = createStorageClient.call(this, credential, service, sdk);
168
168
  return S3.headBucket({ Bucket }).promise()
@@ -172,7 +172,7 @@ function createBucketV2(credential, Bucket, ACL, options, service = 'aws', sdk =
172
172
  }
173
173
  return true;
174
174
  })
175
- .catch(() => {
175
+ .catch(async () => {
176
176
  const input = { ...options, Bucket };
177
177
  const region = credential.region;
178
178
  if (region && (region !== 'us-east-1' || service !== 'aws')) {
@@ -202,7 +202,7 @@ function createBucketV2(credential, Bucket, ACL, options, service = 'aws', sdk =
202
202
  });
203
203
  }
204
204
  exports.createBucketV2 = createBucketV2;
205
- function setBucketPolicy(credential, Bucket, options, service = 'aws', sdk = 'aws-sdk/clients/s3') {
205
+ async function setBucketPolicy(credential, Bucket, options, service = 'aws', sdk = 'aws-sdk/clients/s3') {
206
206
  const ibm = service === 'ibm';
207
207
  const S3 = createStorageClient.call(this, credential, service, sdk);
208
208
  options.Bucket = Bucket;
@@ -223,7 +223,7 @@ function setBucketPolicy(credential, Bucket, options, service = 'aws', sdk = 'aw
223
223
  });
224
224
  }
225
225
  exports.setBucketPolicy = setBucketPolicy;
226
- function setBucketWebsite(credential, Bucket, options, service = 'aws', sdk = 'aws-sdk/clients/s3') {
226
+ async function setBucketWebsite(credential, Bucket, options, service = 'aws', sdk = 'aws-sdk/clients/s3') {
227
227
  const S3 = createStorageClient.call(this, credential, service, sdk);
228
228
  const WebsiteConfiguration = {};
229
229
  const { indexPage: Suffix, errorPage: Key } = options;
@@ -246,18 +246,18 @@ function setBucketWebsite(credential, Bucket, options, service = 'aws', sdk = 'a
246
246
  });
247
247
  }
248
248
  exports.setBucketWebsite = setBucketWebsite;
249
- function deleteObjects(credential, Bucket, service = 'aws', sdk = 'aws-sdk/clients/s3') {
249
+ async function deleteObjects(credential, Bucket, service = 'aws', sdk = 'aws-sdk/clients/s3') {
250
250
  return deleteObjectsV2.call(this, credential, Bucket, true, service, sdk);
251
251
  }
252
252
  exports.deleteObjects = deleteObjects;
253
253
  async function deleteObjectsV2(credential, Bucket, recursive = true, service = 'aws', sdk = 'aws-sdk/clients/s3') {
254
254
  const S3 = createStorageClient.call(this, credential, service, sdk);
255
255
  return S3.listObjects({ Bucket }).promise()
256
- .then(({ Contents }) => {
256
+ .then(async ({ Contents }) => {
257
257
  if (Contents?.length) {
258
258
  let Objects = Contents.map(data => ({ Key: data.Key }));
259
259
  if (!recursive) {
260
- Objects = Objects.filter(value => value.Key.indexOf('/') === -1);
260
+ Objects = Objects.filter(value => !value.Key.includes('/'));
261
261
  }
262
262
  return S3.deleteObjects({ Bucket, Delete: { Objects } }).promise()
263
263
  .then(data => {
@@ -284,40 +284,39 @@ async function executeQuery(credential, data, sessionKey) {
284
284
  }
285
285
  exports.executeQuery = executeQuery;
286
286
  async function executeBatchQuery(credential, batch, sessionKey) {
287
+ var _a;
287
288
  const length = batch.length;
288
289
  const result = new Array(length);
289
290
  const caching = length > 0 && this.hasCache(batch[0].service, sessionKey);
290
291
  const cacheValue = { value: this.valueOfKey(credential, 'cache'), sessionKey };
291
292
  let client;
292
- const createClient = () => {
293
- setDatabaseEndpoint(credential);
294
- return client || (client = createDatabaseClient.call(this, length === 1 ? credential : { ...credential }));
295
- };
293
+ const createClient = () => client || (client = createDatabaseClient.call(this, credential));
294
+ setDatabaseEndpoint(credential);
296
295
  for (let i = 0; i < length; ++i) {
297
296
  const item = batch[i];
298
- const { service, table, id = '', query, partitionKey, key = partitionKey, limit = 0, update, ignoreCache } = item;
299
- if (!table) {
300
- throw (0, util_1.formatError)(item, "Missing database table" /* ERR_DB.TABLE */);
301
- }
302
- const renewCache = ignoreCache === 0;
297
+ let { service, table: TableName, id, query, partitionKey, key = partitionKey, limit = 0, update, ignoreCache } = item;
298
+ const useCache = caching && ignoreCache !== true;
303
299
  const getCache = (value) => {
304
- if (ignoreCache === 1) {
305
- return;
300
+ if (ignoreCache !== 1) {
301
+ cacheValue.renewCache = ignoreCache === 0;
302
+ return this.getQueryResult(service, credential, value, cacheValue);
306
303
  }
307
- cacheValue.renewCache = renewCache;
308
- return this.getQueryResult(service, credential, value, cacheValue);
309
304
  };
310
- let rows, queryString = caching && ignoreCache !== true || ignoreCache === false || ignoreCache === 1 || renewCache ? table + '_' : '';
305
+ cacheValue.exclusiveOf = Array.isArray(ignoreCache) ? ignoreCache : undefined;
306
+ let rows, queryString = '';
311
307
  if (key && (id || (0, types_1.isPlainObject)(key))) {
312
- if (queryString) {
313
- queryString += Module.asString(key, true) + id;
308
+ if (!TableName) {
309
+ throw (0, util_1.formatError)(item, "Missing database table" /* ERR_DB.TABLE */);
310
+ }
311
+ if (useCache) {
312
+ queryString = TableName + '_' + Module.asString(key, true) + (id !== undefined ? '_' + Module.asString(id, true) : '');
314
313
  if (!update && (rows = getCache(queryString))) {
315
314
  result[i] = rows;
316
315
  continue;
317
316
  }
318
317
  }
319
- const Key = (0, types_1.isPlainObject)(key) ? key : { [key]: id };
320
- const command = { TableName: table, Key };
318
+ const Key = (0, types_1.isPlainObject)(key) ? key : { [key]: parseAttributeValue(id) };
319
+ const command = { TableName, Key };
321
320
  client = createClient();
322
321
  if (update) {
323
322
  await client.update({ ...command, ...update }).promise();
@@ -328,19 +327,63 @@ async function executeBatchQuery(credential, batch, sessionKey) {
328
327
  }
329
328
  }
330
329
  else if ((0, types_1.isPlainObject)(query)) {
331
- if (queryString && (rows = getCache(queryString += Module.asString(query, true) + limit))) {
332
- result[i] = rows;
333
- continue;
330
+ if (TableName) {
331
+ query.TableName = TableName;
334
332
  }
335
- query.TableName = table;
336
333
  if (limit > 0) {
337
334
  query.Limit = limit;
338
335
  }
336
+ if (!TableName) {
337
+ throw (0, util_1.formatError)(item, "Missing database table" /* ERR_DB.TABLE */);
338
+ }
339
+ if (useCache && (rows = getCache(queryString = Module.asString(query, true)))) {
340
+ result[i] = rows;
341
+ continue;
342
+ }
339
343
  const { Count, Items } = await createClient().query(query).promise();
340
344
  if (Count && Items) {
341
345
  rows = Items;
342
346
  }
343
347
  }
348
+ else if ((0, types_1.isArray)(query)) {
349
+ let params = (item.params || {});
350
+ if (!(0, types_1.isPlainObject)(params.RequestItems)) {
351
+ params.RequestItems = {};
352
+ }
353
+ TableName || (TableName = Object.keys(params.RequestItems)[0]);
354
+ if (!TableName) {
355
+ throw (0, util_1.formatError)(item, "Missing database table" /* ERR_DB.TABLE */);
356
+ }
357
+ // @ts-ignore
358
+ const Item = (_a = params.RequestItems)[TableName] || (_a[TableName] = {});
359
+ Item.Keys = query;
360
+ params = { RequestItems: { [TableName]: Item } };
361
+ if (useCache && (rows = getCache(queryString = Module.asString(params, true)))) {
362
+ result[i] = rows;
363
+ continue;
364
+ }
365
+ const { Responses } = await createClient().batchGet(params).promise();
366
+ if (Responses) {
367
+ rows = Responses[TableName];
368
+ }
369
+ }
370
+ else if (TableName) {
371
+ let params = item.params;
372
+ if ((0, types_1.isPlainObject)(params)) {
373
+ params.TableName = TableName;
374
+ }
375
+ else {
376
+ params = { TableName };
377
+ }
378
+ if (useCache && (rows = getCache(queryString = Module.asString(params, true)))) {
379
+ result[i] = rows;
380
+ continue;
381
+ }
382
+ const { Count, Items } = await createClient().scan(params).promise();
383
+ if (Count && Items) {
384
+ rows = Items;
385
+ }
386
+ }
344
387
  else {
345
388
  throw (0, util_1.formatError)(item, "Missing database query" /* ERR_DB.QUERY */);
346
389
  }
@@ -385,6 +428,36 @@ function writeMessageDefaultRetention(bucket, retention, service = 'aws') {
385
428
  this.formatMessage(64 /* LOG_TYPE.CLOUD */, service, ["Bucket configured" /* VAL_CLOUD.CONFIGURE_BUCKET */ + ' (retention policy)', bucket], status.join(' '), { ...Cloud.LOG_CLOUD_COMMAND });
386
429
  }
387
430
  exports.writeMessageDefaultRetention = writeMessageDefaultRetention;
431
+ function parseAttributeValue(value) {
432
+ switch (typeof value) {
433
+ case 'string':
434
+ return { S: value };
435
+ case 'number':
436
+ return { N: value.toString() };
437
+ case 'boolean':
438
+ return { BOOL: value };
439
+ case 'object':
440
+ if (value !== null) {
441
+ if ('S' in value || 'N' in value || 'BOOL' in value || 'B' in value || 'SS' in value || 'NS' in value || 'BS' in value || 'L' in value || 'M' in value || 'NULL' in value) {
442
+ return value;
443
+ }
444
+ if (Buffer.isBuffer(value)) {
445
+ return { B: value.toString('base64') };
446
+ }
447
+ if (Array.isArray(value)) {
448
+ return value.every(item => typeof item === 'string') ? { SS: value } : value.every(item => typeof item === 'number') ? { NS: value.map((item) => item.toString()) } : value.every(item => Buffer.isBuffer(item)) ? { BS: value.map((item) => item.toString('base64')) } : { L: value.map(item => parseAttributeValue(item)) };
449
+ }
450
+ const M = {};
451
+ for (const attr in value) {
452
+ M[attr] = parseAttributeValue(value[attr]);
453
+ }
454
+ return { M };
455
+ }
456
+ break;
457
+ }
458
+ return { NULL: true };
459
+ }
460
+ exports.parseAttributeValue = parseAttributeValue;
388
461
  const getBucketKey = (credential, Bucket, acl, service, sdk) => Module.asString(credential, true) + Bucket + '_' + (acl || '') + service + sdk;
389
462
  exports.getBucketKey = getBucketKey;
390
463
  const isNoSuchBucket = (err) => err instanceof Error && err.code === 'NoSuchBucket';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-r/aws",
3
- "version": "0.5.0",
3
+ "version": "0.6.1",
4
4
  "description": "AWS V2 cloud functions for E-mc.",
5
5
  "main": "client/index.js",
6
6
  "types": "client/index.d.ts",
@@ -21,9 +21,9 @@
21
21
  "license": "MIT",
22
22
  "homepage": "https://github.com/anpham6/pi-r#readme",
23
23
  "dependencies": {
24
- "@e-mc/cloud": "^0.7.0",
25
- "@e-mc/module": "^0.7.0",
26
- "@e-mc/types": "^0.7.0",
27
- "aws-sdk": "^2.1514.0"
24
+ "@e-mc/cloud": "^0.8.1",
25
+ "@e-mc/module": "^0.8.1",
26
+ "@e-mc/types": "^0.8.1",
27
+ "aws-sdk": "^2.1531.0"
28
28
  }
29
29
  }
package/types/index.d.ts CHANGED
@@ -3,7 +3,7 @@ import type { CloudDatabase } from '@e-mc/types/lib/cloud';
3
3
 
4
4
  import type { ConfigurationOptions } from 'aws-sdk/lib/core';
5
5
  import type { ServiceConfigurationOptions } from 'aws-sdk/lib/service';
6
- import type { Key, QueryInput, UpdateItemInput } from 'aws-sdk/clients/dynamodb';
6
+ import type { Key, BatchGetItemInput, QueryInput, ScanInput, UpdateItemInput } from 'aws-sdk/clients/dynamodb';
7
7
  import type { PutBucketAclRequest, PutBucketPolicyRequest, PutPublicAccessBlockRequest } from 'aws-sdk/clients/s3';
8
8
 
9
9
  export type BucketCannedACL = "authenticated-read" | "private" | "public-read" | "public-read-write";
@@ -15,7 +15,7 @@ export interface AWSStorageCredential extends ConfigurationOptions {
15
15
  fromPath?: string;
16
16
  }
17
17
 
18
- export interface AWSDatabaseQuery extends CloudDatabase<QueryInput, PlainObject, UpdateItemInput> {
18
+ export interface AWSDatabaseQuery extends CloudDatabase<QueryInput | Key[], PlainObject, UpdateItemInput, BatchGetItemInput | ScanInput> {
19
19
  key?: string | Key;
20
20
  partitionKey?: string | Key;
21
21
  }
package/upload/index.js CHANGED
@@ -1,7 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const path = require("path");
4
- const fs = require("fs");
5
4
  const util_1 = require("@e-mc/cloud/util");
6
5
  const types_1 = require("@e-mc/types");
7
6
  const Module = require("@e-mc/module");
@@ -26,7 +25,7 @@ function upload(credential, service = 'aws', sdk = 'aws-sdk/clients/s3') {
26
25
  cleanup();
27
26
  callback(err);
28
27
  };
29
- const addLog = (err) => err instanceof Error && this.addLog(this.statusType.WARN, err.message, service + ': ' + Bucket);
28
+ const addLog = (err) => err instanceof Error && this.addLog(this.statusType.WARN, err, service, Bucket);
30
29
  const configBucket = admin.configBucket;
31
30
  if (!BUCKET_SESSION.has(service + Bucket)) {
32
31
  const bucketAcl = admin.publicRead ? 'public-read' : admin.acl;
@@ -81,15 +80,10 @@ function upload(credential, service = 'aws', sdk = 'aws-sdk/clients/s3') {
81
80
  const Body = [data.buffer];
82
81
  const ContentType = [contentType];
83
82
  if (fileGroup) {
84
- for (const [content, ext, localFile] of fileGroup) {
85
- try {
86
- Body.push(typeof content === 'string' ? fs.readFileSync(content) : content);
87
- Key.push(ext === '.map' && localFile ? path.basename(localFile) : filename + ext);
88
- }
89
- catch (err) {
90
- addLog(err);
91
- }
92
- }
83
+ const [key, body, type] = (0, util_1.createKeyAndBody)(filename, fileGroup, addLog);
84
+ Key.push(...key);
85
+ Body.push(...body);
86
+ ContentType.push(...type);
93
87
  }
94
88
  for (let i = 0; i < Key.length; ++i) {
95
89
  const first = i === 0;