diff --git a/.release-please-manifest.json b/.release-please-manifest.json index a915e8c..2be9c43 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.1.1" + ".": "0.2.0" } diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..024b1c9 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,45 @@ +# Changelog + +## [0.2.0](https://github.com/developmentseed/multistore/compare/multistore-v0.1.1...multistore-v0.2.0) (2026-03-19) + + +### Features + +* add display_name field to ResolvedBucket ([263d324](https://github.com/developmentseed/multistore/commit/263d324fe417a9bb9a4d04fcac9b029688d7be19)) +* add metering middleware ([20395f7](https://github.com/developmentseed/multistore/commit/20395f74def521b4ee74260e8cc8e399e81be25c)) +* add metering middleware ([73c2d2c](https://github.com/developmentseed/multistore/commit/73c2d2cdc9dd28606b2da0e4217e222881c05600)) +* add OidcDiscoveryRouteHandler for .well-known endpoints ([d5f01a0](https://github.com/developmentseed/multistore/commit/d5f01a0e9b52ce92e9c309f03b48c99adc3ef11a)) +* add RouteHandler trait and RequestInfo for pluggable pre-dispatch routing ([1db06a8](https://github.com/developmentseed/multistore/commit/1db06a873b4af645082899520c14439d5b419202)) +* add StsRouteHandler for AssumeRoleWithWebIdentity interception ([c6d6d66](https://github.com/developmentseed/multistore/commit/c6d6d66fb908d8471f0e607b1f8ded10b916f30e)) +* **cf-workers:** add azure/gcp feature flags for StoreBuilder variants ([61aa2f5](https://github.com/developmentseed/multistore/commit/61aa2f53e4ba6c9ec28c061ed7d1ec7b86e6e6a2)) +* **core:** support percent encoding ([8c69f11](https://github.com/developmentseed/multistore/commit/8c69f118ac71bf088e305d9c9e5db825dc303dcc)) +* create multistore-cf-workers crate with reusable Workers adapters ([73c79b5](https://github.com/developmentseed/multistore/commit/73c79b582d88334fb7a65970905aaa6bda4b3f57)) +* create multistore-path-mapping crate for hierarchical path routing ([19d6626](https://github.com/developmentseed/multistore/commit/19d66268b8d038eae403f51ebb9ca869f4d194ae)) +* get-object ([#4](https://github.com/developmentseed/multistore/issues/4)) ([9f3d8e8](https://github.com/developmentseed/multistore/commit/9f3d8e85ce97a265907e4473401b94829258c992)) +* support pagination on bucket list ([017f22d](https://github.com/developmentseed/multistore/commit/017f22d531d6a54e90f2d560fe46b2b1aebce6ea)) +* support range requests ([4053c5f](https://github.com/developmentseed/multistore/commit/4053c5f8ae6cf5089c863018ac575ba2caba8e25)) +* **workers:** add rate-limiting ([47a5973](https://github.com/developmentseed/multistore/commit/47a5973856f8a4c46167951ce439fe2abf65be59)) + + +### Bug Fixes + +* add default allowed roles ([35dd823](https://github.com/developmentseed/multistore/commit/35dd82352e7f14fb8f87c71e98862f737cb96a07)) +* apply ListRewrite.add_prefix to Prefix element and fix double-slash in rewrite_key ([3ba9890](https://github.com/developmentseed/multistore/commit/3ba98907a0eea206741afe85c4c042281630709e)) +* **ci:** add --cwd to wrangler commands and fix step reference ([a250cf2](https://github.com/developmentseed/multistore/commit/a250cf2efd0ae0d32a36132c935fec9b1fcce5bf)) +* **ci:** let wrangler output stream directly ([f98780e](https://github.com/developmentseed/multistore/commit/f98780e55380086dae3e2e3ec83bfa34187a0c11)) +* **ci:** pass CLOUDFLARE_ACCOUNT_ID as secret to reusable workflow ([c2ff2a7](https://github.com/developmentseed/multistore/commit/c2ff2a7b70b304e4b99c3b41aa3b45d0332a12bc)) +* correct endpoint ([0d9fd27](https://github.com/developmentseed/multistore/commit/0d9fd27a9f3e55055a1a3723f55a528e9e974cce)) +* correct STS endpoint ([3f6b2be](https://github.com/developmentseed/multistore/commit/3f6b2be6f868957fd6d2b19536ae43a2aae6a990)) +* ensure cloudflare streams data properly ([19053b2](https://github.com/developmentseed/multistore/commit/19053b29ecc41896f05bd062713f36927289d57d)) +* handle Azure and GCS URLs in UnsignedUrlSigner ([3af3845](https://github.com/developmentseed/multistore/commit/3af3845c900843e073dca031a8f15bbe692a1089)) +* match S3 ListObjectsV2 delimiter behavior ([ad0acfb](https://github.com/developmentseed/multistore/commit/ad0acfbe953f1ca9dc57c9f2a5b53844143e969f)) +* pin worker version ([2752efb](https://github.com/developmentseed/multistore/commit/2752efb7e6cea5b74a6f399e4e025b525f4124dd)) +* **rate-limit:** ensure middleware runs before bucket resolution ([b15cd64](https://github.com/developmentseed/multistore/commit/b15cd64664e195c6ed39e3cc8673c62dcd7d4f25)) +* support range HEAD requests ([758c44c](https://github.com/developmentseed/multistore/commit/758c44c13cc59a9f9ee6381b3d6b0573fa084c55)) +* **workers:** support multipart downloads ([7e4c313](https://github.com/developmentseed/multistore/commit/7e4c313e693d02c4b9adfaa36c82f3851504c41c)) +* **workers:** us sqlite durable object storage ([65b7101](https://github.com/developmentseed/multistore/commit/65b71017691d868037815ca8f284bddc6e1c80d8)) + + +### Performance Improvements + +* use Cow<BucketConfig> in OidcBackendAuth to avoid per-request clones ([4dff450](https://github.com/developmentseed/multistore/commit/4dff4509a87524ce5eb3d3154de6dfa8c39b9256)) diff --git a/Cargo.toml b/Cargo.toml index c6e639d..7b65c7e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,7 +24,7 @@ default-members = [ resolver = "2" [workspace.package] -version = "0.1.1" +version = "0.2.0" edition = "2021" license = "MIT" @@ -100,10 +100,10 @@ console_error_panic_hook = "0.1.7" lambda_http = "0.13" # Internal crates -multistore = { path = "crates/core", version = "0.1.1" } -multistore-static-config = { path = "crates/static-config", version = "0.1.1" } -multistore-sts = { path = "crates/sts", version = "0.1.1" } -multistore-metering = { path = "crates/metering", version = "0.1.1" } -multistore-cf-workers = { path = "crates/cf-workers", version = "0.1.1" } -multistore-oidc-provider = { path = "crates/oidc-provider", version = "0.1.1" } -multistore-path-mapping = { path = "crates/path-mapping", version = "0.1.1" } +multistore = { path = "crates/core", version = "0.2.0" } +multistore-static-config = { path = "crates/static-config", version = "0.2.0" } +multistore-sts = { path = "crates/sts", version = "0.2.0" } +multistore-metering = { path = "crates/metering", version = "0.2.0" } +multistore-cf-workers = { path = "crates/cf-workers", version = "0.2.0" } +multistore-oidc-provider = { path = "crates/oidc-provider", version = "0.2.0" } +multistore-path-mapping = { path = "crates/path-mapping", version = "0.2.0" } diff --git a/crates/core/src/api/list.rs b/crates/core/src/api/list.rs index b8c576e..529c416 100644 --- a/crates/core/src/api/list.rs +++ b/crates/core/src/api/list.rs @@ -147,13 +147,12 @@ pub(crate) fn build_list_xml( if url_encode { // S3 URL-encodes per RFC 3986: leave unreserved chars + '/' unencoded. // Unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~" - const S3_ENCODE_SET: &percent_encoding::AsciiSet = - &percent_encoding::NON_ALPHANUMERIC - .remove(b'-') - .remove(b'.') - .remove(b'_') - .remove(b'~') - .remove(b'/'); + const S3_ENCODE_SET: &percent_encoding::AsciiSet = &percent_encoding::NON_ALPHANUMERIC + .remove(b'-') + .remove(b'.') + .remove(b'_') + .remove(b'~') + .remove(b'/'); percent_encoding::utf8_percent_encode(&s, S3_ENCODE_SET).to_string() } else { s @@ -375,16 +374,36 @@ mod tests { let xml = build_list_xml(¶ms, &list_result, &config, None).unwrap(); // EncodingType element should be present - assert!(xml.contains("url"), "Missing EncodingType element: {}", xml); + assert!( + xml.contains("url"), + "Missing EncodingType element: {}", + xml + ); // Key: spaces encoded, but '/', '.', '-' preserved (RFC 3986 unreserved + '/') - assert!(xml.contains("dir/file%20with%20spaces.txt"), "Key not encoded correctly: {}", xml); + assert!( + xml.contains("dir/file%20with%20spaces.txt"), + "Key not encoded correctly: {}", + xml + ); // CommonPrefix: spaces encoded, '/' preserved - assert!(xml.contains("dir/sub%20dir/"), "CommonPrefix not encoded correctly: {}", xml); + assert!( + xml.contains("dir/sub%20dir/"), + "CommonPrefix not encoded correctly: {}", + xml + ); // Prefix: '/' preserved - assert!(xml.contains("dir/") || xml.contains("dir/sub%20dir/"), - "Prefix not encoded correctly: {}", xml); + assert!( + xml.contains("dir/") + || xml.contains("dir/sub%20dir/"), + "Prefix not encoded correctly: {}", + xml + ); // Delimiter: '/' preserved - assert!(xml.contains("/"), "Delimiter should not encode '/': {}", xml); + assert!( + xml.contains("/"), + "Delimiter should not encode '/': {}", + xml + ); } #[test] @@ -409,8 +428,11 @@ mod tests { let xml = build_list_xml(¶ms, &list_result, &config, None).unwrap(); - assert!(xml.contains("test_file%283%29.png"), - "Expected S3-style encoding of parens: {}", xml); + assert!( + xml.contains("test_file%283%29.png"), + "Expected S3-style encoding of parens: {}", + xml + ); } #[test] @@ -434,9 +456,17 @@ mod tests { let xml = build_list_xml(¶ms, &list_result, &config, None).unwrap(); // No EncodingType element - assert!(!xml.contains(""), "EncodingType should not be present: {}", xml); + assert!( + !xml.contains(""), + "EncodingType should not be present: {}", + xml + ); // Key should NOT be URL-encoded (spaces are XML-safe) - assert!(xml.contains("dir/file with spaces.txt"), "Key should be raw: {}", xml); + assert!( + xml.contains("dir/file with spaces.txt"), + "Key should be raw: {}", + xml + ); } #[test]