sentienhq / ultralight-s3

šŸŖ½ A turbo lightweight S3 client, no-dependency, ideal for edges or platforms like @Cloudflare @AWS @azure @GoogleCloudPlatform @ceph @minio
https://www.npmjs.com/package/ultralight-s3
MIT License
15 stars 1 forks source link
aws-lambda-node cloudflare-worker edge-computing node-js nodejs-s3 s3 s3-sdk typescript-library

šŸŖ½ ultralight-s3

~15KB lightweight S3 client with zero dependencies, designed for Node.js, edge computing like Cloudflare workers, AWS Lambda (and browsers - not implemented yet).

npm package version npm package minimized gzipped sizeNPM License GitHub Issues or Pull Requests GitHub Repo stars Contributions welcome

Dev branch: Test Runner CodeQL

Features

Table of Contents

Simple usage

import { S3 } from 'ultralight-s3';

// ... your configuration
const s3 = new S3({
  accessKeyId: 'your-access-key-id',
  secretAccessKey: 'your-secret-access-key',
  region: 'auto',
  bucket: 'your-bucket-name',
});

// List objects
const objects = await s3.list();
// or with prefix
// const specificObjectsUnderPrefix = await s3.list('/', 'prefix');
console.log(objects);

// Check if a file exists
const exists = await s3.fileExists('path/to/file.txt');

// Get a life
const data = await s3.get('path/to/life.txt');
console.log(data);

// get a stream of a large file (first chunk)
const firstChunk = await s3.getResponse('path/to/large-file.mp4', false, 0).body;

// get a stream of a large file (all chunks)
const allChunks = await s3.getResponse('path/to/large-file.mp4', true);
for await (const chunk of allChunks.body) {
  console.log(chunk);
}

// Upload a large file
// by default is 5MB per request (minimum for AWS S3 is 5MB)
const chunkSize = s3.getMaxRequestSizeInBytes();
// Initiate multipart upload
const uploadId = await s3.getMultipartUploadId('randomFileName.fastaq', 'text/plain');
const buffer = randomBytes(chunkSize * 2 + 1024); // Just over 2 parts
const upload = await s3.uploadPart('randomFileName.fastaq', buffer, uploadId, 1);
const upload2 = await s3.uploadPart('randomFileName.fastaq', buffer, uploadId, 2);
const upload3 = await s3.uploadPart('randomFileName.fastaq', buffer, uploadId, 3);

// Complete multipart upload
const result = await s3.completeMultipartUpload('randomFileName.fastaq', uploadId, [
  { partNumber: 1, ETag: upload.ETag },
  { partNumber: 2, ETag: upload2.ETag },
  { partNumber: 3, ETag: upload3.ETag },
]);
console.log(result);

// Get file size
const size = await s3.getContentLength('path/to/file.txt');
console.log(size);

// Put a file
await s3.put('path/to/file.txt', Buffer.from('Hello, World!'));

// Delete a file
await s3.delete('path/to/file.txt');

For some examples, check the dev directory and try to use it with Hono or Cloudflare Workers.

Installation

npm install ultralight-s3

# or

yarn add ultralight-s3

# or

pnpm add ultralight-s3

# or
# Not yet implemented
# <script src="https://unpkg.com/ultralight-s3/dist/ultralight-s3.min.js" defer></script>

Configuration

Minio (āœ… tested)

import { S3 } from 'ultralight-s3';

const s3 = new S3({
  accessKeyId: 'your-access-key-id',
  secretAccessKey: 'your-secret-access-key',
  endpoint: 'https://your-s3-endpoint.com' || 'http://127.0.0.1:9000',
  bucketName: 'your-bucket-name',
  region: 'auto', //optional -  by default is auto
  maxRequestSizeInBytes: 5242880, // optional - by default is 5MB
  requestAbortTimeout: undefined, // optional - for aborting requests
  logger: console, // optional - for debugging
});

Cloudflare R2 (āœ… tested)

import { S3 } from 'ultralight-s3';

const s3 = new S3({
  accessKeyId: 'your-access-key-id',
  secretAccessKey: 'your-secret-access-key',
  endpoint: 'https://your-clouflare-id.r2.cloudflarestorage.com/your-bucket-name',
  bucketName: 'your-bucket-name',
  region: 'auto', //optional -  by default is auto
  maxRequestSizeInBytes: 5242880, // optional - by default is 5MB
  requestAbortTimeout: undefined, // optional - for aborting requests
  logger: console, // optional - for debugging
});

Others

(AWS Lambda, Azure, Google Cloud, Ceph, etc)

Not tested, but should work with other S3 compatible services. Full list - soon to come. PRs are welcome.

Public functions

Bucket Operations

Object Operations

Listing Operations

Multipart Upload Operations

Configuration and Utility Methods

API

new S3(config: Object)

list(delimiter?: string, prefix?: string, maxKeys?: number, method?: string, opts?: Object): Promise<Array<Object>

put(key: string, data: Buffer | string): Promise<Object>

get(key: string, opts?: Object): Promise

getObjectWithETag(key: string, opts?: Object): Promise<{ etag: string | null; data: string | null }>

getResponse(key: string, wholeFile?: boolean, rangeFrom?: number, rangeTo?: number, opts?: Object): Promise<Response>

getEtag(key: string, opts?: Object): Promise<string | null>

delete(key: string): Promise

fileExists(key: string): Promise

getContentLength(key: string): Promise<number>

listMultiPartUploads(delimiter?: string, prefix?: string, method?: string, opts?: Object): Promise<Array<Object>

getMultipartUploadId(key: string, fileType?: string): Promise

uploadPart(key: string, data: Buffer | string, uploadId: string, partNumber: number, opts?: Object): Promise<{ partNumber: number, ETag: string }>

completeMultipartUpload(key: string, uploadId: string, parts: Array<{ partNumber: number, ETag: string }>): Promise<Object>

abortMultipartUpload(key: string, uploadId: string): Promise<Object>

bucketExists(): Promise<boolean>

sanitizeETag(etag: string): string

Also all essential getters and setters for the config object.

Community

Stay connected with the community and get support.

Contributing

Contributions are welcome! Please open an issue or submit a pull request.

License

This project is licensed under the MIT License - see the LICENSE.md file for details.