diff --git a/Cargo.lock b/Cargo.lock index 236039f0ff..4625474b48 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,9 +4,9 @@ version = 4 [[package]] name = "addr2line" -version = "0.24.2" +version = "0.25.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" +checksum = "1b5d307320b3181d6d7954e663bd7c774a838b8220fe0593c86d9fb09f498b4b" dependencies = [ "gimli", ] @@ -23,16 +23,16 @@ version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" dependencies = [ - "getrandom 0.2.16", + "getrandom 0.2.17", "once_cell", "version_check", ] [[package]] name = "aho-corasick" -version = "1.1.3" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" dependencies = [ "memchr", ] @@ -43,12 +43,6 @@ version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" -[[package]] -name = "android-tzdata" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" - [[package]] name = "android_system_properties" version = "0.1.5" @@ -66,9 +60,9 @@ checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" [[package]] name = "anstream" -version = "0.6.19" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "301af1932e46185686725e0fad2f8f2aa7da69dd70bf6ecc44d6b703844a3933" +checksum = "824a212faf96e9acacdbd09febd34438f8f711fb84e09a8916013cd7815ca28d" dependencies = [ "anstyle", "anstyle-parse", @@ -81,44 +75,44 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.11" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd" +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", ] [[package]] name = "anstyle-query" -version = "1.1.3" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8bdeb6047d8983be085bab0ba1472e6dc604e7041dbf6fcd5e71523014fae9" +checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] name = "anstyle-wincon" -version = "3.0.9" +version = "3.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "403f75924867bb1033c59fbf0797484329750cfbe3c4325cd33127941fabc882" +checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" dependencies = [ "anstyle", "once_cell_polyfill", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] name = "anyhow" -version = "1.0.98" +version = "1.0.102" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" +checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" [[package]] name = "argon2" @@ -151,14 +145,14 @@ checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" [[package]] name = "assert_cmd" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcbb6924530aa9e0432442af08bbcafdad182db80d2e560da42a6d442535bf85" +checksum = "9a686bbee5efb88a82df0621b236e74d925f470e5445d3220a5648b892ec99c9" dependencies = [ "anstyle", "bstr", "libc", - "predicates 3.1.3", + "predicates 3.1.4", "predicates-core", "predicates-tree", "wait-timeout", @@ -199,9 +193,9 @@ dependencies = [ [[package]] name = "async-executor" -version = "1.13.2" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb812ffb58524bdd10860d7d974e2f01cc0950c2438a74ee5ec2e2280c6c4ffa" +checksum = "c96bf972d85afc50bf5ab8fe2d54d1586b4e0b46c97c50a0c9e71e2f7bcd812a" dependencies = [ "async-task", "concurrent-queue", @@ -213,9 +207,9 @@ dependencies = [ [[package]] name = "async-fs" -version = "2.1.2" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebcd09b382f40fcd159c2d695175b2ae620ffa5f3bd6f664131efff4e8b9e04a" +checksum = "8034a681df4aed8b8edbd7fbe472401ecf009251c8b40556b304567052e294c5" dependencies = [ "async-lock", "blocking", @@ -253,30 +247,29 @@ dependencies = [ [[package]] name = "async-io" -version = "2.4.1" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1237c0ae75a0f3765f58910ff9cdd0a12eeb39ab2f4c7de23262f337f0aacbb3" +checksum = "456b8a8feb6f42d237746d4b3e9a178494627745c3c56c6ea55d92ba50d026fc" dependencies = [ - "async-lock", + "autocfg", "cfg-if", "concurrent-queue", "futures-io", "futures-lite", "parking", "polling", - "rustix 1.0.7", + "rustix", "slab", - "tracing", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] name = "async-lock" -version = "3.4.0" +version = "3.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18" +checksum = "290f7f2596bd5b78a9fec8088ccd89180d7f9f55b94b0576823bbbdc72ee8311" dependencies = [ - "event-listener 5.4.0", + "event-listener 5.4.1", "event-listener-strategy", "pin-project-lite", ] @@ -294,9 +287,9 @@ dependencies = [ [[package]] name = "async-process" -version = "2.3.1" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cde3f4e40e6021d7acffc90095cbd6dc54cb593903d1de5832f435eb274b85dc" +checksum = "fc50921ec0055cdd8a16de48773bfeec5c972598674347252c0399676be7da75" dependencies = [ "async-channel 2.5.0", "async-io", @@ -305,17 +298,16 @@ dependencies = [ "async-task", "blocking", "cfg-if", - "event-listener 5.4.0", + "event-listener 5.4.1", "futures-lite", - "rustix 1.0.7", - "tracing", + "rustix", ] [[package]] name = "async-signal" -version = "0.2.11" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7605a4e50d4b06df3898d5a70bf5fde51ed9059b0434b73105193bc27acce0d" +checksum = "43c070bbf59cd3570b6b2dd54cd772527c7c3620fce8be898406dd3ed6adc64c" dependencies = [ "async-io", "async-lock", @@ -323,17 +315,17 @@ dependencies = [ "cfg-if", "futures-core", "futures-io", - "rustix 1.0.7", + "rustix", "signal-hook-registry", "slab", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] name = "async-std" -version = "1.13.1" +version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "730294c1c08c2e0f85759590518f6333f0d5a0a766a27d519c1b244c3dfd8a24" +checksum = "2c8e079a4ab67ae52b7403632e4618815d6db36d2a010cfe41b02c1b1578f93b" dependencies = [ "async-attributes", "async-channel 1.9.0", @@ -364,13 +356,13 @@ checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" [[package]] name = "async-trait" -version = "0.1.88" +version = "0.1.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e539d3fca749fcee5236ab05e93a52867dd549cc157c8cb7f99595f3cedffdb5" +checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.117", ] [[package]] @@ -396,9 +388,9 @@ checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "aws-lc-rs" -version = "1.13.1" +version = "1.16.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93fcc8f365936c834db5514fc45aee5b1202d677e6b40e48468aaaa8183ca8c7" +checksum = "a054912289d18629dc78375ba2c3726a3afe3ff71b4edba9dedfca0e3446d1fc" dependencies = [ "aws-lc-sys", "zeroize", @@ -406,11 +398,10 @@ dependencies = [ [[package]] name = "aws-lc-sys" -version = "0.29.0" +version = "0.39.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61b1d86e7705efe1be1b569bab41d4fa1e14e220b60a160f78de2db687add079" +checksum = "83a25cf98105baa966497416dbd42565ce3a8cf8dbfd59803ec9ad46f3126399" dependencies = [ - "bindgen", "cc", "cmake", "dunce", @@ -484,7 +475,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b62ddb9cb1ec0a098ad4bbf9344d0713fa193ae1a80af55febcff2627b6a00c1" dependencies = [ "futures-core", - "getrandom 0.2.16", + "getrandom 0.2.17", "instant", "pin-project-lite", "rand", @@ -493,9 +484,9 @@ dependencies = [ [[package]] name = "backtrace" -version = "0.3.75" +version = "0.3.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002" +checksum = "bb531853791a215d7c62a30daf0dde835f381ab5de4589cfe7c649d2cbe92bd6" dependencies = [ "addr2line", "cfg-if", @@ -503,7 +494,7 @@ dependencies = [ "miniz_oxide", "object", "rustc-demangle", - "windows-targets 0.52.6", + "windows-link", ] [[package]] @@ -520,15 +511,15 @@ checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "base64ct" -version = "1.8.0" +version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55248b47b0caf0546f7988906588779981c43bb1bc9d0c44087278f80cdb44ba" +checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" [[package]] name = "bigdecimal" -version = "0.4.8" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a22f228ab7a1b23027ccc6c350b72868017af7ea8356fbdf19f8d991c690013" +checksum = "4d6867f1565b3aad85681f1015055b087fcfd840d6aeee6eee7f2da317603695" dependencies = [ "autocfg", "libm", @@ -543,21 +534,18 @@ version = "0.69.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "271383c67ccabffb7381723dea0672a673f292304fcb45c01cc648c7a8d58088" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.11.0", "cexpr", "clang-sys", "itertools 0.12.1", "lazy_static", "lazycell", - "log", - "prettyplease", "proc-macro2", "quote", "regex", "rustc-hash", "shlex", - "syn 2.0.104", - "which", + "syn 2.0.117", ] [[package]] @@ -574,11 +562,11 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.9.1" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" +checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" dependencies = [ - "serde", + "serde_core", ] [[package]] @@ -626,32 +614,33 @@ dependencies = [ [[package]] name = "borsh" -version = "1.5.7" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad8646f98db542e39fc66e68a20b2144f6a732636df7c2354e74645faaa433ce" +checksum = "cfd1e3f8955a5d7de9fab72fc8373fade9fb8a703968cb200ae3dc6cf08e185a" dependencies = [ "borsh-derive", + "bytes", "cfg_aliases", ] [[package]] name = "borsh-derive" -version = "1.5.7" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdd1d3c0c2f5833f22386f252fe8ed005c7f59fdcddeef025c01b4c3b9fd9ac3" +checksum = "bfcfdc083699101d5a7965e49925975f2f55060f94f9a05e7187be95d530ca59" dependencies = [ "once_cell", "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.117", ] [[package]] name = "bstr" -version = "1.12.0" +version = "1.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "234113d19d0d7d613b40e86fb654acf958910802bcceab913a4f9e7cda03b1a4" +checksum = "63044e1ae8e69f3b5a92c736ca6269b8d12fa7efe39bf34ddb06d102cf0e2cab" dependencies = [ "memchr", "regex-automata", @@ -660,9 +649,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.19.0" +version = "3.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" +checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" [[package]] name = "bytecheck" @@ -694,17 +683,17 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.10.1" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" +checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" [[package]] name = "camino" -version = "1.1.10" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0da45bc31171d8d6960122e222a67740df867c1dd53b4d51caa297084c185cab" +checksum = "e629a66d692cb9ff1a1c664e41771b3dcaf961985a9774c0eb0bd1b51cf60a48" dependencies = [ - "serde", + "serde_core", ] [[package]] @@ -744,19 +733,20 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "castaway" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0abae9be0aaf9ea96a3b1b8b1b55c602ca751eba1b1500220cea4ecbafe7c0d5" +checksum = "dec551ab6e7578819132c713a93c022a05d60159dc86e7a7050223577484c55a" dependencies = [ "rustversion", ] [[package]] name = "cc" -version = "1.2.29" +version = "1.2.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c1599538de2394445747c8cf7935946e3cc27e9625f889d979bfb2aaf569362" +checksum = "e1e928d4b69e3077709075a938a05ffbedfa53a84c8f766efbf8220bb1ff60e1" dependencies = [ + "find-msvc-tools", "jobserver", "libc", "shlex", @@ -773,9 +763,9 @@ dependencies = [ [[package]] name = "cfg-if" -version = "1.0.1" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "cfg_aliases" @@ -785,11 +775,10 @@ checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" [[package]] name = "chrono" -version = "0.4.41" +version = "0.4.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c469d952047f47f91b68d1cba3f10d63c11d73e4636f24f08daf0278abf01c4d" +checksum = "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0" dependencies = [ - "android-tzdata", "iana-time-zone", "js-sys", "num-traits", @@ -838,9 +827,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.40" +version = "4.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40b6887a1d8685cebccf115538db5c0efe625ccac9696ad45c409d96566e910f" +checksum = "b193af5b67834b676abd72466a96c1024e6a6ad978a1f484bd90b85c94041351" dependencies = [ "clap_builder", "clap_derive", @@ -848,9 +837,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.40" +version = "4.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0c66c08ce9f0c698cbce5c0279d0bb6ac936d8674174fe48f736533b964f59e" +checksum = "714a53001bf66416adb0e2ef5ac857140e7dc3a0c48fb28b2f10762fc4b5069f" dependencies = [ "anstream", "anstyle", @@ -861,36 +850,36 @@ dependencies = [ [[package]] name = "clap_complete" -version = "4.5.54" +version = "4.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aad5b1b4de04fead402672b48897030eec1f3bfe1550776322f59f6d6e6a5677" +checksum = "19c9f1dde76b736e3681f28cec9d5a61299cbaae0fce80a68e43724ad56031eb" dependencies = [ "clap", ] [[package]] name = "clap_derive" -version = "4.5.40" +version = "4.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2c7947ae4cc3d851207c1adb5b5e260ff0cca11446b1d6d1423788e442257ce" +checksum = "1110bd8a634a1ab8cb04345d8d878267d57c3cf1b38d91b71af6686408bbca6a" dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.117", ] [[package]] name = "clap_lex" -version = "0.7.5" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675" +checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9" [[package]] name = "cmake" -version = "0.1.54" +version = "0.1.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7caa3f9de89ddbe2c607f4101924c5abec803763ae9534e4f4d7d8f84aa81f0" +checksum = "c0f78a02292a74a88ac736019ab962ece0bc380e3f977bf72e376c5d78ff0678" dependencies = [ "cc", ] @@ -924,9 +913,9 @@ dependencies = [ [[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 = "compact_str" @@ -950,6 +939,19 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "connect-test" +version = "0.1.0" +dependencies = [ + "anyhow", + "clap", + "dotenvy", + "futures", + "sqlx", + "tokio", + "wasip3 0.5.0+wasi-0.3.0-rc-2026-03-15", +] + [[package]] name = "console" version = "0.15.11" @@ -959,7 +961,7 @@ dependencies = [ "encode_unicode", "libc", "once_cell", - "unicode-width 0.2.1", + "unicode-width 0.2.2", "windows-sys 0.59.0", ] @@ -969,16 +971,6 @@ version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" -[[package]] -name = "core-foundation" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" -dependencies = [ - "core-foundation-sys", - "libc", -] - [[package]] name = "core-foundation" version = "0.10.1" @@ -1006,9 +998,9 @@ dependencies = [ [[package]] name = "crc" -version = "3.3.0" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9710d3b3739c2e349eb44fe848ad0b7c8cb1e42bd87ee49371df2f7acaf3e675" +checksum = "5eb8a2a1cd12ab0d987a5d5e825195d372001a4094a0376319d5a0ad71c1ba0d" dependencies = [ "crc-catalog", ] @@ -1097,7 +1089,7 @@ version = "0.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f476fe445d41c9e991fd07515a6f463074b782242ccf4a5b7b1d1012e70824df" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.11.0", "crossterm_winapi", "libc", "mio 0.8.11", @@ -1124,9 +1116,9 @@ checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" [[package]] name = "crypto-common" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" dependencies = [ "generic-array", "typenum", @@ -1153,7 +1145,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.104", + "syn 2.0.117", ] [[package]] @@ -1164,7 +1156,7 @@ checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" dependencies = [ "darling_core", "quote", - "syn 2.0.104", + "syn 2.0.117", ] [[package]] @@ -1180,12 +1172,12 @@ dependencies = [ [[package]] name = "deranged" -version = "0.4.0" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c9e6a11ca8224451684bc0d7d5a7adbf8f2fd6887261a1cfc3c0432f9d4068e" +checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" dependencies = [ "powerfmt", - "serde", + "serde_core", ] [[package]] @@ -1225,7 +1217,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.117", ] [[package]] @@ -1263,9 +1255,9 @@ checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0" [[package]] name = "env_filter" -version = "0.1.3" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "186e05a59d4c50738528153b83b0b0194d3a29507dfec16eccd4b342903397d0" +checksum = "32e90c2accc4b07a8456ea0debdc2e7587bdd890680d71173a15d4ae604f6eef" dependencies = [ "log", "regex", @@ -1273,9 +1265,9 @@ dependencies = [ [[package]] name = "env_logger" -version = "0.11.8" +version = "0.11.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13c863f0904021b108aa8b2f55046443e6b1ebde8fd4a15c399893aae4fa069f" +checksum = "0621c04f2196ac3f488dd583365b9c09be011a4ab8b9f37248ffcc8f6198b56a" dependencies = [ "anstream", "anstyle", @@ -1292,12 +1284,12 @@ checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "errno" -version = "0.3.13" +version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "778e2ac28f6c47af28e4907f13ffd1e1ddbd400980a9abd7c8df189bf578a5ad" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -1319,9 +1311,9 @@ checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" [[package]] name = "event-listener" -version = "5.4.0" +version = "5.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3492acde4c3fc54c845eaab3eed8bd00c7a7d881f78bfc801e43a93dec1331ae" +checksum = "e13b66accf52311f30a0db42147dadea9850cb48cd070028831ae5f5d4b856ab" dependencies = [ "concurrent-queue", "parking", @@ -1334,10 +1326,23 @@ version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93" dependencies = [ - "event-listener 5.4.0", + "event-listener 5.4.1", "pin-project-lite", ] +[[package]] +name = "execute-query-test" +version = "0.1.0" +dependencies = [ + "anyhow", + "clap", + "dotenvy", + "futures", + "sqlx", + "tokio", + "wasip3 0.5.0+wasi-0.3.0-rc-2026-03-15", +] + [[package]] name = "eyre" version = "0.6.12" @@ -1356,16 +1361,21 @@ checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" [[package]] name = "filetime" -version = "0.2.25" +version = "0.2.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35c0522e981e68cbfa8c3f978441a5f34b30b96e146b33cd3359176b50fe8586" +checksum = "f98844151eee8917efc50bd9e8318cb963ae8b297431495d3f758616ea5c57db" dependencies = [ "cfg-if", "libc", "libredox", - "windows-sys 0.59.0", ] +[[package]] +name = "find-msvc-tools" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" + [[package]] name = "float-cmp" version = "0.9.0" @@ -1448,12 +1458,13 @@ checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" [[package]] name = "futures" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" +checksum = "8b147ee9d1f6d097cef9ce628cd2ee62288d963e16fb287bd9286455b241382d" dependencies = [ "futures-channel", "futures-core", + "futures-executor", "futures-io", "futures-sink", "futures-task", @@ -1462,9 +1473,9 @@ dependencies = [ [[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", @@ -1472,15 +1483,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", @@ -1500,15 +1511,15 @@ 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-lite" -version = "2.6.0" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5edaec856126859abb19ed65f39e90fea3a9574b9707f13539acf4abf7eb532" +checksum = "f78e10609fe0e0b3f4157ffab1876319b5b0db102a2c60dc4626306dc46b44ad" dependencies = [ "fastrand", "futures-core", @@ -1519,33 +1530,34 @@ dependencies = [ [[package]] name = "futures-macro" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" +checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.117", ] [[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-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-channel", "futures-core", "futures-io", "futures-macro", @@ -1553,7 +1565,6 @@ dependencies = [ "futures-task", "memchr", "pin-project-lite", - "pin-utils", "slab", ] @@ -1569,38 +1580,51 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" dependencies = [ "cfg-if", "libc", - "wasi 0.11.1+wasi-snapshot-preview1", + "wasi", ] [[package]] name = "getrandom" -version = "0.3.3" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if", + "libc", + "r-efi 5.3.0", + "wasip2", +] + +[[package]] +name = "getrandom" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" +checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555" dependencies = [ "cfg-if", "libc", - "r-efi", - "wasi 0.14.2+wasi-0.2.4", + "r-efi 6.0.0", + "wasip2", + "wasip3 0.4.0+wasi-0.3.0-rc-2026-01-06", ] [[package]] name = "gimli" -version = "0.31.1" +version = "0.32.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" +checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7" [[package]] name = "glob" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" +checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" [[package]] name = "gloo-timers" @@ -1616,12 +1640,13 @@ dependencies = [ [[package]] name = "half" -version = "2.6.0" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "459196ed295495a68f7d7fe1d84f6c4b7ff0e21fe3017b2f283c6fac3ad803c9" +checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b" dependencies = [ "cfg-if", "crunchy", + "zerocopy", ] [[package]] @@ -1635,9 +1660,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.15.4" +version = "0.15.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" dependencies = [ "allocator-api2", "equivalent", @@ -1646,9 +1671,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.16.0" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" dependencies = [ "allocator-api2", "equivalent", @@ -1661,7 +1686,7 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ea0b22561a9c04a7cb1a302c013e0259cd3b4bb619f145b32f72b8b4bcbed230" dependencies = [ - "hashbrown 0.16.0", + "hashbrown 0.16.1", ] [[package]] @@ -1708,11 +1733,11 @@ dependencies = [ [[package]] name = "home" -version = "0.5.11" +version = "0.5.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf" +checksum = "cc627f471c528ff0c4a49e1d5e60450c8f6461dd6d10ba9dcd3a61d3dff7728d" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -1771,7 +1796,7 @@ dependencies = [ "httpdate", "itoa", "pin-project-lite", - "socket2", + "socket2 0.5.10", "tokio", "tower-service", "tracing", @@ -1780,9 +1805,9 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.63" +version = "0.1.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0c919e5debc312ad217002b8048a17b7d83f80703865bbfcfebb0458b0b27d8" +checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -1804,9 +1829,9 @@ dependencies = [ [[package]] name = "icu_collections" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47" +checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" dependencies = [ "displaydoc", "potential_utf", @@ -1817,9 +1842,9 @@ dependencies = [ [[package]] name = "icu_locale_core" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a" +checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" dependencies = [ "displaydoc", "litemap", @@ -1830,11 +1855,10 @@ dependencies = [ [[package]] name = "icu_normalizer" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979" +checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" dependencies = [ - "displaydoc", "icu_collections", "icu_normalizer_data", "icu_properties", @@ -1845,42 +1869,38 @@ dependencies = [ [[package]] name = "icu_normalizer_data" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3" +checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" [[package]] name = "icu_properties" -version = "2.0.1" +version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b" +checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec" dependencies = [ - "displaydoc", "icu_collections", "icu_locale_core", "icu_properties_data", "icu_provider", - "potential_utf", "zerotrie", "zerovec", ] [[package]] name = "icu_properties_data" -version = "2.0.1" +version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632" +checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af" [[package]] name = "icu_provider" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af" +checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" dependencies = [ "displaydoc", "icu_locale_core", - "stable_deref_trait", - "tinystr", "writeable", "yoke", "zerofrom", @@ -1888,6 +1908,12 @@ dependencies = [ "zerovec", ] +[[package]] +name = "id-arena" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" + [[package]] name = "ident_case" version = "1.0.1" @@ -1906,9 +1932,9 @@ dependencies = [ [[package]] name = "idna" -version = "1.0.3" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" dependencies = [ "idna_adapter", "smallvec", @@ -1927,15 +1953,15 @@ dependencies = [ [[package]] name = "if_chain" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb56e1aa765b4b4f3aadfab769793b7087bb03a4ea4920644a6d238e2df5b9ed" +checksum = "cd62e6b5e86ea8eeeb8db1de02880a6abc01a397b2ebb64b5d74ac255318f5cb" [[package]] name = "indenter" -version = "0.3.3" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" +checksum = "964de6e86d545b246d84badc0fef527924ace5134f30641c203ef52ba83f58d5" [[package]] name = "indexmap" @@ -1950,12 +1976,14 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.10.0" +version = "2.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe4cd85333e22411419a0bcae1297d25e58c9443848b11dc6a86fefe8c78a661" +checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" dependencies = [ "equivalent", - "hashbrown 0.15.4", + "hashbrown 0.16.1", + "serde", + "serde_core", ] [[package]] @@ -1967,22 +1995,11 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "io-uring" -version = "0.7.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b86e202f00093dcba4275d4636b93ef9dd75d025ae560d2521b45ea28ab49013" -dependencies = [ - "bitflags 2.9.1", - "cfg-if", - "libc", -] - [[package]] name = "ipnet" -version = "2.11.0" +version = "2.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" +checksum = "d98f6fed1fde3f8c21bc40a1abb88dd75e67924f9cffc3ef95607bad8017f8e2" [[package]] name = "ipnetwork" @@ -1992,20 +2009,20 @@ checksum = "cf370abdafd54d13e54a620e8c3e1145f28e46cc9d704bc6d94414559df41763" [[package]] name = "is-terminal" -version = "0.4.16" +version = "0.4.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e04d7f318608d35d4b61ddd75cbdaee86b023ebe2bd5a66ee0915f0bf93095a9" +checksum = "3640c1c38b8e4e43584d8df18be5fc6b0aa314ce6ebf51b53313d4306cca8e46" dependencies = [ "hermit-abi", "libc", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] name = "is_terminal_polyfill" -version = "1.70.1" +version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" +checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" [[package]] name = "itertools" @@ -2036,50 +2053,52 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.15" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" [[package]] name = "jiff" -version = "0.2.15" +version = "0.2.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be1f93b8b1eb69c77f24bbb0afdf66f54b632ee39af40ca21c4365a1d7347e49" +checksum = "1a3546dc96b6d42c5f24902af9e2538e82e39ad350b0c766eb3fbf2d8f3d8359" dependencies = [ "jiff-static", "log", "portable-atomic", "portable-atomic-util", - "serde", + "serde_core", ] [[package]] name = "jiff-static" -version = "0.2.15" +version = "0.2.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03343451ff899767262ec32146f6d559dd759fdadf42ff0e227c7c48f72594b4" +checksum = "2a8c8b344124222efd714b73bb41f8b5120b27a7cc1c75593a6ff768d9d05aa4" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.117", ] [[package]] name = "jobserver" -version = "0.1.33" +version = "0.1.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38f262f097c174adebe41eb73d66ae9c06b2844fb0da69969647bbddd9b0538a" +checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" dependencies = [ - "getrandom 0.3.3", + "getrandom 0.3.4", "libc", ] [[package]] name = "js-sys" -version = "0.3.77" +version = "0.3.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" +checksum = "797146bb2677299a1eb6b7b50a890f4c361b29ef967addf5b2fa45dae1bb6d7d" dependencies = [ + "cfg-if", + "futures-util", "once_cell", "wasm-bindgen", ] @@ -2108,37 +2127,44 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" +[[package]] +name = "leb128fmt" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" + [[package]] name = "libc" -version = "0.2.174" +version = "0.2.183" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776" +checksum = "b5b646652bf6661599e1da8901b3b9522896f01e736bad5f723fe7a3a27f899d" [[package]] name = "libloading" -version = "0.8.8" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667" +checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55" dependencies = [ "cfg-if", - "windows-targets 0.53.2", + "windows-link", ] [[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.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d0b95e02c851351f877147b7deea7b1afb1df71b63aa5f8270716e0c5720616" +checksum = "7ddbf48fd451246b1f8c2610bd3b4ac0cc6e149d89832867093ab69a17194f08" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.11.0", "libc", - "redox_syscall 0.7.0", + "plain", + "redox_syscall 0.7.3", ] [[package]] @@ -2155,37 +2181,30 @@ dependencies = [ [[package]] name = "linux-raw-sys" -version = "0.4.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" - -[[package]] -name = "linux-raw-sys" -version = "0.9.4" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" +checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" [[package]] name = "litemap" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" +checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" [[package]] name = "lock_api" -version = "0.4.13" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" dependencies = [ - "autocfg", "scopeguard", ] [[package]] name = "log" -version = "0.4.27" +version = "0.4.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" dependencies = [ "value-bag", ] @@ -2196,7 +2215,7 @@ version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38" dependencies = [ - "hashbrown 0.15.4", + "hashbrown 0.15.5", ] [[package]] @@ -2227,9 +2246,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.7.5" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" [[package]] name = "memoffset" @@ -2269,19 +2288,19 @@ checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" dependencies = [ "libc", "log", - "wasi 0.11.1+wasi-snapshot-preview1", + "wasi", "windows-sys 0.48.0", ] [[package]] name = "mio" -version = "1.0.4" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c" +checksum = "50b7e5b27aa02a74bac8c3f23f448f8d87ff11f92d3aac1a6ed369ee08cc56c1" dependencies = [ "libc", - "wasi 0.11.1+wasi-snapshot-preview1", - "windows-sys 0.59.0", + "wasi", + "windows-sys 0.61.2", ] [[package]] @@ -2313,9 +2332,9 @@ 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", @@ -2323,7 +2342,7 @@ dependencies = [ "openssl-probe", "openssl-sys", "schannel", - "security-framework 2.11.1", + "security-framework", "security-framework-sys", "tempfile", ] @@ -2334,7 +2353,7 @@ version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.11.0", "cfg-if", "cfg_aliases", "libc", @@ -2359,12 +2378,11 @@ checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be" [[package]] name = "nu-ansi-term" -version = "0.46.0" +version = "0.50.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" dependencies = [ - "overload", - "winapi", + "windows-sys 0.61.2", ] [[package]] @@ -2379,11 +2397,10 @@ dependencies = [ [[package]] name = "num-bigint-dig" -version = "0.8.4" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc84195820f291c7697304f3cbdadd1cb7199c0efc917ff5eafd71225c136151" +checksum = "e661dda6640fad38e827a6d4a310ff4763082116fe217f279885c97f511bb0b7" dependencies = [ - "byteorder", "lazy_static", "libm", "num-integer", @@ -2396,9 +2413,9 @@ dependencies = [ [[package]] name = "num-conv" -version = "0.1.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" +checksum = "c6673768db2d862beb9b39a78fdcb1a69439615d5794a1be50caa9bc92c81967" [[package]] name = "num-integer" @@ -2432,24 +2449,24 @@ dependencies = [ [[package]] name = "object" -version = "0.36.7" +version = "0.37.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" +checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe" dependencies = [ "memchr", ] [[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" -version = "1.70.1" +version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad" +checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" [[package]] name = "oorandom" @@ -2459,11 +2476,11 @@ checksum = "d6790f58c7ff633d8771f42965289203411a5e5c68388703c06e14f24770b41e" [[package]] name = "openssl" -version = "0.10.73" +version = "0.10.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8505734d46c8ab1e19a1dce3aef597ad87dcb4c37e7188231769bd6bd51cebf8" +checksum = "951c002c75e16ea2c65b8c7e4d3d51d5530d8dfa7d060b4776828c88cfb18ecf" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.11.0", "cfg-if", "foreign-types", "libc", @@ -2480,29 +2497,29 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.117", ] [[package]] name = "openssl-probe" -version = "0.1.6" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" +checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" [[package]] name = "openssl-src" -version = "300.5.1+3.5.1" +version = "300.5.5+3.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "735230c832b28c000e3bc117119e6466a663ec73506bc0a9907ea4187508e42a" +checksum = "3f1787d533e03597a7934fd0a765f0d28e94ecc5fb7789f8053b1e699a56f709" dependencies = [ "cc", ] [[package]] name = "openssl-sys" -version = "0.9.109" +version = "0.9.112" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90096e2e47630d78b7d1c20952dc621f957103f8bc2c8359ec81290d75238571" +checksum = "57d55af3b3e226502be1526dfdba67ab0e9c96fc293004e79576b2b9edb0dbdb" dependencies = [ "cc", "libc", @@ -2511,17 +2528,11 @@ dependencies = [ "vcpkg", ] -[[package]] -name = "overload" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" - [[package]] name = "owo-colors" -version = "4.2.2" +version = "4.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48dd4f4a2c8405440fd0462561f0e5806bd0f77e86f51c761481bdd4018b545e" +checksum = "d211803b9b6b570f68772237e415a029d5a50c65d382910b879fb19d3271f94d" [[package]] name = "parking" @@ -2531,9 +2542,9 @@ checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" [[package]] name = "parking_lot" -version = "0.12.4" +version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" dependencies = [ "lock_api", "parking_lot_core", @@ -2541,15 +2552,15 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.11" +version = "0.9.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.5.13", + "redox_syscall 0.5.18", "smallvec", - "windows-targets 0.52.6", + "windows-link", ] [[package]] @@ -2591,35 +2602,35 @@ dependencies = [ [[package]] name = "percent-encoding" -version = "2.3.1" +version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" [[package]] name = "pin-project" -version = "1.1.10" +version = "1.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677f1add503faace112b9f1373e43e9e054bfdd22ff1a63c1bc485eaec6a6a8a" +checksum = "f1749c7ed4bcaf4c3d0a3efc28538844fb29bcdd7d2b67b2be7e20ba861ff517" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.10" +version = "1.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" +checksum = "d9b20ed30f105399776b9c883e68e536ef602a16ae6f596d2c473591d6ad64c6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.117", ] [[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" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" [[package]] name = "pin-utils" @@ -2629,9 +2640,9 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "piper" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96c8c490f422ef9a4efd2cb5b42b76c8613d7e7dfc1caf667b8a3350a5acc066" +checksum = "c835479a4443ded371d6c535cbfd8d31ad92c5d23ae9770a61bc155e4992a3c1" dependencies = [ "atomic-waker", "fastrand", @@ -2665,6 +2676,12 @@ version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" +[[package]] +name = "plain" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" + [[package]] name = "plotters" version = "0.3.7" @@ -2695,39 +2712,51 @@ dependencies = [ [[package]] name = "polling" -version = "3.8.0" +version = "3.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b53a684391ad002dd6a596ceb6c74fd004fdce75f4be2e3f615068abbea5fd50" +checksum = "5d0e4f59085d47d8241c88ead0f274e8a0cb551f3625263c05eb8dd897c34218" dependencies = [ "cfg-if", "concurrent-queue", "hermit-abi", "pin-project-lite", - "rustix 1.0.7", - "tracing", - "windows-sys 0.59.0", + "rustix", + "windows-sys 0.61.2", +] + +[[package]] +name = "pool-crud-test" +version = "0.1.0" +dependencies = [ + "anyhow", + "clap", + "dotenvy", + "futures", + "sqlx", + "tokio", + "wasip3 0.5.0+wasi-0.3.0-rc-2026-03-15", ] [[package]] name = "portable-atomic" -version = "1.11.1" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483" +checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" [[package]] name = "portable-atomic-util" -version = "0.2.4" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507" +checksum = "091397be61a01d4be58e7841595bd4bfedb15f1cd54977d79b8271e94ed799a3" dependencies = [ "portable-atomic", ] [[package]] name = "potential_utf" -version = "0.1.2" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5a7c30837279ca13e7c867e9e40053bc68740f988cb07f7ca6df43cc734b585" +checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" dependencies = [ "zerovec", ] @@ -2763,9 +2792,9 @@ dependencies = [ [[package]] name = "predicates" -version = "3.1.3" +version = "3.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5d19ee57562043d37e82899fade9a22ebab7be9cef5026b07fda9cdd4293573" +checksum = "ada8f2932f28a27ee7b70dd6c1c39ea0675c55a36879ab92f3a715eaa1e63cfe" dependencies = [ "anstyle", "difflib", @@ -2774,37 +2803,50 @@ dependencies = [ [[package]] name = "predicates-core" -version = "1.0.9" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "727e462b119fe9c93fd0eb1429a5f7647394014cf3c04ab2c0350eeb09095ffa" +checksum = "cad38746f3166b4031b1a0d39ad9f954dd291e7854fcc0eed52ee41a0b50d144" [[package]] name = "predicates-tree" -version = "1.0.12" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72dd2d6d381dfb73a193c7fca536518d7caee39fc8503f74e7dc0be0531b425c" +checksum = "d0de1b847b39c8131db0467e9df1ff60e6d0562ab8e9a16e568ad0fdb372e2f2" dependencies = [ "predicates-core", "termtree", ] +[[package]] +name = "prepared-query-test" +version = "0.1.0" +dependencies = [ + "anyhow", + "clap", + "dotenvy", + "futures", + "sqlx", + "tokio", + "wasip3 0.5.0+wasi-0.3.0-rc-2026-03-15", +] + [[package]] name = "prettyplease" -version = "0.2.35" +version = "0.2.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "061c1221631e079b26479d25bbf2275bfe5917ae8419cd7e34f13bfc2aa7539a" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" dependencies = [ "proc-macro2", - "syn 2.0.104", + "syn 2.0.117", ] [[package]] name = "proc-macro-crate" -version = "3.3.0" +version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edce586971a4dfaa28950c6f18ed55e0406c1ab88bbce2c6f6293a7aaba73d35" +checksum = "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f" dependencies = [ - "toml_edit", + "toml_edit 0.25.8+spec-1.1.0", ] [[package]] @@ -2833,9 +2875,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.95" +version = "1.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" dependencies = [ "unicode-ident", ] @@ -2862,9 +2904,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.40" +version = "1.0.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" dependencies = [ "proc-macro2", ] @@ -2875,6 +2917,12 @@ version = "5.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" +[[package]] +name = "r-efi" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" + [[package]] name = "radium" version = "0.7.0" @@ -2908,7 +2956,7 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.16", + "getrandom 0.2.17", ] [[package]] @@ -2926,7 +2974,7 @@ version = "0.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d16546c5b5962abf8ce6e2881e722b4e0ae3b6f1a08a26ae3573c55853ca68d3" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.11.0", "cassowary", "compact_str", "crossterm", @@ -2943,9 +2991,9 @@ dependencies = [ [[package]] name = "rayon" -version = "1.10.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" +checksum = "368f01d005bf8fd9b1206fb6fa653e6c4a81ceb1466406b81792d87c5677a58f" dependencies = [ "either", "rayon-core", @@ -2953,9 +3001,9 @@ dependencies = [ [[package]] name = "rayon-core" -version = "1.12.1" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" +checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91" dependencies = [ "crossbeam-deque", "crossbeam-utils", @@ -2963,27 +3011,27 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.13" +version = "0.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d04b7d0ee6b4a0207a0a7adb104d23ecb0b47d6beae7152d0fa34b692b29fd6" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.11.0", ] [[package]] name = "redox_syscall" -version = "0.7.0" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f3fe0889e69e2ae9e41f4d6c4c0181701d00e4697b356fb1f74173a5e0ee27" +checksum = "6ce70a74e890531977d37e532c34d45e9055d2409ed08ddba14529471ed0be16" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.11.0", ] [[package]] name = "regex" -version = "1.11.1" +version = "1.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" dependencies = [ "aho-corasick", "memchr", @@ -2993,9 +3041,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.9" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" +checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" dependencies = [ "aho-corasick", "memchr", @@ -3004,9 +3052,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.5" +version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" +checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" [[package]] name = "rend" @@ -3025,7 +3073,7 @@ checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" dependencies = [ "cc", "cfg-if", - "getrandom 0.2.16", + "getrandom 0.2.17", "libc", "untrusted", "windows-sys 0.52.0", @@ -3033,9 +3081,9 @@ dependencies = [ [[package]] name = "rkyv" -version = "0.7.45" +version = "0.7.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9008cd6385b9e161d8229e1f6549dd23c3d022f132a2ea37ac3a10ac4935779b" +checksum = "2297bf9c81a3f0dc96bc9521370b88f054168c29826a75e89c55ff196e7ed6a1" dependencies = [ "bitvec", "bytecheck", @@ -3051,9 +3099,9 @@ dependencies = [ [[package]] name = "rkyv_derive" -version = "0.7.45" +version = "0.7.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "503d1d27590a2b0a3a4ca4c94755aa2875657196ecbf401a42eff41d7de532c0" +checksum = "84d7b42d4b8d06048d3ac8db0eb31bcb942cbeb709f0b5f2b2ebde398d3038f5" dependencies = [ "proc-macro2", "quote", @@ -3062,9 +3110,9 @@ dependencies = [ [[package]] name = "rsa" -version = "0.9.8" +version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78928ac1ed176a5ca1d17e578a1825f3d81ca54cf41053a592584b020cfd691b" +checksum = "b8573f03f5883dcaebdfcf4725caa1ecb9c15b2ef50c43a07b816e06799bb12d" dependencies = [ "const-oid", "digest", @@ -3082,9 +3130,9 @@ dependencies = [ [[package]] name = "rust_decimal" -version = "1.37.2" +version = "1.41.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b203a6425500a03e0919c42d3c47caca51e79f1132046626d2c8871c5092035d" +checksum = "2ce901f9a19d251159075a4c37af514c3b8ef99c22e02dd8c19161cf397ee94a" dependencies = [ "arrayvec", "borsh", @@ -3094,13 +3142,14 @@ dependencies = [ "rkyv", "serde", "serde_json", + "wasm-bindgen", ] [[package]] name = "rustc-demangle" -version = "0.1.25" +version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "989e6739f80c4ad5b13e0fd7fe89531180375b18520cc8c82080e4dc4035b84f" +checksum = "b50b8869d9fc858ce7266cce0194bd74df58b9d0e3f6df3a9fc8eb470d95c09d" [[package]] name = "rustc-hash" @@ -3110,35 +3159,22 @@ checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" [[package]] name = "rustix" -version = "0.38.44" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" +checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.11.0", "errno", "libc", - "linux-raw-sys 0.4.15", - "windows-sys 0.59.0", -] - -[[package]] -name = "rustix" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266" -dependencies = [ - "bitflags 2.9.1", - "errno", - "libc", - "linux-raw-sys 0.9.4", - "windows-sys 0.59.0", + "linux-raw-sys", + "windows-sys 0.61.2", ] [[package]] name = "rustls" -version = "0.23.28" +version = "0.23.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7160e3e10bf4535308537f3c4e1641468cd0e485175d6163087c0393c7d46643" +checksum = "758025cb5fccfd3bc2fd74708fd4682be41d99e5dff73c377c0646c6012c73a4" dependencies = [ "aws-lc-rs", "once_cell", @@ -3151,30 +3187,30 @@ dependencies = [ [[package]] name = "rustls-native-certs" -version = "0.8.1" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcff2dd52b58a8d98a70243663a0d234c4e2b79235637849d15913394a247d3" +checksum = "612460d5f7bea540c490b2b6395d8e34a953e52b491accd6c86c8164c5932a63" dependencies = [ "openssl-probe", "rustls-pki-types", "schannel", - "security-framework 3.2.0", + "security-framework", ] [[package]] name = "rustls-pki-types" -version = "1.12.0" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "229a4a4c221013e7e1f1a043678c5cc39fe5171437c88fb47151a21e6f5b5c79" +checksum = "be040f8b0a225e40375822a563fa9524378b9d63112f53e19ffff34df5d33fdd" dependencies = [ "zeroize", ] [[package]] name = "rustls-webpki" -version = "0.103.3" +version = "0.103.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4a72fe2bcf7a6ac6fd7d0b9e5cb68aeb7d4c0a0271730218b3e92d43b4eb435" +checksum = "df33b2b81ac578cabaf06b89b0631153a3f416b0a886e8a7a1707fb51abbd1ef" dependencies = [ "aws-lc-rs", "ring", @@ -3184,15 +3220,15 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.21" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" [[package]] name = "ryu" -version = "1.0.20" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" +checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" [[package]] name = "same-file" @@ -3205,11 +3241,11 @@ dependencies = [ [[package]] name = "schannel" -version = "0.1.27" +version = "0.1.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" +checksum = "91c1b7e4904c873ef0710c1f407dde2e6287de2bebc1bbbf7d430bb7cbffd939" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -3226,79 +3262,78 @@ checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" [[package]] name = "security-framework" -version = "2.11.1" +version = "3.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" +checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d" dependencies = [ - "bitflags 2.9.1", - "core-foundation 0.9.4", + "bitflags 2.11.0", + "core-foundation", "core-foundation-sys", "libc", "security-framework-sys", ] [[package]] -name = "security-framework" -version = "3.2.0" +name = "security-framework-sys" +version = "2.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "271720403f46ca04f7ba6f55d438f8bd878d6b8ca0a1046e8228c4145bcbb316" +checksum = "6ce2691df843ecc5d231c0b14ece2acc3efb62c0a398c7e1d875f3983ce020e3" dependencies = [ - "bitflags 2.9.1", - "core-foundation 0.10.1", "core-foundation-sys", "libc", - "security-framework-sys", ] [[package]] -name = "security-framework-sys" -version = "2.14.0" +name = "semver" +version = "1.0.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32" +checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" dependencies = [ - "core-foundation-sys", - "libc", + "serde", + "serde_core", ] [[package]] -name = "semver" -version = "1.0.26" +name = "serde" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" dependencies = [ - "serde", + "serde_core", + "serde_derive", ] [[package]] -name = "serde" -version = "1.0.219" +name = "serde_core" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.219" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.117", ] [[package]] name = "serde_json" -version = "1.0.140" +version = "1.0.149" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" dependencies = [ "itoa", "memchr", - "ryu", "serde", + "serde_core", + "zmij", ] [[package]] @@ -3310,6 +3345,15 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_spanned" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "876ac351060d4f882bb1032b6369eb0aef79ad9df1ea8bc404874d8cc3d0cd98" +dependencies = [ + "serde_core", +] + [[package]] name = "serde_urlencoded" version = "0.7.1" @@ -3347,7 +3391,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.117", ] [[package]] @@ -3383,9 +3427,9 @@ dependencies = [ [[package]] name = "shell-words" -version = "1.1.0" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde" +checksum = "dc6fe69c597f9c37bfeeeeeb33da3530379845f10be461a66d16d03eca2ded77" [[package]] name = "shlex" @@ -3405,9 +3449,9 @@ dependencies = [ [[package]] name = "signal-hook-mio" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34db1a06d485c9142248b7a054f034b349b212551f3dfd19c94d45a754a217cd" +checksum = "b75a19a7a740b25bc7944bdee6172368f988763b744e3d4dfe753f6b4ece40cc" dependencies = [ "libc", "mio 0.8.11", @@ -3416,10 +3460,11 @@ dependencies = [ [[package]] name = "signal-hook-registry" -version = "1.4.5" +version = "1.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9203b8055f63a2a00e2f593bb0510367fe707d7ff1e5c872de2f537b339e5410" +checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b" dependencies = [ + "errno", "libc", ] @@ -3441,9 +3486,9 @@ checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" [[package]] name = "slab" -version = "0.4.10" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04dc19736151f35336d325007ac991178d504a119863a2fcb3758cdb5e52c50d" +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" [[package]] name = "smallvec" @@ -3481,6 +3526,16 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "socket2" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + [[package]] name = "spin" version = "0.9.8" @@ -3528,6 +3583,7 @@ dependencies = [ "tokio", "trybuild", "url", + "wasip3 0.5.0+wasi-0.3.0-rc-2026-03-15", ] [[package]] @@ -3573,14 +3629,15 @@ dependencies = [ "crc", "crossbeam-queue", "either", - "event-listener 5.4.0", + "event-listener 5.4.1", + "futures", "futures-core", "futures-intrusive", "futures-io", "futures-util", - "hashbrown 0.16.0", + "hashbrown 0.16.1", "hashlink", - "indexmap 2.10.0", + "indexmap 2.13.0", "ipnet", "ipnetwork", "log", @@ -3597,15 +3654,18 @@ dependencies = [ "smallvec", "smol", "sqlx", - "thiserror 2.0.17", + "thiserror 2.0.18", "time", "tokio", "tokio-stream", - "toml", + "tokio-util", + "toml 0.8.23", "tracing", "url", "uuid", + "wasip3 0.5.0+wasi-0.3.0-rc-2026-03-15", "webpki-roots", + "wit-bindgen 0.54.0", ] [[package]] @@ -3632,7 +3692,7 @@ dependencies = [ "serde_json", "serde_with", "sqlx", - "thiserror 2.0.17", + "thiserror 2.0.18", "time", "tokio", "tower", @@ -3860,7 +3920,7 @@ dependencies = [ "quote", "sqlx-core", "sqlx-macros-core", - "syn 2.0.104", + "syn 2.0.117", ] [[package]] @@ -3884,8 +3944,8 @@ dependencies = [ "sqlx-mysql", "sqlx-postgres", "sqlx-sqlite", - "syn 2.0.104", - "thiserror 2.0.17", + "syn 2.0.117", + "thiserror 2.0.18", "tokio", "url", ] @@ -3897,7 +3957,7 @@ dependencies = [ "atoi", "base64 0.22.1", "bigdecimal", - "bitflags 2.9.1", + "bitflags 2.11.0", "byteorder", "bytes", "chrono", @@ -3928,7 +3988,7 @@ dependencies = [ "sqlx", "sqlx-core", "stringprep", - "thiserror 2.0.17", + "thiserror 2.0.18", "time", "tracing", "uuid", @@ -3942,7 +4002,7 @@ dependencies = [ "base64 0.22.1", "bigdecimal", "bit-vec", - "bitflags 2.9.1", + "bitflags 2.11.0", "byteorder", "chrono", "crc", @@ -3954,6 +4014,7 @@ dependencies = [ "hex", "hkdf", "hmac", + "home", "ipnet", "ipnetwork", "itoa", @@ -3971,7 +4032,7 @@ dependencies = [ "sqlx", "sqlx-core", "stringprep", - "thiserror 2.0.17", + "thiserror 2.0.18", "time", "tracing", "uuid", @@ -3985,7 +4046,6 @@ dependencies = [ "atoi", "chrono", "flume", - "form_urlencoded", "futures-channel", "futures-core", "futures-executor", @@ -3996,9 +4056,10 @@ dependencies = [ "percent-encoding", "regex", "serde", + "serde_urlencoded", "sqlx", "sqlx-core", - "thiserror 2.0.17", + "thiserror 2.0.18", "time", "tracing", "url", @@ -4022,14 +4083,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d904e7009df136af5297832a3ace3370cd14ff1546a232f4f185036c2736fcac" dependencies = [ "quote", - "syn 2.0.104", + "syn 2.0.117", ] [[package]] name = "stable_deref_trait" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" [[package]] name = "static_assertions" @@ -4073,7 +4134,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.104", + "syn 2.0.117", ] [[package]] @@ -4095,9 +4156,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.104" +version = "2.0.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" dependencies = [ "proc-macro2", "quote", @@ -4118,7 +4179,7 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.117", ] [[package]] @@ -4129,21 +4190,21 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "target-triple" -version = "0.1.4" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ac9aa371f599d22256307c24a9d748c041e548cbf599f35d890f9d365361790" +checksum = "591ef38edfb78ca4771ee32cf494cb8771944bee237a9b91fc9c1424ac4b777b" [[package]] name = "tempfile" -version = "3.20.0" +version = "3.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8a64e3985349f2441a1a9ef0b853f869006c3855f2cda6862a94d26ebb9d6a1" +checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" dependencies = [ "fastrand", - "getrandom 0.3.3", + "getrandom 0.4.2", "once_cell", - "rustix 1.0.7", - "windows-sys 0.59.0", + "rustix", + "windows-sys 0.61.2", ] [[package]] @@ -4157,12 +4218,12 @@ dependencies = [ [[package]] name = "terminal_size" -version = "0.4.2" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45c6481c4829e4cc63825e62c49186a34538b7b2750b73b266581ffb612fb5ed" +checksum = "230a1b821ccbd75b185820a1f1ff7b14d21da1e442e22c0863ea5f08771a8874" dependencies = [ - "rustix 1.0.7", - "windows-sys 0.59.0", + "rustix", + "windows-sys 0.61.2", ] [[package]] @@ -4182,11 +4243,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]] @@ -4197,18 +4258,18 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.117", ] [[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", - "syn 2.0.104", + "syn 2.0.117", ] [[package]] @@ -4222,30 +4283,30 @@ dependencies = [ [[package]] name = "time" -version = "0.3.41" +version = "0.3.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a7619e19bc266e0f9c5e6686659d394bc57973859340060a69221e57dbc0c40" +checksum = "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c" dependencies = [ "deranged", "itoa", "num-conv", "powerfmt", - "serde", + "serde_core", "time-core", "time-macros", ] [[package]] name = "time-core" -version = "0.1.4" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c" +checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca" [[package]] name = "time-macros" -version = "0.2.22" +version = "0.2.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3526739392ec93fd8b359c8e98514cb3e8e021beb4e5f597b00a0221f8ed8a49" +checksum = "2e70e4c5a0e0a8a4823ad65dfe1a6930e4f4d756dcd9dd7939022b5e8c501215" dependencies = [ "num-conv", "time-core", @@ -4253,9 +4314,9 @@ dependencies = [ [[package]] name = "tinystr" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b" +checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" dependencies = [ "displaydoc", "zerovec", @@ -4273,9 +4334,9 @@ dependencies = [ [[package]] name = "tinyvec" -version = "1.9.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09b3661f17e86524eccd4371ab0429194e0d7c008abb45f7a7495b1719463c71" +checksum = "3e61e67053d25a4e82c844e8424039d9745781b3fc4f32b8d55ed50f5f667ef3" dependencies = [ "tinyvec_macros", ] @@ -4286,48 +4347,68 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" +[[package]] +name = "tls-connect-test" +version = "0.1.0" +dependencies = [ + "anyhow", + "sqlx", + "tokio", + "wasip3 0.5.0+wasi-0.3.0-rc-2026-03-15", +] + [[package]] name = "tokio" -version = "1.46.1" +version = "1.50.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cc3a2344dafbe23a245241fe8b09735b521110d30fcefbbd5feb1797ca35d17" +checksum = "27ad5e34374e03cfffefc301becb44e9dc3c17584f414349ebe29ed26661822d" dependencies = [ - "backtrace", "bytes", - "io-uring", "libc", - "mio 1.0.4", + "mio 1.2.0", "parking_lot", "pin-project-lite", "signal-hook-registry", - "slab", - "socket2", + "socket2 0.6.3", "tokio-macros", - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] name = "tokio-macros" -version = "2.5.0" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" +checksum = "5c55a2eff8b69ce66c84f85e1da1c233edc36ceb85a2058d11b0d6a3c7e7569c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.117", ] [[package]] name = "tokio-stream" -version = "0.1.17" +version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eca58d7bba4a75707817a2c44174253f9236b2d5fbd055602e9d5c07c139a047" +checksum = "32da49809aab5c3bc678af03902d4ccddea2a87d028d86392a4b1560c6906c70" dependencies = [ "futures-core", "pin-project-lite", "tokio", ] +[[package]] +name = "tokio-util" +version = "0.7.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ae9cec805b01e8fc3fd2fe289f89149a9b66dd16786abd8b19cfa7b48cb0098" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", +] + [[package]] name = "toml" version = "0.8.23" @@ -4335,9 +4416,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" dependencies = [ "serde", - "serde_spanned", - "toml_datetime", - "toml_edit", + "serde_spanned 0.6.9", + "toml_datetime 0.6.11", + "toml_edit 0.22.27", +] + +[[package]] +name = "toml" +version = "1.1.0+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8195ca05e4eb728f4ba94f3e3291661320af739c4e43779cbdfae82ab239fcc" +dependencies = [ + "indexmap 2.13.0", + "serde_core", + "serde_spanned 1.1.0", + "toml_datetime 1.1.0+spec-1.1.0", + "toml_parser", + "toml_writer", + "winnow 1.0.1", ] [[package]] @@ -4349,18 +4445,48 @@ dependencies = [ "serde", ] +[[package]] +name = "toml_datetime" +version = "1.1.0+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97251a7c317e03ad83774a8752a7e81fb6067740609f75ea2b585b569a59198f" +dependencies = [ + "serde_core", +] + [[package]] name = "toml_edit" version = "0.22.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" dependencies = [ - "indexmap 2.10.0", + "indexmap 2.13.0", "serde", - "serde_spanned", - "toml_datetime", + "serde_spanned 0.6.9", + "toml_datetime 0.6.11", "toml_write", - "winnow", + "winnow 0.7.15", +] + +[[package]] +name = "toml_edit" +version = "0.25.8+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16bff38f1d86c47f9ff0647e6838d7bb362522bdf44006c7068c2b1e606f1f3c" +dependencies = [ + "indexmap 2.13.0", + "toml_datetime 1.1.0+spec-1.1.0", + "toml_parser", + "winnow 1.0.1", +] + +[[package]] +name = "toml_parser" +version = "1.1.0+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2334f11ee363607eb04df9b8fc8a13ca1715a72ba8662a26ac285c98aabb4011" +dependencies = [ + "winnow 1.0.1", ] [[package]] @@ -4369,6 +4495,12 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" +[[package]] +name = "toml_writer" +version = "1.1.0+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d282ade6016312faf3e41e57ebbba0c073e4056dab1232ab1cb624199648f8ed" + [[package]] name = "tower" version = "0.4.13" @@ -4418,9 +4550,9 @@ checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" [[package]] name = "tracing" -version = "0.1.41" +version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" dependencies = [ "log", "pin-project-lite", @@ -4430,20 +4562,20 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.30" +version = "0.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" +checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.117", ] [[package]] name = "tracing-core" -version = "0.1.34" +version = "0.1.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" dependencies = [ "once_cell", "valuable", @@ -4472,9 +4604,9 @@ dependencies = [ [[package]] name = "tracing-subscriber" -version = "0.3.19" +version = "0.3.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008" +checksum = "cb7f578e5945fb242538965c2d0b04418d38ec25c79d160cd279bf0731c8d319" dependencies = [ "nu-ansi-term", "sharded-slab", @@ -4492,9 +4624,9 @@ checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "trybuild" -version = "1.0.105" +version = "1.0.116" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c9bf9513a2f4aeef5fdac8677d7d349c79fdbcc03b9c86da6e9d254f1e43be2" +checksum = "47c635f0191bd3a2941013e5062667100969f8c4e9cd787c14f977265d73616e" dependencies = [ "glob", "serde", @@ -4502,14 +4634,14 @@ dependencies = [ "serde_json", "target-triple", "termcolor", - "toml", + "toml 1.1.0+spec-1.1.0", ] [[package]] name = "typenum" -version = "1.18.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" +checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" [[package]] name = "unicode-bidi" @@ -4519,30 +4651,30 @@ checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5" [[package]] name = "unicode-ident" -version = "1.0.18" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" [[package]] name = "unicode-normalization" -version = "0.1.24" +version = "0.1.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" +checksum = "5fd4f6878c9cb28d874b009da9e8d183b5abc80117c40bbd187a1fde336be6e8" dependencies = [ "tinyvec", ] [[package]] name = "unicode-properties" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e70f2a8b45122e719eb623c01822704c4e0907e7e426a05927e1a1cfff5b75d0" +checksum = "7df058c713841ad818f1dc5d3fd88063241cc61f49f5fbea4b951e8cf5a8d71d" [[package]] name = "unicode-segmentation" -version = "1.12.0" +version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" +checksum = "9629274872b2bfaf8d66f5f15725007f635594914870f65218920345aa11aa8c" [[package]] name = "unicode-truncate" @@ -4563,9 +4695,15 @@ checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" [[package]] name = "unicode-width" -version = "0.2.1" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254" + +[[package]] +name = "unicode-xid" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a1a07cc7db3810833284e8d372ccdc6da29741639ecc70c9ec107df0fa6154c" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" [[package]] name = "untrusted" @@ -4575,13 +4713,14 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "url" -version = "2.5.4" +version = "2.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" +checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" dependencies = [ "form_urlencoded", - "idna 1.0.3", + "idna 1.1.0", "percent-encoding", + "serde", ] [[package]] @@ -4598,12 +4737,12 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.17.0" +version = "1.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cf4199d1e5d15ddd86a694e4d0dffa9c323ce759fea589f00fef9d81cc1931d" +checksum = "5ac8b6f42ead25368cf5b098aeb3dc8a1a2c05a3eee8a9a1a68c640edbfc79d9" dependencies = [ "js-sys", - "serde", + "serde_core", "wasm-bindgen", ] @@ -4657,9 +4796,9 @@ checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" [[package]] name = "value-bag" -version = "1.11.1" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "943ce29a8a743eb10d6082545d861b24f9d1b160b7d741e0f2cdf726bec909c5" +checksum = "7ba6f5989077681266825251a52748b8c1d8a4ad098cc37e440103d0ea717fc0" [[package]] name = "vcpkg" @@ -4708,58 +4847,61 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] -name = "wasi" -version = "0.14.2+wasi-0.2.4" +name = "wasip2" +version = "1.0.2+wasi-0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" +checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" dependencies = [ - "wit-bindgen-rt", + "wit-bindgen 0.51.0", ] [[package]] -name = "wasm-bindgen" -version = "0.2.100" +name = "wasip3" +version = "0.4.0+wasi-0.3.0-rc-2026-01-06" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" +checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" dependencies = [ - "cfg-if", - "once_cell", - "rustversion", - "wasm-bindgen-macro", + "wit-bindgen 0.51.0", ] [[package]] -name = "wasm-bindgen-backend" -version = "0.2.100" +name = "wasip3" +version = "0.5.0+wasi-0.3.0-rc-2026-03-15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" +checksum = "1d201c7ba74bcf9d527011d7eb65499cc2a177d3500399fea1134b291873dd08" dependencies = [ - "bumpalo", - "log", - "proc-macro2", - "quote", - "syn 2.0.104", + "wit-bindgen 0.54.0", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.116" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dc0882f7b5bb01ae8c5215a1230832694481c1a4be062fd410e12ea3da5b631" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "serde", + "wasm-bindgen-macro", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.50" +version = "0.4.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61" +checksum = "19280959e2844181895ef62f065c63e0ca07ece4771b53d89bfdb967d97cbf05" dependencies = [ - "cfg-if", "js-sys", - "once_cell", "wasm-bindgen", - "web-sys", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.100" +version = "0.2.116" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" +checksum = "75973d3066e01d035dbedaad2864c398df42f8dd7b1ea057c35b8407c015b537" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -4767,66 +4909,119 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.100" +version = "0.2.116" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" +checksum = "91af5e4be765819e0bcfee7322c14374dc821e35e72fa663a830bbc7dc199eac" dependencies = [ + "bumpalo", "proc-macro2", "quote", - "syn 2.0.104", - "wasm-bindgen-backend", + "syn 2.0.117", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.100" +version = "0.2.116" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +checksum = "c9bf0406a78f02f336bf1e451799cca198e8acde4ffa278f0fb20487b150a633" dependencies = [ "unicode-ident", ] [[package]] -name = "web-sys" -version = "0.3.77" +name = "wasm-encoder" +version = "0.244.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" +checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319" dependencies = [ - "js-sys", - "wasm-bindgen", + "leb128fmt", + "wasmparser 0.244.0", ] [[package]] -name = "webpki-roots" -version = "1.0.1" +name = "wasm-encoder" +version = "0.245.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8782dd5a41a24eed3a4f40b606249b3e236ca61adf1f25ea4d45c73de122b502" +checksum = "3f9dca005e69bf015e45577e415b9af8c67e8ee3c0e38b5b0add5aa92581ed5c" dependencies = [ - "rustls-pki-types", + "leb128fmt", + "wasmparser 0.245.1", ] [[package]] -name = "which" -version = "4.4.2" +name = "wasm-metadata" +version = "0.244.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" +checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" dependencies = [ - "either", - "home", - "once_cell", - "rustix 0.38.44", + "anyhow", + "indexmap 2.13.0", + "wasm-encoder 0.244.0", + "wasmparser 0.244.0", ] [[package]] -name = "whoami" -version = "2.0.2" +name = "wasm-metadata" +version = "0.245.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ace4d5c7b5ab3d99629156d4e0997edbe98a4beb6d5ba99e2cae830207a81983" +checksum = "da55e60097e8b37b475a0fa35c3420dd71d9eb7bd66109978ab55faf56a57efb" dependencies = [ - "libredox", + "anyhow", + "indexmap 2.13.0", + "wasm-encoder 0.245.1", + "wasmparser 0.245.1", +] + +[[package]] +name = "wasmparser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" +dependencies = [ + "bitflags 2.11.0", + "hashbrown 0.15.5", + "indexmap 2.13.0", + "semver", ] +[[package]] +name = "wasmparser" +version = "0.245.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f08c9adee0428b7bddf3890fc27e015ac4b761cc608c822667102b8bfd6995e" +dependencies = [ + "bitflags 2.11.0", + "hashbrown 0.16.1", + "indexmap 2.13.0", + "semver", +] + +[[package]] +name = "web-sys" +version = "0.3.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "749466a37ee189057f54748b200186b59a03417a117267baf3fd89cecc9fb837" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webpki-roots" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22cfaf3c063993ff62e73cb4311efde4db1efb31ab78a3e5c457939ad5cc0bed" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "whoami" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6a5b12f9df4f978d2cfdb1bd3bac52433f44393342d7ee9c25f5a1c14c0f45d" + [[package]] name = "winapi" version = "0.3.9" @@ -4845,11 +5040,11 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.9" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -4860,9 +5055,9 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows-core" -version = "0.61.2" +version = "0.62.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" +checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" dependencies = [ "windows-implement", "windows-interface", @@ -4873,46 +5068,46 @@ dependencies = [ [[package]] name = "windows-implement" -version = "0.60.0" +version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.117", ] [[package]] name = "windows-interface" -version = "0.59.1" +version = "0.59.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.117", ] [[package]] name = "windows-link" -version = "0.1.3" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" [[package]] name = "windows-result" -version = "0.3.4" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" dependencies = [ "windows-link", ] [[package]] name = "windows-strings" -version = "0.4.2" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" dependencies = [ "windows-link", ] @@ -4946,11 +5141,11 @@ dependencies = [ [[package]] name = "windows-sys" -version = "0.60.2" +version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" dependencies = [ - "windows-targets 0.53.2", + "windows-link", ] [[package]] @@ -4977,29 +5172,13 @@ dependencies = [ "windows_aarch64_gnullvm 0.52.6", "windows_aarch64_msvc 0.52.6", "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm 0.52.6", + "windows_i686_gnullvm", "windows_i686_msvc 0.52.6", "windows_x86_64_gnu 0.52.6", "windows_x86_64_gnullvm 0.52.6", "windows_x86_64_msvc 0.52.6", ] -[[package]] -name = "windows-targets" -version = "0.53.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c66f69fcc9ce11da9966ddb31a40968cad001c5bedeb5c2b82ede4253ab48aef" -dependencies = [ - "windows_aarch64_gnullvm 0.53.0", - "windows_aarch64_msvc 0.53.0", - "windows_i686_gnu 0.53.0", - "windows_i686_gnullvm 0.53.0", - "windows_i686_msvc 0.53.0", - "windows_x86_64_gnu 0.53.0", - "windows_x86_64_gnullvm 0.53.0", - "windows_x86_64_msvc 0.53.0", -] - [[package]] name = "windows_aarch64_gnullvm" version = "0.48.5" @@ -5012,12 +5191,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" - [[package]] name = "windows_aarch64_msvc" version = "0.48.5" @@ -5030,12 +5203,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" -[[package]] -name = "windows_aarch64_msvc" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" - [[package]] name = "windows_i686_gnu" version = "0.48.5" @@ -5048,24 +5215,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" -[[package]] -name = "windows_i686_gnu" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" - [[package]] name = "windows_i686_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" -[[package]] -name = "windows_i686_gnullvm" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" - [[package]] name = "windows_i686_msvc" version = "0.48.5" @@ -5078,12 +5233,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" -[[package]] -name = "windows_i686_msvc" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" - [[package]] name = "windows_x86_64_gnu" version = "0.48.5" @@ -5096,12 +5245,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" -[[package]] -name = "windows_x86_64_gnu" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" - [[package]] name = "windows_x86_64_gnullvm" version = "0.48.5" @@ -5114,12 +5257,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" - [[package]] name = "windows_x86_64_msvc" version = "0.48.5" @@ -5133,34 +5270,206 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] -name = "windows_x86_64_msvc" -version = "0.53.0" +name = "winnow" +version = "0.7.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" +checksum = "df79d97927682d2fd8adb29682d1140b343be4ac0f08fd68b7765d9c059d3945" +dependencies = [ + "memchr", +] [[package]] name = "winnow" -version = "0.7.11" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74c7b26e3480b707944fc872477815d29a8e429d2f93a1ce000f5fa84a15cbcd" +checksum = "09dac053f1cd375980747450bfc7250c264eaae0583872e845c0c7cd578872b5" dependencies = [ "memchr", ] [[package]] -name = "wit-bindgen-rt" -version = "0.39.0" +name = "wit-bindgen" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" +dependencies = [ + "wit-bindgen-rust-macro 0.51.0", +] + +[[package]] +name = "wit-bindgen" +version = "0.54.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bb00254d5051d69730ee32580b7373592f10ad786757c372f0f2c7b61f86a2c" +dependencies = [ + "futures", + "wit-bindgen-rust-macro 0.54.0", +] + +[[package]] +name = "wit-bindgen-core" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" +dependencies = [ + "anyhow", + "heck 0.5.0", + "wit-parser 0.244.0", +] + +[[package]] +name = "wit-bindgen-core" +version = "0.54.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99cdef5ccf0b0e9bf30868d6f9c5ed116c84ae95f84ba29d2216d3e922de3963" +dependencies = [ + "anyhow", + "heck 0.5.0", + "wit-parser 0.245.1", +] + +[[package]] +name = "wit-bindgen-rust" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" +dependencies = [ + "anyhow", + "heck 0.5.0", + "indexmap 2.13.0", + "prettyplease", + "syn 2.0.117", + "wasm-metadata 0.244.0", + "wit-bindgen-core 0.51.0", + "wit-component 0.244.0", +] + +[[package]] +name = "wit-bindgen-rust" +version = "0.54.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e76541e2f37ac1729db85765729daa0f3c2b5975d66699114d107525f6d6c8d5" +dependencies = [ + "anyhow", + "heck 0.5.0", + "indexmap 2.13.0", + "prettyplease", + "syn 2.0.117", + "wasm-metadata 0.245.1", + "wit-bindgen-core 0.54.0", + "wit-component 0.245.1", +] + +[[package]] +name = "wit-bindgen-rust-macro" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a" +dependencies = [ + "anyhow", + "prettyplease", + "proc-macro2", + "quote", + "syn 2.0.117", + "wit-bindgen-core 0.51.0", + "wit-bindgen-rust 0.51.0", +] + +[[package]] +name = "wit-bindgen-rust-macro" +version = "0.54.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" +checksum = "a284e17b2bc808c72ba008f6694626fa76bcac608b3d1ed0880f9add3f558f8e" dependencies = [ - "bitflags 2.9.1", + "anyhow", + "prettyplease", + "proc-macro2", + "quote", + "syn 2.0.117", + "wit-bindgen-core 0.54.0", + "wit-bindgen-rust 0.54.0", +] + +[[package]] +name = "wit-component" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" +dependencies = [ + "anyhow", + "bitflags 2.11.0", + "indexmap 2.13.0", + "log", + "serde", + "serde_derive", + "serde_json", + "wasm-encoder 0.244.0", + "wasm-metadata 0.244.0", + "wasmparser 0.244.0", + "wit-parser 0.244.0", +] + +[[package]] +name = "wit-component" +version = "0.245.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4894f10d2d5cbc17c77e91f86a1e48e191a788da4425293b55c98b44ba3fcac9" +dependencies = [ + "anyhow", + "bitflags 2.11.0", + "indexmap 2.13.0", + "log", + "serde", + "serde_derive", + "serde_json", + "wasm-encoder 0.245.1", + "wasm-metadata 0.245.1", + "wasmparser 0.245.1", + "wit-parser 0.245.1", +] + +[[package]] +name = "wit-parser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" +dependencies = [ + "anyhow", + "id-arena", + "indexmap 2.13.0", + "log", + "semver", + "serde", + "serde_derive", + "serde_json", + "unicode-xid", + "wasmparser 0.244.0", +] + +[[package]] +name = "wit-parser" +version = "0.245.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "330698718e82983499419494dd1e3d7811a457a9bf9f69734e8c5f07a2547929" +dependencies = [ + "anyhow", + "hashbrown 0.16.1", + "id-arena", + "indexmap 2.13.0", + "log", + "semver", + "serde", + "serde_derive", + "serde_json", + "unicode-xid", + "wasmparser 0.245.1", ] [[package]] name = "writeable" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" +checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" [[package]] name = "wyz" @@ -5173,11 +5482,10 @@ dependencies = [ [[package]] name = "yoke" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc" +checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" dependencies = [ - "serde", "stable_deref_trait", "yoke-derive", "zerofrom", @@ -5185,34 +5493,34 @@ dependencies = [ [[package]] name = "yoke-derive" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" +checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.117", "synstructure", ] [[package]] name = "zerocopy" -version = "0.8.26" +version = "0.8.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1039dd0d3c310cf05de012d8a39ff557cb0d23087fd44cad61df08fc31907a2f" +checksum = "eed437bf9d6692032087e337407a86f04cd8d6a16a37199ed57949d415bd68e9" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.26" +version = "0.8.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ecf5b4cc5364572d7f4c329661bcc82724222973f2cab6f050a4e5c22f75181" +checksum = "70e3cd084b1788766f53af483dd21f93881ff30d7320490ec3ef7526d203bad4" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.117", ] [[package]] @@ -5232,21 +5540,21 @@ checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.117", "synstructure", ] [[package]] name = "zeroize" -version = "1.8.1" +version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" +checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" [[package]] name = "zerotrie" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595" +checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" dependencies = [ "displaydoc", "yoke", @@ -5255,9 +5563,9 @@ dependencies = [ [[package]] name = "zerovec" -version = "0.11.2" +version = "0.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a05eb080e015ba39cc9e23bbe5e7fb04d5fb040350f99f34e338d5fdd294428" +checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" dependencies = [ "yoke", "zerofrom", @@ -5266,11 +5574,17 @@ dependencies = [ [[package]] name = "zerovec-derive" -version = "0.11.1" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" +checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.117", ] + +[[package]] +name = "zmij" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" diff --git a/Cargo.toml b/Cargo.toml index c88ab231e2..b8701095ff 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,6 +24,11 @@ members = [ "examples/postgres/transaction", "examples/sqlite/todos", "examples/sqlite/extension", + "tests/mysql/wasm-components/connect-test", + "tests/mysql/wasm-components/execute-query-test", + "tests/mysql/wasm-components/pool-crud-test", + "tests/mysql/wasm-components/prepared-query-test", + "tests/mysql/wasm-components/tls-connect-test", ] [workspace.package] @@ -106,6 +111,9 @@ tls-rustls-ring = ["tls-rustls-ring-webpki"] # For backwards compatibility tls-rustls-ring-webpki = ["sqlx-core/_tls-rustls-ring-webpki", "sqlx-macros?/_tls-rustls-ring-webpki"] tls-rustls-ring-native-roots = ["sqlx-core/_tls-rustls-ring-native-roots", "sqlx-macros?/_tls-rustls-ring-native-roots"] +# WASM-native TLS via wasi-tls host interface. Only effective on wasm32 targets. +tls-wasm = ["sqlx-core/_tls-wasm"] + # No-op feature used by the workflows to compile without TLS enabled. Not meant for general use. tls-none = [] @@ -186,11 +194,13 @@ mac_address = "1.1.5" rust_decimal = { version = "1.26.1", default-features = false, features = ["std"] } time = { version = "0.3.36", features = ["formatting", "parsing", "macros"] } uuid = "1.1.2" - +tokio-util = { version = "*" } # Common utility crates cfg-if = "1.0.0" dotenvy = { version = "0.15.0", default-features = false } thiserror = { version = "2.0.17", default-features = false, features = ["std"] } +wasip3 = "0.5.0" +wit-bindgen = { version = "0.54", default-features = false, features = ["async", "async-spawn", "inter-task-wakeup", "macros"] } # Runtimes [workspace.dependencies.async-global-executor] @@ -207,7 +217,7 @@ default-features = false [workspace.dependencies.tokio] version = "1" -features = ["time", "net", "sync", "fs", "io-util", "rt"] +features = ["time", "sync", "io-util", "rt"] default-features = false [dependencies] @@ -223,6 +233,7 @@ anyhow = "1.0.52" time_ = { version = "0.3.2", package = "time" } futures-util = { version = "0.3.19", default-features = false, features = ["alloc"] } env_logger = "0.11" +wasip3 = "0.5.0" async-std = { workspace = true, features = ["attributes"] } tokio = { version = "1.15.0", features = ["full"] } dotenvy = "0.15.0" @@ -254,6 +265,9 @@ cast_sign_loss = 'deny' # See `clippy.toml` disallowed_methods = 'deny' +# [patch.crates-io] +# whoami = { git = "https://github.com/Aditya1404Sal/whoami", branch = "v2" } + [lints.rust.unexpected_cfgs] level = 'warn' @@ -361,6 +375,10 @@ name = "mysql" path = "tests/mysql/mysql.rs" required-features = ["mysql"] +[[test]] +name = "wasi_integration_test" +path = "tests/mysql/wasi_integration_test.rs" + [[test]] name = "mysql-types" path = "tests/mysql/types.rs" @@ -453,4 +471,4 @@ required-features = ["postgres"] [[test]] name = "postgres-rustsec" path = "tests/postgres/rustsec.rs" -required-features = ["postgres", "macros", "migrate"] +required-features = ["postgres", "macros", "migrate"] \ No newline at end of file diff --git a/sqlx-core/Cargo.toml b/sqlx-core/Cargo.toml index 9ccb441e45..bffe60a6fe 100644 --- a/sqlx-core/Cargo.toml +++ b/sqlx-core/Cargo.toml @@ -32,6 +32,7 @@ _tls-rustls-aws-lc-rs = ["_tls-rustls", "rustls/aws-lc-rs", "webpki-roots"] _tls-rustls-ring-webpki = ["_tls-rustls", "rustls/ring", "webpki-roots"] _tls-rustls-ring-native-roots = ["_tls-rustls", "rustls/ring", "rustls-native-certs"] _tls-rustls = ["rustls"] +_tls-wasm = [] _tls-none = [] # support offline/decoupled building (enables serialization of `Describe`) @@ -92,8 +93,7 @@ serde = { version = "1.0.132", features = ["derive", "rc"], optional = true } serde_json = { version = "1.0.73", features = ["raw_value"], optional = true } toml = { version = "0.8.16", optional = true } sha2 = { version = "0.10.0", default-features = false, optional = true } -#sqlformat = "0.2.0" -tokio-stream = { version = "0.1.8", features = ["fs"], optional = true } +tokio-stream = { version = "0.1.8", optional = true } tracing = { version = "0.1.37", features = ["log"] } smallvec = "1.7.0" url = { version = "2.2.2" } @@ -105,6 +105,19 @@ hashbrown = "0.16.0" thiserror.workspace = true +# WASM/WASIP3 dependencies (always enabled on wasm32) +[target.'cfg(target_arch = "wasm32")'.dependencies] +tokio = { workspace = true, features = ["sync", "rt"] } +tokio-util = { workspace = true } +wasip3 = { workspace = true } +wit-bindgen = { workspace = true } +futures = "0.3" + +# Non-WASM dependencies with platform-specific features +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +tokio = { workspace = true, features = ["net", "fs"], optional = true } +tokio-stream = { version = "0.1.8", features = ["fs"], optional = true } + [dev-dependencies] tokio = { version = "1", features = ["rt"] } diff --git a/sqlx-core/src/fs.rs b/sqlx-core/src/fs.rs index 0993cbeec6..b5cff3ce14 100644 --- a/sqlx-core/src/fs.rs +++ b/sqlx-core/src/fs.rs @@ -3,10 +3,17 @@ use std::fs::Metadata; use std::io; use std::path::{Path, PathBuf}; +#[cfg(not(target_arch = "wasm32"))] use crate::rt; pub struct ReadDir { + #[cfg(not(target_arch = "wasm32"))] inner: Option, + + // On wasm32, all entries are collected upfront into a VecDeque so + // next() can pop them one at a time without needing an async stream handle. + #[cfg(target_arch = "wasm32")] + pub(crate) entries: std::collections::VecDeque, } pub struct DirEntry { @@ -23,34 +30,77 @@ pub struct DirEntry { pub async fn read>(path: P) -> io::Result> { let path = PathBuf::from(path.as_ref()); - rt::spawn_blocking(move || std::fs::read(path)).await + #[cfg(not(target_arch = "wasm32"))] + { + rt::spawn_blocking(move || std::fs::read(path)).await + } + #[cfg(target_arch = "wasm32")] + { + crate::wasm::fs::read(path).await + } } pub async fn read_to_string>(path: P) -> io::Result { let path = PathBuf::from(path.as_ref()); - rt::spawn_blocking(move || std::fs::read_to_string(path)).await + #[cfg(not(target_arch = "wasm32"))] + { + rt::spawn_blocking(move || std::fs::read_to_string(path)).await + } + #[cfg(target_arch = "wasm32")] + { + crate::wasm::fs::read_to_string(path).await + } } pub async fn create_dir_all>(path: P) -> io::Result<()> { let path = PathBuf::from(path.as_ref()); - rt::spawn_blocking(move || std::fs::create_dir_all(path)).await + #[cfg(not(target_arch = "wasm32"))] + { + rt::spawn_blocking(move || std::fs::create_dir_all(path)).await + } + #[cfg(target_arch = "wasm32")] + { + crate::wasm::fs::create_dir_all(path).await + } } pub async fn remove_file>(path: P) -> io::Result<()> { let path = PathBuf::from(path.as_ref()); - rt::spawn_blocking(move || std::fs::remove_file(path)).await + #[cfg(not(target_arch = "wasm32"))] + { + rt::spawn_blocking(move || std::fs::remove_file(path)).await + } + #[cfg(target_arch = "wasm32")] + { + crate::wasm::fs::remove_file(path).await + } } pub async fn remove_dir>(path: P) -> io::Result<()> { let path = PathBuf::from(path.as_ref()); - rt::spawn_blocking(move || std::fs::remove_dir(path)).await + #[cfg(not(target_arch = "wasm32"))] + { + rt::spawn_blocking(move || std::fs::remove_dir(path)).await + } + #[cfg(target_arch = "wasm32")] + { + crate::wasm::fs::remove_dir(path).await + } } pub async fn remove_dir_all>(path: P) -> io::Result<()> { let path = PathBuf::from(path.as_ref()); - rt::spawn_blocking(move || std::fs::remove_dir_all(path)).await + #[cfg(not(target_arch = "wasm32"))] + { + rt::spawn_blocking(move || std::fs::remove_dir_all(path)).await + } + #[cfg(target_arch = "wasm32")] + { + crate::wasm::fs::remove_dir_all(path).await + } } +#[cfg(not(target_arch = "wasm32"))] pub async fn read_dir(path: PathBuf) -> io::Result { let read_dir = rt::spawn_blocking(move || std::fs::read_dir(path)).await?; @@ -59,38 +109,48 @@ pub async fn read_dir(path: PathBuf) -> io::Result { }) } +#[cfg(target_arch = "wasm32")] +pub async fn read_dir(path: PathBuf) -> io::Result { + crate::wasm::fs::read_dir(path).await +} + impl ReadDir { pub async fn next(&mut self) -> io::Result> { - if let Some(mut read_dir) = self.inner.take() { - let maybe = rt::spawn_blocking(move || { - let entry = read_dir.next().transpose()?; - - entry - .map(|entry| -> io::Result<_> { - Ok(( - read_dir, - DirEntry { - path: entry.path(), - file_name: entry.file_name(), - // We always want the metadata as well so might as well fetch - // it in the same blocking call. - metadata: entry.metadata()?, - }, - )) - }) - .transpose() - }) - .await?; - - match maybe { - Some((read_dir, entry)) => { - self.inner = Some(read_dir); - Ok(Some(entry)) + #[cfg(not(target_arch = "wasm32"))] + { + if let Some(mut read_dir) = self.inner.take() { + let maybe = rt::spawn_blocking(move || { + let entry = read_dir.next().transpose()?; + + entry + .map(|entry| -> io::Result<_> { + Ok(( + read_dir, + DirEntry { + path: entry.path(), + file_name: entry.file_name(), + // We always want the metadata as well so might as well fetch + // it in the same blocking call. + metadata: entry.metadata()?, + }, + )) + }) + .transpose() + }) + .await?; + + match maybe { + Some((read_dir, entry)) => { + self.inner = Some(read_dir); + Ok(Some(entry)) + } + None => Ok(None), } - None => Ok(None), + } else { + Ok(None) } - } else { - Ok(None) } + #[cfg(target_arch = "wasm32")] + crate::wasm::fs::next(self).await } } diff --git a/sqlx-core/src/lib.rs b/sqlx-core/src/lib.rs index 494c41e9bf..4c33008b67 100644 --- a/sqlx-core/src/lib.rs +++ b/sqlx-core/src/lib.rs @@ -22,6 +22,9 @@ // #![cfg_attr(docsrs, feature(doc_cfg))] +#[cfg(target_arch = "wasm32")] +pub mod wasm; + #[macro_use] pub mod ext; diff --git a/sqlx-core/src/migrate/migration.rs b/sqlx-core/src/migrate/migration.rs index 79721d244d..51576491e7 100644 --- a/sqlx-core/src/migrate/migration.rs +++ b/sqlx-core/src/migrate/migration.rs @@ -64,6 +64,7 @@ pub fn checksum(sql: &str) -> Vec { Vec::from(Sha384::digest(sql).as_slice()) } +#[cfg(not(target_arch = "wasm32"))] pub fn checksum_fragments<'a>(fragments: impl Iterator) -> Vec { let mut digest = Sha384::new(); diff --git a/sqlx-core/src/migrate/mod.rs b/sqlx-core/src/migrate/mod.rs index 39347cf421..50d405b521 100644 --- a/sqlx-core/src/migrate/mod.rs +++ b/sqlx-core/src/migrate/mod.rs @@ -13,5 +13,9 @@ pub use migration_type::MigrationType; pub use migrator::Migrator; pub use source::{MigrationSource, ResolveConfig, ResolveWith}; +#[cfg(target_arch = "wasm32")] +#[doc(hidden)] +pub use source::resolve; +#[cfg(not(target_arch = "wasm32"))] #[doc(hidden)] pub use source::{resolve_blocking, resolve_blocking_with_config}; diff --git a/sqlx-core/src/migrate/source.rs b/sqlx-core/src/migrate/source.rs index 4648e53f1e..215814dbf9 100644 --- a/sqlx-core/src/migrate/source.rs +++ b/sqlx-core/src/migrate/source.rs @@ -1,12 +1,15 @@ use crate::error::BoxDynError; -use crate::migrate::{migration, Migration, MigrationType}; +use crate::migrate::Migration; +#[cfg(not(target_arch = "wasm32"))] +use crate::migrate::{migration, MigrationType}; +#[cfg(not(target_arch = "wasm32"))] use crate::sql_str::{AssertSqlSafe, SqlSafeStr}; use futures_core::future::BoxFuture; +#[cfg(not(target_arch = "wasm32"))] use std::borrow::Cow; use std::collections::BTreeSet; use std::fmt::Debug; -use std::fs; use std::io; use std::path::{Path, PathBuf}; @@ -38,20 +41,15 @@ impl<'s> MigrationSource<'s> for &'s Path { impl MigrationSource<'static> for PathBuf { fn resolve(self) -> BoxFuture<'static, Result, BoxDynError>> { - // Technically this could just be `Box::pin(spawn_blocking(...))` - // but that would actually be a breaking behavior change because it would call - // `spawn_blocking()` on the current thread - Box::pin(async move { - crate::rt::spawn_blocking(move || { - let migrations_with_paths = resolve_blocking(&self)?; - - Ok(migrations_with_paths.into_iter().map(|(m, _p)| m).collect()) - }) - .await - }) + Box::pin(async move { self.as_path().resolve().await }) } } +#[cfg(target_arch = "wasm32")] +pub async fn resolve(_path: &PathBuf) -> Result, ResolveError> { + todo!(); +} + /// A [`MigrationSource`] implementation with configurable resolution. /// /// `S` may be `PathBuf`, `&Path` or any type that implements `Into`. @@ -64,12 +62,14 @@ impl<'s, S: Debug + Into + Send + 's> MigrationSource<'s> for ResolveWi fn resolve(self) -> BoxFuture<'s, Result, BoxDynError>> { Box::pin(async move { let path = self.0.into(); - let config = self.1; - - let migrations_with_paths = + #[cfg(not(target_arch = "wasm32"))] + let migrations_with_paths = { + let config = self.1; crate::rt::spawn_blocking(move || resolve_blocking_with_config(&path, &config)) - .await?; - + .await? + }; + #[cfg(target_arch = "wasm32")] + let migrations_with_paths = resolve(&path).await?; Ok(migrations_with_paths.into_iter().map(|(m, _p)| m).collect()) }) } @@ -148,11 +148,13 @@ impl ResolveConfig { // FIXME: paths should just be part of `Migration` but we can't add a field backwards compatibly // since it's `#[non_exhaustive]`. #[doc(hidden)] +#[cfg(not(target_arch = "wasm32"))] pub fn resolve_blocking(path: &Path) -> Result, ResolveError> { resolve_blocking_with_config(path, &ResolveConfig::new()) } #[doc(hidden)] +#[cfg(not(target_arch = "wasm32"))] pub fn resolve_blocking_with_config( path: &Path, config: &ResolveConfig, @@ -161,7 +163,7 @@ pub fn resolve_blocking_with_config( message: format!("error canonicalizing path {}", path.display()), source: Some(e), })?; - + use std::fs; let s = fs::read_dir(&path).map_err(|e| ResolveError { message: format!("error reading migration directory {}", path.display()), source: Some(e), @@ -254,6 +256,7 @@ pub fn resolve_blocking_with_config( Ok(migrations) } +#[cfg(not(target_arch = "wasm32"))] fn checksum_with(sql: &str, ignored_chars: &BTreeSet) -> Vec { if ignored_chars.is_empty() { // This is going to be much faster because it doesn't have to UTF-8 decode `sql`. diff --git a/sqlx-core/src/net/socket/mod.rs b/sqlx-core/src/net/socket/mod.rs index 0f9aae61b4..1d1cf0a4b8 100644 --- a/sqlx-core/src/net/socket/mod.rs +++ b/sqlx-core/src/net/socket/mod.rs @@ -6,6 +6,7 @@ use std::task::{ready, Context, Poll}; pub use buffered::{BufferedSocket, WriteBuffer}; use bytes::BufMut; +#[cfg(not(target_arch = "wasm32"))] use cfg_if::cfg_if; use crate::io::ReadBuf; @@ -186,18 +187,26 @@ pub async fn connect_tcp( port: u16, with_socket: Ws, ) -> crate::Result { - #[cfg(feature = "_rt-tokio")] - if crate::rt::rt_tokio::available() { - return Ok(with_socket - .with_socket(tokio::net::TcpStream::connect((host, port)).await?) - .await); + #[cfg(target_arch = "wasm32")] + { + return crate::rt::rt_wasip3::connect_tcp(host, port, with_socket).await; } - cfg_if! { - if #[cfg(feature = "_rt-async-io")] { - Ok(with_socket.with_socket(connect_tcp_async_io(host, port).await?).await) - } else { - crate::rt::missing_rt((host, port, with_socket)) + #[cfg(not(target_arch = "wasm32"))] + { + #[cfg(feature = "_rt-tokio")] + if crate::rt::rt_tokio::available() { + return Ok(with_socket + .with_socket(tokio::net::TcpStream::connect((host, port)).await?) + .await); + } + + cfg_if! { + if #[cfg(feature = "_rt-async-io")] { + Ok(with_socket.with_socket(connect_tcp_async_io(host, port).await?).await) + } else { + crate::rt::missing_rt((host, port, with_socket)) + } } } } @@ -291,4 +300,4 @@ pub async fn connect_uds, Ws: WithSocket>( ) .into()) } -} +} \ No newline at end of file diff --git a/sqlx-core/src/net/tls/mod.rs b/sqlx-core/src/net/tls/mod.rs index 7bb1744189..1444722575 100644 --- a/sqlx-core/src/net/tls/mod.rs +++ b/sqlx-core/src/net/tls/mod.rs @@ -12,6 +12,9 @@ mod tls_rustls; #[cfg(feature = "_tls-native-tls")] mod tls_native_tls; +#[cfg(all(feature = "_tls-wasm", target_arch = "wasm32"))] +mod tls_wasi; + mod util; /// X.509 Certificate input, either a file path or a PEM encoded inline certificate(s). @@ -75,6 +78,11 @@ where S: Socket, Ws: WithSocket, { + #[cfg(all(feature = "_tls-wasm", target_arch = "wasm32"))] + return Ok(with_socket + .with_socket(tls_wasi::handshake(socket, config).await?) + .await); + #[cfg(feature = "_tls-native-tls")] return Ok(with_socket .with_socket(tls_native_tls::handshake(socket, config).await?) @@ -85,7 +93,11 @@ where .with_socket(tls_rustls::handshake(socket, config).await?) .await); - #[cfg(not(any(feature = "_tls-native-tls", feature = "_tls-rustls")))] + #[cfg(not(any( + all(feature = "_tls-wasm", target_arch = "wasm32"), + feature = "_tls-native-tls", + feature = "_tls-rustls" + )))] { drop((socket, config, with_socket)); panic!("one of the `runtime-*-native-tls` or `runtime-*-rustls` features must be enabled") @@ -93,7 +105,11 @@ where } pub fn available() -> bool { - cfg!(any(feature = "_tls-native-tls", feature = "_tls-rustls")) + cfg!(any( + all(feature = "_tls-wasm", target_arch = "wasm32"), + feature = "_tls-native-tls", + feature = "_tls-rustls" + )) } pub fn error_if_unavailable() -> crate::Result<()> { diff --git a/sqlx-core/src/net/tls/tls_wasi.rs b/sqlx-core/src/net/tls/tls_wasi.rs new file mode 100644 index 0000000000..1e751ecf89 --- /dev/null +++ b/sqlx-core/src/net/tls/tls_wasi.rs @@ -0,0 +1,275 @@ +//! WASM-native TLS using the wasi-tls component model interface. +//! +//! This module implements TLS for WASM targets via the `wasi:tls/client` WIT +//! interface. The host runtime (e.g. wasmtime) provides the actual TLS +//! implementation; we just wire up the stream plumbing. + +use bytes::BytesMut; +use core::task::{Context, Poll}; +use futures_util::future::{AbortHandle, Abortable}; +use std::io; +use tokio::sync::mpsc; +use tokio::sync::mpsc::error::TryRecvError; +use wit_bindgen::rt::async_support; + +use crate::io::ReadBuf; +use crate::net::Socket; +use crate::rt::rt_wasip3::WasiPollSender; +use bytes::BufMut as _; +use tracing::debug; + +use super::TlsConfig; + +// Generate bindings from the wasi-tls WIT specification. +wit_bindgen::generate!({ + path: "src/net/tls/wasi-tls.wit", + world: "tls-client", +}); + +/// A TLS-wrapped socket that implements the `Socket` trait. +/// +/// Data written by the application flows through the wasi-tls connector's +/// encryption pipeline before being sent over the underlying TCP socket. +/// Incoming TCP data flows through the decryption pipeline before being +/// readable by the application. +pub struct WasiTlsSocket { + /// Application writes cleartext here; background tasks encrypt and forward to TCP. + tx: WasiPollSender>, + /// Application reads decrypted data from here. + rx: mpsc::Receiver>, + /// Buffer for partially consumed received data. + buf: BytesMut, + /// Cancellation handle for all background plumbing tasks. + abort_handle: AbortHandle, +} + +impl Drop for WasiTlsSocket { + fn drop(&mut self) { + self.abort_handle.abort(); + } +} + +impl Socket for WasiTlsSocket { + fn try_read(&mut self, buf: &mut dyn ReadBuf) -> io::Result { + let n = buf.remaining_mut(); + + if !self.buf.is_empty() { + let to_copy = n.min(self.buf.len()); + buf.put_slice(&self.buf.split_to(to_copy)); + return Ok(to_copy); + } + + match self.rx.try_recv() { + Ok(rx_vec) => { + if rx_vec.is_empty() { + return Err(io::ErrorKind::WouldBlock.into()); + } + if rx_vec.len() <= n { + buf.put_slice(&rx_vec); + Ok(rx_vec.len()) + } else { + buf.put_slice(&rx_vec[..n]); + self.buf.extend_from_slice(&rx_vec[n..]); + Ok(n) + } + } + Err(TryRecvError::Empty) => Err(io::ErrorKind::WouldBlock.into()), + Err(TryRecvError::Disconnected) => Ok(0), + } + } + + fn try_write(&mut self, buf: &[u8]) -> io::Result { + if buf.is_empty() { + return Ok(0); + } + let n = buf.len(); + match self.tx.try_send(buf.to_vec()) { + Ok(()) => Ok(n), + Err(_) => Err(io::ErrorKind::WouldBlock.into()), + } + } + + fn poll_read_ready(&mut self, cx: &mut Context<'_>) -> Poll> { + if !self.buf.is_empty() { + return Poll::Ready(Ok(())); + } + match self.rx.poll_recv(cx) { + Poll::Ready(Some(v)) => { + if !v.is_empty() { + self.buf.extend(v); + Poll::Ready(Ok(())) + } else { + Poll::Pending + } + } + Poll::Ready(None) => Poll::Ready(Ok(())), + Poll::Pending => Poll::Pending, + } + } + + fn poll_write_ready(&mut self, cx: &mut Context<'_>) -> Poll> { + match self.tx.poll_reserve(cx) { + Poll::Ready(Ok(())) => Poll::Ready(Ok(())), + Poll::Ready(Err(())) => Poll::Ready(Err(io::ErrorKind::ConnectionReset.into())), + Poll::Pending => Poll::Pending, + } + } + + fn poll_shutdown(&mut self, _cx: &mut Context<'_>) -> Poll> { + Poll::Ready(Ok(())) + } +} + +/// Perform a TLS handshake over an existing socket using the wasi-tls host +/// implementation. +/// +/// The pipeline is: +/// +/// ```text +/// App writes cleartext +/// → cleartext_tx (wit stream) +/// → [connector.send] → encrypted_rx (wit stream) +/// → background drain → underlying socket write +/// +/// Underlying socket read +/// → background drain → ciphertext_tx (wit stream) +/// → [connector.receive] → decrypted_rx (wit stream) +/// → background drain → App reads decrypted +/// ``` +pub async fn handshake( + mut socket: S, + config: TlsConfig<'_>, +) -> crate::Result { + let hostname = config.hostname.to_string(); + debug!("wasi-tls: starting handshake for {}", hostname); + + // Create the wasi-tls connector resource. + let connector = wasi::tls::client::Connector::new(); + + // Create two pairs of wit-streams: + // 1. cleartext pair: app writes cleartext → connector encrypts + // 2. ciphertext pair: TCP data → connector decrypts + let (mut cleartext_tx, cleartext_rx) = wasip3::wit_stream::new::(); + let (mut ciphertext_tx, ciphertext_rx) = wasip3::wit_stream::new::(); + + // Wire up the TLS transform pipelines. + let (mut encrypted_rx, _send_done) = connector.send(cleartext_rx); + let (mut decrypted_rx, _recv_done) = connector.receive(ciphertext_rx); + + // App-facing channels: the WasiTlsSocket will use these. + let (app_cleartext_tx, mut app_cleartext_rx) = mpsc::channel::>(4); + let (app_decrypted_tx, app_decrypted_rx) = mpsc::channel::>(4); + + // Internal channels that bridge the socket IO to the wit-stream pipeline. + // These decouple the read and write paths so each can be handled in a + // separate async branch without sharing a `&mut socket`. + let (tcp_write_tx, mut tcp_write_rx) = mpsc::channel::>(4); + let (tcp_read_tx, mut tcp_read_rx) = mpsc::channel::>(4); + + let (abort_handle, abort_registration) = AbortHandle::new_pair(); + + async_support::yield_async().await; + + // Socket pump: handles all actual TCP IO in a single async task that owns + // `socket` exclusively. Encrypted bytes to send arrive on `tcp_write_rx`; + // raw bytes received from TCP are forwarded on `tcp_read_tx`. + let socket_pump = async move { + let mut read_storage = [0u8; 4096]; + loop { + // Try to drain any pending writes first. + while let Ok(data) = tcp_write_rx.try_recv() { + let mut pos = 0; + while pos < data.len() { + match socket.try_write(&data[pos..]) { + Ok(n) => pos += n, + Err(e) if e.kind() == io::ErrorKind::WouldBlock => { + async_support::yield_async().await; + } + Err(e) => { + debug!("wasi-tls: TCP write error: {:?}", e); + return; + } + } + } + } + // Try to read incoming data. + { + let mut slice: &mut [u8] = &mut read_storage; + match socket.try_read(&mut slice) { + Ok(0) => return, + Ok(n) => { + let _ = tcp_read_tx.send(read_storage[..n].to_vec()).await; + } + Err(e) if e.kind() == io::ErrorKind::WouldBlock => { + async_support::yield_async().await; + } + Err(e) => { + debug!("wasi-tls: TCP read error: {:?}", e); + return; + } + } + } + } + }; + + let background = Abortable::new( + async move { + futures_util::join!( + socket_pump, + // Task 1: App cleartext → wit stream (for encryption) + async { + while let Some(data) = app_cleartext_rx.recv().await { + debug!("wasi-tls: writing {} cleartext bytes to encrypt", data.len()); + let _ = cleartext_tx.write(data).await; + } + drop(cleartext_tx); + }, + // Task 2: Encrypted wit stream → tcp_write channel + async { + while let Some(byte) = encrypted_rx.next().await { + let _ = tcp_write_tx.send(vec![byte]).await; + } + drop(encrypted_rx); + }, + // Task 3: tcp_read channel → ciphertext wit stream (for decryption) + async { + while let Some(data) = tcp_read_rx.recv().await { + debug!("wasi-tls: forwarding {} bytes to decrypt", data.len()); + for b in data { + let _ = ciphertext_tx.write(vec![b]).await; + } + } + drop(ciphertext_tx); + }, + // Task 4: Decrypted wit stream → app-facing channel + async { + while let Some(byte) = decrypted_rx.next().await { + let _ = app_decrypted_tx.send(vec![byte]).await; + } + drop(decrypted_rx); + drop(app_decrypted_tx); + }, + ); + }, + abort_registration, + ); + + async_support::spawn(async move { + let _ = background.await; + }); + + // Perform the TLS handshake. This drives the connector to exchange + // handshake bytes through the send/receive pipelines we set up above. + wasi::tls::client::Connector::connect(connector, hostname.clone()) + .await + .map_err(|e| crate::Error::tls(e.to_debug_string()))?; + + debug!("wasi-tls: handshake complete for {}", hostname); + + Ok(WasiTlsSocket { + tx: WasiPollSender::new(app_cleartext_tx), + rx: app_decrypted_rx, + buf: BytesMut::new(), + abort_handle, + }) +} diff --git a/sqlx-core/src/net/tls/wasi-tls.wit b/sqlx-core/src/net/tls/wasi-tls.wit new file mode 100644 index 0000000000..6bb3e04781 --- /dev/null +++ b/sqlx-core/src/net/tls/wasi-tls.wit @@ -0,0 +1,35 @@ +package wasi:tls@0.3.0-draft; + +interface types { + resource error { + to-debug-string: func() -> string; + } +} + +interface client { + use types.{error}; + + resource connector { + constructor(); + + /// Set up the encryption stream transform. + /// This takes an unprotected `cleartext` application data stream and + /// returns an encrypted data stream, ready to be sent out over the network. + /// Closing the `cleartext` stream will cause a `close_notify` packet to be emitted on the returned output stream. + send: func(cleartext: stream) -> tuple, future>>; + + /// Set up the decryption stream transform. + /// This takes an encrypted data stream, as received via e.g. the network, + /// and returns a decrypted application data stream. + receive: func(ciphertext: stream) -> tuple, future>>; + + /// Perform the handshake. + /// The `send` & `receive` streams must be set up before calling this method. + connect: static async func(this: connector, server-name: string) -> result<_, error>; + } +} + +world tls-client { + import types; + import client; +} diff --git a/sqlx-core/src/rt/mod.rs b/sqlx-core/src/rt/mod.rs index 273a1bfcd9..b83dbb91af 100644 --- a/sqlx-core/src/rt/mod.rs +++ b/sqlx-core/src/rt/mod.rs @@ -4,6 +4,7 @@ use std::pin::Pin; use std::task::{Context, Poll}; use std::time::Duration; +#[cfg(not(target_arch = "wasm32"))] use cfg_if::cfg_if; #[cfg(feature = "_rt-async-io")] @@ -12,6 +13,9 @@ pub mod rt_async_io; #[cfg(feature = "_rt-tokio")] pub mod rt_tokio; +#[cfg(target_arch = "wasm32")] +pub mod rt_wasip3; + #[derive(Debug, thiserror::Error)] #[error("operation timed out")] pub struct TimeoutError; @@ -20,7 +24,7 @@ pub enum JoinHandle { #[cfg(feature = "_rt-async-std")] AsyncStd(async_std::task::JoinHandle), - #[cfg(feature = "_rt-tokio")] + #[cfg(any(feature = "_rt-tokio", target_arch = "wasm32"))] Tokio(tokio::task::JoinHandle), // Implementation shared by `smol` and `async-global-executor` @@ -35,13 +39,30 @@ pub async fn timeout(duration: Duration, f: F) -> Result Ok(res), + _ = timer => Err(TimeoutError), + }; + } + + #[cfg(all(feature = "_rt-tokio", not(target_arch = "wasm32")))] if rt_tokio::available() { return tokio::time::timeout(duration, f) .await .map_err(|_| TimeoutError); } + #[cfg(not(target_arch = "wasm32"))] cfg_if! { if #[cfg(feature = "_rt-async-io")] { rt_async_io::timeout(duration, f).await @@ -52,11 +73,20 @@ pub async fn timeout(duration: Duration, f: F) -> Result(fut: F) -> JoinHandle where @@ -90,6 +121,17 @@ where } } +#[cfg(target_arch = "wasm32")] +#[track_caller] +pub fn spawn(fut: F) -> JoinHandle +where + F: Future + 'static, + F::Output: 'static, +{ + JoinHandle::Tokio(tokio::task::spawn_local(fut)) +} + +#[cfg(not(target_arch = "wasm32"))] #[track_caller] pub fn spawn_blocking(f: F) -> JoinHandle where @@ -145,18 +187,42 @@ pub async fn yield_now() { #[track_caller] pub fn test_block_on(f: F) -> F::Output { - cfg_if! { - if #[cfg(feature = "_rt-async-io")] { - async_io::block_on(f) - } else if #[cfg(feature = "_rt-tokio")] { - tokio::runtime::Builder::new_current_thread() - .enable_all() - .build() - .expect("failed to start Tokio runtime") - .block_on(f) - } else { - missing_rt(f) - } + #[cfg(feature = "_rt-async-io")] + { + return async_io::block_on(f); + } + + #[cfg(target_arch = "wasm32")] + { + return futures::executor::block_on(f); + } + + #[cfg(all(feature = "_rt-tokio", not(target_arch = "wasm32")))] + { + let rt = tokio::runtime::Builder::new_current_thread() + .enable_all() + .build() + .expect("failed to start Tokio runtime"); + return rt.block_on(f); + } + + #[cfg(all( + feature = "_rt-async-std", + not(feature = "_rt-async-io"), + not(any(feature = "_rt-tokio", target_arch = "wasm32")) + ))] + { + return async_std::task::block_on(f); + } + + #[cfg(not(any( + feature = "_rt-async-io", + feature = "_rt-async-std", + feature = "_rt-tokio", + target_arch = "wasm32", + )))] + { + missing_rt(f) } } @@ -184,7 +250,7 @@ impl Future for JoinHandle { .expect("BUG: task taken") .poll(cx), - #[cfg(feature = "_rt-tokio")] + #[cfg(any(feature = "_rt-tokio", target_arch = "wasm32"))] Self::Tokio(handle) => Pin::new(handle) .poll(cx) .map(|res| res.expect("spawned task panicked")), diff --git a/sqlx-core/src/rt/rt_tokio/mod.rs b/sqlx-core/src/rt/rt_tokio/mod.rs index ce699456db..b22a4453a7 100644 --- a/sqlx-core/src/rt/rt_tokio/mod.rs +++ b/sqlx-core/src/rt/rt_tokio/mod.rs @@ -1,3 +1,4 @@ +#[cfg(not(target_arch = "wasm32"))] mod socket; pub fn available() -> bool { diff --git a/sqlx-core/src/rt/rt_wasip3/mod.rs b/sqlx-core/src/rt/rt_wasip3/mod.rs new file mode 100644 index 0000000000..1272f14432 --- /dev/null +++ b/sqlx-core/src/rt/rt_wasip3/mod.rs @@ -0,0 +1,663 @@ +use bytes::BytesMut; +use core::future::Future; +use core::pin::Pin; +use core::task::{Context, Poll}; +use std::sync::Arc; +use futures_util::future::{AbortHandle, Abortable}; +use tokio::sync::mpsc; +use wit_bindgen::rt::async_support; +use futures::channel::oneshot; + +use crate::net::WithSocket; +use tracing::debug; + +mod socket; + +pub struct JoinHandle { + rx: oneshot::Receiver, +} + +impl Future for JoinHandle { + type Output = T; + + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + match Pin::new(&mut self.rx).poll(cx) { + Poll::Ready(Ok(v)) => Poll::Ready(v), + Poll::Ready(Err(oneshot::Canceled)) => panic!("wasip3 JoinHandle canceled"), + Poll::Pending => Poll::Pending, + } + } +} + +pub fn spawn(fut: impl Future + 'static) -> JoinHandle { + let (tx, rx) = oneshot::channel(); + async_support::spawn(async move { + let v = fut.await; + _ = tx.send(v); + }); + JoinHandle { rx } +} + +// A tiny poll-aware sender shim backed by `futures::channel::mpsc::Sender`. +// This provides the minimal API `socket.rs` expects: `try_send`, `get_ref` and +// `poll_reserve`. +pub struct WasiPollSender { + inner: Option>, +} + +impl WasiPollSender { + pub fn new(s: mpsc::Sender) -> Self { + Self { inner: Some(s) } + } + + pub fn get_ref(&self) -> Option<&mpsc::Sender> { + // Note: inner holds a `tokio::sync::mpsc::Sender` stored as a + // `Option>` (type alias imported above). Return a + // reference to it if present. + self.inner.as_ref() + } + + pub fn try_send(&self, item: T) -> Result<(), ()> { + if let Some(s) = &self.inner { + s.try_send(item).map_err(|_| ()) + } else { + Err(()) + } + } + + pub fn poll_reserve(&self, _cx: &mut Context<'_>) -> Poll> { + // There's no exact `poll_reserve` equivalent in futures mpsc. We emulate + // it by checking if `poll_ready` would be `Ready` by attempting to + // reserve via a short-lived future that yields `Ready` when the sink + // can accept an item. For simplicity, we attempt a non-allocating + // check: futures mpsc provides `poll_ready` on the Sink trait but + // that's not directly available here. As a pragmatic approach, treat + // the sender as always ready and return Pending only if the channel + // is closed. + if self.inner.is_some() { + Poll::Ready(Ok(())) + } else { + Poll::Ready(Err(())) + } + } +} + +pub struct TcpSocket { + pub tx: WasiPollSender>, + pub rx: mpsc::Receiver>, + pub buf: BytesMut, + // Abort handle for the background task spawned with `async_support::spawn`. + pub abort_handle: AbortHandle, +} + +impl Drop for TcpSocket { + fn drop(&mut self) { + // Abort the background task if it's still running. + self.abort_handle.abort(); + } +} + +pub async fn connect_tcp( + _host: &str, + port: u16, + with_socket: Ws, +) -> crate::Result { + // address resolution requires additional processing + // let addresses = wasip3::sockets::ip_name_lookup::resolve_addresses(host.to_string()) + // .await + // .map_err(|e| { + // crate::Error::Io(std::io::Error::new( + // std::io::ErrorKind::Other, + // format!("DNS failed: {:?}", e), + // )) + // })?; + + // let ip = addresses.into_iter().next().ok_or_else(|| { + // crate::Error::Io(std::io::Error::new( + // std::io::ErrorKind::Other, + // "No addresses found", + // )) + // })?; + + // let addr = match ip { + // wasip3::sockets::types::IpAddress::Ipv4(ipv4) => { + // IpSocketAddress::Ipv4(wasip3::sockets::types::Ipv4SocketAddress { + // address: ipv4, + // port, + // }) + // } + // wasip3::sockets::types::IpAddress::Ipv6(ipv6) => { + // IpSocketAddress::Ipv6(wasip3::sockets::types::Ipv6SocketAddress { + // address: ipv6, + // port, + // flow_info: 0, + // scope_id: 0, + // }) + // } + // }; + debug!("wasip3: creating tcp socket for port {}", port); + let sock = + wasip3::sockets::types::TcpSocket::create(wasip3::sockets::types::IpAddressFamily::Ipv4) + .expect("failed to create TCP socket"); + debug!("wasip3: created tcp socket for port {}", port); + sock.connect(wasip3::sockets::types::IpSocketAddress::Ipv4( + wasip3::sockets::types::Ipv4SocketAddress { + address: (127, 0, 0, 1), + port, + }, + )) + .await + .map_err(|e| { + debug!("wasip3: connect failed: {:?}", e); + e + }) + .expect(&format!("failed to connect to 127.0.0.1:{port}")); + + // explicit channel item types so the compiler can infer types used below + let (rx_tx, rx_rx) = mpsc::channel::>(1); + let (tx_tx, mut tx_rx) = mpsc::channel::>(1); + let (mut send_tx, send_rx) = wasip3::wit_stream::new(); + debug!("wasip3: created wit_stream for send/recv"); + let (mut recv_rx, recv_fut) = sock.receive(); + + // Spawn a background task using the wasip3 async runtime and make it abortable. + let (abort_handle, abort_registration) = AbortHandle::new_pair(); + // Give the wasip3 scheduler a quick yield before spawning the background + // task. Use the host-aware `yield_async` so spawned tasks are eligible to + // be polled promptly by the local runtime. + async_support::yield_async().await; + let background = Abortable::new( + async move { + let sock = Arc::new(sock); + debug!("wasip3: background task starting; sock arc cloned"); + + let (ready_tx, ready_rx) = oneshot::channel(); + let spawn_ts = std::time::SystemTime::now() + .duration_since(std::time::UNIX_EPOCH) + .map(|d| d.as_millis()) + .unwrap_or_default(); + debug!("wasip3: spawning sock.send task at {}ms", spawn_ts); + + async_support::spawn({ + let sock = Arc::clone(&sock); + async move { + let start_ts = std::time::SystemTime::now() + .duration_since(std::time::UNIX_EPOCH) + .map(|d| d.as_millis()) + .unwrap_or_default(); + debug!("wasip3: sock.send task started at {}ms", start_ts); + let fut = sock.send(send_rx); + let sig_ts = std::time::SystemTime::now() + .duration_since(std::time::UNIX_EPOCH) + .map(|d| d.as_millis()) + .unwrap_or_default(); + _ = ready_tx.send(()); + debug!("wasip3: sock.send signalled ready at {}ms", sig_ts); + match fut.await { + Ok(_) => { + let done_ts = std::time::SystemTime::now() + .duration_since(std::time::UNIX_EPOCH) + .map(|d| d.as_millis()) + .unwrap_or_default(); + debug!("wasip3: sock.send completed at {}ms", done_ts); + } + Err(e) => { + let err_ts = std::time::SystemTime::now() + .duration_since(std::time::UNIX_EPOCH) + .map(|d| d.as_millis()) + .unwrap_or_default(); + debug!("wasip3: sock.send error at {}ms: {:?}", err_ts, e); + } + } + drop(sock); + } + }); + // Yield after spawning the send task so the runtime can poll it. + async_support::yield_async().await; + async_support::spawn({ + let sock = Arc::clone(&sock); + async move { + let start_ts = std::time::SystemTime::now() + .duration_since(std::time::UNIX_EPOCH) + .map(|d| d.as_millis()) + .unwrap_or_default(); + debug!("wasip3: recv_fut task started at {}ms", start_ts); + match recv_fut.await { + Ok(_) => { + let done_ts = std::time::SystemTime::now() + .duration_since(std::time::UNIX_EPOCH) + .map(|d| d.as_millis()) + .unwrap_or_default(); + debug!("wasip3: recv_fut completed at {}ms", done_ts); + } + Err(e) => { + let err_ts = std::time::SystemTime::now() + .duration_since(std::time::UNIX_EPOCH) + .map(|d| d.as_millis()) + .unwrap_or_default(); + debug!("wasip3: recv_fut error at {}ms: {:?}", err_ts, e); + } + } + drop(sock); + } + }); + // Yield to the wasip3 scheduler to give the spawned tasks a chance + // to be polled immediately. Without this yield the local runtime + // may not poll newly spawned tasks until the current task yields, + // which can cause head-of-line blocking observed during handshakes. + async_support::yield_async().await; + futures_util::join!( + async { + while let Some(result) = recv_rx.next().await { + // `recv_rx` yields single bytes from the wasip3 receive stream. + debug!("wasip3: recv_rx.next yielded byte: {:#x}", result); + _ = rx_tx.send(vec![result]).await; + } + drop(recv_rx); + drop(rx_tx); + }, + async { + _ = ready_rx.await; + debug!("wasip3: send task ready, draining tx_rx -> send_tx"); + while let Some(buf) = tx_rx.recv().await { + debug!("wasip3: writing {} bytes to send_tx", buf.len()); + let _ = send_tx.write(buf).await; + } + drop(tx_rx); + drop(send_tx); + }, + ); + }, + abort_registration, + ); + + async_support::spawn(async move { + let _ = background.await; + }); + Ok(with_socket + .with_socket(TcpSocket { + tx: WasiPollSender::new(tx_tx), + rx: rx_rx, + buf: bytes::BytesMut::new(), + abort_handle, + }) + .await) +} + +#[cfg(test)] +mod tests { + use super::*; + use std::sync::atomic::{AtomicBool, AtomicU32, Ordering}; + use std::sync::Arc; + use std::time::{Duration, Instant}; + + #[test] + fn test_spawn_completes_successfully() { + async { + let handle = spawn(async { 42 }); + let result = handle.await; + assert_eq!(result, 42); + }; + } + + #[test] + fn test_spawn_with_async_computation() { + async { + let handle = spawn(async { + let mut sum = 0; + for i in 1..=10 { + sum += i; + } + sum + }); + + let result = handle.await; + assert_eq!(result, 55); + }; + } + + #[test] + fn test_spawn_multiple_tasks() { + async { + let handle1 = spawn(async { 1 }); + let handle2 = spawn(async { 2 }); + let handle3 = spawn(async { 3 }); + + let result1 = handle1.await; + let result2 = handle2.await; + let result3 = handle3.await; + + assert_eq!(result1 + result2 + result3, 6); + }; + } + + #[test] + fn test_spawn_with_sleep() { + async { + let started = Instant::now(); + + let handle = spawn(async { + crate::rt::sleep(Duration::from_millis(100)).await; + "completed" + }); + + let result = handle.await; + let elapsed = started.elapsed(); + + assert_eq!(result, "completed"); + assert!(elapsed >= Duration::from_millis(100)); + }; + } + + #[test] + fn test_spawn_nested_tasks() { + async { + let outer = spawn(async { + let inner = spawn(async { 10 }); + let value = inner.await; + value * 2 + }); + + let result = outer.await; + assert_eq!(result, 20); + }; + } + + #[test] + fn test_spawn_with_shared_state() { + async { + let counter = Arc::new(AtomicU32::new(0)); + let counter_clone = counter.clone(); + + let handle = spawn(async move { + counter_clone.fetch_add(1, Ordering::SeqCst); + counter_clone.fetch_add(1, Ordering::SeqCst); + }); + + handle.await; + assert_eq!(counter.load(Ordering::SeqCst), 2); + }; + } + + #[test] + fn test_spawn_concurrent_tasks_with_shared_state() { + async { + let counter = Arc::new(AtomicU32::new(0)); + let mut handles = vec![]; + + for _ in 0..5 { + let counter_clone = counter.clone(); + let handle = spawn(async move { + counter_clone.fetch_add(1, Ordering::SeqCst); + }); + handles.push(handle); + } + + for handle in handles { + handle.await; + } + + assert_eq!(counter.load(Ordering::SeqCst), 5); + }; + } + + #[test] + fn test_sleep_duration_accuracy() { + async { + let durations = [ + Duration::from_millis(50), + Duration::from_millis(100), + Duration::from_millis(200), + ]; + + for expected_duration in durations { + let start = Instant::now(); + crate::rt::sleep(expected_duration).await; + let elapsed = start.elapsed(); + + // Allow for some timing variance (±20ms) + assert!( + elapsed >= expected_duration, + "Sleep was too short: expected {:?}, got {:?}", + expected_duration, + elapsed + ); + assert!( + elapsed < expected_duration + Duration::from_millis(50), + "Sleep was too long: expected {:?}, got {:?}", + expected_duration, + elapsed + ); + } + }; + } + + #[test] + fn test_sleep_zero_duration() { + async { + let start = Instant::now(); + crate::rt::sleep(Duration::ZERO).await; + let elapsed = start.elapsed(); + + // Should complete very quickly + assert!(elapsed < Duration::from_millis(10)); + }; + } + + #[test] + fn test_timeout_completes_before_deadline() { + async { + let result = crate::rt::timeout(Duration::from_secs(1), async { + crate::rt::sleep(Duration::from_millis(50)).await; + 42 + }) + .await; + + assert!(result.is_ok()); + assert_eq!(result.unwrap(), 42); + }; + } + + #[test] + fn test_timeout_exceeds_deadline() { + async { + let result = crate::rt::timeout(Duration::from_millis(50), async { + crate::rt::sleep(Duration::from_millis(200)).await; + 42 + }) + .await; + + assert!(result.is_err()); + }; + } + + #[test] + fn test_timeout_immediate_completion() { + async { + let result = crate::rt::timeout(Duration::from_secs(1), async { "immediate" }).await; + + assert!(result.is_ok()); + assert_eq!(result.unwrap(), "immediate"); + }; + } + + #[test] + fn test_timeout_with_computation() { + async { + let result = crate::rt::timeout(Duration::from_secs(1), async { + let mut sum = 0; + for i in 1..=100 { + sum += i; + } + sum + }) + .await; + + assert!(result.is_ok()); + assert_eq!(result.unwrap(), 5050); + }; + } + + #[test] + fn test_spawn_and_timeout_combined() { + async { + let handle = spawn(async { + crate::rt::timeout(Duration::from_millis(100), async { + crate::rt::sleep(Duration::from_millis(50)).await; + "success" + }) + .await + }); + + let result = handle.await; + assert!(result.is_ok()); + assert_eq!(result.unwrap(), "success"); + }; + } + + #[test] + fn test_multiple_sleeps_sequential() { + async { + let start = Instant::now(); + + crate::rt::sleep(Duration::from_millis(50)).await; + crate::rt::sleep(Duration::from_millis(50)).await; + crate::rt::sleep(Duration::from_millis(50)).await; + + let elapsed = start.elapsed(); + + // Total should be at least 150ms + assert!(elapsed >= Duration::from_millis(150)); + }; + } + + #[test] + fn test_multiple_sleeps_concurrent() { + async { + let start = Instant::now(); + + let h1 = spawn(async { + crate::rt::sleep(Duration::from_millis(100)).await; + }); + let h2 = spawn(async { + crate::rt::sleep(Duration::from_millis(100)).await; + }); + let h3 = spawn(async { + crate::rt::sleep(Duration::from_millis(100)).await; + }); + + h1.await; + h2.await; + h3.await; + + let elapsed = start.elapsed(); + + // Should complete in ~100ms, not 300ms (concurrent execution) + assert!(elapsed < Duration::from_millis(200)); + }; + } + + #[test] + fn test_join_handle_future_trait() { + async { + use std::future::Future; + use std::pin::Pin; + use std::task::{Context, Poll}; + + let handle = spawn(async { 99 }); + + // Pin the handle to test Future implementation + let mut pinned = Box::pin(handle); + + // Create a simple waker for testing + let waker = futures_util::task::noop_waker(); + let mut cx = Context::from_waker(&waker); + + // Poll until ready + loop { + match pinned.as_mut().poll(&mut cx) { + Poll::Ready(value) => { + assert_eq!(value, 99); + break; + } + Poll::Pending => continue, + } + } + }; + } + + #[test] + fn test_spawn_with_boolean_result() { + async { + let flag = Arc::new(AtomicBool::new(false)); + let flag_clone = flag.clone(); + + let handle = spawn(async move { + flag_clone.store(true, Ordering::SeqCst); + flag_clone.load(Ordering::SeqCst) + }); + + let result = handle.await; + assert!(result); + assert!(flag.load(Ordering::SeqCst)); + }; + } + + #[test] + fn test_complex_async_workflow() { + async { + // Simulate a complex workflow with spawning, sleeping, and timeouts + let step1 = spawn(async { + crate::rt::sleep(Duration::from_millis(50)).await; + 10 + }); + + let step2 = spawn(async { + crate::rt::sleep(Duration::from_millis(30)).await; + 20 + }); + + let result1 = step1.await; + let result2 = step2.await; + + let step3 = spawn(async move { + crate::rt::timeout(Duration::from_millis(100), async { result1 + result2 }).await + }); + + let final_result = step3.await; + assert!(final_result.is_ok()); + assert_eq!(final_result.unwrap(), 30); + }; + } + + #[test] + fn test_spawn_return_string() { + async { + let handle = spawn(async { String::from("Hello from WASI!") }); + + let result = handle.await; + assert_eq!(result, "Hello from WASI!"); + }; + } + + #[test] + fn test_spawn_with_option_result() { + async { + let handle = spawn(async { Some(42) }); + + let result = handle.await; + assert_eq!(result, Some(42)); + }; + } + + #[test] + fn test_spawn_with_result_type() { + async { + let handle = spawn(async { Ok::(100) }); + + let result = handle.await; + assert!(result.is_ok()); + assert_eq!(result.unwrap(), 100); + }; + } +} diff --git a/sqlx-core/src/rt/rt_wasip3/socket.rs b/sqlx-core/src/rt/rt_wasip3/socket.rs new file mode 100644 index 0000000000..13c386d00e --- /dev/null +++ b/sqlx-core/src/rt/rt_wasip3/socket.rs @@ -0,0 +1,93 @@ +use core::task::{Context, Poll}; + +use bytes::BufMut as _; +use std::io; +use tokio::sync::mpsc::error::TryRecvError; + +use crate::io::ReadBuf; +use crate::net::Socket; + +impl Socket for super::TcpSocket { + fn try_read(&mut self, buf: &mut dyn ReadBuf) -> io::Result { + let n = buf.remaining_mut(); + + // First, drain any buffered data + if !self.buf.is_empty() { + let to_copy = n.min(self.buf.len()); + buf.put_slice(&self.buf.split_to(to_copy)); + return Ok(to_copy); + } + + // Try to receive new data + match self.rx.try_recv() { + Ok(rx_vec) => { + if rx_vec.is_empty() { + return Err(io::ErrorKind::WouldBlock.into()); + } + + if rx_vec.len() <= n { + // All data fits in the buffer + buf.put_slice(&rx_vec); + Ok(rx_vec.len()) + } else { + // Data is larger than buffer, store remainder + buf.put_slice(&rx_vec[..n]); + self.buf.extend_from_slice(&rx_vec[n..]); + Ok(n) + } + } + Err(TryRecvError::Empty) => Err(io::ErrorKind::WouldBlock.into()), + Err(TryRecvError::Disconnected) => Ok(0), + } + } + + fn try_write(&mut self, buf: &[u8]) -> io::Result { + if buf.is_empty() { + return Ok(0); + } + + let n = buf.len(); + match self.tx.try_send(buf.to_vec()) { + Ok(()) => Ok(n), + Err(_) => Err(io::ErrorKind::WouldBlock.into()), + } + } + + fn poll_read_ready(&mut self, cx: &mut Context<'_>) -> Poll> { + // If we have buffered data, we're ready to read + if !self.buf.is_empty() { + return Poll::Ready(Ok(())); + } + + match self.rx.poll_recv(cx) { + Poll::Ready(Some(v)) => { + if !v.is_empty() { + self.buf.extend(v); + Poll::Ready(Ok(())) + } else { + // Empty vec received, wait for more + Poll::Pending + } + } + Poll::Ready(None) => { + // Channel closed + Poll::Ready(Ok(())) + } + Poll::Pending => Poll::Pending, + } + } + + fn poll_write_ready(&mut self, cx: &mut Context<'_>) -> Poll> { + match self.tx.poll_reserve(cx) { + Poll::Ready(Ok(())) => Poll::Ready(Ok(())), + Poll::Ready(Err(())) => Poll::Ready(Err(io::ErrorKind::ConnectionReset.into())), + Poll::Pending => Poll::Pending, + } + } + + fn poll_shutdown(&mut self, _cx: &mut Context<'_>) -> Poll> { + // Drop the sender to signal shutdown + // The abort_handle will be dropped when TcpSocket is dropped + Poll::Ready(Ok(())) + } +} diff --git a/sqlx-core/src/wasm/fs.rs b/sqlx-core/src/wasm/fs.rs new file mode 100644 index 0000000000..394ad58ed0 --- /dev/null +++ b/sqlx-core/src/wasm/fs.rs @@ -0,0 +1,225 @@ +use std::collections::VecDeque; +use std::future::Future; +use std::io; +use std::path::{Component, Path, PathBuf}; +use std::pin::Pin; + +use wasip3::filesystem::{ + preopens, + types::{DescriptorFlags, DescriptorType, ErrorCode, OpenFlags, PathFlags}, +}; + +use crate::fs::{DirEntry, ReadDir}; + +// --------------------------------------------------------------------------- +// Helpers +// --------------------------------------------------------------------------- + +/// Find the preopened directory descriptor whose path best covers `path`, +/// and return `(descriptor, relative_path_string)`. +/// +/// WASI uses a capability model: all paths must be relative to a preopened +/// descriptor. We pick the preopen with the longest matching prefix so that +/// the most specific sandbox root wins. +fn resolve_path(path: &Path) -> io::Result<(wasip3::filesystem::types::Descriptor, String)> { + let path_str = path + .to_str() + .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidInput, "non-UTF-8 path"))?; + + let dirs = preopens::get_directories(); + + // Relative paths: use the first preopen as root. + if !path_str.starts_with('/') { + if let Some((desc, _)) = dirs.into_iter().next() { + return Ok((desc, path_str.trim_start_matches("./").to_string())); + } + return Err(io::Error::new(io::ErrorKind::NotFound, "no preopens available")); + } + + // Absolute paths: find the preopen whose string is the longest prefix. + let best = dirs + .into_iter() + .filter_map(|(desc, root)| { + let normalized = root.trim_end_matches('/'); + if path_str.starts_with(normalized) { + let rel = path_str[normalized.len()..] + .trim_start_matches('/') + .to_string(); + Some((desc, rel, normalized.len())) + } else { + None + } + }) + .max_by_key(|(_, _, depth)| *depth); + + best.map(|(desc, rel, _)| (desc, rel)) + .ok_or_else(|| { + io::Error::new( + io::ErrorKind::NotFound, + format!("no preopen covers path: {}", path.display()), + ) + }) +} + +/// Map a WASI `ErrorCode` to a `std::io::Error`. +fn wasi_err(code: ErrorCode) -> io::Error { + use io::ErrorKind as K; + let kind = match code { + ErrorCode::Access | ErrorCode::NotPermitted => K::PermissionDenied, + ErrorCode::NoEntry => K::NotFound, + ErrorCode::Exist => K::AlreadyExists, + ErrorCode::NotDirectory => K::NotADirectory, + ErrorCode::IsDirectory => K::IsADirectory, + ErrorCode::ReadOnly => K::ReadOnlyFilesystem, + ErrorCode::NotEmpty => K::DirectoryNotEmpty, + ErrorCode::NameTooLong => K::InvalidInput, + ErrorCode::InsufficientMemory => K::OutOfMemory, + ErrorCode::Unsupported => K::Unsupported, + ErrorCode::InvalidSeek => K::InvalidInput, + _ => K::Other, + }; + io::Error::new(kind, format!("{code:?}")) +} + +// --------------------------------------------------------------------------- +// Public async fs functions +// --------------------------------------------------------------------------- + +pub async fn read>(path: P) -> io::Result> { + let (dir, rel) = resolve_path(path.as_ref())?; + let file = dir + .open_at( + PathFlags::SYMLINK_FOLLOW, + rel, + OpenFlags::empty(), + DescriptorFlags::READ, + ) + .await + .map_err(wasi_err)?; + + // read_via_stream is NOT async — returns (StreamReader, FutureReader<…>) directly. + // Await the stream to collect all bytes, then await the completion future for errors. + let (stream, result_fut) = file.read_via_stream(0); + let bytes = stream.collect().await; + result_fut.await.map_err(wasi_err)?; + Ok(bytes) +} + +pub async fn read_to_string>(path: P) -> io::Result { + let bytes = read(path).await?; + String::from_utf8(bytes).map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e)) +} + +pub async fn create_dir_all>(path: P) -> io::Result<()> { + let (dir, rel) = resolve_path(path.as_ref())?; + if rel.is_empty() { + return Ok(()); + } + + let mut cur = String::new(); + for component in Path::new(&rel).components() { + if let Component::Normal(c) = component { + let c = c.to_str().ok_or_else(|| { + io::Error::new(io::ErrorKind::InvalidInput, "non-UTF-8 path component") + })?; + if !cur.is_empty() { + cur.push('/'); + } + cur.push_str(c); + match dir.create_directory_at(cur.clone()).await { + Ok(()) | Err(ErrorCode::Exist) => {} + Err(e) => return Err(wasi_err(e)), + } + } + } + Ok(()) +} + +pub async fn remove_file>(path: P) -> io::Result<()> { + let (dir, rel) = resolve_path(path.as_ref())?; + // unlink_file_at accepts paths with subdirectory components (like unlinkat(2)) + dir.unlink_file_at(rel).await.map_err(wasi_err) +} + +pub async fn remove_dir>(path: P) -> io::Result<()> { + let (dir, rel) = resolve_path(path.as_ref())?; + dir.remove_directory_at(rel).await.map_err(wasi_err) +} + +pub async fn remove_dir_all>(path: P) -> io::Result<()> { + remove_dir_all_inner(path.as_ref()).await +} + +/// Boxed recursive helper required because async recursion needs an explicit +/// `Box::pin` to give the compiler a known stack size. +fn remove_dir_all_inner(path: &Path) -> Pin> + '_>> { + Box::pin(async move { + let (dir, rel) = resolve_path(path)?; + let child_dir = dir + .open_at( + PathFlags::empty(), + rel, + OpenFlags::DIRECTORY, + DescriptorFlags::READ | DescriptorFlags::MUTATE_DIRECTORY, + ) + .await + .map_err(wasi_err)?; + + let (stream, result_fut) = child_dir.read_directory(); + let entries = stream.collect().await; + result_fut.await.map_err(wasi_err)?; + + for entry in entries { + if entry.name == "." || entry.name == ".." { + continue; + } + let child_path = path.join(&entry.name); + if matches!(entry.type_, DescriptorType::Directory) { + remove_dir_all_inner(&child_path).await?; + } else { + remove_file(&child_path).await?; + } + } + + remove_dir(path).await + }) +} + +pub async fn read_dir(path: PathBuf) -> io::Result { + let (dir, rel) = resolve_path(&path)?; + let child_dir = dir + .open_at( + PathFlags::SYMLINK_FOLLOW, + rel, + OpenFlags::DIRECTORY, + DescriptorFlags::READ | DescriptorFlags::MUTATE_DIRECTORY, + ) + .await + .map_err(wasi_err)?; + + let (stream, result_fut) = child_dir.read_directory(); + let raw_entries = stream.collect().await; + result_fut.await.map_err(wasi_err)?; + + let mut entries = VecDeque::new(); + for entry in raw_entries { + if entry.name == "." || entry.name == ".." { + continue; + } + let entry_path = path.join(&entry.name); + // std::fs::metadata is available on wasm32-wasip2 via the standard + // library's WASI P2 syscall bindings. + let metadata = std::fs::metadata(&entry_path)?; + entries.push_back(DirEntry { + path: entry_path, + file_name: entry.name.into(), + metadata, + }); + } + + Ok(ReadDir { entries }) +} + +pub async fn next(read_dir: &mut ReadDir) -> io::Result> { + Ok(read_dir.entries.pop_front()) +} diff --git a/sqlx-core/src/wasm/mod.rs b/sqlx-core/src/wasm/mod.rs new file mode 100644 index 0000000000..d521fbd77e --- /dev/null +++ b/sqlx-core/src/wasm/mod.rs @@ -0,0 +1 @@ +pub mod fs; diff --git a/sqlx-macros/Cargo.toml b/sqlx-macros/Cargo.toml index 95954d72ef..911d1e2214 100644 --- a/sqlx-macros/Cargo.toml +++ b/sqlx-macros/Cargo.toml @@ -61,4 +61,4 @@ syn = { version = "2.0.52", default-features = false, features = ["parsing", "pr quote = { version = "1.0.26", default-features = false } [lints] -workspace = true +workspace = true \ No newline at end of file diff --git a/sqlx-mysql/src/any.rs b/sqlx-mysql/src/any.rs index b0950e0b41..aa436cf716 100644 --- a/sqlx-mysql/src/any.rs +++ b/sqlx-mysql/src/any.rs @@ -8,11 +8,12 @@ use futures_core::future::BoxFuture; use futures_core::stream::BoxStream; use futures_util::{stream, FutureExt, StreamExt, TryFutureExt, TryStreamExt}; use sqlx_core::any::{ - AnyArguments, AnyColumn, AnyConnectOptions, AnyConnectionBackend, AnyQueryResult, AnyRow, + Any, AnyArguments, AnyColumn, AnyConnectOptions, AnyConnectionBackend, AnyQueryResult, AnyRow, AnyStatement, AnyTypeInfo, AnyTypeInfoKind, }; use sqlx_core::connection::Connection; use sqlx_core::database::Database; +use sqlx_core::describe::Describe; use sqlx_core::executor::Executor; use sqlx_core::sql_str::SqlStr; use sqlx_core::transaction::TransactionManager; @@ -140,11 +141,7 @@ impl AnyConnectionBackend for MySqlConnection { }) } - #[cfg(feature = "offline")] - fn describe( - &mut self, - sql: SqlStr, - ) -> BoxFuture<'_, sqlx_core::Result>> { + fn describe(&mut self, sql: SqlStr) -> BoxFuture<'_, sqlx_core::Result>> { Box::pin(async move { let describe = Executor::describe(self, sql).await?; describe.try_into_any() @@ -220,4 +217,4 @@ fn map_result(result: MySqlQueryResult) -> AnyQueryResult { #[allow(clippy::cast_possible_wrap)] last_insert_id: Some(result.last_insert_id as i64), } -} +} \ No newline at end of file diff --git a/sqlx-mysql/src/connection/stream.rs b/sqlx-mysql/src/connection/stream.rs index e6aa8b48c8..fe85b188c1 100644 --- a/sqlx-mysql/src/connection/stream.rs +++ b/sqlx-mysql/src/connection/stream.rs @@ -1,8 +1,6 @@ use std::collections::VecDeque; use std::ops::{Deref, DerefMut}; -use bytes::{Buf, Bytes, BytesMut}; - use crate::error::Error; use crate::io::MySqlBufExt; use crate::io::{ProtocolDecode, ProtocolEncode}; @@ -10,6 +8,8 @@ use crate::net::{BufferedSocket, Socket}; use crate::protocol::response::{EofPacket, ErrPacket, OkPacket, Status}; use crate::protocol::{Capabilities, Packet}; use crate::{MySqlConnectOptions, MySqlDatabaseError}; +use bytes::{Buf, Bytes, BytesMut}; +use log::debug; pub struct MySqlStream> { // Wrapping the socket in `Box` allows us to unsize in-place. @@ -103,7 +103,15 @@ impl MySqlStream { T: ProtocolEncode<'en, Capabilities>, { self.sequence_id = 0; + debug!( + "mysql: send_packet - writing packet (sequence_id={})", + self.sequence_id + ); self.write_packet(payload)?; + debug!( + "mysql: send_packet - flushing write buffer (is_empty={})", + self.socket.write_buffer().is_empty() + ); self.flush().await?; Ok(()) } @@ -112,15 +120,38 @@ impl MySqlStream { where T: ProtocolEncode<'en, Capabilities>, { - self.socket - .write_with(Packet(payload), (self.capabilities, &mut self.sequence_id)) + debug!( + "mysql: write_packet - encoding packet (sequence_id={})", + self.sequence_id + ); + let res = self + .socket + .write_with(Packet(payload), (self.capabilities, &mut self.sequence_id)); + debug!( + "mysql: write_packet - encoded packet, result={:?}", + res.is_ok() + ); + res } async fn recv_packet_part(&mut self) -> Result { // https://dev.mysql.com/doc/dev/mysql-server/8.0.12/page_protocol_basic_packets.html // https://mariadb.com/kb/en/library/0-packet/#standard-packet - let mut header: Bytes = self.socket.read(4).await?; + let mut header: Bytes = match self.socket.read::(4).await { + Ok(h) => { + debug!( + "mysql: recv_packet_part: read header ({} bytes): {:?}", + h.len(), + &h + ); + h + } + Err(e) => { + debug!("mysql: recv_packet_part: error reading header: {:#?}", e); + return Err(e); + } + }; // cannot overflow #[allow(clippy::cast_possible_truncation)] @@ -129,7 +160,19 @@ impl MySqlStream { self.sequence_id = sequence_id.wrapping_add(1); - let payload: Bytes = self.socket.read(packet_size).await?; + let payload: Bytes = match self.socket.read::(packet_size).await { + Ok(p) => { + debug!("mysql: recv_packet_part: read payload ({} bytes)", p.len()); + p + } + Err(e) => { + debug!( + "mysql: recv_packet_part: error reading payload (expected {} bytes): {:#?}", + packet_size, e + ); + return Err(e); + } + }; // TODO: packet compression diff --git a/sqlx-postgres/Cargo.toml b/sqlx-postgres/Cargo.toml index 2943049f0b..8dbee7ab9d 100644 --- a/sqlx-postgres/Cargo.toml +++ b/sqlx-postgres/Cargo.toml @@ -11,9 +11,9 @@ rust-version.workspace = true [features] any = ["sqlx-core/any"] -json = ["dep:serde", "dep:serde_json", "sqlx-core/json"] +json = ["sqlx-core/json"] migrate = ["sqlx-core/migrate"] -offline = ["json", "sqlx-core/offline", "smallvec/serde"] +offline = ["sqlx-core/offline"] # Type Integration features bigdecimal = ["dep:bigdecimal", "dep:num-bigint", "sqlx-core/bigdecimal"] @@ -56,33 +56,33 @@ atoi = "2.0" base64 = { version = "0.22.0", default-features = false, features = ["std"] } bitflags = { version = "2", default-features = false } byteorder = { version = "1.4.3", default-features = false, features = ["std"] } +dotenvy = { workspace = true } hex = "0.4.3" +home = "0.5.5" itoa = "1.0.1" log = "0.4.18" memchr = { version = "2.4.1", default-features = false } num-bigint = { version = "0.4.3", optional = true } -smallvec = { version = "1.7.0" } +smallvec = { version = "1.7.0", features = ["serde"] } stringprep = "0.1.2" +thiserror = "2.0.0" tracing = { version = "0.1.37", features = ["log"] } -whoami = { version = "2.0.2", default-features = false } +whoami = { version = "2.0.0-pre", default-features = false } -dotenvy.workspace = true -thiserror.workspace = true - -serde = { version = "1.0.144", optional = true, features = ["derive"] } -serde_json = { version = "1.0.85", optional = true, features = ["raw_value"] } +serde = { version = "1.0.144", features = ["derive"] } +serde_json = { version = "1.0.85", features = ["raw_value"] } [dependencies.sqlx-core] workspace = true +# We use JSON in the driver implementation itself so there's no reason not to enable it here. +features = ["json"] [dev-dependencies.sqlx] -# FIXME: https://github.com/rust-lang/cargo/issues/15622 -# workspace = true -path = ".." +workspace = true features = ["postgres", "derive"] [target.'cfg(target_os = "windows")'.dependencies] etcetera = "0.10.0" [lints] -workspace = true +workspace = true \ No newline at end of file diff --git a/sqlx-sqlite/Cargo.toml b/sqlx-sqlite/Cargo.toml index 69a79baca7..056a47083a 100644 --- a/sqlx-sqlite/Cargo.toml +++ b/sqlx-sqlite/Cargo.toml @@ -56,7 +56,7 @@ _unstable-docs = [ [dependencies.libsqlite3-sys] # See `sqlx-sqlite/src/lib.rs` for details. -version = ">=0.30.0, <0.37.0" +version = ">=0.30.0, <0.36.0" default-features = false features = [ "pkg-config", @@ -77,16 +77,15 @@ uuid = { workspace = true, optional = true } url = { version = "2.2.2" } percent-encoding = "2.1.0" -form_urlencoded = "1.2.2" +serde_urlencoded = "0.7" -flume = { version = "0.12.0", default-features = false, features = ["async"] } +flume = { version = "0.11.0", default-features = false, features = ["async"] } atoi = "2.0" log = "0.4.18" tracing = { version = "0.1.37", features = ["log"] } - -thiserror.workspace = true +thiserror = "2.0.0" serde = { version = "1.0.145", features = ["derive"], optional = true } regex = { version = "1.5.5", optional = true } @@ -94,15 +93,11 @@ regex = { version = "1.5.5", optional = true } [dependencies.sqlx-core] workspace = true -[dev-dependencies.sqlx] -# FIXME: https://github.com/rust-lang/cargo/issues/15622 -# workspace = true -path = ".." -default-features = false -features = ["macros", "runtime-tokio", "tls-none", "sqlite"] +[dev-dependencies] +sqlx = { workspace = true, features = ["macros", "runtime-tokio", "tls-none", "sqlite"] } [lints] workspace = true [package.metadata.docs.rs] -features = ["__unstable_docs"] +features = ["__unstable_docs"] \ No newline at end of file diff --git a/tests/mysql/wasi_integration_test.rs b/tests/mysql/wasi_integration_test.rs new file mode 100644 index 0000000000..7285cdf235 --- /dev/null +++ b/tests/mysql/wasi_integration_test.rs @@ -0,0 +1,101 @@ +use std::env; +use std::path::PathBuf; +use std::process::Command; + +fn build_wasm_component(component_name: &str) -> PathBuf { + let manifest_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + let component_dir = manifest_dir + .join("tests/mysql/wasm-components") + .join(component_name); + + println!("Building component: {}", component_name); + + let output = Command::new("cargo") + .current_dir(&component_dir) + .args(&["build", "--target", "wasm32-wasip2", "--release"]) + .output() + .expect("Failed to build WASM component"); + + if !output.status.success() { + panic!( + "Failed to build {}: {}", + component_name, + String::from_utf8_lossy(&output.stderr) + ); + } + + // WASM binaries are stored in the workspace root target directory + manifest_dir + .join("target/wasm32-wasip2/release") + .join(format!("{}.wasm", component_name.replace("-", "_"))) +} + +fn run_wasm_test(wasm_path: PathBuf, test_name: &str) -> Result<(), Box> { + run_wasm_test_with_flags(wasm_path, test_name, &[]) +} + +fn run_wasm_test_with_flags( + wasm_path: PathBuf, + test_name: &str, + extra_flags: &[&str], +) -> Result<(), Box> { + println!("Running test: {}", test_name); + + let database_url = "mysql://mysql:Password123!@127.0.0.1:3306/todos"; + + let mut cmd = Command::new("wasmtime"); + cmd.args(&[ + "run", + "-Scli=y", + "-Stcp=y", + "-Sinherit-env=y", + "-Sudp=y", + "-Sp3", + "-Sallow-ip-name-lookup=y", + "-Wcomponent-model-async=y", + "-Sinherit-network=y", + ]); + cmd.args(extra_flags); + cmd.env("DATABASE_URL", database_url) + .arg(wasm_path.as_os_str()); + + let status = cmd.status()?; + + if !status.success() { + return Err(format!("{} failed", test_name).into()); + } + + println!("✓ {} passed!", test_name); + Ok(()) +} + +#[test] +fn test_wasi_mysql_connect() { + let wasm = build_wasm_component("connect-test"); + run_wasm_test(wasm, "Connect Test").expect("Connect test failed"); +} + +#[test] +fn test_wasi_mysql_execute_query() { + let wasm = build_wasm_component("execute-query-test"); + run_wasm_test(wasm, "Execute Query Test").expect("Execute query test failed"); +} + +#[test] +fn test_wasi_mysql_prepared_query() { + let wasm = build_wasm_component("prepared-query-test"); + run_wasm_test(wasm, "Prepared Query Test").expect("Prepared query test failed"); +} + +#[test] +fn test_wasi_mysql_pool_crud() { + let wasm = build_wasm_component("pool-crud-test"); + run_wasm_test(wasm, "Pool CRUD Test").expect("Pool CRUD test failed"); +} + +#[test] +fn test_wasi_mysql_tls_connect() { + let wasm = build_wasm_component("tls-connect-test"); + run_wasm_test_with_flags(wasm, "TLS Connect Test", &["-Stls=y"]) + .expect("TLS connect test failed"); +} diff --git a/tests/mysql/wasm-components/connect-test/Cargo.toml b/tests/mysql/wasm-components/connect-test/Cargo.toml new file mode 100644 index 0000000000..f211f09bbe --- /dev/null +++ b/tests/mysql/wasm-components/connect-test/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "connect-test" +version = "0.1.0" +edition = "2021" +workspace = "../../../../" + +[lib] +crate-type = ["cdylib"] + +[dependencies] +anyhow = "1.0" +futures = "0.3" +sqlx = { path = "../../../../", features = [ "mysql", "runtime-tokio" ] } +clap = { version = "4", features = ["derive"] } +tokio = { version = "1.20.0", features = ["rt"]} +dotenvy = "0.15.0" +wasip3 = "0.5.0" + + +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +sqlx = { path = "../../../../", features = ["tls-native-tls"] } \ No newline at end of file diff --git a/tests/mysql/wasm-components/connect-test/README.md b/tests/mysql/wasm-components/connect-test/README.md new file mode 100644 index 0000000000..6f2f8d6c66 --- /dev/null +++ b/tests/mysql/wasm-components/connect-test/README.md @@ -0,0 +1,41 @@ +# TODOs Example + +## Setup + +1. Declare the database URL + + ``` + export DATABASE_URL="mysql://root:password@localhost/todos" + ``` + +2. Create the database. + + ``` + $ sqlx db create + ``` + +3. Run sql migrations + + ``` + $ sqlx migrate run + ``` + +## Usage + +Add a todo + +``` +cargo run -- add "todo description" +``` + +Complete a todo. + +``` +cargo run -- done +``` + +List all todos + +``` +cargo run +``` diff --git a/tests/mysql/wasm-components/connect-test/migrations/20200718111257_todos.sql b/tests/mysql/wasm-components/connect-test/migrations/20200718111257_todos.sql new file mode 100644 index 0000000000..700d99900f --- /dev/null +++ b/tests/mysql/wasm-components/connect-test/migrations/20200718111257_todos.sql @@ -0,0 +1,6 @@ +CREATE TABLE IF NOT EXISTS todos +( + id BIGINT UNSIGNED PRIMARY KEY NOT NULL AUTO_INCREMENT, + description TEXT NOT NULL, + done BOOLEAN NOT NULL DEFAULT FALSE +); diff --git a/tests/mysql/wasm-components/connect-test/src/lib.rs b/tests/mysql/wasm-components/connect-test/src/lib.rs new file mode 100644 index 0000000000..0c09dd63a5 --- /dev/null +++ b/tests/mysql/wasm-components/connect-test/src/lib.rs @@ -0,0 +1,31 @@ +use sqlx::mysql::MySqlConnection; +use sqlx::Connection; +use std::env; + +async fn run() -> anyhow::Result<()> { + let database_url = env::var("DATABASE_URL")?; + let mut conn = MySqlConnection::connect(&database_url).await?; + conn.ping().await?; + conn.close().await?; + eprintln!("Connect test passed!"); + Ok(()) +} + +wasip3::cli::command::export!(Component); + +struct Component; + +impl wasip3::exports::cli::run::Guest for Component { + async fn run() -> Result<(), ()> { + tokio::task::LocalSet::new() + .run_until(async { + if let Err(err) = run().await { + eprintln!("Connect test failed: {err:#}"); + Err(()) + } else { + Ok(()) + } + }) + .await + } +} diff --git a/tests/mysql/wasm-components/execute-query-test/Cargo.toml b/tests/mysql/wasm-components/execute-query-test/Cargo.toml new file mode 100644 index 0000000000..28a9a9e97e --- /dev/null +++ b/tests/mysql/wasm-components/execute-query-test/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "execute-query-test" +version = "0.1.0" +edition = "2021" +workspace = "../../../.." + +[lib] +crate-type = ["cdylib"] + +[dependencies] +anyhow = "1.0" +futures = "0.3" +sqlx = { path = "../../../../", features = [ "mysql", "runtime-tokio" ] } +clap = { version = "4", features = ["derive"] } +tokio = { version = "1.20.0", features = ["rt"]} +dotenvy = "0.15.0" +wasip3 = "0.5.0" + +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +sqlx = { path = "../../../../", features = ["tls-native-tls"] } \ No newline at end of file diff --git a/tests/mysql/wasm-components/execute-query-test/README.md b/tests/mysql/wasm-components/execute-query-test/README.md new file mode 100644 index 0000000000..6f2f8d6c66 --- /dev/null +++ b/tests/mysql/wasm-components/execute-query-test/README.md @@ -0,0 +1,41 @@ +# TODOs Example + +## Setup + +1. Declare the database URL + + ``` + export DATABASE_URL="mysql://root:password@localhost/todos" + ``` + +2. Create the database. + + ``` + $ sqlx db create + ``` + +3. Run sql migrations + + ``` + $ sqlx migrate run + ``` + +## Usage + +Add a todo + +``` +cargo run -- add "todo description" +``` + +Complete a todo. + +``` +cargo run -- done +``` + +List all todos + +``` +cargo run +``` diff --git a/tests/mysql/wasm-components/execute-query-test/migrations/20200718111257_todos.sql b/tests/mysql/wasm-components/execute-query-test/migrations/20200718111257_todos.sql new file mode 100644 index 0000000000..700d99900f --- /dev/null +++ b/tests/mysql/wasm-components/execute-query-test/migrations/20200718111257_todos.sql @@ -0,0 +1,6 @@ +CREATE TABLE IF NOT EXISTS todos +( + id BIGINT UNSIGNED PRIMARY KEY NOT NULL AUTO_INCREMENT, + description TEXT NOT NULL, + done BOOLEAN NOT NULL DEFAULT FALSE +); diff --git a/tests/mysql/wasm-components/execute-query-test/src/lib.rs b/tests/mysql/wasm-components/execute-query-test/src/lib.rs new file mode 100644 index 0000000000..a0a94730af --- /dev/null +++ b/tests/mysql/wasm-components/execute-query-test/src/lib.rs @@ -0,0 +1,35 @@ +use sqlx::mysql::MySqlConnection; +use sqlx::{Connection, Executor}; +use std::env; + +async fn run() -> anyhow::Result<()> { + let database_url = env::var("DATABASE_URL")?; + let mut conn = MySqlConnection::connect(&database_url).await?; + + let result = conn.execute("DO 1").await?; + // DO statement affects 0 rows but executes successfully + assert_eq!(result.rows_affected(), 0); + + conn.close().await?; + eprintln!("Execute query test passed!"); + Ok(()) +} + +wasip3::cli::command::export!(Component); + +struct Component; + +impl wasip3::exports::cli::run::Guest for Component { + async fn run() -> Result<(), ()> { + tokio::task::LocalSet::new() + .run_until(async { + if let Err(err) = run().await { + eprintln!("Execute query test failed: {err:#}"); + Err(()) + } else { + Ok(()) + } + }) + .await + } +} diff --git a/tests/mysql/wasm-components/pool-crud-test/Cargo.toml b/tests/mysql/wasm-components/pool-crud-test/Cargo.toml new file mode 100644 index 0000000000..877d05d59c --- /dev/null +++ b/tests/mysql/wasm-components/pool-crud-test/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "pool-crud-test" +version = "0.1.0" +edition = "2021" +workspace = "../../../../" + +[lib] +crate-type = ["cdylib"] + +[dependencies] +anyhow = "1.0" +futures = "0.3" +sqlx = { path = "../../../../", features = [ "mysql", "runtime-tokio" ] } +clap = { version = "4", features = ["derive"] } +tokio = { version = "1.20.0", features = ["rt"]} +dotenvy = "0.15.0" +wasip3 = "0.5.0" + +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +sqlx = { path = "../../../../", features = ["tls-native-tls"] } \ No newline at end of file diff --git a/tests/mysql/wasm-components/pool-crud-test/README.md b/tests/mysql/wasm-components/pool-crud-test/README.md new file mode 100644 index 0000000000..6f2f8d6c66 --- /dev/null +++ b/tests/mysql/wasm-components/pool-crud-test/README.md @@ -0,0 +1,41 @@ +# TODOs Example + +## Setup + +1. Declare the database URL + + ``` + export DATABASE_URL="mysql://root:password@localhost/todos" + ``` + +2. Create the database. + + ``` + $ sqlx db create + ``` + +3. Run sql migrations + + ``` + $ sqlx migrate run + ``` + +## Usage + +Add a todo + +``` +cargo run -- add "todo description" +``` + +Complete a todo. + +``` +cargo run -- done +``` + +List all todos + +``` +cargo run +``` diff --git a/tests/mysql/wasm-components/pool-crud-test/migrations/20200718111257_todos.sql b/tests/mysql/wasm-components/pool-crud-test/migrations/20200718111257_todos.sql new file mode 100644 index 0000000000..700d99900f --- /dev/null +++ b/tests/mysql/wasm-components/pool-crud-test/migrations/20200718111257_todos.sql @@ -0,0 +1,6 @@ +CREATE TABLE IF NOT EXISTS todos +( + id BIGINT UNSIGNED PRIMARY KEY NOT NULL AUTO_INCREMENT, + description TEXT NOT NULL, + done BOOLEAN NOT NULL DEFAULT FALSE +); diff --git a/tests/mysql/wasm-components/pool-crud-test/src/lib.rs b/tests/mysql/wasm-components/pool-crud-test/src/lib.rs new file mode 100644 index 0000000000..9b9022a12d --- /dev/null +++ b/tests/mysql/wasm-components/pool-crud-test/src/lib.rs @@ -0,0 +1,74 @@ +use sqlx::mysql::MySqlPoolOptions; +use sqlx::{Executor, Row}; +use std::env; + +async fn run() -> anyhow::Result<()> { + let database_url = env::var("DATABASE_URL")?; + let pool = MySqlPoolOptions::new() + .max_connections(2) + .connect(&database_url) + .await?; + + // Create table + pool.execute( + r#" + CREATE TABLE IF NOT EXISTS wasi_todos ( + id BIGINT PRIMARY KEY AUTO_INCREMENT, + description TEXT NOT NULL, + done BOOL NOT NULL DEFAULT FALSE + ) + "#, + ) + .await?; + + // Insert + let insert_result = sqlx::query("INSERT INTO wasi_todos (description) VALUES (?)") + .bind("Test todo") + .execute(&pool) + .await?; + assert!(insert_result.last_insert_id() > 0); + + // Select + let row = sqlx::query("SELECT id, description, done FROM wasi_todos WHERE id = ?") + .bind(insert_result.last_insert_id()) + .fetch_one(&pool) + .await?; + let description: &str = row.try_get("description")?; + assert_eq!(description, "Test todo"); + + // Update + let update_result = sqlx::query("UPDATE wasi_todos SET done = TRUE WHERE id = ?") + .bind(insert_result.last_insert_id()) + .execute(&pool) + .await?; + assert_eq!(update_result.rows_affected(), 1); + + // Delete + let delete_result = sqlx::query("DELETE FROM wasi_todos WHERE id = ?") + .bind(insert_result.last_insert_id()) + .execute(&pool) + .await?; + assert_eq!(delete_result.rows_affected(), 1); + + eprintln!("Pool CRUD test passed!"); + Ok(()) +} + +wasip3::cli::command::export!(Component); + +struct Component; + +impl wasip3::exports::cli::run::Guest for Component { + async fn run() -> Result<(), ()> { + tokio::task::LocalSet::new() + .run_until(async { + if let Err(err) = run().await { + eprintln!("Pool CRUD test failed: {err:#}"); + Err(()) + } else { + Ok(()) + } + }) + .await + } +} diff --git a/tests/mysql/wasm-components/prepared-query-test/Cargo.toml b/tests/mysql/wasm-components/prepared-query-test/Cargo.toml new file mode 100644 index 0000000000..1f39869d7f --- /dev/null +++ b/tests/mysql/wasm-components/prepared-query-test/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "prepared-query-test" +version = "0.1.0" +edition = "2021" +workspace = "../../../../" + +[lib] +crate-type = ["cdylib"] + +[dependencies] +anyhow = "1.0" +futures = "0.3" +sqlx = { path = "../../../../", features = [ "mysql", "runtime-tokio" ] } +clap = { version = "4", features = ["derive"] } +tokio = { version = "1.20.0", features = ["rt"]} +dotenvy = "0.15.0" +wasip3 = "0.5.0" + + +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +sqlx = { path = "../../../../", features = ["tls-native-tls"] } \ No newline at end of file diff --git a/tests/mysql/wasm-components/prepared-query-test/README.md b/tests/mysql/wasm-components/prepared-query-test/README.md new file mode 100644 index 0000000000..6f2f8d6c66 --- /dev/null +++ b/tests/mysql/wasm-components/prepared-query-test/README.md @@ -0,0 +1,41 @@ +# TODOs Example + +## Setup + +1. Declare the database URL + + ``` + export DATABASE_URL="mysql://root:password@localhost/todos" + ``` + +2. Create the database. + + ``` + $ sqlx db create + ``` + +3. Run sql migrations + + ``` + $ sqlx migrate run + ``` + +## Usage + +Add a todo + +``` +cargo run -- add "todo description" +``` + +Complete a todo. + +``` +cargo run -- done +``` + +List all todos + +``` +cargo run +``` diff --git a/tests/mysql/wasm-components/prepared-query-test/migrations/20200718111257_todos.sql b/tests/mysql/wasm-components/prepared-query-test/migrations/20200718111257_todos.sql new file mode 100644 index 0000000000..700d99900f --- /dev/null +++ b/tests/mysql/wasm-components/prepared-query-test/migrations/20200718111257_todos.sql @@ -0,0 +1,6 @@ +CREATE TABLE IF NOT EXISTS todos +( + id BIGINT UNSIGNED PRIMARY KEY NOT NULL AUTO_INCREMENT, + description TEXT NOT NULL, + done BOOLEAN NOT NULL DEFAULT FALSE +); diff --git a/tests/mysql/wasm-components/prepared-query-test/src/lib.rs b/tests/mysql/wasm-components/prepared-query-test/src/lib.rs new file mode 100644 index 0000000000..f9ec6b710a --- /dev/null +++ b/tests/mysql/wasm-components/prepared-query-test/src/lib.rs @@ -0,0 +1,39 @@ +use sqlx::mysql::MySqlConnection; +use sqlx::Connection; +use std::env; + +async fn run() -> anyhow::Result<()> { + let database_url = env::var("DATABASE_URL")?; + let mut conn = MySqlConnection::connect(&database_url).await?; + + // MySQL returns DOUBLE for arithmetic, so use f64 or cast to INT + let value: i64 = sqlx::query_scalar("SELECT CAST(? + ? AS SIGNED)") + .bind(2_i32) + .bind(3_i32) + .fetch_one(&mut conn) + .await?; + assert_eq!(value, 5); + + conn.close().await?; + eprintln!("Prepared query test passed!"); + Ok(()) +} + +wasip3::cli::command::export!(Component); + +struct Component; + +impl wasip3::exports::cli::run::Guest for Component { + async fn run() -> Result<(), ()> { + tokio::task::LocalSet::new() + .run_until(async { + if let Err(err) = run().await { + eprintln!("Prepared query test failed: {err:#}"); + Err(()) + } else { + Ok(()) + } + }) + .await + } +} diff --git a/tests/mysql/wasm-components/tls-connect-test/Cargo.toml b/tests/mysql/wasm-components/tls-connect-test/Cargo.toml new file mode 100644 index 0000000000..36b476c8fa --- /dev/null +++ b/tests/mysql/wasm-components/tls-connect-test/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "tls-connect-test" +version = "0.1.0" +edition = "2021" +workspace = "../../../../" + +[lib] +crate-type = ["cdylib"] + +[dependencies] +anyhow = "1.0" +sqlx = { path = "../../../../", features = ["mysql", "runtime-tokio", "tls-wasm"] } +wasip3 = "0.5.0" +tokio = { version = "1.20.0", features = ["rt"] } diff --git a/tests/mysql/wasm-components/tls-connect-test/src/lib.rs b/tests/mysql/wasm-components/tls-connect-test/src/lib.rs new file mode 100644 index 0000000000..c4bbd59fb9 --- /dev/null +++ b/tests/mysql/wasm-components/tls-connect-test/src/lib.rs @@ -0,0 +1,37 @@ +use sqlx::mysql::{MySqlConnectOptions, MySqlConnection, MySqlSslMode}; +use sqlx::Connection; +use std::env; +use std::str::FromStr; + +async fn run() -> anyhow::Result<()> { + let database_url = env::var("DATABASE_URL")?; + + // Force TLS — exercises the wasi-tls code path via the `_tls-wasm` feature. + let opts = MySqlConnectOptions::from_str(&database_url)? + .ssl_mode(MySqlSslMode::Required); + + let mut conn = MySqlConnection::connect_with(&opts).await?; + conn.ping().await?; + conn.close().await?; + eprintln!("TLS connect test passed!"); + Ok(()) +} + +wasip3::cli::command::export!(Component); + +struct Component; + +impl wasip3::exports::cli::run::Guest for Component { + async fn run() -> Result<(), ()> { + tokio::task::LocalSet::new() + .run_until(async { + if let Err(err) = run().await { + eprintln!("TLS connect test failed: {err:#}"); + Err(()) + } else { + Ok(()) + } + }) + .await + } +}