s3mini 0.9.2 β 0.9.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +27 -2
- package/dist/s3mini.d.ts +20 -6
- package/dist/s3mini.js +280 -85
- package/dist/s3mini.js.map +1 -1
- package/dist/s3mini.min.js +1 -1
- package/dist/s3mini.min.js.map +1 -1
- package/package.json +13 -9
- package/src/S3.ts +299 -84
- package/src/types.ts +54 -0
- package/src/utils.ts +18 -1
package/README.md
CHANGED
|
@@ -2,13 +2,17 @@
|
|
|
2
2
|
|
|
3
3
|
`s3mini` is an ultra-lightweight Typescript client (~20 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!)
|
|
4
4
|
|
|
5
|
+

|
|
6
|
+

|
|
7
|
+

|
|
8
|
+
|
|
5
9
|
[[github](https://github.com/good-lly/s3mini)]
|
|
6
10
|
[[issues](https://github.com/good-lly/s3mini/issues)]
|
|
7
11
|
[[npm](https://www.npmjs.com/package/s3mini)]
|
|
8
12
|
|
|
9
13
|
## Features
|
|
10
14
|
|
|
11
|
-
- π Light and fast:
|
|
15
|
+
- π Light and fast: ~20 KB (minified, not gzipped), up to 1.37x faster on Bun vs Node.
|
|
12
16
|
- π§ Zero dependencies; supports AWS SigV4, pre-signed URLs, and SSE-C headers (tested on Cloudflare)
|
|
13
17
|
- π Works on Cloudflare Workers; ideal for edge computing, Node, and Bun (no browser support).
|
|
14
18
|
- π Only the essential S3 APIsβimproved list, put, get, delete, and a few more.
|
|
@@ -44,6 +48,10 @@ Dev:
|
|
|
44
48
|
|
|
45
49
|
<a href="https://github.com/good-lly/s3mini/issues/"> <img src="https://img.shields.io/badge/contributions-welcome-brightgreen.svg" alt="Contributions welcome" /></a>
|
|
46
50
|
|
|
51
|
+
### Bun vs Node
|
|
52
|
+
|
|
53
|
+
s3mini is tested on both Node and Bun. In our benchmarks against MinIO, Bun is roughly **~1.4x faster** on most operations (median across ~40 tests). Blob multipart uploads see the largest gain (~20x) thanks to Bun's native `Blob.slice()`. Results are approximate and will vary by environment.
|
|
54
|
+
|
|
47
55
|
## Table of Contents
|
|
48
56
|
|
|
49
57
|
- [Installation](#installation)
|
|
@@ -515,6 +523,21 @@ const url = await s3.getPresignedUrl('GET', 'report.pdf', 3600, {
|
|
|
515
523
|
});
|
|
516
524
|
```
|
|
517
525
|
|
|
526
|
+
**Signed headers (enforce headers on the client request):**
|
|
527
|
+
|
|
528
|
+
```typescript
|
|
529
|
+
// Upload URL that requires Content-Type β client MUST send this exact header
|
|
530
|
+
const url = await s3.getPresignedUrl('PUT', 'uploads/data.json', 300, {}, {
|
|
531
|
+
'Content-Type': 'application/json',
|
|
532
|
+
});
|
|
533
|
+
|
|
534
|
+
await fetch(url, {
|
|
535
|
+
method: 'PUT',
|
|
536
|
+
body: JSON.stringify({ ok: true }),
|
|
537
|
+
headers: { 'Content-Type': 'application/json' },
|
|
538
|
+
});
|
|
539
|
+
```
|
|
540
|
+
|
|
518
541
|
**Method signature:**
|
|
519
542
|
|
|
520
543
|
```typescript
|
|
@@ -523,6 +546,7 @@ getPresignedUrl(
|
|
|
523
546
|
key: string,
|
|
524
547
|
expiresIn?: number, // Default: 3600 (1 hour), max: 604800 (7 days)
|
|
525
548
|
queryParams?: Record<string, string>,
|
|
549
|
+
headers?: Record<string, string>, // HTTP headers to sign (e.g. Content-Type)
|
|
526
550
|
): Promise<string>
|
|
527
551
|
```
|
|
528
552
|
|
|
@@ -532,6 +556,7 @@ getPresignedUrl(
|
|
|
532
556
|
- Works with both virtual-hosted-style and path-style endpoints.
|
|
533
557
|
- Special characters and unicode in keys are handled automatically.
|
|
534
558
|
- Throws `TypeError` for empty keys or out-of-range `expiresIn`.
|
|
559
|
+
- When `headers` are provided, they are included in `X-Amz-SignedHeaders` and the signature. The client consuming the URL must send those exact headers with matching values. The `host` header is always signed automatically.
|
|
535
560
|
|
|
536
561
|
---
|
|
537
562
|
|
|
@@ -603,7 +628,7 @@ await s3.copyObject('secret.dat', 'backup/secret.dat', {
|
|
|
603
628
|
| `getContentLength(key, ssec?)` | `Promise<number>` | Get size in bytes |
|
|
604
629
|
| `copyObject(source, dest, opts?)` | `Promise<CopyObjectResult>` | Server-side copy |
|
|
605
630
|
| `moveObject(source, dest, opts?)` | `Promise<CopyObjectResult>` | Copy + delete |
|
|
606
|
-
| `getPresignedUrl(method, key, expiresIn?, queryParams?)`
|
|
631
|
+
| `getPresignedUrl(method, key, expiresIn?, queryParams?, headers?)` | `Promise<string>` | Generate pre-signed URL |
|
|
607
632
|
| `getMultipartUploadId(key, type?, ssec?, headers?)` | `Promise<string>` | Init multipart |
|
|
608
633
|
| `uploadPart(key, uploadId, data, partNum, opts?, ssec?, headers?)` | `Promise<UploadPart>` | Upload part |
|
|
609
634
|
| `completeMultipartUpload(key, uploadId, parts)` | `Promise<CompleteResult>` | Complete multipart |
|
package/dist/s3mini.d.ts
CHANGED
|
@@ -164,6 +164,7 @@ declare class S3mini {
|
|
|
164
164
|
readonly logger?: Logger;
|
|
165
165
|
readonly _fetch: typeof fetch;
|
|
166
166
|
readonly minPartSize: number;
|
|
167
|
+
private readonly _bun?;
|
|
167
168
|
private signingKeyDate?;
|
|
168
169
|
private signingKey?;
|
|
169
170
|
constructor({ accessKeyId, secretAccessKey, endpoint, region, requestSizeInBytes, requestAbortTimeout, logger, fetch, minPartSize, }: S3Config);
|
|
@@ -175,6 +176,8 @@ declare class S3mini {
|
|
|
175
176
|
* @returns true if both accessKeyId and secretAccessKey are non-empty.
|
|
176
177
|
*/
|
|
177
178
|
private _hasCredentials;
|
|
179
|
+
/** Run a read op via Bun-native S3, returning null on NoSuchKey. */
|
|
180
|
+
private _bunRead;
|
|
178
181
|
private _ensureValidUrl;
|
|
179
182
|
private _validateMethodIsGetOrHead;
|
|
180
183
|
private _checkKey;
|
|
@@ -249,6 +252,10 @@ declare class S3mini {
|
|
|
249
252
|
private _parseListObjectsResponse;
|
|
250
253
|
private _extractObjectsFromResponse;
|
|
251
254
|
private _extractContinuationToken;
|
|
255
|
+
private _bunListAll;
|
|
256
|
+
private _bunFetchPage;
|
|
257
|
+
private _bunNextCursor;
|
|
258
|
+
private _bunMapListResult;
|
|
252
259
|
/**
|
|
253
260
|
* Lists multipart uploads in the bucket.
|
|
254
261
|
* This method sends a request to list multipart uploads in the specified bucket.
|
|
@@ -579,6 +586,9 @@ declare class S3mini {
|
|
|
579
586
|
*/
|
|
580
587
|
deleteObject(key: string): Promise<boolean>;
|
|
581
588
|
private _deleteObjectsProcess;
|
|
589
|
+
private _sendDeleteRequest;
|
|
590
|
+
private _markDeletedKeys;
|
|
591
|
+
private _logDeleteErrors;
|
|
582
592
|
/**
|
|
583
593
|
* Deletes multiple objects from the bucket.
|
|
584
594
|
* @param {string[]} keys - An array of object keys to delete.
|
|
@@ -597,20 +607,24 @@ declare class S3mini {
|
|
|
597
607
|
* @param {'GET' | 'PUT'} method - HTTP method ('GET' for download, 'PUT' for upload)
|
|
598
608
|
* @param {string} key - The object key/path
|
|
599
609
|
* @param {number} [expiresIn=3600] - URL expiration time in seconds (1β604800)
|
|
600
|
-
* @param {Record<string, string>} [queryParams={}] - Additional query parameters to
|
|
610
|
+
* @param {Record<string, string>} [queryParams={}] - Additional query parameters to include in the URL
|
|
611
|
+
* @param {Record<string, string>} [headers={}] - HTTP headers to sign. The consumer of the URL
|
|
612
|
+
* MUST send these exact headers with matching values. The `host` header is always signed automatically.
|
|
601
613
|
* @returns {Promise<string>} Pre-signed URL string
|
|
602
614
|
* @throws {TypeError} If key is empty or expiresIn is out of range
|
|
603
615
|
* @example
|
|
604
616
|
* // Download URL valid for 1 hour
|
|
605
617
|
* const url = await s3.getPresignedUrl('GET', 'photos/vacation.jpg');
|
|
606
618
|
*
|
|
607
|
-
* // Upload URL valid for 5 minutes
|
|
608
|
-
* const url = await s3.getPresignedUrl('PUT', 'uploads/file.bin', 300
|
|
619
|
+
* // Upload URL valid for 5 minutes with signed Content-Type
|
|
620
|
+
* const url = await s3.getPresignedUrl('PUT', 'uploads/file.bin', 300, {}, {
|
|
621
|
+
* 'Content-Type': 'application/octet-stream',
|
|
622
|
+
* });
|
|
609
623
|
*
|
|
610
|
-
* // Client-side usage (
|
|
611
|
-
* await fetch(url, { method: 'PUT', body: data });
|
|
624
|
+
* // Client-side usage (must include signed headers)
|
|
625
|
+
* await fetch(url, { method: 'PUT', body: data, headers: { 'Content-Type': 'application/octet-stream' } });
|
|
612
626
|
*/
|
|
613
|
-
getPresignedUrl(method: 'GET' | 'PUT', key: string, expiresIn?: number, queryParams?: Record<string, string>): Promise<string>;
|
|
627
|
+
getPresignedUrl(method: 'GET' | 'PUT', key: string, expiresIn?: number, queryParams?: Record<string, string>, headers?: Record<string, string>): Promise<string>;
|
|
614
628
|
private _presign;
|
|
615
629
|
private _getSignatureKey;
|
|
616
630
|
}
|