Gathering detailed insights and metrics for s3mini
Gathering detailed insights and metrics for s3mini
Gathering detailed insights and metrics for s3mini
Gathering detailed insights and metrics for s3mini
👶 Tiny S3 client. Edge computing ready. No-dep. In Typescript. Works with @cloudflare @minio @backblaze @digitalocean @garagehq @oracle
npm install s3mini
Typescript
Module System
Min. Node Version
Node Version
NPM Version
v0.4 / Pain & suffer in signature calculation
Updated on Jul 01, 2025
New deleteObjects, fixies and breakings!
Updated on Jun 22, 2025
New providers & fixies
Updated on Jun 14, 2025
Garage testing and minor fixies
Updated on Jun 09, 2025
Release the Kraken!
Updated on May 13, 2025
TypeScript (58.73%)
JavaScript (41.27%)
Total Downloads
0
Last Day
0
Last Week
0
Last Month
0
Last Year
0
MIT License
1,174 Stars
70 Commits
14 Forks
3 Watchers
2 Branches
3 Contributors
Updated on Jul 09, 2025
Latest Version
0.4.0
Package Id
s3mini@0.4.0
Unpacked Size
226.95 kB
Size
57.82 kB
File Count
13
NPM Version
10.9.2
Node Version
22.14.0
Published on
Jul 01, 2025
Cumulative downloads
Total Downloads
Last Day
0%
NaN
Compared to previous day
Last Week
0%
NaN
Compared to previous week
Last Month
0%
NaN
Compared to previous month
Last Year
0%
NaN
Compared to previous year
24
s3mini
is an ultra-lightweight Typescript client (~14 KB minified, ≈15 % more ops/s) for S3-compatible object storage. It runs on Node, Bun, Cloudflare Workers, and other edge platforms. It has been tested on Cloudflare R2, Backblaze B2, DigitalOcean Spaces, Ceph, Oracle, Garage and MinIO. (No Browser support!)
Dev:
Performance tests was done on local Minio instance. Your results may vary depending on environment and network conditions, so take it with a grain of salt.
The library supports a subset of S3 operations, focusing on essential features, making it suitable for environments with limited resources.
Put/Get objects with SSE-C (server-side encryption with customer-provided keys) is supported, but only tested on Cloudflare R2!
1npm install s3mini
1yarn add s3mini
1pnpm add s3mini
To use s3mini
, you need to set up your environment variables for provider credentials and S3 endpoint. Create a .env
file in your project root directory. Checkout the example.env file for reference.
1# On Windows, Mac, or Linux 2mv example.env .env
⚠️ Environment Support Notice
This library is designed to run in environments like Node.js, Bun, and Cloudflare Workers. It does not support browser environments due to the use of Node.js APIs and polyfills.
Cloudflare Workers: To enable built-in Node.js Crypto API, add the
nodejs_compat
compatibility flag to your Wrangler configuration file. This also enablesnodejs_compat_v2
as long as your compatibility date is2024-09-23
or later. Learn more about the Node.js compatibility flag and v2.
[!WARNING]
s3mini
is a deprecated alias retained solely for backward compatibility. It is scheduled for removal in a future release. Please migrate to the newS3mini
class.
1import { S3mini, sanitizeETag } from 's3mini'; 2 3const s3client = new S3mini({ 4 accessKeyId: config.accessKeyId, 5 secretAccessKey: config.secretAccessKey, 6 endpoint: config.endpoint, 7 region: config.region, 8}); 9 10// Basic bucket ops 11let exists: boolean = false; 12try { 13 // Check if the bucket exists 14 exists = await s3client.bucketExists(); 15} catch (err) { 16 throw new Error(`Failed bucketExists() call, wrong credentials maybe: ${err.message}`); 17} 18if (!exists) { 19 // Create the bucket based on the endpoint bucket name 20 await s3client.createBucket(); 21} 22 23// Basic object ops 24// key is the name of the object in the bucket 25const smallObjectKey: string = 'small-object.txt'; 26// content is the data you want to store in the object 27// it can be a string or Buffer (recommended for large objects) 28const smallObjectContent: string = 'Hello, world!'; 29 30// check if the object exists 31const objectExists: boolean = await s3client.objectExists(smallObjectKey); 32let etag: string | null = null; 33if (!objectExists) { 34 // put/upload the object, content can be a string or Buffer 35 // to add object into "folder", use "folder/filename.txt" as key 36 // Third argument is optional, it can be used to set content type ... default is 'application/octet-stream' 37 const resp: Response = await s3client.putObject(smallObjectKey, smallObjectContent); 38 // example with content type: 39 // const resp: Response = await s3client.putObject(smallObjectKey, smallObjectContent, 'image/png'); 40 // you can also get etag via getEtag method 41 // const etag: string = await s3client.getEtag(smallObjectKey); 42 etag = sanitizeETag(resp.headers.get('etag')); 43} 44 45// get the object, null if not found 46const objectData: string | null = await s3client.getObject(smallObjectKey); 47console.log('Object data:', objectData); 48 49// get the object with ETag, null if not found 50const response2: Response = await S3mini.getObject(smallObjectKey, { 'if-none-match': etag }); 51if (response2) { 52 // ETag changed so we can get the object data and new ETag 53 // Note: ETag is not guaranteed to be the same as the MD5 hash of the object 54 // ETag is sanitized to remove quotes 55 const etag2: string = sanitizeETag(response2.headers.get('etag')); 56 console.log('Object data with ETag:', response2.body, 'ETag:', etag2); 57} else { 58 console.log('Object not found or ETag does match.'); 59} 60 61// list objects in the bucket, null if bucket is empty 62// Note: listObjects uses listObjectsV2 API and iterate over all pages 63// so it will return all objects in the bucket which can take a while 64// If you want to limit the number of objects returned, use the maxKeys option 65// If you want to list objects in a specific "folder", use "folder/" as prefix 66// Example s3client.listObjects({"/" "myfolder/"}) 67const list: object[] | null = await s3client.listObjects(); 68if (list) { 69 console.log('List of objects:', list); 70} else { 71 console.log('No objects found in the bucket.'); 72} 73 74// delete the object 75const wasDeleted: boolean = await s3client.deleteObject(smallObjectKey); 76// to delete multiple objects, use deleteObjects method 77// const keysToDelete: string[] = ['object1.txt', 'object2.txt']; 78// const deletedArray: boolean[] = await s3client.deleteObjects(keysToDelete); 79// Note: deleteObjects returns an array of booleans, one for each key, indicating if the object was deleted or not 80 81// Multipart upload 82const multipartKey = 'multipart-object.txt'; 83const large_buffer = new Uint8Array(1024 * 1024 * 15); // 15 MB buffer 84const partSize = 8 * 1024 * 1024; // 8 MB 85const totalParts = Math.ceil(large_buffer.length / partSize); 86// Beware! This will return always a new uploadId 87// if you want to use the same uploadId, you need to store it somewhere 88const uploadId = await s3client.getMultipartUploadId(multipartKey); 89const uploadPromises = []; 90for (let i = 0; i < totalParts; i++) { 91 const partBuffer = large_buffer.subarray(i * partSize, (i + 1) * partSize); 92 // upload each part 93 // Note: uploadPart returns a promise, so you can use Promise.all to upload all parts in parallel 94 // but be careful with the number of parallel uploads, it can cause throttling 95 // or errors if you upload too many parts at once 96 // You can also use generator functions to upload parts in batches 97 uploadPromises.push(s3client.uploadPart(multipartKey, uploadId, partBuffer, i + 1)); 98} 99const uploadResponses = await Promise.all(uploadPromises); 100const parts = uploadResponses.map((response, index) => ({ 101 partNumber: index + 1, 102 etag: response.etag, 103})); 104// Complete the multipart upload 105const completeResponse = await s3client.completeMultipartUpload(multipartKey, uploadId, parts); 106const completeEtag = completeResponse.etag; 107 108// List multipart uploads 109// returns object with uploadId and key 110const multipartUploads: object = await s3client.listMultipartUploads(); 111// Abort the multipart upload 112const abortResponse = await s3client.abortMultipartUpload(multipartUploads.key, multipartUploads.uploadId); 113 114// Multipart download 115// lets test getObjectRaw with range 116const rangeStart = 2048 * 1024; // 2 MB 117const rangeEnd = 8 * 1024 * 1024 * 2; // 16 MB 118const rangeResponse = await s3client.getObjectRaw(multipartKey, false, rangeStart, rangeEnd); 119const rangeData = await rangeResponse.arrayBuffer();
For more check USAGE.md file, examples and tests.
Contributions are greatly appreciated! If you have an idea for a new feature or have found a bug, we encourage you to get involved in this order:
Open/Report Issues or Ideas: If you encounter a problem, have an idea or a feature request, please open an issue on GitHub (FIRST!) . Be concise but include as much detail as necessary (environment, error messages, logs, steps to reproduce, etc.) so we can understand and address the issue and have a dialog.
Create Pull Requests: We welcome PRs! If you want to implement a new feature or fix a bug, feel free to submit a pull request to the latest dev branch
. For major changes, it's a necessary to discuss your plans in an issue first!
Lightweight Philosophy: When contributing, keep in mind that s3mini aims to remain lightweight and dependency-free. Please avoid adding heavy dependencies. New features should provide significant value to justify any increase in size.
Community Conduct: Be respectful and constructive in communications. We want a welcoming environment for all contributors. For more details, please refer to our CODE_OF_CONDUCT.md. No one reads it, but it's there for a reason.
If you figure out a solution to your question or problem on your own, please consider posting the answer or closing the issue with an explanation. It could help the next person who runs into the same thing!
This project is licensed under the MIT License - see the LICENSE.md file for details.
Developing and maintaining s3mini (and other open-source projects) requires time and effort. If you find this library useful, please consider sponsoring its development. Your support helps ensure I can continue improving s3mini and other projects. Thank you!
No vulnerabilities found.
No security vulnerabilities found.