eip-cloud-services 1.1.3 → 1.1.5

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.
Files changed (3) hide show
  1. package/package.json +1 -1
  2. package/src/redis.js +2 -2
  3. package/src/s3.js +64 -41
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eip-cloud-services",
3
- "version": "1.1.3",
3
+ "version": "1.1.5",
4
4
  "description": "Houses a collection of helpers for connecting with Cloud services.",
5
5
  "main": "index.js",
6
6
  "scripts": {
package/src/redis.js CHANGED
@@ -212,7 +212,7 @@ exports.multiGet = async ( keys ) => {
212
212
  if ( Array.isArray ( keys ) ) {
213
213
  const client = await getClient ();
214
214
 
215
- const fullKeys = ( !config?.redis?.prefix || keys.map ( key => key.startsWith ( config?.redis?.prefix ) ) ? key : config?.redis?.prefix + key );
215
+ const fullKeys = keys.map ( key => ( !config?.redis?.prefix || key.startsWith ( config?.redis?.prefix ) ) ? key : config?.redis?.prefix + key );
216
216
 
217
217
  // Use the mget method directly
218
218
  const data = await client.mget ( ...fullKeys );
@@ -313,7 +313,7 @@ exports.multiDel = async ( keys ) => {
313
313
  const client = await getClient ();
314
314
 
315
315
  // Prepend the Redis prefix to each key if necessary
316
- const fullKeys = ( !config?.redis?.prefix || keys.map ( key => key.startsWith ( config?.redis?.prefix ) ) ? key : config?.redis?.prefix + key );
316
+ const fullKeys = keys.map ( key => ( !config?.redis?.prefix || key.startsWith ( config?.redis?.prefix ) ) ? key : config?.redis?.prefix + key );
317
317
 
318
318
  // Use the del method with multiple keys
319
319
  return await client.del ( ...fullKeys );
package/src/s3.js CHANGED
@@ -38,8 +38,9 @@
38
38
  * and ensures the best CWVs performance.
39
39
  */
40
40
 
41
- const { S3Client, HeadObjectCommand, GetObjectCommand, PutObjectCommand, DeleteObjectCommand, CopyObjectCommand, DeleteObjectsCommand } = require ( '@aws-sdk/client-s3' );
41
+ const { S3Client, HeadObjectCommand, GetObjectCommand, PutObjectCommand, DeleteObjectCommand, CopyObjectCommand, ListObjectsV2Command } = require ( '@aws-sdk/client-s3' );
42
42
  const fs = require ( 'fs' );
43
+ const path = require ( 'path' );
43
44
  let config = {};
44
45
  const configDirPath = `${ process.cwd ()}/config`;
45
46
  if ( fs.existsSync ( configDirPath ) && fs.statSync ( configDirPath ).isDirectory () ) {
@@ -82,14 +83,16 @@ exports.exists = async ( key, bucket = config?.s3?.Bucket ) => {
82
83
  };
83
84
 
84
85
  /**
85
- * Get an object from S3.
86
+ * Get an object from S3 and optionally download it to a file.
86
87
  *
87
88
  * @param {string} key - The object key.
88
89
  * @param {string} [bucket=config?.s3?.Bucket] - The bucket name. Defaults to the configured bucket.
89
- * @returns {Promise} A promise that resolves to the retrieved object.
90
- * @description Retrieves an object from S3 based on the provided key.
90
+ * @param {Object} [options] - Optional parameters, including targetFolder for file download.
91
+ * @param {string} [options.targetFolder] - If provided the requested object will be downloaded to this folder instead of being returned. The response will be the file path.
92
+ * @returns {Promise} A promise that resolves to the retrieved object or the path to the downloaded file.
93
+ * @description Retrieves an object from S3 based on the provided key and optionally downloads it to a specified folder.
91
94
  */
92
- exports.get = async ( key, bucket = config?.s3?.Bucket ) => {
95
+ exports.get = async ( key, bucket = config?.s3?.Bucket, options = {} ) => {
93
96
  try {
94
97
  const command = new GetObjectCommand ( {
95
98
  Bucket: bucket,
@@ -98,50 +101,70 @@ exports.get = async ( key, bucket = config?.s3?.Bucket ) => {
98
101
 
99
102
  if ( config?.s3?.logs === 'verbose' )
100
103
  log ( `S3 [GET]: Getting ${bucket}/${key}.` );
101
-
104
+
102
105
  const response = await S3.send ( command );
103
- let data = await streamToBuffer ( response.Body );
104
106
 
105
- if ( response.ContentEncoding && response.ContentEncoding === 'gzip' ) {
107
+ // If options.targetFolder is specified, download the file
108
+ if ( options.targetFolder ) {
109
+ const filePath = path.join ( options.targetFolder, key.replace ( /\//g, '_' ) );
110
+ const fileStream = fs.createWriteStream ( filePath );
111
+ response.Body.pipe ( fileStream );
112
+ await new Promise ( ( resolve, reject ) => {
113
+ fileStream.on ( 'finish', resolve );
114
+ fileStream.on ( 'error', reject );
115
+ } );
106
116
 
107
- if ( config?.s3?.logs === 'verbose' )
108
- log ( `S3 [GET]: ${key} on ${bucket} was unzipped (was gzipped).` );
117
+ if ( config?.s3?.logs === 'outputs' || config?.s3?.logs === 'verbose' )
118
+ log ( `S3 [GET]: Downloaded ${key} to ${filePath}.` );
109
119
 
110
- data = zlib.unzipSync ( data );
111
- }
120
+ return filePath;
121
+ }
122
+ else {
123
+
124
+ const response = await S3.send ( command );
125
+ let data = await streamToBuffer ( response.Body );
112
126
 
113
- if ( response.ContentType !== 'application/json' && !response.Metadata[ 'tmg-json' ] ) {
114
- if ( config?.s3?.logs === 'output' )
115
- log ( `S3 [GET]: Returned ${response.ContentType} from ${bucket}/${key}.` );
127
+ if ( response.ContentEncoding && response.ContentEncoding === 'gzip' ) {
128
+
129
+ if ( config?.s3?.logs === 'verbose' )
130
+ log ( `S3 [GET]: ${key} on ${bucket} was unzipped (was gzipped).` );
131
+
132
+ data = zlib.unzipSync ( data );
133
+ }
134
+
135
+ if ( response.ContentType !== 'application/json' && !response.Metadata[ 'tmg-json' ] ) {
136
+ if ( config?.s3?.logs === 'output' )
137
+ log ( `S3 [GET]: Returned ${response.ContentType} from ${bucket}/${key}.` );
138
+
139
+ return data.toString ( 'utf8' );
140
+ }
116
141
 
117
- return data.toString ( 'utf8' );
118
- }
119
-
120
- if ( ( response.ContentType === 'application/json' || response.Metadata[ 'tmg-json' ] ) && response.Metadata[ 'tmg-crypt' ] && response.Metadata[ 'tmg-crypt-vec' ] ) {
121
- const key = await crypto.subtle.importKey (
122
- 'raw',
123
- Buffer.from ( response.Metadata[ 'tmg-crypt' ], 'base64' ),
124
- { name: 'AES-CBC', length: 256 },
125
- false,
126
- [ 'decrypt' ]
127
- );
128
- const iv = Buffer.from ( response.Metadata[ 'tmg-crypt-vec' ], 'base64' );
129
- const decryptedArrayBuffer = await crypto.subtle.decrypt (
130
- { name: 'AES-CBC', iv },
131
- key,
132
- Buffer.from ( data.toString (), 'base64' )
133
- );
134
-
135
- data = Buffer.from ( decryptedArrayBuffer ).toString ( 'utf8' );
136
-
137
- if ( config?.s3?.logs === 'verbose' )
138
- log ( `S3 [GET]: ${key} on ${bucket} - JSON content was decrypted.` );
139
- }
142
+ if ( ( response.ContentType === 'application/json' || response.Metadata[ 'tmg-json' ] ) && response.Metadata[ 'tmg-crypt' ] && response.Metadata[ 'tmg-crypt-vec' ] ) {
143
+ const key = await crypto.subtle.importKey (
144
+ 'raw',
145
+ Buffer.from ( response.Metadata[ 'tmg-crypt' ], 'base64' ),
146
+ { name: 'AES-CBC', length: 256 },
147
+ false,
148
+ [ 'decrypt' ]
149
+ );
150
+ const iv = Buffer.from ( response.Metadata[ 'tmg-crypt-vec' ], 'base64' );
151
+ const decryptedArrayBuffer = await crypto.subtle.decrypt (
152
+ { name: 'AES-CBC', iv },
153
+ key,
154
+ Buffer.from ( data.toString (), 'base64' )
155
+ );
156
+
157
+ data = Buffer.from ( decryptedArrayBuffer ).toString ( 'utf8' );
158
+
159
+ if ( config?.s3?.logs === 'verbose' )
160
+ log ( `S3 [GET]: ${key} on ${bucket} - JSON content was decrypted.` );
161
+ }
140
162
 
141
- if ( config?.s3?.logs === 'output' )
142
- log ( `S3 [GET]: ${bucket}/${key} - JSON content was returned.` );
163
+ if ( config?.s3?.logs === 'output' )
164
+ log ( `S3 [GET]: ${bucket}/${key} - JSON content was returned.` );
143
165
 
144
- return JSON.parse ( data.toString ( 'utf8' ) );
166
+ return JSON.parse ( data.toString ( 'utf8' ) );
167
+ }
145
168
  }
146
169
  catch ( error ) {
147
170
  if ( error.Code === 'NoSuchKey' ) {