@amag-ch/sap_cap_common_objectstore
Version:
NodeJS library to communicate with an objectstore
127 lines (104 loc) • 3.37 kB
JavaScript
const {
S3Client: NativeClient,
ListObjectsV2Command,
HeadObjectCommand,
GetObjectCommand,
PutObjectCommand,
DeleteObjectCommand
} = require('@aws-sdk/client-s3')
const Client = require('./Client')
const { ObjectStoreError, ObjectStoreCommunicationError } = require('../errors')
module.exports = class S3Client extends Client {
#client
#bucket
#host
constructor(credentials) {
super(credentials)
const { region, access_key_id: accessKeyId, secret_access_key: secretAccessKey, bucket, host } = credentials
this.#client = new NativeClient({
region,
credentials: {
accessKeyId,
secretAccessKey
}
})
this.#bucket = bucket
this.#host = host
}
/**
* List all files in store.
*
* @returns {Promise<[{filename: string, modifiedAt: Date, contentLength: integer}]>}
*/
list = async () => {
const objects = await this.#send(new ListObjectsV2Command())
return (objects?.Contents ?? []).map(({ Key, LastModified, Size }) => ({
filename: Key,
modifiedAt: LastModified,
contentLength: Size
}))
}
/**
* Read metadata from file.
*
* @param {string} filename
* @returns {Promise<{modifiedAt: Date, contentLength: integer}>}
*/
head = async (filename) => {
if (!filename) throw new Error('filename not provided')
const object = await this.#send(new HeadObjectCommand({ Key: filename }))
return {
modifiedAt: object.LastModified,
contentLength: object.ContentLength
}
}
/**
* Read file.
*
* @param {string} filename
* @returns {Promise<ReadableStream>}
*/
get = async (filename) => {
if (!filename) throw new Error('filename not provided')
const object = await this.#send(new GetObjectCommand({ Key: filename }))
return object.Body
}
/**
* Put new file to store.
*
* @param {string} filename
* @param {string|Readable|Blob|ReadableStream<any>|Uint8Array|Buffer} content
* @param {{contentType?: string}} options
* @returns {Promise<void>}
*/
put = async (filename, content, { contentType }={}) => {
if (!filename) throw new Error('filename not provided')
if (!content) throw new Error('content not provided')
await this.#send(new PutObjectCommand({
Key: filename,
Body: content,
ContentType: contentType
}))
}
/**
* Delete file in store.
*
* @param {string} filename
* @returns {Promise<void>}
*/
delete = async (filename) => {
if (!filename) throw new Error('filename not provided')
await this.#send(new DeleteObjectCommand({ Key: filename }))
}
#send = async (command = {}) => {
command.input ??= {}
command.input.Bucket = this.#bucket
try {
return await this.#client.send(command)
} catch (err) {
if (err.code === 'ECONNRESET')
throw new ObjectStoreCommunicationError(`Cannot connect to S3 service: ${this.#host}`)
throw new ObjectStoreError(err.message, { cause: err })
}
}
}