diff --git a/.gitignore b/.gitignore index 24f0029..cab688c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ /target /result /uploads +/test_data diff --git a/Cargo.lock b/Cargo.lock index c32a0ee..4f5fd9f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -28,9 +28,9 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.21" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a" +checksum = "824a212faf96e9acacdbd09febd34438f8f711fb84e09a8916013cd7815ca28d" dependencies = [ "anstyle", "anstyle-parse", @@ -43,15 +43,15 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.13" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" +checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000" [[package]] name = "anstyle-parse" -version = "0.2.7" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" +checksum = "52ce7f38b242319f7cabaa6813055467063ecdc9d355bbb4ce0c68908cd8130e" dependencies = [ "utf8parse", ] @@ -78,9 +78,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.100" +version = "1.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" +checksum = "2a4385e2e34eb35d6b3efe798b9eb88096925d87726c0798709bf56d9ed84af3" [[package]] name = "argon2" @@ -90,7 +90,7 @@ checksum = "3c3610892ee6e0cbce8ae2700349fcf8f98adb0dbfbee85aec3c9179d29cc072" dependencies = [ "base64ct", "blake2", - "cpufeatures", + "cpufeatures 0.2.17", "password-hash", ] @@ -122,15 +122,15 @@ checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" [[package]] name = "autocfg" -version = "1.5.0" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" +checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53" [[package]] name = "aws-lc-rs" -version = "1.15.4" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b7b6141e96a8c160799cc2d5adecd5cbbe5054cb8c7c4af53da0f83bb7ad256" +checksum = "5ec2f1fc3ec205783a5da9a7e6c1509cc69dedf09a1949e412c1e18469326d00" dependencies = [ "aws-lc-sys", "zeroize", @@ -138,9 +138,9 @@ dependencies = [ [[package]] name = "aws-lc-sys" -version = "0.37.0" +version = "0.41.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c34dda4df7017c8db52132f0f8a2e0f8161649d15723ed63fc00c82d0f2081a" +checksum = "1a2f9779ce85b93ab6170dd940ad0169b5766ff848247aff13bb788b832fe3f4" dependencies = [ "cc", "cmake", @@ -150,9 +150,9 @@ dependencies = [ [[package]] name = "axum" -version = "0.8.8" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b52af3cb4058c895d37317bb27508dccc8e5f2d39454016b297bf4a400597b8" +checksum = "31b698c5f9a010f6573133b09e0de5408834d0c82f8d7475a89fc1867a71cd90" dependencies = [ "axum-core", "base64", @@ -206,9 +206,9 @@ dependencies = [ [[package]] name = "axum-extra" -version = "0.12.5" +version = "0.12.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fef252edff26ddba56bbcdf2ee3307b8129acb86f5749b68990c168a6fcc9c76" +checksum = "be44683b41ccb9ab2d23a5230015c9c3c55be97a25e4428366de8873103f7970" dependencies = [ "axum", "axum-core", @@ -226,6 +226,35 @@ dependencies = [ "tracing", ] +[[package]] +name = "axum-test" +version = "21.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ce104337e4cced59ded9c61f9f18dab0a4670fd339e84f334312686440a9958" +dependencies = [ + "anyhow", + "axum", + "bytes", + "bytesize", + "cookie", + "educe", + "expect-json", + "http", + "http-body-util", + "hyper", + "hyper-util", + "mime", + "pretty_assertions", + "reserve-port", + "rust-multipart-rfc7578_2", + "serde", + "serde_json", + "serde_urlencoded", + "tokio", + "tower", + "url", +] + [[package]] name = "base64" version = "0.22.1" @@ -240,9 +269,9 @@ checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" [[package]] name = "bitflags" -version = "2.10.0" +version = "2.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" +checksum = "b4388bee8683e3d04af747c73422af53102d2bd24d9eadb6cbc100baef4b43f8" dependencies = [ "serde_core", ] @@ -253,7 +282,7 @@ version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" dependencies = [ - "digest", + "digest 0.10.7", ] [[package]] @@ -266,10 +295,19 @@ dependencies = [ ] [[package]] -name = "bumpalo" -version = "3.19.1" +name = "block-buffer" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510" +checksum = "d2f6c7dbe95a6ed67ad9f18e57daf93a2f034c524b99fd2b76d18fdfeb6660aa" +dependencies = [ + "hybrid-array", +] + +[[package]] +name = "bumpalo" +version = "3.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649" [[package]] name = "byteorder" @@ -279,15 +317,21 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.11.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3" +checksum = "8ae3f5d315924270530207e2a68396c3cc547f6dca3fbdca317cfb1a51edb593" + +[[package]] +name = "bytesize" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49e78e506b9d7633710dab98996f22f95f3d0f488e8f1aa162830556ed9fc14d" [[package]] name = "cc" -version = "1.2.52" +version = "1.2.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd4932aefd12402b36c60956a4fe0035421f544799057659ff86f923657aada3" +checksum = "e228eec9be7c17ccb640b59b36a5cd805ea2a564a4c5e162c2f659fea30d3b96" dependencies = [ "find-msvc-tools", "jobserver", @@ -295,12 +339,6 @@ dependencies = [ "shlex", ] -[[package]] -name = "cesu8" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" - [[package]] name = "cfb" version = "0.7.3" @@ -325,10 +363,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" [[package]] -name = "chrono" -version = "0.4.42" +name = "chacha20" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "145052bdd345b87320e369255277e3fb5152762ad123a901ef5c262dd38fe8d2" +checksum = "d524456ba66e72eb8b115ff89e01e497f8e6d11d78b70b1aa13c0fbd97540a81" +dependencies = [ + "cfg-if", + "cpufeatures 0.3.0", + "rand_core 0.10.1", +] + +[[package]] +name = "chrono" +version = "0.4.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aa79e62e7697b8e29b513a68abacf485adcd1fe8284a4316c5ae868e6633327" dependencies = [ "iana-time-zone", "js-sys", @@ -340,9 +389,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.54" +version = "4.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6e6ff9dcd79cff5cd969a17a545d79e84ab086e444102a591e288a8aa3ce394" +checksum = "1ddb117e43bbf7dacf0a4190fef4d345b9bad68dfc649cb349e7d17d28428e51" dependencies = [ "clap_builder", "clap_derive", @@ -350,9 +399,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.54" +version = "4.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa42cf4d2b7a41bc8f663a7cab4031ebafa1bf3875705bfaf8466dc60ab52c00" +checksum = "714a53001bf66416adb0e2ef5ac857140e7dc3a0c48fb28b2f10762fc4b5069f" dependencies = [ "anstream", "anstyle", @@ -362,9 +411,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.49" +version = "4.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a0b5487afeab2deb2ff4e03a807ad1a03ac532ff5a2cee5d86884440c7f7671" +checksum = "f2ce8604710f6733aa641a2b3731eaa1e8b3d9973d5e3565da11800813f997a9" dependencies = [ "heck", "proc-macro2", @@ -374,24 +423,24 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.7.7" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3e64b0cc0439b12df2fa678eae89a1c56a529fd067a9115f7827f1fffd22b32" +checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9" [[package]] name = "cmake" -version = "0.1.57" +version = "0.1.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75443c44cd6b379beb8c5b45d85d0773baf31cce901fe7bb252f4eff3008ef7d" +checksum = "c0f78a02292a74a88ac736019ab962ece0bc380e3f977bf72e376c5d78ff0678" dependencies = [ "cc", ] [[package]] name = "colorchoice" -version = "1.0.4" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" +checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570" [[package]] name = "combine" @@ -418,6 +467,22 @@ version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" +[[package]] +name = "const-oid" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6ef517f0926dd24a1582492c791b6a4818a4d94e789a334894aa15b0d12f55c" + +[[package]] +name = "cookie" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ddef33a339a91ea89fb53151bd0a4689cfce27055c291dfa69945475d22c747" +dependencies = [ + "time", + "version_check", +] + [[package]] name = "core-foundation" version = "0.9.4" @@ -453,6 +518,15 @@ dependencies = [ "libc", ] +[[package]] +name = "cpufeatures" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201" +dependencies = [ + "libc", +] + [[package]] name = "crc" version = "3.4.0" @@ -464,9 +538,9 @@ dependencies = [ [[package]] name = "crc-catalog" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" +checksum = "217698eaf96b4a3f0bc4f3662aaa55bdf913cd54d7204591faa790070c6d0853" [[package]] name = "crossbeam-queue" @@ -494,10 +568,19 @@ dependencies = [ ] [[package]] -name = "dashmap" -version = "6.1.0" +name = "crypto-common" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5041cc499144891f3790297212f32a74fb938e5136a14943f338ef9e0ae276cf" +checksum = "ce6e4c961d6cd6c9a86db418387425e8bdeaf05b3c8bc1411e6dca4c252f1453" +dependencies = [ + "hybrid-array", +] + +[[package]] +name = "dashmap" +version = "6.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6361d5c062261c78a176addb82d4c821ae42bed6089de0e12603cd25de2059c" dependencies = [ "cfg-if", "crossbeam-utils", @@ -509,9 +592,9 @@ dependencies = [ [[package]] name = "data-encoding" -version = "2.10.0" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7a1e2f27636f116493b8b860f5546edb47c8d8f8ea73e1d2a20be88e28d1fea" +checksum = "a4ae5f15dda3c708c0ade84bfee31ccab44a3da4f88015ed22f63732abe300c8" [[package]] name = "der" @@ -519,19 +602,22 @@ version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" dependencies = [ - "const-oid", + "const-oid 0.9.6", "pem-rfc7468", "zeroize", ] [[package]] name = "deranged" -version = "0.5.5" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ececcb659e7ba858fb4f10388c250a7252eb0a27373f1a72b8748afdd248e587" -dependencies = [ - "powerfmt", -] +checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" + +[[package]] +name = "diff" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" [[package]] name = "digest" @@ -539,17 +625,28 @@ version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ - "block-buffer", - "const-oid", - "crypto-common", + "block-buffer 0.10.4", + "const-oid 0.9.6", + "crypto-common 0.1.7", "subtle", ] [[package]] -name = "displaydoc" -version = "0.2.5" +name = "digest" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +checksum = "f1dd6dbb5841937940781866fa1281a1ff7bd3bf827091440879f9994983d5c2" +dependencies = [ + "block-buffer 0.12.1", + "const-oid 0.10.2", + "crypto-common 0.2.2", +] + +[[package]] +name = "displaydoc" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ac70aa55017e108007fbaf5aa0f54b021c98f92ff8af59d42eda9da96e3dd4f" dependencies = [ "proc-macro2", "quote", @@ -569,10 +666,31 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" [[package]] -name = "either" -version = "1.15.0" +name = "educe" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" +checksum = "1d7bc049e1bd8cdeb31b68bbd586a9464ecf9f3944af3958a7a9d0f8b9799417" +dependencies = [ + "enum-ordinalize", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "either" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91622ff5e7162018101f2fea40d6ebf4a78bbe5a49736a2020649edf9693679e" +dependencies = [ + "serde", +] + +[[package]] +name = "email_address" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e079f19b08ca6239f47f8ba8509c11cf3ea30095831f7fed61441475edd8c449" dependencies = [ "serde", ] @@ -586,12 +704,43 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "enum-ordinalize" +version = "4.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07f808d588c10e464ea6f7d3eaed500049eff30aaac103460f61828c2d65b3eb" +dependencies = [ + "enum-ordinalize-derive", +] + +[[package]] +name = "enum-ordinalize-derive" +version = "4.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42e528e2d34ba8a67a1a650b86beae8ef69fc5fdb638016f386b973226590432" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "equivalent" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" +[[package]] +name = "erased-serde" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2add8a07dd6a8d93ff627029c51de145e12686fbc36ecb298ac22e74cf02dec" +dependencies = [ + "serde", + "serde_core", + "typeid", +] + [[package]] name = "errno" version = "0.3.14" @@ -625,16 +774,45 @@ dependencies = [ ] [[package]] -name = "fastrand" -version = "2.3.0" +name = "expect-json" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" +checksum = "5e80819dbfe83c8a651f5344b08910d0037dac72988aef27ee4e6bedd7ae2e33" +dependencies = [ + "chrono", + "email_address", + "expect-json-macros", + "num", + "regex", + "serde", + "serde_json", + "thiserror 2.0.18", + "typetag", + "uuid", +] + +[[package]] +name = "expect-json-macros" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0637949cd816934f3b7aab44ff98e7ec1fb903c379e07dcb9eac943ec33499e" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "fastrand" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6" [[package]] name = "find-msvc-tools" -version = "0.1.7" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f449e6c6c08c865631d4890cfacf252b3d396c9bcc83adb6623cdb02a8336c41" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" [[package]] name = "flume" @@ -707,6 +885,7 @@ dependencies = [ "argon2", "axum", "axum-extra", + "axum-test", "bytes", "chrono", "clap", @@ -718,6 +897,7 @@ dependencies = [ "reqwest", "serde", "serde_json", + "sha2 0.11.0", "sqlx", "tokio", "tower", @@ -737,9 +917,9 @@ checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" [[package]] name = "futures-channel" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" +checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d" dependencies = [ "futures-core", "futures-sink", @@ -747,15 +927,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" +checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" [[package]] name = "futures-executor" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" +checksum = "baf29c38818342a3b26b5b923639e7b1f4a61fc5e76102d4b1981c6dc7a7579d" dependencies = [ "futures-core", "futures-task", @@ -775,33 +955,33 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" +checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718" [[package]] name = "futures-sink" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" +checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893" [[package]] name = "futures-task" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" +checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" [[package]] name = "futures-timer" -version = "3.0.3" +version = "3.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24" +checksum = "af43fadb8a98512d547e37b4e92e0ced13e205c061b87b4623eff01d918d6968" [[package]] name = "futures-util" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" dependencies = [ "futures-core", "futures-io", @@ -809,7 +989,6 @@ dependencies = [ "futures-task", "memchr", "pin-project-lite", - "pin-utils", "slab", ] @@ -845,11 +1024,23 @@ dependencies = [ "cfg-if", "js-sys", "libc", - "r-efi", + "r-efi 5.3.0", "wasip2", "wasm-bindgen", ] +[[package]] +name = "getrandom" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099" +dependencies = [ + "cfg-if", + "libc", + "r-efi 6.0.0", + "rand_core 0.10.1", +] + [[package]] name = "governor" version = "0.10.4" @@ -867,7 +1058,7 @@ dependencies = [ "parking_lot", "portable-atomic", "quanta", - "rand 0.9.2", + "rand 0.9.4", "smallvec", "spinning_top", "web-time", @@ -875,9 +1066,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.4.13" +version = "0.4.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f44da3a8150a6703ed5d34e164b875fd14c2cdab9af1252a9a1020bde2bdc54" +checksum = "6cb093c84e8bd9b188d4c4a8cb6579fc016968d14c99882163cd3ff402a4f155" dependencies = [ "atomic-waker", "bytes", @@ -920,6 +1111,12 @@ dependencies = [ "foldhash 0.2.0", ] +[[package]] +name = "hashbrown" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" + [[package]] name = "hashlink" version = "0.10.0" @@ -980,7 +1177,7 @@ version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" dependencies = [ - "digest", + "digest 0.10.7", ] [[package]] @@ -994,9 +1191,9 @@ dependencies = [ [[package]] name = "http" -version = "1.4.0" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a" +checksum = "6970f50e31d6fc17d3fa27329444bfa74e196cf62e95052a3f6fee181dba6425" dependencies = [ "bytes", "itoa", @@ -1025,6 +1222,12 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "http-range-header" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9171a2ea8a68358193d15dd5d70c1c10a2afc3e7e4c5bc92bc9f025cebd7359c" + [[package]] name = "httparse" version = "1.10.1" @@ -1038,10 +1241,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] -name = "hyper" -version = "1.8.1" +name = "hybrid-array" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ab2d4f250c3d7b1c9fcdff1cece94ea4e2dfbec68614f7b87cb205f24ca9d11" +checksum = "818356c5132c1fede50f837ca96afbe78ff42413047f4abb886217845e1b6c8c" +dependencies = [ + "typenum", +] + +[[package]] +name = "hyper" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55281c53a1894c864990125767da440a4e630446785086f52523b20033b74498" dependencies = [ "atomic-waker", "bytes", @@ -1054,7 +1266,6 @@ dependencies = [ "httpdate", "itoa", "pin-project-lite", - "pin-utils", "smallvec", "tokio", "want", @@ -1062,15 +1273,14 @@ dependencies = [ [[package]] name = "hyper-rustls" -version = "0.27.7" +version = "0.27.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" +checksum = "33ca68d021ef39cf6463ab54c1d0f5daf03377b70561305bb89a8f83aab66e0f" dependencies = [ "http", "hyper", "hyper-util", "rustls", - "rustls-pki-types", "tokio", "tokio-rustls", "tower-service", @@ -1091,14 +1301,13 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.19" +version = "0.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "727805d60e7938b76b826a6ef209eb70eaa1812794f9424d4a4e2d740662df5f" +checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0" dependencies = [ "base64", "bytes", "futures-channel", - "futures-core", "futures-util", "http", "http-body", @@ -1117,9 +1326,9 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.64" +version = "0.1.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33e57f83510bb73707521ebaffa789ec8caf86f9657cad665b092b581d40e9fb" +checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -1141,12 +1350,13 @@ dependencies = [ [[package]] name = "icu_collections" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" +checksum = "2984d1cd16c883d7935b9e07e44071dca8d917fd52ecc02c04d5fa0b5a3f191c" dependencies = [ "displaydoc", "potential_utf", + "utf8_iter", "yoke", "zerofrom", "zerovec", @@ -1154,9 +1364,9 @@ dependencies = [ [[package]] name = "icu_locale_core" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" +checksum = "92219b62b3e2b4d88ac5119f8904c10f8f61bf7e95b640d25ba3075e6cac2c29" dependencies = [ "displaydoc", "litemap", @@ -1167,9 +1377,9 @@ dependencies = [ [[package]] name = "icu_normalizer" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" +checksum = "c56e5ee99d6e3d33bd91c5d85458b6005a22140021cc324cea84dd0e72cff3b4" dependencies = [ "icu_collections", "icu_normalizer_data", @@ -1181,15 +1391,15 @@ dependencies = [ [[package]] name = "icu_normalizer_data" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" +checksum = "da3be0ae77ea334f4da67c12f149704f19f81d1adf7c51cf482943e84a2bad38" [[package]] name = "icu_properties" -version = "2.1.2" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec" +checksum = "bee3b67d0ea5c2cca5003417989af8996f8604e34fb9ddf96208a033901e70de" dependencies = [ "icu_collections", "icu_locale_core", @@ -1201,15 +1411,15 @@ dependencies = [ [[package]] name = "icu_properties_data" -version = "2.1.2" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af" +checksum = "8e2bbb201e0c04f7b4b3e14382af113e17ba4f63e2c9d2ee626b720cbce54a14" [[package]] name = "icu_provider" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" +checksum = "139c4cf31c8b5f33d7e199446eff9c1e02decfc2f0eec2c8d71f65befa45b421" dependencies = [ "displaydoc", "icu_locale_core", @@ -1233,9 +1443,9 @@ dependencies = [ [[package]] name = "idna_adapter" -version = "1.2.1" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" +checksum = "cb68373c0d6620ef8105e855e7745e18b0d00d3bdb07fb532e434244cdb9a714" dependencies = [ "icu_normalizer", "icu_properties", @@ -1243,12 +1453,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.13.0" +version = "2.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" +checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" dependencies = [ "equivalent", - "hashbrown 0.16.1", + "hashbrown 0.17.1", ] [[package]] @@ -1261,20 +1471,19 @@ dependencies = [ ] [[package]] -name = "ipnet" -version = "2.11.0" +name = "inventory" +version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" +checksum = "a4f0c30c76f2f4ccee3fe55a2435f691ca00c0e4bd87abe4f4a851b1d4dac39b" +dependencies = [ + "rustversion", +] [[package]] -name = "iri-string" -version = "0.7.10" +name = "ipnet" +version = "2.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c91338f0783edbd6195decb37bae672fd3b165faffb89bf7b9e6942f8b1a731a" -dependencies = [ - "memchr", - "serde", -] +checksum = "d98f6fed1fde3f8c21bc40a1abb88dd75e67924f9cffc3ef95607bad8017f8e2" [[package]] name = "is_terminal_polyfill" @@ -1284,31 +1493,58 @@ checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" [[package]] name = "itoa" -version = "1.0.17" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" [[package]] name = "jni" -version = "0.21.1" +version = "0.22.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97" +checksum = "5efd9a482cf3a427f00d6b35f14332adc7902ce91efb778580e180ff90fa3498" dependencies = [ - "cesu8", "cfg-if", "combine", + "jni-macros", "jni-sys", "log", - "thiserror 1.0.69", + "simd_cesu8", + "thiserror 2.0.18", "walkdir", - "windows-sys 0.45.0", + "windows-link", +] + +[[package]] +name = "jni-macros" +version = "0.22.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a00109accc170f0bdb141fed3e393c565b6f5e072365c3bd58f5b062591560a3" +dependencies = [ + "proc-macro2", + "quote", + "rustc_version", + "simd_cesu8", + "syn", ] [[package]] name = "jni-sys" -version = "0.3.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" +checksum = "c6377a88cb3910bee9b0fa88d4f42e1d2da8e79915598f65fb0c7ee14c878af2" +dependencies = [ + "jni-sys-macros", +] + +[[package]] +name = "jni-sys-macros" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38c0b942f458fe50cdac086d2f946512305e5631e720728f2a61aabcd47a6264" +dependencies = [ + "quote", + "syn", +] [[package]] name = "jobserver" @@ -1322,11 +1558,12 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.83" +version = "0.3.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "464a3709c7f55f1f721e5389aa6ea4e3bc6aba669353300af094b29ffbdde1d8" +checksum = "53b44bfcdb3f8d5837a46dae1ca9660a837176eee74a28b229bc626816589102" dependencies = [ - "once_cell", + "cfg-if", + "futures-util", "wasm-bindgen", ] @@ -1356,25 +1593,26 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.180" +version = "0.2.186" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcc35a38544a891a5f7c865aca548a982ccb3b8650a5b06d0fd33a10283c56fc" +checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" [[package]] name = "libm" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" +checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" [[package]] name = "libredox" -version = "0.1.12" +version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d0b95e02c851351f877147b7deea7b1afb1df71b63aa5f8270716e0c5720616" +checksum = "f02ab6bace2054fb888a3c16f990117b579d14a3088e472d63c6011fa185c9d3" dependencies = [ "bitflags", "libc", - "redox_syscall 0.7.0", + "plain", + "redox_syscall 0.8.1", ] [[package]] @@ -1389,15 +1627,15 @@ dependencies = [ [[package]] name = "linux-raw-sys" -version = "0.11.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" +checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" [[package]] name = "litemap" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" +checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0" [[package]] name = "lock_api" @@ -1410,9 +1648,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.29" +version = "0.4.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" +checksum = "0ceec5bc11778974d1bcb055b18002eba7f4b3518b6a0081b3af5f21666da9ad" [[package]] name = "lru-slab" @@ -1442,14 +1680,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" dependencies = [ "cfg-if", - "digest", + "digest 0.10.7", ] [[package]] name = "memchr" -version = "2.7.6" +version = "2.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" +checksum = "88904434abc2901f197fe8cc55f0445e7ded921dba5911dad2e2b39b48e663c4" [[package]] name = "mime" @@ -1458,10 +1696,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" [[package]] -name = "mio" -version = "1.1.1" +name = "mime_guess" +version = "2.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc" +checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e" +dependencies = [ + "mime", + "unicase", +] + +[[package]] +name = "mio" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02bd0af71c67b473010cbbc60715ee815645a4dc942899111f494b4b737d6fda" dependencies = [ "libc", "wasi", @@ -1487,17 +1735,17 @@ dependencies = [ [[package]] name = "native-tls" -version = "0.2.14" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87de3442987e9dbec73158d5c715e7ad9072fda936bb03d19d7fa10e00520f0e" +checksum = "465500e14ea162429d264d44189adc38b199b62b1c21eea9f69e4b73cb03bbf2" dependencies = [ "libc", "log", "openssl", - "openssl-probe 0.1.6", + "openssl-probe", "openssl-sys", "schannel", - "security-framework 2.11.1", + "security-framework", "security-framework-sys", "tempfile", ] @@ -1523,6 +1771,20 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "num" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" +dependencies = [ + "num-bigint", + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "num-traits", +] + [[package]] name = "num-bigint" version = "0.4.6" @@ -1544,16 +1806,25 @@ dependencies = [ "num-integer", "num-iter", "num-traits", - "rand 0.8.5", + "rand 0.8.6", "smallvec", "zeroize", ] [[package]] -name = "num-conv" -version = "0.1.0" +name = "num-complex" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" +checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-conv" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "521739c6d2bac4aa25192232afe6841231376b2b26d4d9fae5ecf8ca5772e441" [[package]] name = "num-integer" @@ -1575,6 +1846,17 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-rational" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" +dependencies = [ + "num-bigint", + "num-integer", + "num-traits", +] + [[package]] name = "num-traits" version = "0.2.19" @@ -1587,9 +1869,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.21.3" +version = "1.21.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" [[package]] name = "once_cell_polyfill" @@ -1599,15 +1881,14 @@ checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" [[package]] name = "openssl" -version = "0.10.75" +version = "0.10.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08838db121398ad17ab8531ce9de97b244589089e290a384c900cb9ff7434328" +checksum = "77823a27f0babb03091cb9ed9ef80af3b39dbc82f97e8fa530374b7dafd87a45" dependencies = [ "bitflags", "cfg-if", "foreign-types", "libc", - "once_cell", "openssl-macros", "openssl-sys", ] @@ -1623,12 +1904,6 @@ dependencies = [ "syn", ] -[[package]] -name = "openssl-probe" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" - [[package]] name = "openssl-probe" version = "0.2.1" @@ -1637,9 +1912,9 @@ checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" [[package]] name = "openssl-sys" -version = "0.9.111" +version = "0.9.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82cab2d520aa75e3c58898289429321eb788c3106963d0dc886ec7a5f4adc321" +checksum = "b47e7e6bb2c38cd930d25a23b40fa52e068c10e85f3e03a7f5ba5aaca5713695" dependencies = [ "cc", "libc", @@ -1714,18 +1989,18 @@ checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" [[package]] name = "pin-project" -version = "1.1.10" +version = "1.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677f1add503faace112b9f1373e43e9e054bfdd22ff1a63c1bc485eaec6a6a8a" +checksum = "2466b2336ed02bcdca6b294417127b90ec92038d1d5c4fbeac971a922e0e0924" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.10" +version = "1.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" +checksum = "c96395f0a926bc13b1c17622aaddda1ecb55d49c8f1bf9777e4d877800a43f8b" dependencies = [ "proc-macro2", "quote", @@ -1734,15 +2009,9 @@ dependencies = [ [[package]] name = "pin-project-lite" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" - -[[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" [[package]] name = "pkcs1" @@ -1767,21 +2036,27 @@ dependencies = [ [[package]] name = "pkg-config" -version = "0.3.32" +version = "0.3.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" +checksum = "19f132c84eca552bf34cab8ec81f1c1dcc229b811638f9d283dceabe58c5569e" + +[[package]] +name = "plain" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" [[package]] name = "portable-atomic" -version = "1.13.0" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f89776e4d69bb58bc6993e99ffa1d11f228b839984854c7daeb5d37f87cbe950" +checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" [[package]] name = "potential_utf" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" +checksum = "0103b1cef7ec0cf76490e969665504990193874ea05c85ff9bab8b911d0a0564" dependencies = [ "zerovec", ] @@ -1802,10 +2077,20 @@ dependencies = [ ] [[package]] -name = "proc-macro2" -version = "1.0.105" +name = "pretty_assertions" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "535d180e0ecab6268a3e718bb9fd44db66bbbc256257165fc699dadf70d16fe7" +checksum = "3ae130e2f271fbc2ac3a40fb1d07180839cdbbe443c7a27e1e3c13c5cac0116d" +dependencies = [ + "diff", + "yansi", +] + +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" dependencies = [ "unicode-ident", ] @@ -1827,9 +2112,9 @@ dependencies = [ [[package]] name = "quinn" -version = "0.11.9" +version = "0.11.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9e20a958963c291dc322d98411f541009df2ced7b5a4f2bd52337638cfccf20" +checksum = "0c1a41e437b6bbd489372cd4971de128e85c855f56c57f283d20ff016cf7c0a8" dependencies = [ "bytes", "cfg_aliases", @@ -1839,7 +2124,7 @@ dependencies = [ "rustc-hash", "rustls", "socket2", - "thiserror 2.0.17", + "thiserror 2.0.18", "tokio", "tracing", "web-time", @@ -1847,21 +2132,21 @@ dependencies = [ [[package]] name = "quinn-proto" -version = "0.11.13" +version = "0.11.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1906b49b0c3bc04b5fe5d86a77925ae6524a19b816ae38ce1e426255f1d8a31" +checksum = "4fcb935c5bec503c2f0e306bdd3e58bb9029dcb14fa8d9ac76e3a5256ac0763e" dependencies = [ "aws-lc-rs", "bytes", "getrandom 0.3.4", "lru-slab", - "rand 0.9.2", + "rand 0.9.4", "ring", "rustc-hash", "rustls", "rustls-pki-types", "slab", - "thiserror 2.0.17", + "thiserror 2.0.18", "tinyvec", "tracing", "web-time", @@ -1883,9 +2168,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.43" +version = "1.0.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc74d9a594b72ae6656596548f56f667211f8a97b3d4c3d467150794690dc40a" +checksum = "dfbc457d0c7a0759a614551b11a6409e5951f6c7537be1f1b7682b9ae9230368" dependencies = [ "proc-macro2", ] @@ -1897,10 +2182,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" [[package]] -name = "rand" -version = "0.8.5" +name = "r-efi" +version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" + +[[package]] +name = "rand" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ca0ecfa931c29007047d1bc58e623ab12e5590e8c7cc53200d5202b69266d8a" dependencies = [ "libc", "rand_chacha 0.3.1", @@ -1909,14 +2200,25 @@ dependencies = [ [[package]] name = "rand" -version = "0.9.2" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" +checksum = "44c5af06bb1b7d3216d91932aed5265164bf384dc89cd6ba05cf59a35f5f76ea" dependencies = [ "rand_chacha 0.9.0", "rand_core 0.9.5", ] +[[package]] +name = "rand" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2e8e8bcc7961af1fdac401278c6a831614941f6164ee3bf4ce61b7edb162207" +dependencies = [ + "chacha20", + "getrandom 0.4.3", + "rand_core 0.10.1", +] + [[package]] name = "rand_chacha" version = "0.3.1" @@ -1955,6 +2257,12 @@ dependencies = [ "getrandom 0.3.4", ] +[[package]] +name = "rand_core" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69" + [[package]] name = "raw-cpuid" version = "11.6.0" @@ -1975,18 +2283,18 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.7.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f3fe0889e69e2ae9e41f4d6c4c0181701d00e4697b356fb1f74173a5e0ee27" +checksum = "5b44b894f2a6e36457d665d1e08c3866add6ed5e70050c1b4ba8a8ddedb02ce7" dependencies = [ "bitflags", ] [[package]] name = "regex" -version = "1.12.2" +version = "1.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "843bc0191f75f3e22651ae5f1e72939ab2f72a4bc30fa80a066bd66edefc24d4" +checksum = "f1292b7759ae1cb9ec195452d1390a074f0cd8541ab7a5a8c31cd6db45d4a6ba" dependencies = [ "aho-corasick", "memchr", @@ -1996,9 +2304,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.13" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c" +checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" dependencies = [ "aho-corasick", "memchr", @@ -2007,15 +2315,15 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.8" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" +checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4" [[package]] name = "reqwest" -version = "0.13.1" +version = "0.13.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04e9018c9d814e5f30cc16a0f03271aeab3571e609612d9fe78c1aa8d11c2f62" +checksum = "219c5811de6525e5416c7d5d53bb656d3afdbc6c5af816e0802bcfa42dbdc1c3" dependencies = [ "base64", "bytes", @@ -2051,6 +2359,15 @@ dependencies = [ "web-sys", ] +[[package]] +name = "reserve-port" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71ea98a177596a4579881992bd2bd4af27772fc95d0e5f5668a8f9535eca6380" +dependencies = [ + "thiserror 2.0.18", +] + [[package]] name = "ring" version = "0.17.14" @@ -2071,8 +2388,8 @@ version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8573f03f5883dcaebdfcf4725caa1ecb9c15b2ef50c43a07b816e06799bb12d" dependencies = [ - "const-oid", - "digest", + "const-oid 0.9.6", + "digest 0.10.7", "num-bigint-dig", "num-integer", "num-traits", @@ -2086,16 +2403,40 @@ dependencies = [ ] [[package]] -name = "rustc-hash" -version = "2.1.1" +name = "rust-multipart-rfc7578_2" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" +checksum = "00bdaa068902270ca7fa8619775e1838e23a63620abac0947ce0f715819b8cec" +dependencies = [ + "bytes", + "futures-core", + "futures-util", + "http", + "mime", + "rand 0.10.1", + "thiserror 2.0.18", +] + +[[package]] +name = "rustc-hash" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94300abf3f1ae2e2b8ffb7b58043de3d399c73fa6f4b73826402a5c457614dbe" + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] [[package]] name = "rustix" -version = "1.1.3" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "146c9e247ccc180c1f61615433868c99f3de3ae256a30a43b49f67c2d9171f34" +checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" dependencies = [ "bitflags", "errno", @@ -2106,9 +2447,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.36" +version = "0.23.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c665f33d38cea657d9614f766881e4d510e0eda4239891eea56b4cadcf01801b" +checksum = "6b92b125634d9b795e7beca796cc790df15a7fb38323bf3196fda83292d06b1f" dependencies = [ "aws-lc-rs", "once_cell", @@ -2120,21 +2461,21 @@ dependencies = [ [[package]] name = "rustls-native-certs" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "612460d5f7bea540c490b2b6395d8e34a953e52b491accd6c86c8164c5932a63" +checksum = "dab5152771c58876a2146916e53e35057e1a4dfa2b9df0f0305b07f611fdea4d" dependencies = [ - "openssl-probe 0.2.1", + "openssl-probe", "rustls-pki-types", "schannel", - "security-framework 3.5.1", + "security-framework", ] [[package]] name = "rustls-pki-types" -version = "1.14.0" +version = "1.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be040f8b0a225e40375822a563fa9524378b9d63112f53e19ffff34df5d33fdd" +checksum = "30a7197ae7eb376e574fe940d068c30fe0462554a3ddbe4eca7838e049c937a9" dependencies = [ "web-time", "zeroize", @@ -2142,9 +2483,9 @@ dependencies = [ [[package]] name = "rustls-platform-verifier" -version = "0.6.2" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d99feebc72bae7ab76ba994bb5e121b8d83d910ca40b36e0921f53becc41784" +checksum = "26d1e2536ce4f35f4846aa13bff16bd0ff40157cdb14cc056c7b14ba41233ba0" dependencies = [ "core-foundation 0.10.1", "core-foundation-sys", @@ -2155,7 +2496,7 @@ dependencies = [ "rustls-native-certs", "rustls-platform-verifier-android", "rustls-webpki", - "security-framework 3.5.1", + "security-framework", "security-framework-sys", "webpki-root-certs", "windows-sys 0.61.2", @@ -2169,9 +2510,9 @@ checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f" [[package]] name = "rustls-webpki" -version = "0.103.9" +version = "0.103.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7df23109aa6c1567d1c575b9952556388da57401e4ace1d15f79eedad0d8f53" +checksum = "61c429a8649f110dddef65e2a5ad240f747e85f7758a6bccc7e5777bd33f756e" dependencies = [ "aws-lc-rs", "ring", @@ -2187,9 +2528,9 @@ checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" [[package]] name = "ryu" -version = "1.0.22" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a50f4cf475b65d88e057964e0e9bb1f0aa9bbb2036dc65c64596b42932536984" +checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" [[package]] name = "same-file" @@ -2202,9 +2543,9 @@ dependencies = [ [[package]] name = "schannel" -version = "0.1.28" +version = "0.1.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "891d81b926048e76efe18581bf793546b4c0eaf8448d72be8de2bbee5fd166e1" +checksum = "91c1b7e4904c873ef0710c1f407dde2e6287de2bebc1bbbf7d430bb7cbffd939" dependencies = [ "windows-sys 0.61.2", ] @@ -2217,22 +2558,9 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "security-framework" -version = "2.11.1" +version = "3.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" -dependencies = [ - "bitflags", - "core-foundation 0.9.4", - "core-foundation-sys", - "libc", - "security-framework-sys", -] - -[[package]] -name = "security-framework" -version = "3.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3297343eaf830f66ede390ea39da1d462b6b0c1b000f420d0a83f898bbbe6ef" +checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d" dependencies = [ "bitflags", "core-foundation 0.10.1", @@ -2243,14 +2571,20 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.15.0" +version = "2.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc1f0cbffaac4852523ce30d8bd3c5cdc873501d96ff467ca09b6767bb8cd5c0" +checksum = "6ce2691df843ecc5d231c0b14ece2acc3efb62c0a398c7e1d875f3983ce020e3" dependencies = [ "core-foundation-sys", "libc", ] +[[package]] +name = "semver" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" + [[package]] name = "serde" version = "1.0.228" @@ -2283,9 +2617,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.149" +version = "1.0.150" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" +checksum = "e8014e44b4736ed0538adeecded0fce2a272f22dc9578a7eb6b2d9993c74cfb9" dependencies = [ "itoa", "memchr", @@ -2324,8 +2658,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" dependencies = [ "cfg-if", - "cpufeatures", - "digest", + "cpufeatures 0.2.17", + "digest 0.10.7", ] [[package]] @@ -2335,8 +2669,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" dependencies = [ "cfg-if", - "cpufeatures", - "digest", + "cpufeatures 0.2.17", + "digest 0.10.7", +] + +[[package]] +name = "sha2" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "446ba717509524cb3f22f17ecc096f10f4822d76ab5c0b9822c5f9c284e825f4" +dependencies = [ + "cfg-if", + "cpufeatures 0.3.0", + "digest 0.11.3", ] [[package]] @@ -2350,9 +2695,9 @@ dependencies = [ [[package]] name = "shlex" -version = "1.3.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" +checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" [[package]] name = "signature" @@ -2360,45 +2705,61 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" dependencies = [ - "digest", + "digest 0.10.7", "rand_core 0.6.4", ] [[package]] -name = "simple_asn1" -version = "0.6.3" +name = "simd_cesu8" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "297f631f50729c8c99b84667867963997ec0b50f32b2a7dbcab828ef0541e8bb" +checksum = "94f90157bb87cddf702797c5dadfa0be7d266cdf49e22da2fcaa32eff75b2c33" +dependencies = [ + "rustc_version", + "simdutf8", +] + +[[package]] +name = "simdutf8" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" + +[[package]] +name = "simple_asn1" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d585997b0ac10be3c5ee635f1bab02d512760d14b7c468801ac8a01d9ae5f1d" dependencies = [ "num-bigint", "num-traits", - "thiserror 2.0.17", + "thiserror 2.0.18", "time", ] [[package]] name = "slab" -version = "0.4.11" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589" +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" [[package]] name = "smallvec" -version = "1.15.1" +version = "1.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" +checksum = "8ed6a63f02c8539c91a8685a86f4099661ba3da017932f6ebbea6de3f0fa7c90" dependencies = [ "serde", ] [[package]] name = "socket2" -version = "0.6.1" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17129e116933cf371d018bb80ae557e889637989d8638274fb25622827b03881" +checksum = "52d1cfed4120b4d927bf7c0f86d2087a4a7d6027c906d9f9d525a80573b9be51" dependencies = [ "libc", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -2469,9 +2830,9 @@ dependencies = [ "percent-encoding", "serde", "serde_json", - "sha2", + "sha2 0.10.9", "smallvec", - "thiserror 2.0.17", + "thiserror 2.0.18", "tokio", "tokio-stream", "tracing", @@ -2507,7 +2868,7 @@ dependencies = [ "quote", "serde", "serde_json", - "sha2", + "sha2 0.10.9", "sqlx-core", "sqlx-mysql", "sqlx-postgres", @@ -2530,7 +2891,7 @@ dependencies = [ "bytes", "chrono", "crc", - "digest", + "digest 0.10.7", "dotenvy", "either", "futures-channel", @@ -2547,15 +2908,15 @@ dependencies = [ "memchr", "once_cell", "percent-encoding", - "rand 0.8.5", + "rand 0.8.6", "rsa", "serde", "sha1", - "sha2", + "sha2 0.10.9", "smallvec", "sqlx-core", "stringprep", - "thiserror 2.0.17", + "thiserror 2.0.18", "tracing", "uuid", "whoami", @@ -2587,14 +2948,14 @@ dependencies = [ "md-5", "memchr", "once_cell", - "rand 0.8.5", + "rand 0.8.6", "serde", "serde_json", - "sha2", + "sha2 0.10.9", "smallvec", "sqlx-core", "stringprep", - "thiserror 2.0.17", + "thiserror 2.0.18", "tracing", "uuid", "whoami", @@ -2620,7 +2981,7 @@ dependencies = [ "serde", "serde_urlencoded", "sqlx-core", - "thiserror 2.0.17", + "thiserror 2.0.18", "tracing", "url", "uuid", @@ -2657,9 +3018,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" -version = "2.0.114" +version = "2.0.118" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4d107df263a3013ef9b1879b0df87d706ff80f65a86ea879bd9c31f9b307c2a" +checksum = "1b9ae57f904213ebb649ce6895b8a66c66f0203b9319718f69a5612a065b1422" dependencies = [ "proc-macro2", "quote", @@ -2688,9 +3049,9 @@ dependencies = [ [[package]] name = "system-configuration" -version = "0.6.1" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" +checksum = "a13f3d0daba03132c0aa9767f98351b3488edc2c100cda2d2ec2b04f3d8d3c8b" dependencies = [ "bitflags", "core-foundation 0.9.4", @@ -2709,12 +3070,12 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.24.0" +version = "3.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "655da9c7eb6305c55742045d5a8d2037996d61d8de95806335c7c86ce0f82e9c" +checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" dependencies = [ "fastrand", - "getrandom 0.3.4", + "getrandom 0.4.3", "once_cell", "rustix", "windows-sys 0.61.2", @@ -2731,11 +3092,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.17" +version = "2.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" +checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" dependencies = [ - "thiserror-impl 2.0.17", + "thiserror-impl 2.0.18", ] [[package]] @@ -2751,9 +3112,9 @@ dependencies = [ [[package]] name = "thiserror-impl" -version = "2.0.17" +version = "2.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" +checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" dependencies = [ "proc-macro2", "quote", @@ -2771,12 +3132,11 @@ dependencies = [ [[package]] name = "time" -version = "0.3.45" +version = "0.3.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9e442fc33d7fdb45aa9bfeb312c095964abdf596f7567261062b2a7107aaabd" +checksum = "85c17d80feb7334b40c484e45ed1a5273dfd8bfda537c3be2e74a06a6686f327" dependencies = [ "deranged", - "itoa", "num-conv", "powerfmt", "serde_core", @@ -2786,15 +3146,15 @@ dependencies = [ [[package]] name = "time-core" -version = "0.1.7" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b36ee98fd31ec7426d599183e8fe26932a8dc1fb76ddb6214d05493377d34ca" +checksum = "9e1c906769ad99c88eaa54e728060edef082f8e358ff32030cb7c7d315e81109" [[package]] name = "time-macros" -version = "0.2.25" +version = "0.2.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71e552d1249bf61ac2a52db88179fd0673def1e1ad8243a00d9ec9ed71fee3dd" +checksum = "dcef1a61bdb119096e153208ec5cbec23944ce8bca13be5c7f60c634f7403935" dependencies = [ "num-conv", "time-core", @@ -2802,9 +3162,9 @@ dependencies = [ [[package]] name = "tinystr" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" +checksum = "c8323304221c2a851516f22236c5722a72eaa19749016521d6dff0824447d96d" dependencies = [ "displaydoc", "zerovec", @@ -2812,9 +3172,9 @@ dependencies = [ [[package]] name = "tinyvec" -version = "1.10.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa5fdc3bce6191a1dbc8c02d5c8bffcf557bafa17c124c5264a458f1b0613fa" +checksum = "3e61e67053d25a4e82c844e8424039d9745781b3fc4f32b8d55ed50f5f667ef3" dependencies = [ "tinyvec_macros", ] @@ -2827,9 +3187,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.49.0" +version = "1.52.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72a2903cd7736441aac9df9d7688bd0ce48edccaadf181c3b90be801e81d3d86" +checksum = "8fc7f01b389ac15039e4dc9531aa973a135d7a4135281b12d7c1bc79fd57fffe" dependencies = [ "bytes", "libc", @@ -2842,9 +3202,9 @@ dependencies = [ [[package]] name = "tokio-macros" -version = "2.6.0" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" +checksum = "385a6cb71ab9ab790c5fe8d67f1645e6c450a7ce006a33de03daa956cf70a496" dependencies = [ "proc-macro2", "quote", @@ -2874,9 +3234,9 @@ dependencies = [ [[package]] name = "tokio-tungstenite" -version = "0.28.0" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d25a406cddcc431a75d3d9afc6a7c0f7428d4891dd973e4d54c56b46127bf857" +checksum = "8f72a05e828585856dacd553fba484c242c46e391fb0e58917c942ee9202915c" dependencies = [ "futures-util", "log", @@ -2899,9 +3259,9 @@ dependencies = [ [[package]] name = "tonic" -version = "0.14.2" +version = "0.14.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb7613188ce9f7df5bfe185db26c5814347d110db17920415cf2fbcad85e7203" +checksum = "ac2a5518c70fa84342385732db33fb3f44bc4cc748936eb5833d2df34d6445ef" dependencies = [ "async-trait", "axum", @@ -2947,22 +3307,30 @@ dependencies = [ [[package]] name = "tower-http" -version = "0.6.8" +version = "0.6.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8" +checksum = "4cfcf7e2740e6fc6d4d688b4ef00650406bb94adf4731e43c096c3a19fe40840" dependencies = [ "bitflags", "bytes", + "futures-core", "futures-util", "http", "http-body", "http-body-util", - "iri-string", + "http-range-header", + "httpdate", + "mime", + "mime_guess", + "percent-encoding", "pin-project-lite", + "tokio", + "tokio-util", "tower", "tower-layer", "tower-service", "tracing", + "url", ] [[package]] @@ -2988,7 +3356,7 @@ dependencies = [ "governor", "http", "pin-project", - "thiserror 2.0.17", + "thiserror 2.0.18", "tonic", "tower", "tracing", @@ -3040,9 +3408,9 @@ dependencies = [ [[package]] name = "tracing-subscriber" -version = "0.3.22" +version = "0.3.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f30143827ddab0d256fd843b7a66d164e9f271cfa0dde49142c5ca0ca291f1e" +checksum = "cb7f578e5945fb242538965c2d0b04418d38ec25c79d160cd279bf0731c8d319" dependencies = [ "matchers", "nu-ansi-term", @@ -3064,26 +3432,61 @@ checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "tungstenite" -version = "0.28.0" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8628dcc84e5a09eb3d8423d6cb682965dea9133204e8fb3efee74c2a0c259442" +checksum = "6c01152af293afb9c7c2a57e4b559c5620b421f6d133261c60dd2d0cdb38e6b8" dependencies = [ "bytes", "data-encoding", "http", "httparse", "log", - "rand 0.9.2", + "rand 0.9.4", "sha1", - "thiserror 2.0.17", - "utf-8", + "thiserror 2.0.18", ] [[package]] -name = "typenum" -version = "1.19.0" +name = "typeid" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" +checksum = "bc7d623258602320d5c55d1bc22793b57daff0ec7efc270ea7d55ce1d5f5471c" + +[[package]] +name = "typenum" +version = "1.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20" + +[[package]] +name = "typetag" +version = "0.2.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5a897b12c6c1151ad0b138b8db50252dc301f93bc3b027db05eec82aeed298c" +dependencies = [ + "erased-serde", + "inventory", + "once_cell", + "serde", + "typetag-impl", +] + +[[package]] +name = "typetag-impl" +version = "0.2.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf808357c6ed7e13ba0f3277ec8d8f21b2d501274895104263985330c726c1c5" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "unicase" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbc4bc3a9f746d862c45cb89d705aa10f187bb96c76001afab07a0d35ce60142" [[package]] name = "unicode-bidi" @@ -3093,9 +3496,9 @@ checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5" [[package]] name = "unicode-ident" -version = "1.0.22" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" [[package]] name = "unicode-normalization" @@ -3130,12 +3533,6 @@ dependencies = [ "serde", ] -[[package]] -name = "utf-8" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" - [[package]] name = "utf8_iter" version = "1.0.4" @@ -3150,11 +3547,11 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.19.0" +version = "1.23.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2e054861b4bd027cd373e18e8d8d8e6548085000e41290d95ce0c373a654b4a" +checksum = "bf80a72845275afea99e7f2b434723d3bc7e38470fcd1c7ed39a599c73319a53" dependencies = [ - "getrandom 0.3.4", + "getrandom 0.4.3", "js-sys", "serde_core", "wasm-bindgen", @@ -3220,9 +3617,9 @@ checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] name = "wasip2" -version = "1.0.1+wasi-0.2.4" +version = "1.0.4+wasi-0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" +checksum = "b67efb37e106e55ce722a510d6b5f9c17f083e5fc79afc2badeb12cc313d9487" dependencies = [ "wit-bindgen", ] @@ -3235,9 +3632,9 @@ checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" [[package]] name = "wasm-bindgen" -version = "0.2.106" +version = "0.2.126" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d759f433fa64a2d763d1340820e46e111a7a5ab75f993d1852d70b03dbb80fd" +checksum = "4b067c0c11094aef6b7a801c1e34a26affafdf3d051dba08456b868789aaf9a4" dependencies = [ "cfg-if", "once_cell", @@ -3248,22 +3645,19 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.56" +version = "0.4.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "836d9622d604feee9e5de25ac10e3ea5f2d65b41eac0d9ce72eb5deae707ce7c" +checksum = "c62df1340f32221cb9c54d6a27b030e3dba64361d4a95bed55f9aacb44da291d" dependencies = [ - "cfg-if", "js-sys", - "once_cell", "wasm-bindgen", - "web-sys", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.106" +version = "0.2.126" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48cb0d2638f8baedbc542ed444afc0644a29166f1595371af4fecf8ce1e7eeb3" +checksum = "167ce5e579f6bcf889c4f7175a8a5a585de84e8ff93976ce393efa5f2837aab1" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -3271,9 +3665,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.106" +version = "0.2.126" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cefb59d5cd5f92d9dcf80e4683949f15ca4b511f4ac0a6e14d4e1ac60c6ecd40" +checksum = "f3997c7839262f4ef12cf90b818d6340c18e80f263f1a94bf157d0ec4420380e" dependencies = [ "bumpalo", "proc-macro2", @@ -3284,18 +3678,18 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.106" +version = "0.2.126" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbc538057e648b67f72a982e708d485b2efa771e1ac05fec311f9f63e5800db4" +checksum = "dc1b4cb0cc549fcf58d7dfc081778139b3d283a081644e833e84682ad71cea24" dependencies = [ "unicode-ident", ] [[package]] name = "web-sys" -version = "0.3.83" +version = "0.3.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b32828d774c412041098d182a8b38b16ea816958e07cf40eec2bc080ae137ac" +checksum = "8622dcb61c0bcc9fffa6938bed81210af2da9a7e4a1a834b2e37a59b6dfb6141" dependencies = [ "js-sys", "wasm-bindgen", @@ -3313,9 +3707,9 @@ dependencies = [ [[package]] name = "webpki-root-certs" -version = "1.0.5" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36a29fc0408b113f68cf32637857ab740edfafdf460c326cd2afaa2d84cc05dc" +checksum = "0d46a5a140e6f7afeccd8eae97eff335163939eac8b929834875168b29b3d267" dependencies = [ "rustls-pki-types", ] @@ -3431,15 +3825,6 @@ dependencies = [ "windows-link", ] -[[package]] -name = "windows-sys" -version = "0.45.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" -dependencies = [ - "windows-targets 0.42.2", -] - [[package]] name = "windows-sys" version = "0.48.0" @@ -3476,21 +3861,6 @@ dependencies = [ "windows-link", ] -[[package]] -name = "windows-targets" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" -dependencies = [ - "windows_aarch64_gnullvm 0.42.2", - "windows_aarch64_msvc 0.42.2", - "windows_i686_gnu 0.42.2", - "windows_i686_msvc 0.42.2", - "windows_x86_64_gnu 0.42.2", - "windows_x86_64_gnullvm 0.42.2", - "windows_x86_64_msvc 0.42.2", -] - [[package]] name = "windows-targets" version = "0.48.5" @@ -3539,12 +3909,6 @@ dependencies = [ "windows_x86_64_msvc 0.53.1", ] -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" - [[package]] name = "windows_aarch64_gnullvm" version = "0.48.5" @@ -3563,12 +3927,6 @@ version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" -[[package]] -name = "windows_aarch64_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" - [[package]] name = "windows_aarch64_msvc" version = "0.48.5" @@ -3587,12 +3945,6 @@ version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" -[[package]] -name = "windows_i686_gnu" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" - [[package]] name = "windows_i686_gnu" version = "0.48.5" @@ -3623,12 +3975,6 @@ version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" -[[package]] -name = "windows_i686_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" - [[package]] name = "windows_i686_msvc" version = "0.48.5" @@ -3647,12 +3993,6 @@ version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" -[[package]] -name = "windows_x86_64_gnu" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" - [[package]] name = "windows_x86_64_gnu" version = "0.48.5" @@ -3671,12 +4011,6 @@ version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" - [[package]] name = "windows_x86_64_gnullvm" version = "0.48.5" @@ -3695,12 +4029,6 @@ version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" -[[package]] -name = "windows_x86_64_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" - [[package]] name = "windows_x86_64_msvc" version = "0.48.5" @@ -3721,21 +4049,27 @@ checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" [[package]] name = "wit-bindgen" -version = "0.46.0" +version = "0.57.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" +checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" [[package]] name = "writeable" -version = "0.6.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" +checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4" + +[[package]] +name = "yansi" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" [[package]] name = "yoke" -version = "0.8.1" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" +checksum = "709fe23a0424b6a435d82152b1bd3fdfb0833487d5fa90d05d42762a9891fef5" dependencies = [ "stable_deref_trait", "yoke-derive", @@ -3744,9 +4078,9 @@ dependencies = [ [[package]] name = "yoke-derive" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" +checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e" dependencies = [ "proc-macro2", "quote", @@ -3756,18 +4090,18 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.8.33" +version = "0.8.52" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "668f5168d10b9ee831de31933dc111a459c97ec93225beb307aed970d1372dfd" +checksum = "ce1022995ff5ff5d841ad7d994facc23098cd40152f2c1d11cd607c6f530653f" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.33" +version = "0.8.52" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c7962b26b0a8685668b671ee4b54d007a67d4eaf05fda79ac0ecf41e32270f1" +checksum = "1ae7f38b72ec2a254e2b87ef277cf2cd4fb97cbebf944faa6f33354da0867930" dependencies = [ "proc-macro2", "quote", @@ -3776,18 +4110,18 @@ dependencies = [ [[package]] name = "zerofrom" -version = "0.1.6" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" +checksum = "0ec05a11813ea801ff6d75110ad09cd0824ddba17dfe17128ea0d5f68e6c5272" dependencies = [ "zerofrom-derive", ] [[package]] name = "zerofrom-derive" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" +checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1" dependencies = [ "proc-macro2", "quote", @@ -3797,15 +4131,15 @@ dependencies = [ [[package]] name = "zeroize" -version = "1.8.2" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" +checksum = "e13c156562582aa81c60cb29407084cdb54c4164760106ab78e6c5b0858cf64e" [[package]] name = "zerotrie" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" +checksum = "0f9152d31db0792fa83f70fb2f83148effb5c1f5b8c7686c3459e361d9bc20bf" dependencies = [ "displaydoc", "yoke", @@ -3814,9 +4148,9 @@ dependencies = [ [[package]] name = "zerovec" -version = "0.11.5" +version = "0.11.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" +checksum = "90f911cbc359ab6af17377d242225f4d75119aec87ea711a880987b18cd7b239" dependencies = [ "yoke", "zerofrom", @@ -3825,9 +4159,9 @@ dependencies = [ [[package]] name = "zerovec-derive" -version = "0.11.2" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" +checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555" dependencies = [ "proc-macro2", "quote", @@ -3836,6 +4170,6 @@ dependencies = [ [[package]] name = "zmij" -version = "1.0.14" +version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd8f3f50b848df28f887acb68e41201b5aea6bc8a8dacc00fb40635ff9a72fea" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" diff --git a/Cargo.toml b/Cargo.toml index 2584b58..bc7a83d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,7 +19,8 @@ serde = { version = "1.0.219", features = ["derive"] } serde_json = "1.0.143" sqlx = { version = "0.8.6", features = ["postgres", "runtime-tokio-native-tls", "macros", "uuid", "chrono"] } tokio = { version = "1.47.1", features = ["rt-multi-thread", "macros"] } -tower-http = { version = "0.6.6", features = ["cors", "limit", "trace"] } +tower = "0.5.3" +tower-http = { version = "0.6.6", features = ["cors", "limit", "trace", "fs"] } tower_governor = "0.8.0" tracing = "0.1.41" tracing-subscriber = { version = "0.3.20", features = ["env-filter"] } @@ -27,6 +28,10 @@ uuid = { version = "1.19.0", features = ["serde", "v7"] } validator = "0.20.0" [dev-dependencies] +axum-test = "21.0.0" http-body-util = "0.1.3" reqwest = { version = "0.13.1", features = ["json"] } +serde_json = "1.0.143" +sha2 = "0.11.0" +tokio = "1.47.1" tower = { version = "0.5.3", features = ["util"] } diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..6af550a --- /dev/null +++ b/Dockerfile @@ -0,0 +1,43 @@ +# Stage 1: Builder - Always uses the latest stable Rust version +FROM rust:latest AS builder + +WORKDIR /app + +# Install build dependencies +RUN apt-get update && apt-get install -y cmake pkg-config libssl-dev + +# 1. Cache dependencies (standard Rust optimization) +COPY Cargo.toml Cargo.lock ./ +RUN mkdir src && echo "fn main() {}" > src/main.rs +RUN cargo build --release +RUN rm -rf src + +# 2. Build the actual application +COPY src ./src +# Ensure the compiler sees the new source files +RUN touch src/main.rs +RUN cargo build --release + +# Stage 2: Runtime - Minimal image +FROM debian:bookworm-slim + +# Install runtime libraries (SSL is required for Postgres/SQLx) +RUN apt-get update && apt-get install -y libssl3 ca-certificates && rm -rf /var/lib/apt/lists/* + +WORKDIR /app + +# Copy the binary from builder +# Note: if your Cargo.toml 'name' is different, change 'frangipane' to your binary name +COPY --from=builder /app/target/release/frangipane /usr/local/bin/frangipane + +# Create storage for avatars +RUN mkdir -p /var/lib/frangipane/avatars + +# Default environment +ENV RUST_LOG="info" + +# Expose Axum port +EXPOSE 8080 + +# Command to run. 'db' matches the service name in docker-compose.yml +CMD ["frangipane", "--database", "db:5432", "--port", "8080", "--data-dir", "/var/lib/frangipane"] diff --git a/db/init.sql b/db/init.sql index 8864e7a..6554112 100644 --- a/db/init.sql +++ b/db/init.sql @@ -48,7 +48,7 @@ CREATE TABLE IF NOT EXISTS room_invite_ ( CREATE TABLE IF NOT EXISTS message_ ( id BIGSERIAL PRIMARY KEY, - uuid UUID NOT NULL, + uuid UUID UNIQUE NOT NULL, sender INT REFERENCES user_(id) NOT NULL, room INT REFERENCES room_(id) NOT NULL, message_type VARCHAR(32) NOT NULL, @@ -56,6 +56,14 @@ CREATE TABLE IF NOT EXISTS message_ ( sent_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ); +CREATE TABLE message_attachment_ ( + id SERIAL PRIMARY KEY, + uuid UUID NOT NULL UNIQUE, + message_uuid UUID NOT NULL REFERENCES message_(uuid), + file_type VARCHAR(20) NOT NULL, + file_name TEXT NOT NULL +); + CREATE TABLE ws_token_ ( token TEXT PRIMARY KEY, expires_at TIMESTAMPTZ NOT NULL @@ -64,6 +72,7 @@ CREATE TABLE ws_token_ ( -- ==== INDICES ==== CREATE INDEX idx_message_room_sent_at ON message_ (room, sent_at); CREATE UNIQUE INDEX idx_membership_user_room ON membership_ (user_id, room) INCLUDE (last_read_at); +CREATE INDEX idx_attachment_message ON message_attachment_(message_uuid); -- Timestamp creation -- CREATE OR REPLACE FUNCTION create_notification_timestamp() diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..3b576bf --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,38 @@ +services: + db: + build: + context: ./db + dockerfile: Dockerfile + ports: + - "5432:5432" + environment: + - POSTGRES_USER=frangipane + - POSTGRES_PASSWORD=secret + - POSTGRES_DB=frangipane + volumes: + - postgres_data:/var/lib/postgresql/data + healthcheck: + test: ["CMD-SHELL", "pg_isready -U frangipane -d frangipane"] + interval: 5s + timeout: 5s + retries: 5 + + app: + build: + context: . + dockerfile: Dockerfile + depends_on: + db: + condition: service_healthy + ports: + - "8080:8080" + environment: + - FRANGIPANE_JWT_SECRET=43aaf85b92f1ae6fbcef7732c50a0904 + - RUST_LOG=frangipane=debug,tower_http=debug + volumes: + - app_data:/var/lib/frangipane + restart: unless-stopped + +volumes: + postgres_data: + app_data: diff --git a/flake.nix b/flake.nix index 6c0c43d..8d75b3f 100644 --- a/flake.nix +++ b/flake.nix @@ -32,6 +32,8 @@ lockFile = ./Cargo.lock; }; + doCheck = false; + nativeBuildInputs = [ rust pkgs.pkg-config diff --git a/src/errors.rs b/src/errors.rs index e8027f6..1862c99 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -7,7 +7,7 @@ use axum::{ }; use serde_json::json; -use crate::{MAX_ROOM_NAME_LENGTH, MAX_USERNAME_LENGTH}; +use crate::{MAX_ATTACHMENTS_PER_MESSAGE, MAX_ROOM_NAME_LENGTH, MAX_USERNAME_LENGTH}; #[derive(Debug)] pub enum APIError { @@ -48,6 +48,8 @@ pub enum APIError { // Uploads WrongFileFormat, + TooManyAttachments, + FileTooLarge, // Technical/Internal DatabaseError(sqlx::Error), @@ -209,6 +211,16 @@ impl IntoResponse for APIError { "WRONG_FILE_FORMAT", "Wrong file format".into(), ), + APIError::TooManyAttachments => ( + StatusCode::BAD_REQUEST, + "MESSAGE_TOO_MANY_FILES", + format!("Maximum {} files allowed", MAX_ATTACHMENTS_PER_MESSAGE).into(), + ), + APIError::FileTooLarge => ( + StatusCode::PAYLOAD_TOO_LARGE, + "FILE_TOO_LARGE", + "One or more files exceed the size limit".into(), + ), // Internal APIError::DatabaseError(e) => { diff --git a/src/lib.rs b/src/lib.rs index a80b891..87e2521 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -24,11 +24,14 @@ use tracing::Level; const MAX_USERNAME_LENGTH: usize = 35; const MAX_ROOM_NAME_LENGTH: usize = 35; -const MAX_UPLOAD_SIZE: usize = 5 * 1024 * 1024; // Not actually used for now +const MAX_UPLOAD_SIZE: usize = 5 * 1024 * 1024; +pub const MAX_ATTACHMENTS_PER_MESSAGE: usize = 8; pub struct AppConfig { pub avatar_dir: PathBuf, pub prohibit_registration: bool, + pub max_file_size: usize, + pub uploads_dir: PathBuf, } #[derive(clap::Parser, Debug)] @@ -50,6 +53,10 @@ pub struct Cli { #[arg(short, long)] pub no_registration: bool, + /// Max file upload size in bytes (default: 10MB) + #[arg(long, default_value = "10485760")] + pub max_file_size: usize, + /// Verbose mode #[arg(short, long)] pub verbose: bool, @@ -61,6 +68,7 @@ pub fn create_app( config: Arc, messages: realtime::RealtimeMessages, voice: realtime::RealTimeVoices, + use_rate_limiter: bool, ) -> Router { let governor_conf = GovernorConfigBuilder::default() .burst_size(20) @@ -90,7 +98,7 @@ pub fn create_app( .allow_methods([Method::GET, Method::POST]) .allow_headers([header::AUTHORIZATION, header::CONTENT_TYPE]); - Router::new() + let mut router = Router::new() .route("/version", get(get_version)) .merge(routes::users::routes()) .merge(routes::rooms::routes()) @@ -102,7 +110,6 @@ pub fn create_app( .layer(Extension(messages)) .layer(Extension(voice)) .layer(Extension(config)) - .layer(GovernorLayer::new(governor_conf)) .layer(cors) .layer(DefaultBodyLimit::max(1024 * 5 * 100)) .layer( @@ -110,7 +117,13 @@ pub fn create_app( .make_span_with(DefaultMakeSpan::new().level(Level::DEBUG)) .on_request(()) .on_response(DefaultOnResponse::new().level(Level::DEBUG)), - ) + ); + + if use_rate_limiter { + router = router.layer(GovernorLayer::new(governor_conf)); + } + + router } /// Public route to get current version diff --git a/src/main.rs b/src/main.rs index 30ad3cf..a7902e1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -31,10 +31,14 @@ async fn main() -> anyhow::Result<()> { let messages = realtime::RealtimeMessages::new(); let voice = realtime::RealTimeVoices::new(); - let data_dir = PathBuf::from(cli.data_dir); + let data_dir = PathBuf::from(&cli.data_dir); + let uploads_dir = PathBuf::from(format!("{}/{}", &cli.data_dir, "/uploads")); + let config = Arc::new(AppConfig { avatar_dir: data_dir.join("avatars"), prohibit_registration: cli.no_registration, + max_file_size: cli.max_file_size, + uploads_dir, }); let port = cli.port; @@ -43,7 +47,7 @@ async fn main() -> anyhow::Result<()> { let listener = tokio::net::TcpListener::bind(&addr).await.unwrap(); tracing::info!("Listening on {addr}"); - let app = create_app(db_pool, config, messages, voice); + let app = create_app(db_pool, config, messages, voice, true); axum::serve( listener, diff --git a/src/routes/messages.rs b/src/routes/messages.rs index e96dbfc..59e0264 100644 --- a/src/routes/messages.rs +++ b/src/routes/messages.rs @@ -1,9 +1,9 @@ -use std::{net::SocketAddr, time::Duration}; +use std::{collections::HashMap, net::SocketAddr, sync::Arc, time::Duration}; use axum::{ Extension, Json, Router, extract::{ - ConnectInfo, Path, Query, WebSocketUpgrade, + ConnectInfo, DefaultBodyLimit, Path, Query, Request, WebSocketUpgrade, ws::{Message as WsMessage, WebSocket}, }, http::{HeaderMap, StatusCode}, @@ -13,9 +13,12 @@ use axum::{ use axum_extra::{TypedHeader, headers}; use sqlx::PgPool; use tokio::select; +use tower::ServiceExt; +use tower_http::services::ServeFile; use uuid::Uuid; use crate::{ + AppConfig, auth::{verify_jwt, verify_jwt_string}, db::room_id_from_uuid, errors::APIError, @@ -37,7 +40,7 @@ pub struct MessageRow { pub sent_at: chrono::NaiveDateTime, } -#[derive(serde::Serialize, Debug, Clone)] +#[derive(serde::Serialize, Debug, Clone, serde::Deserialize)] pub struct Message { pub uuid: Uuid, pub room_uuid: Uuid, @@ -45,9 +48,17 @@ pub struct Message { pub sender_uuid: Uuid, pub message_type: String, pub content: String, + pub attachments: Vec, pub sent_at: String, } +#[derive(serde::Serialize, serde::Deserialize, Clone, Debug)] +pub struct Attachment { + pub uuid: Uuid, + pub file_type: String, // image, video, textfile, binaryfile + pub file_name: String, +} + #[derive(serde::Deserialize)] pub struct NewMessagePayload { pub message_type: String, @@ -64,6 +75,11 @@ pub fn routes() -> Router { Router::new() .route("/messages/{room_uuid}", get(list_messages)) .route("/messages/{room_uuid}", post(create_message)) + .route( + "/messages/{room_uuid}/upload", + post(create_message_with_attachments).layer(DefaultBodyLimit::disable()), + ) + .route("/uploads/{file_uuid}", get(get_upload)) .route("/ws/messages", get(message_ws_handler)) } @@ -87,7 +103,8 @@ async fn list_messages( let mut tx = db.begin().await?; - let messages = sqlx::query_as::<_, MessageRow>( + // 1. Fetch the messages (Simple query) + let rows = sqlx::query_as::<_, MessageRow>( r#" SELECT m.uuid, @@ -112,28 +129,62 @@ async fn list_messages( .fetch_all(&mut *tx) .await?; - let mut messages: Vec = messages + // 2. Collect all the UUIDs of the messages we just found + let message_uuids: Vec = rows.iter().map(|m| m.uuid).collect(); + + // 3. Fetch all attachments for these specific messages in one batch + // We use a temporary struct to capture the message_uuid link from the DB + #[derive(sqlx::FromRow)] + struct AttachmentRow { + uuid: Uuid, + message_uuid: Uuid, + file_type: String, + file_name: String, + } + + let attachment_rows = sqlx::query_as::<_, AttachmentRow>( + "SELECT uuid, message_uuid, file_type, file_name FROM message_attachment_ WHERE message_uuid = ANY($1)" + ) + .bind(&message_uuids) + .fetch_all(&mut *tx) + .await?; + + // 4. Group the attachments by their message_uuid in a HashMap + let mut attachment_map: HashMap> = HashMap::new(); + for att in attachment_rows { + attachment_map + .entry(att.message_uuid) + .or_default() + .push(Attachment { + uuid: att.uuid, + file_type: att.file_type, + file_name: att.file_name, + }); + } + + // 5. Map the MessageRow to the final Message struct, pulling from the HashMap + let mut messages: Vec = rows .into_iter() - .map(|m| Message { - uuid: m.uuid, - room_uuid: m.room_uuid, - sender: m.sender, - sender_uuid: m.sender_uuid, - message_type: m.message_type, - content: m.content, - sent_at: m.sent_at.format("%Y-%m-%d %H:%M:%S").to_string(), + .map(|m| { + let attachments = attachment_map.remove(&m.uuid).unwrap_or_default(); + Message { + uuid: m.uuid, + room_uuid: m.room_uuid, + sender: m.sender, + sender_uuid: m.sender_uuid, + message_type: m.message_type, + content: m.content, + attachments, // Populated from HashMap + sent_at: m.sent_at.format("%Y-%m-%d %H:%M:%S").to_string(), + } }) .collect(); messages.reverse(); + // Reset last_read_at sqlx::query( - r#" - UPDATE membership_ - SET last_read_at = CURRENT_TIMESTAMP - WHERE user_id = $1 - AND room = $2 - "#, + "UPDATE membership_ SET last_read_at = CURRENT_TIMESTAMP WHERE user_id = $1 AND room = $2", ) .bind(user_id) .bind(room_id) @@ -184,6 +235,7 @@ async fn create_message( sender_uuid: claims.sub, message_type: payload.message_type, content: payload.content, + attachments: Vec::new(), sent_at: sent_at.format("%Y-%m-%d %H:%M:%S").to_string(), }; @@ -309,3 +361,173 @@ async fn handle_message_socket( } } } + +async fn create_message_with_attachments( + Path(room_uuid): Path, + Extension(db): Extension, + Extension(realtime): Extension, + Extension(config): Extension>, + headers: HeaderMap, + mut multipart: axum::extract::Multipart, +) -> Result<(StatusCode, Json), APIError> { + let claims = verify_jwt(headers)?; + let user_id = user_id_from_uuid(&db, claims.sub).await?; + let room_id = room_id_from_uuid(&db, room_uuid).await?; + + if !is_member(user_id, room_id, &db).await { + return Err(APIError::NotAMember); + } + + let mut message_content = String::new(); + let mut attachments = Vec::new(); + + // Process fields + while let Some(field) = multipart + .next_field() + .await + .map_err(|e| APIError::Internal(e.to_string()))? + { + let name = field.name().unwrap_or_default().to_string(); + + if name == "content" { + message_content = field.text().await.unwrap_or_default(); + } else if name == "file" { + if attachments.len() >= crate::MAX_ATTACHMENTS_PER_MESSAGE { + return Err(APIError::TooManyAttachments); + } + + let file_name = field.file_name().unwrap_or("unnamed").to_string(); + let data = field + .bytes() + .await + .map_err(|_| APIError::Internal("Read error".into()))?; + + if data.len() > config.max_file_size { + return Err(APIError::FileTooLarge); + } + + // Determine file type + let kind = infer::get(&data); + let mime = kind + .map(|k| k.mime_type()) + .unwrap_or("application/octet-stream"); + + let file_type = if mime.starts_with("image/") { + "image" + } else if mime.starts_with("video/") { + "video" + } else if mime.starts_with("text/") { + "textfile" + } else { + "binaryfile" + }; + + let file_uuid = Uuid::now_v7(); + let storage_name = format!("{}_{}", file_uuid, file_name); + let path = config.uploads_dir.join(&storage_name); + + tokio::fs::create_dir_all(&config.uploads_dir).await.ok(); + tokio::fs::write(&path, data) + .await + .map_err(|e| APIError::Internal(e.to_string()))?; + + attachments.push(Attachment { + uuid: file_uuid, + file_type: file_type.to_string(), + file_name: storage_name, + }); + } + } + + let message_uuid = Uuid::now_v7(); + let mut tx = db.begin().await?; + + let sent_at: chrono::NaiveDateTime = sqlx::query_scalar( + "INSERT INTO message_ (sender, room, message_type, content, uuid) + VALUES ($1, $2, $3, $4, $5) RETURNING sent_at", + ) + .bind(user_id) + .bind(room_id) + .bind("attachment") + .bind(&message_content) + .bind(&message_uuid) + .fetch_one(&mut *tx) + .await?; + + // Insert attachments + for att in &attachments { + sqlx::query( + "INSERT INTO message_attachment_ (uuid, message_uuid, file_type, file_name) VALUES ($1, $2, $3, $4)" + ) + .bind(att.uuid) + .bind(message_uuid) + .bind(&att.file_type) + .bind(&att.file_name) + .execute(&mut *tx) + .await?; + } + + tx.commit().await?; + + let sender_name = username_from_uuid(&db, claims.sub).await?; + let message = Message { + uuid: message_uuid, + room_uuid, + sender: sender_name, + sender_uuid: claims.sub, + message_type: "attachment".to_string(), + content: message_content, + sent_at: sent_at.format("%Y-%m-%d %H:%M:%S").to_string(), + attachments, + }; + + let recipients: Vec = sqlx::query_scalar( + r#" + SELECT u.uuid + FROM membership_ m + JOIN user_ u ON u.id = m.user_id + WHERE m.room = $1 + "#, + ) + .bind(room_id) + .fetch_all(&db) + .await?; + + let rt = realtime.clone(); + let msg_clone = message.clone(); + + tokio::spawn(async move { + rt.broadcast(recipients, msg_clone); + }); + + Ok((StatusCode::CREATED, Json(message))) +} + +async fn get_upload( + Path(file_uuid): Path, + Extension(config): Extension>, + Extension(db): Extension, + req: Request, +) -> Result { + let file_name: String = + sqlx::query_scalar("SELECT file_name FROM message_attachment_ WHERE uuid = $1") + .bind(file_uuid) + .fetch_one(&db) + .await + .map_err(|_| APIError::Internal("File not found in DB".into()))?; + + let path = config.uploads_dir.join(&file_name); + + if !path.exists() { + return Err(APIError::Internal("File missing on disk".into())); + } + + let service = ServeFile::new(path); + + let result = service + .oneshot(req) + .await + .map_err(|e| APIError::Internal(format!("File service error: {}", e)))?; + + Ok(result) +} diff --git a/src/routes/rooms.rs b/src/routes/rooms.rs index 1e0b6c5..acc5943 100644 --- a/src/routes/rooms.rs +++ b/src/routes/rooms.rs @@ -13,7 +13,7 @@ use crate::{ routes::users::UserProfile, }; -#[derive(sqlx::FromRow, serde::Serialize)] +#[derive(sqlx::FromRow, serde::Serialize, serde::Deserialize)] pub struct Room { pub uuid: Uuid, pub name: String, @@ -60,7 +60,7 @@ pub fn routes() -> Router { .route("/rooms", get(list_rooms)) .route("/rooms", post(create_room)) .route("/rooms/{room_uuid}", get(get_room)) - .route("/rooms/{room-uuid}/members", get(list_members)) + .route("/rooms/{room_uuid}/members", get(list_members)) .route("/rooms/invites", get(list_invites)) .route("/rooms/invite", post(send_invite)) .route("/rooms/join", post(accept_request)) @@ -95,9 +95,6 @@ async fn list_rooms( Extension(db): Extension, ) -> Result>, APIError> { let claims = verify_jwt(headers)?; - if claims.sub != claims.sub { - return Err(APIError::InvalidToken); - } let user_id = user_id_from_uuid(&db, claims.sub).await?; diff --git a/src/routes/users.rs b/src/routes/users.rs index 8d1b495..4c498df 100644 --- a/src/routes/users.rs +++ b/src/routes/users.rs @@ -38,7 +38,7 @@ pub struct LoginPayload { pub password: String, } -#[derive(serde::Serialize)] +#[derive(serde::Serialize, serde::Deserialize)] pub struct LoginResponse { pub uuid: Uuid, pub username: String, @@ -60,7 +60,7 @@ pub struct UpdateUserPayoad { pub password: String, } -#[derive(serde::Serialize)] +#[derive(serde::Serialize, serde::Deserialize)] pub struct UpdateUserResponse { pub email: String, pub username: String, diff --git a/tests/tests.rs b/tests/tests.rs new file mode 100644 index 0000000..9d5e8f7 --- /dev/null +++ b/tests/tests.rs @@ -0,0 +1,720 @@ +use axum::{ + body::Body, + http::{Request, StatusCode, header}, +}; +use frangipane::{ + AppConfig, + auth::{create_jwt, hash_password, verify_jwt_string, verify_password}, + create_app, realtime, + routes::{messages::Message, rooms::Room}, + users::LoginResponse, +}; +use serde_json::json; +use sha2::{Digest, Sha256}; +use sqlx::PgPool; +use std::sync::Arc; +use tower::ServiceExt; +use uuid::Uuid; + +// --- HELPERS --- + +async fn get_test_pool() -> sqlx::PgPool { + let database_url = format!("postgres://frangipane:secret@127.0.0.1/frangipane"); + PgPool::connect(database_url.as_str()).await.unwrap() +} + +fn get_test_config() -> Arc { + let mut path = std::env::current_dir().unwrap(); + path.push("target"); + path.push("test_uploads"); + std::fs::create_dir_all(&path).ok(); + + Arc::new(AppConfig { + avatar_dir: path.clone(), + prohibit_registration: false, + max_file_size: 1024 * 1024 * 10, + uploads_dir: path, + }) +} + +async fn setup_app() -> (axum::Router, sqlx::PgPool) { + let _ = tracing_subscriber::fmt() + .with_env_filter("debug") + .with_test_writer() + .try_init(); + + let pool = get_test_pool().await; + let app = create_app( + pool.clone(), + get_test_config(), + realtime::RealtimeMessages::new(), + realtime::RealTimeVoices::new(), + false, + ); + (app, pool) +} + +/// Helper to register a user and return credentials. +async fn register_test_user(app: &mut axum::Router, username: &str, email: &str) -> (String, Uuid) { + let payload = json!({ + "username": username, + "email": email, + "password": "secure_password_123" + }); + + let response = app + .clone() + .oneshot( + Request::builder() + .method("POST") + .uri("/register") + .header(header::CONTENT_TYPE, "application/json") + .body(Body::from(serde_json::to_vec(&payload).unwrap())) + .unwrap(), + ) + .await + .unwrap(); + + let status = response.status(); + let body_bytes = axum::body::to_bytes(response.into_body(), usize::MAX) + .await + .unwrap(); + + if !status.is_success() { + panic!( + "Registration failed for {} with status {}. Body: {:?}", + username, + status, + String::from_utf8_lossy(&body_bytes) + ); + } + + let data: LoginResponse = + serde_json::from_slice(&body_bytes).expect("Failed to parse LoginResponse"); + (data.token, data.uuid) +} + +// --- AUTH TESTS --- + +#[test] +fn test_password_hashing_logic() { + let pass = "hunter2_extra_safe"; + let hash = hash_password(pass).unwrap(); + assert!(verify_password(&hash, pass)); + assert!(!verify_password(&hash, "wrong_pass")); +} + +#[test] +fn test_jwt_logic() { + let id = Uuid::now_v7(); + let token = create_jwt(id).unwrap(); + let claims = verify_jwt_string(&token).unwrap(); + assert_eq!(claims.sub, id); +} + +// --- USER / REGISTRATION TESTS --- + +#[tokio::test] +async fn test_api_register_success() { + let (mut app, _) = setup_app().await; + let username = format!("u{}", Uuid::now_v7().simple()); + let email = format!("{}@example.com", username); + + let (token, _) = register_test_user(&mut app, &username, &email).await; + assert!(!token.is_empty()); +} + +#[tokio::test] +async fn test_api_register_duplicate_username() { + let (mut app, _) = setup_app().await; + let name = format!("d{}", Uuid::now_v7().simple()); + let email1 = format!("{}1@test.com", name); + let email2 = format!("{}2@test.com", name); + + register_test_user(&mut app, &name, &email1).await; + + let payload = json!({ + "username": name, + "email": email2, + "password": "password123" + }); + + let res = app + .oneshot( + Request::builder() + .method("POST") + .uri("/register") + .header(header::CONTENT_TYPE, "application/json") + .body(Body::from(serde_json::to_vec(&payload).unwrap())) + .unwrap(), + ) + .await + .unwrap(); + + assert_eq!(res.status(), StatusCode::CONFLICT); +} + +#[tokio::test] +async fn test_api_register_invalid_email() { + let (app, _) = setup_app().await; + let payload = json!({ + "username": "bademail", + "email": "not-an-email", + "password": "password123" + }); + + let res = app + .oneshot( + Request::builder() + .method("POST") + .uri("/register") + .header(header::CONTENT_TYPE, "application/json") + .body(Body::from(serde_json::to_vec(&payload).unwrap())) + .unwrap(), + ) + .await + .unwrap(); + + assert_eq!(res.status(), StatusCode::BAD_REQUEST); +} + +#[tokio::test] +async fn test_api_login_success() { + let (mut app, _) = setup_app().await; + let id = Uuid::now_v7().simple(); + let name = format!("l{}", id); + let email = format!("{}@test.com", id); + register_test_user(&mut app, &name, &email).await; + + let payload = json!({ "email": email, "password": "secure_password_123" }); + + let res = app + .oneshot( + Request::builder() + .method("POST") + .uri("/login") + .header(header::CONTENT_TYPE, "application/json") + .body(Body::from(serde_json::to_vec(&payload).unwrap())) + .unwrap(), + ) + .await + .unwrap(); + + assert_eq!(res.status(), StatusCode::OK); +} + +// --- ROOM TESTS --- + +#[tokio::test] +async fn test_create_room_and_list() { + let (mut app, _) = setup_app().await; + let id = Uuid::now_v7().simple(); + let name = format!("o{}", id); + let (token, _) = register_test_user(&mut app, &name, &format!("{}@t.com", id)).await; + + let room_name = "Testing Room"; + let _ = app + .clone() + .oneshot( + Request::builder() + .method("POST") + .uri("/rooms") + .header(header::AUTHORIZATION, format!("Bearer {token}")) + .header(header::CONTENT_TYPE, "application/json") + .body(Body::from( + serde_json::to_vec(&json!({"name": room_name, "global": false})).unwrap(), + )) + .unwrap(), + ) + .await + .unwrap(); + + let res = app + .oneshot( + Request::builder() + .method("GET") + .uri("/rooms") + .header(header::AUTHORIZATION, format!("Bearer {token}")) + .body(Body::empty()) + .unwrap(), + ) + .await + .unwrap(); + + let body = axum::body::to_bytes(res.into_body(), usize::MAX) + .await + .unwrap(); + let rooms: Vec = serde_json::from_slice(&body).unwrap(); + assert!(rooms.iter().any(|r| r.name == room_name)); +} + +#[tokio::test] +async fn test_delete_room_permission() { + let (mut app, _) = setup_app().await; + let id1 = Uuid::now_v7().simple(); + let id2 = Uuid::now_v7().simple(); + let (t1, _) = + register_test_user(&mut app, &format!("u1{}", id1), &format!("{}@t.com", id1)).await; + let (t2, _) = + register_test_user(&mut app, &format!("u2{}", id2), &format!("{}@t.com", id2)).await; + + // u1 creates room + let res = app + .clone() + .oneshot( + Request::builder() + .method("POST") + .uri("/rooms") + .header(header::AUTHORIZATION, format!("Bearer {t1}")) + .header(header::CONTENT_TYPE, "application/json") + .body(Body::from( + serde_json::to_vec(&json!({"name": "KillMe", "global": false})).unwrap(), + )) + .unwrap(), + ) + .await + .unwrap(); + let room: Room = serde_json::from_slice( + &axum::body::to_bytes(res.into_body(), usize::MAX) + .await + .unwrap(), + ) + .unwrap(); + + // u2 tries to delete it + let res = app + .oneshot( + Request::builder() + .method("DELETE") + .uri(format!("/rooms/{}/delete", room.uuid)) + .header(header::AUTHORIZATION, format!("Bearer {t2}")) + .body(Body::empty()) + .unwrap(), + ) + .await + .unwrap(); + + assert_eq!(res.status(), StatusCode::FORBIDDEN); +} + +// --- FRIEND TESTS --- + +#[tokio::test] +async fn test_friend_request_self_error() { + let (mut app, _) = setup_app().await; + let id = Uuid::now_v7().simple(); + let name = format!("s{}", id); + let (token, _) = register_test_user(&mut app, &name, &format!("{}@t.com", id)).await; + + let res = app + .oneshot( + Request::builder() + .method("POST") + .uri("/friends/request") + .header(header::AUTHORIZATION, format!("Bearer {token}")) + .header(header::CONTENT_TYPE, "application/json") + .body(Body::from( + serde_json::to_vec(&json!({"receiver_username": name})).unwrap(), + )) + .unwrap(), + ) + .await + .unwrap(); + + assert_eq!(res.status(), StatusCode::BAD_REQUEST); +} + +#[tokio::test] +async fn test_accept_friend_request() { + let (mut app, _) = setup_app().await; + let id1 = Uuid::now_v7().simple(); + let id2 = Uuid::now_v7().simple(); + let n1 = format!("f1{}", id1); + let n2 = format!("f2{}", id2); + let (t1, u1_uuid) = register_test_user(&mut app, &n1, &format!("{}@t.com", id1)).await; + let (t2, _) = register_test_user(&mut app, &n2, &format!("{}@t.com", id2)).await; + + // t1 sends to t2 + let _ = app + .clone() + .oneshot( + Request::builder() + .method("POST") + .uri("/friends/request") + .header(header::AUTHORIZATION, format!("Bearer {t1}")) + .header(header::CONTENT_TYPE, "application/json") + .body(Body::from( + serde_json::to_vec(&json!({"receiver_username": n2})).unwrap(), + )) + .unwrap(), + ) + .await + .unwrap(); + + // t2 accepts + let res = app + .oneshot( + Request::builder() + .method("POST") + .uri("/friends/accept") + .header(header::AUTHORIZATION, format!("Bearer {t2}")) + .header(header::CONTENT_TYPE, "application/json") + .body(Body::from( + serde_json::to_vec(&json!({"sender_uuid": u1_uuid})).unwrap(), + )) + .unwrap(), + ) + .await + .unwrap(); + + assert_eq!(res.status(), StatusCode::CREATED); +} + +// --- MESSAGE TESTS --- + +#[tokio::test] +async fn test_send_message_not_member() { + let (mut app, _) = setup_app().await; + let id1 = Uuid::now_v7().simple(); + let id2 = Uuid::now_v7().simple(); + let n1 = format!("ma{}", id1); + let n2 = format!("mb{}", id2); + let (t1, _) = register_test_user(&mut app, &n1, &format!("{}@t.com", id1)).await; + let (t2, _) = register_test_user(&mut app, &n2, &format!("{}@t.com", id2)).await; + + // t1 creates room + let res = app + .clone() + .oneshot( + Request::builder() + .method("POST") + .uri("/rooms") + .header(header::AUTHORIZATION, format!("Bearer {t1}")) + .header(header::CONTENT_TYPE, "application/json") + .body(Body::from( + serde_json::to_vec(&json!({"name": "Private", "global": false})).unwrap(), + )) + .unwrap(), + ) + .await + .unwrap(); + let room: Room = serde_json::from_slice( + &axum::body::to_bytes(res.into_body(), usize::MAX) + .await + .unwrap(), + ) + .unwrap(); + + // t2 (non-member) tries to send + let res = app + .oneshot( + Request::builder() + .method("POST") + .uri(format!("/messages/{}", room.uuid)) + .header(header::AUTHORIZATION, format!("Bearer {t2}")) + .header(header::CONTENT_TYPE, "application/json") + .body(Body::from( + serde_json::to_vec(&json!({"message_type": "text", "content": "spy"})).unwrap(), + )) + .unwrap(), + ) + .await + .unwrap(); + + assert_eq!(res.status(), StatusCode::FORBIDDEN); +} + +#[tokio::test] +async fn test_send_and_list_messages() { + let (mut app, _) = setup_app().await; + let id = Uuid::now_v7().simple(); + let n = format!("m{}", id); + let (token, _) = register_test_user(&mut app, &n, &format!("{}@t.com", id)).await; + + let res = app + .clone() + .oneshot( + Request::builder() + .method("POST") + .uri("/rooms") + .header(header::AUTHORIZATION, format!("Bearer {token}")) + .header(header::CONTENT_TYPE, "application/json") + .body(Body::from( + serde_json::to_vec(&json!({"name": "Chat", "global": false})).unwrap(), + )) + .unwrap(), + ) + .await + .unwrap(); + let room: Room = serde_json::from_slice( + &axum::body::to_bytes(res.into_body(), usize::MAX) + .await + .unwrap(), + ) + .unwrap(); + + // Send + let _ = app + .clone() + .oneshot( + Request::builder() + .method("POST") + .uri(format!("/messages/{}", room.uuid)) + .header(header::AUTHORIZATION, format!("Bearer {token}")) + .header(header::CONTENT_TYPE, "application/json") + .body(Body::from( + serde_json::to_vec(&json!({"message_type": "text", "content": "hello"})) + .unwrap(), + )) + .unwrap(), + ) + .await + .unwrap(); + + // List + let res = app + .oneshot( + Request::builder() + .method("GET") + .uri(format!("/messages/{}", room.uuid)) + .header(header::AUTHORIZATION, format!("Bearer {token}")) + .body(Body::empty()) + .unwrap(), + ) + .await + .unwrap(); + + assert_eq!(res.status(), StatusCode::OK); + let messages: Vec = serde_json::from_slice( + &axum::body::to_bytes(res.into_body(), usize::MAX) + .await + .unwrap(), + ) + .unwrap(); + assert_eq!(messages.len(), 1); +} + +// --- MISC / SYSTEM TESTS --- + +#[tokio::test] +async fn test_update_settings_and_validate() { + let (mut app, _) = setup_app().await; + let id = Uuid::now_v7().simple(); + let n = format!("st{}", id); + let (token, _) = register_test_user(&mut app, &n, &format!("{}@t.com", id)).await; + + let new_id = Uuid::now_v7().simple(); + let new_name = format!("nw{}", new_id); + let new_email = format!("{}@new.com", new_id); + let res = app + .clone() + .oneshot( + Request::builder() + .method("PUT") + .uri("/account/settings") + .header(header::AUTHORIZATION, format!("Bearer {token}")) + .header(header::CONTENT_TYPE, "application/json") + .body(Body::from( + serde_json::to_vec(&json!({ + "username": new_name, + "email": new_email, + "password": "new_secure_pass_123" + })) + .unwrap(), + )) + .unwrap(), + ) + .await + .unwrap(); + assert_eq!(res.status(), StatusCode::CREATED); + + let res = app + .oneshot( + Request::builder() + .method("GET") + .uri("/validate-token") + .header(header::AUTHORIZATION, format!("Bearer {token}")) + .body(Body::empty()) + .unwrap(), + ) + .await + .unwrap(); + assert_eq!(res.status(), StatusCode::OK); +} + +#[tokio::test] +async fn test_version_route() { + let (app, _) = setup_app().await; + let res = app + .oneshot( + Request::builder() + .uri("/version") + .body(Body::empty()) + .unwrap(), + ) + .await + .unwrap(); + assert_eq!(res.status(), StatusCode::OK); +} + +#[tokio::test] +async fn test_unauthorized_access() { + let (app, _) = setup_app().await; + let paths = vec![ + ("GET", "/rooms", Body::empty()), + ("GET", "/friends", Body::empty()), + ("GET", "/friends/requests", Body::empty()), + ( + "PUT", + "/account/settings", + Body::from( + json!({ + "username": "a", + "email": "a@a.com", + "password": "p" + }) + .to_string(), + ), + ), + ]; + for (method, path, body) in paths { + let res = app + .clone() + .oneshot( + Request::builder() + .method(method) + .uri(path) + .header("content-type", "application/json") + .body(body) + .unwrap(), + ) + .await + .unwrap(); + assert_eq!( + res.status(), + StatusCode::UNAUTHORIZED, + "Path {} should be protected", + path + ); + } +} + +#[tokio::test] +async fn test_upload_large_file_and_verify_hash() { + let (mut app, _) = setup_app().await; + let id = Uuid::now_v7().simple(); + let username = format!("u{}", id); + let (token, _) = register_test_user(&mut app, &username, &format!("{}@t.com", id)).await; + + // Create a room to upload into + let res = app + .clone() + .oneshot( + Request::builder() + .method("POST") + .uri("/rooms") + .header(header::AUTHORIZATION, format!("Bearer {token}")) + .header(header::CONTENT_TYPE, "application/json") + .body(Body::from( + json!({"name": "UploadRoom", "global": false}).to_string(), + )) + .unwrap(), + ) + .await + .unwrap(); + + let room: Room = serde_json::from_slice( + &axum::body::to_bytes(res.into_body(), usize::MAX) + .await + .unwrap(), + ) + .unwrap(); + + // Prepare file + let file_size = 1024 * 1024; + let file_bytes: Vec = (0..file_size).map(|i| (i % 255) as u8).collect(); + + let mut hasher = Sha256::new(); + hasher.update(&file_bytes); + let original_hash = hasher.finalize(); + + let boundary = "boundary123"; + let mut body_content = Vec::new(); + + // First boundary + body_content.extend_from_slice(format!("--{boundary}\r\n").as_bytes()); + + body_content.extend_from_slice(b"Content-Disposition: form-data; name=\"content\"\r\n\r\n"); + body_content.extend_from_slice(b"Check out this file"); + body_content.extend_from_slice(b"\r\n"); // CRLF denoting end of field data + + body_content.extend_from_slice(format!("--{boundary}\r\n").as_bytes()); + body_content.extend_from_slice( + b"Content-Disposition: form-data; name=\"file\"; filename=\"test_file.bin\"\r\n", + ); + body_content.extend_from_slice(b"Content-Type: application/octet-stream\r\n\r\n"); + body_content.extend_from_slice(&file_bytes); + body_content.extend_from_slice(b"\r\n"); // CRLF denoting end of field data + + // Final boundary + body_content.extend_from_slice(format!("--{boundary}--\r\n").as_bytes()); + + let upload_res = app + .clone() + .oneshot( + Request::builder() + .method("POST") + .uri(format!("/messages/{}/upload", room.uuid)) + .header(header::AUTHORIZATION, format!("Bearer {token}")) + .header( + header::CONTENT_TYPE, + format!("multipart/form-data; boundary={boundary}"), + ) + .body(Body::from(body_content)) + .unwrap(), + ) + .await + .unwrap(); + + assert_eq!(upload_res.status(), StatusCode::CREATED); + + let message_resp: Message = serde_json::from_slice( + &axum::body::to_bytes(upload_res.into_body(), usize::MAX) + .await + .unwrap(), + ) + .unwrap(); + + let file_uuid = message_resp.attachments[0].uuid; + + // Download the file back + let download_res = app + .oneshot( + Request::builder() + .method("GET") + .uri(format!("/uploads/{}", file_uuid)) + .header(header::AUTHORIZATION, format!("Bearer {token}")) + .body(Body::empty()) + .unwrap(), + ) + .await + .unwrap(); + + assert_eq!(download_res.status(), StatusCode::OK); + + let downloaded_bytes = axum::body::to_bytes(download_res.into_body(), usize::MAX) + .await + .unwrap(); + + // Verify integrity + let mut hasher = Sha256::new(); + hasher.update(&downloaded_bytes); + let downloaded_hash = hasher.finalize(); + + assert_eq!( + file_bytes.len(), + downloaded_bytes.len(), + "File sizes must match" + ); + assert_eq!(original_hash, downloaded_hash, "File hashes must match"); +}