UNPKG

do-spaces

Version:

Unofficial package for simple managing file operations hosted on "Digital Ocean Spaces" written in Typescript

231 lines (196 loc) 5.35 kB
import AWS, { S3 } from 'aws-sdk'; import mime from 'mime-types'; type AwsParam = { [key: string]: any }; export type Privacy = 'private' | 'public-read'; export type Credentials = { endpoint: string; accessKey: string; secret: string; bucket: string; }; export type ListFiles = { maxFiles?: number; path: string; nextMarker?: string; awsParams?: AwsParam; }; export type UploadFile = { pathname: string; privacy: Privacy; file: Blob | BinaryType | string | Buffer; awsParams?: AwsParam; }; export type CopyFile = { pathname: string; copiedPathname: string; privacy: Privacy; fromBucket?: string; awsParams?: AwsParam; }; export type FolderParam = { path: string; awsParams?: AwsParam; }; export type FileParam = { pathname: string; awsParams?: AwsParam; }; export type DeleteFolder = { path: string; awsListParams?: AwsParam; awsDeleteParams?: AwsParam; }; export class Spaces { s3: S3; bucket: string; endpoint: string; constructor({ endpoint, accessKey, secret, bucket }: Credentials) { const spacesEndpoint = new AWS.Endpoint(endpoint); const s3 = new AWS.S3({ endpoint: spacesEndpoint, accessKeyId: accessKey, secretAccessKey: secret, }); this.endpoint = endpoint; this.bucket = bucket; this.s3 = s3; } private _removeLeadingSlash(pathname: string) { return pathname[0] === '/' ? pathname.slice(1) : pathname; } private _getContentTypeFromExtension(pathname: string) { const _split = pathname.split('.'); const extension = _split[_split.length - 1]; return mime.lookup(extension) || 'application/octet-stream'; } public async createFolder({ path, awsParams }: FolderParam) { if (path[path.length - 1] !== '/') { throw new Error("do-spaces ~ createFolder - path must end with '/'"); } const params = { Bucket: this.bucket, Key: this._removeLeadingSlash(path), ...awsParams, }; return await this.s3.putObject(params).promise(); } /** * Removed all files inside folder */ public async deleteFolder({ path, awsListParams, awsDeleteParams, }: DeleteFolder) { if (path[path.length - 1] !== '/') { throw new Error("do-spaces ~ deleteFolder - path must end with '/'"); } const that = this; // @ts-ignore async function _delete({ path, nextMarker, }: { path: string; nextMarker?: string; }) { const { Contents, NextMarker } = await that.listFiles({ maxFiles: 1000, path, nextMarker, ...awsListParams, }); if (Contents && Contents.length) { const _filesToDelete = Contents.map((item: any) => { return { Key: item.Key }; }); const params = { Bucket: that.bucket, Delete: { Objects: _filesToDelete }, ...awsDeleteParams, }; if (NextMarker) { await that.s3.deleteObjects(params).promise(); return await _delete({ path, nextMarker }); } else { return await that.s3.deleteObjects(params).promise(); } } else { console.info( `do-spaces ~ removeFolder - nothing to remove for path ${path}` ); return null; } } return await _delete({ path }); } public async downloadFile({ pathname, awsParams }: FileParam) { let _pathname = pathname; const _fullUrl = `https://${this.bucket}.${this.endpoint}`; if (_pathname.indexOf(_fullUrl) === 0) { _pathname = _pathname.replace(_fullUrl, ''); } const params = { Bucket: this.bucket, Key: this._removeLeadingSlash(_pathname), ...awsParams, }; return this.s3.getObject(params).promise(); } public async listFiles({ maxFiles = 1000, path, nextMarker, awsParams, }: ListFiles) { if (path[path.length - 1] !== '/') { throw new Error("do-spaces ~ listFiles - path must end with '/'"); } const params = { Bucket: this.bucket, MaxKeys: maxFiles, Prefix: this._removeLeadingSlash(path), Marker: nextMarker, ...awsParams, }; return await this.s3.listObjects(params).promise(); } public async uploadFile({ pathname, privacy, file, awsParams }: UploadFile) { const params = { Bucket: this.bucket, Key: this._removeLeadingSlash(pathname), Body: file, ACL: privacy, ContentType: this._getContentTypeFromExtension(pathname), ...awsParams, }; return await this.s3.putObject(params).promise(); } public async copyFile({ pathname, copiedPathname, privacy, fromBucket, awsParams, }: CopyFile) { const _copyPathname = `/${fromBucket || this.bucket}/${this._removeLeadingSlash(copiedPathname)}`; const params = { Bucket: this.bucket, Key: this._removeLeadingSlash(pathname), CopySource: _copyPathname, ACL: privacy, ...awsParams, }; return await this.s3.copyObject(params).promise(); } public async deleteFile({ pathname, awsParams }: FileParam) { const params = { Bucket: this.bucket, Key: this._removeLeadingSlash(pathname), ...awsParams, }; return await this.s3.deleteObject(params).promise(); } } export default Spaces;