- Bun native fast paths need Bun 1.4.0+ (older Bun mis-encodes
#and?in keys).listObjectsalways uses signed requests.
SignatureDoesNotMatchwhen a query value contained! ' ( ) *, e.g.filename*=UTF-8''…inresponse-content-disposition.- Numeric XML entities like
'are decoded, so MinIO list keys and ETags come back intact.
- Object versioning support (issue #3):
setBucketVersioning/getBucketVersioning(Put/GetBucketVersioning).listObjects/listObjectsPagedaccept{ versions: true }and parseListVersionsResult(Version+DeleteMarkerentries with optionalVersionId,IsLatest,IsDeleteMarker).- New
listObjectVersions(key)returns all versions for a specific object key (exact match), including which entry is latest. copyObjectaccepts optionalversionIdonCopyObjectOptions(appended tox-amz-copy-source) for restore-by-copy.deleteObject/deleteObjectsacceptDeleteObject({ key, versionId? }) in addition to string keys; bulk delete XML includes<VersionId>when set.deleteObject/deleteObjectsaccept{ versionInfo: true }to return aDeleteObjectResult/DeleteObjectResult[]carrying the deletedversionId,deleteMarker, and newdeleteMarkerVersionId— read from the response headers/body so no follow-up list request is needed. Default boolean return is unchanged.copyObjectresult now includes the new object'sversionId(from thex-amz-version-idresponse header) on versioned buckets.
- Exported types:
ListObject,DeleteObject,DeleteObjectResult,CopyObjectOptions,CopyObjectResult. - E2E: real versioning lifecycle test (enable bucket → multi-put → list/get/copy-restore → versioned delete) against live providers; MinIO global setup enables versioning.
tests/bun-native.test.js(npm run test:bun-native): checks that the native client is engaged only when it should be, that its reads, listings and deletes match the signed path, and that the list cursor advances or fails loudly.
- ESM only package, no more minified CJS build.
- Bun is detected with
process.versions.bunplus aBun.S3Clientcapability check. The previous check comparednavigator.userAgentto'Bun'while Bun reportsBun/<version>, so the fast paths added in 0.9.4 never ran. They do now — see BREAKING.md for what that changes. - The native client is skipped when the caller supplies a custom
fetch(its transport would be bypassed) or when credentials are empty (anonymous access to public buckets). - Errors from native operations are re-thrown as
S3ServiceError, with the HTTP status recovered from the error code where the S3 API pins it, so both runtimes throw the same shape. putObject,putAnyObject,getObjectRawandgetObjectWithETaghave no Bun fast path. They were listed in 0.9.4 but never active, and each was wrong or slower than one signed request: Bun'swrite()rewritestext/plaintotext/plain;charset=utf-8, stores aReadableStreamas the string[object ReadableStream]and never switches to multipart, while the two read helpers cost an extra round trip andgetObjectRawbuffered the whole body instead of streaming it.- Dropped the
extractBaseEndpointutility added in 0.9.4. The Bun client is configured with the endpoint origin plusvirtualHostedStyleinstead. retryFetchin the E2E harness also retries HTTP 500/502/503/504 (replayable bodies only), which the S3 API defines as transient. Backblaze returnsInternalErroroften enough to fail a run.- Under Bun the harness installs
retryFetchasglobalThis.fetchrather than passing it in the config, where it would have kept the whole run on the signed path and out of the native client.
- Bun
listObjectspaginated withstartAfterderived from the last key, which stalled on a page holding onlyCommonPrefixes. It now followscontinuationToken, and throws instead of looping forever when a truncated page repeats or omits the token. - Bun
listObjectsreturned emptyETags (Bun spells the fieldeTag) and forced a/delimiter, grouping results the signed path returns flat. - Bun clients for virtual-hosted endpoints signed
bucket.host/bucket/key. - Anonymous (credential-less) clients threw
ERR_S3_MISSING_CREDENTIALSunder Bun.
- Bun native S3 support via
Bun.S3Client— automatic fast paths forgetObject,getObjectAsBytes,getObjectAsJson,getObjectWithETag,getObjectRaw(incl. range requests viaslice()),putObject,putAnyObject,deleteObject,objectExists,getEtag,getContentLength,getPresignedUrl, andlistObjects. All operations transparently fall back to the standard HTTP path when Bun-specific conditions aren't met (e.g. SSE-C headers, extra opts). isBunruntime detection andextractBaseEndpointutility for Bun S3 client initialization.- Correction: none of these Bun fast paths ever activated.
isBuncomparednavigator.userAgentto'Bun', which Bun never reports. Fixed in 1.0.0, whereputObject,putAnyObject,getObjectRawandgetObjectWithETagwere also dropped from the list.
- Correction: none of these Bun fast paths ever activated.
- Bun test runner (
tests/run-bun.js) with Docker lifecycle management for provider tests. - CI workflow now runs E2E tests on both Node and Bun runtimes.
retryFetchwrapper in E2E test infrastructure for transient network error resilience (ETIMEDOUT, ECONNRESET).
- Rewrote
_extractBucketName()— cleaner logic, correctly handles IP addresses, virtual-hosted and path-style URLs. - Optimized E2E test suite from 54 to 43 tests per provider by removing redundant coverage and merging related tests.
- Moved all Bun native type definitions (
NativeS3Stat,NativeS3File,NativeS3ListObject,NativeS3ListResult,NativeS3Client) fromS3.tstotypes.ts. - Migrated test files from
@jest/globalsimports to framework-agnostic globals (compatible with both Jest and Bun test runner).
- Fixed paginated listing for large buckets.
- Fixed false positive parseXml regex ReDoS scanner report.
- Presigned URLs now support signing additional HTTP headers via a new optional
headersparameter ingetPresignedUrl(). Previously,X-Amz-SignedHeaderswas hardcoded tohost, making it impossible to enforce headers likeContent-Typeon presigned PUT uploads.
- New
headersparameter (5th, optional) ongetPresignedUrl(method, key, expiresIn, queryParams, headers). Signed headers are included inX-Amz-SignedHeadersand the canonical request per AWS SigV4 spec. Thehostheader is always signed automatically. Fully backward-compatible — omittingheaderspreserves existing behavior.
- Renamed
s3miniclass toS3minito follow TypeScript naming conventions. s3miniis now an alias forS3miniwith deprecated usage flag.- Updated all references in the codebase to use
S3miniinstead ofs3mini. - Fixed Minio health check and its docker image. (Thanks @ScArLeXiA)
- Added
ListObjectinterface type for better type safety in list operations. - Added
CHANGELOG.mdto track changes andBREAKING.mdfor breaking changes. - Added SSE-C support for server-side encryption with customer-provided keys. (Tested on Cloudflare only!)
- Fixed
getEtagmethod to properly handle conditional requests and returnnullwhen no ETag is present.
- Response objects now use uppercase property names to match AWS S3 API conventions (except for
etagwhich remains lowercase) key→Keysize→SizelastModified→LastModifiedetagremainsetag