UNPKG

@amag-ch/sap_cap_common_objectstore

Version:

NodeJS library to communicate with an objectstore

127 lines (104 loc) 3.37 kB
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 }) } } }