diff --git a/libs/Cargo.lock b/libs/Cargo.lock index 52714ce3d..a1c57f7ff 100644 --- a/libs/Cargo.lock +++ b/libs/Cargo.lock @@ -192,6 +192,15 @@ dependencies = [ "syn", ] +[[package]] +name = "atoi" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f28d99ec8bfea296261ca1af174f24225171fea9664ba9003cbebee704810528" +dependencies = [ + "num-traits", +] + [[package]] name = "atomic-waker" version = "1.1.2" @@ -240,6 +249,12 @@ version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" +[[package]] +name = "base64ct" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" + [[package]] name = "better-panic" version = "0.3.0" @@ -518,6 +533,15 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" +[[package]] +name = "concurrent-queue" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "config" version = "0.14.1" @@ -550,6 +574,12 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + [[package]] name = "const-random" version = "0.1.18" @@ -637,6 +667,15 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "crossbeam-queue" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df0346b5d5e76ac2fe4e327c5fd1118d6be7c51dfb18f9b7922923f287471e35" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "crossbeam-utils" version = "0.8.20" @@ -725,6 +764,17 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da692b8d1080ea3045efaab14434d40468c3d8657e42abddfffca87b428f4c1b" +[[package]] +name = "der" +version = "0.7.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" +dependencies = [ + "const-oid", + "pem-rfc7468", + "zeroize", +] + [[package]] name = "deranged" version = "0.3.11" @@ -784,6 +834,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer", + "const-oid", "crypto-common", "subtle", ] @@ -814,11 +865,20 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" +[[package]] +name = "dotenvy" +version = "0.15.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" + [[package]] name = "either" version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" +dependencies = [ + "serde", +] [[package]] name = "elsa" @@ -866,6 +926,28 @@ version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5692dd7b5a1978a5aeb0ce83b7655c58ca8efdcb79d21036ea249da95afec2c6" +[[package]] +name = "etcetera" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "136d1b5283a1ab77bd9257427ffd09d8667ced0570b6f938942bc7568ed5b943" +dependencies = [ + "cfg-if", + "home", + "windows-sys 0.48.0", +] + +[[package]] +name = "event-listener" +version = "5.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6032be9bd27023a771701cc49f9f053c751055f71efb2e0ae5c15809093675ba" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + [[package]] name = "fallible-iterator" version = "0.3.0" @@ -912,6 +994,17 @@ dependencies = [ "miniz_oxide", ] +[[package]] +name = "flume" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da0e4dd2a88388a1f4ccc7c9ce104604dab68d9f408dc34cd45823d5a9069095" +dependencies = [ + "futures-core", + "futures-sink", + "spin", +] + [[package]] name = "fnv" version = "1.0.7" @@ -992,6 +1085,17 @@ dependencies = [ "futures-util", ] +[[package]] +name = "futures-intrusive" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d930c203dd0b6ff06e0201a4a2fe9149b43c684fd4420555b26d21b1a02956f" +dependencies = [ + "futures-core", + "lock_api", + "parking_lot 0.12.3", +] + [[package]] name = "futures-io" version = "0.3.31" @@ -1240,6 +1344,15 @@ dependencies = [ "digest", ] +[[package]] +name = "home" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" +dependencies = [ + "windows-sys 0.52.0", +] + [[package]] name = "http" version = "1.1.0" @@ -1695,6 +1808,9 @@ name = "lazy_static" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" +dependencies = [ + "spin", +] [[package]] name = "libc" @@ -1702,6 +1818,12 @@ version = "0.2.162" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "18d287de67fe55fd7e1581fe933d965a5a9477b38e949cfa9f8574ef01506398" +[[package]] +name = "libm" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa" + [[package]] name = "libredox" version = "0.1.3" @@ -1869,6 +1991,16 @@ version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd0aa4b8ca861b08d68afc8702af3250776898c1508b278e1da9d01e01d4b45c" +[[package]] +name = "md-5" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" +dependencies = [ + "cfg-if", + "digest", +] + [[package]] name = "memchr" version = "2.7.4" @@ -1996,6 +2128,23 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-bigint-dig" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc84195820f291c7697304f3cbdadd1cb7199c0efc917ff5eafd71225c136151" +dependencies = [ + "byteorder", + "lazy_static", + "libm", + "num-integer", + "num-iter", + "num-traits", + "rand", + "smallvec", + "zeroize", +] + [[package]] name = "num-conv" version = "0.1.0" @@ -2011,6 +2160,17 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-iter" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + [[package]] name = "num-traits" version = "0.2.19" @@ -2018,6 +2178,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", + "libm", ] [[package]] @@ -2097,6 +2258,12 @@ version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fb37767f6569cd834a413442455e0f066d0d522de8630436e2a1761d9726ba56" +[[package]] +name = "parking" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" + [[package]] name = "parking_lot" version = "0.11.2" @@ -2380,6 +2547,23 @@ dependencies = [ "tracing", ] +[[package]] +name = "pavex_session_sqlx" +version = "0.1.53" +dependencies = [ + "anyhow", + "async-trait", + "pavex_session", + "pavex_session_sqlx", + "pavex_tracing", + "px_workspace_hack", + "serde_json", + "sqlx", + "time", + "tokio", + "tracing", +] + [[package]] name = "pavex_test_runner" version = "0.1.53" @@ -2545,6 +2729,15 @@ dependencies = [ "serde", ] +[[package]] +name = "pem-rfc7468" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" +dependencies = [ + "base64ct", +] + [[package]] name = "percent-encoding" version = "2.3.1" @@ -2629,6 +2822,27 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "pkcs1" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f" +dependencies = [ + "der", + "pkcs8", + "spki", +] + +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] + [[package]] name = "pkg-config" version = "0.3.31" @@ -2702,23 +2916,29 @@ version = "0.1.0" dependencies = [ "ahash", "aho-corasick", + "base64 0.22.1", + "bitflags 2.6.0", "byteorder", "cc", "clap", "clap_builder", "console", + "crossbeam-utils", "crypto-common", "deranged", "digest", + "either", "fixedbitset", "form_urlencoded", "futures-channel", "futures-core", + "futures-io", "futures-sink", "futures-util", "getrandom", "hashbrown 0.14.5", "hmac", + "idna", "indexmap", "log", "memchr", @@ -2728,6 +2948,7 @@ dependencies = [ "petgraph", "proc-macro2", "quote", + "rand", "regex", "regex-automata 0.4.8", "regex-syntax 0.8.5", @@ -2736,6 +2957,11 @@ dependencies = [ "serde_json", "sha2", "smallvec", + "sqlx", + "sqlx-core", + "sqlx-macros", + "sqlx-macros-core", + "sqlx-postgres", "stable_deref_trait", "subtle", "syn", @@ -2747,7 +2973,9 @@ dependencies = [ "tracing", "tracing-core", "tracing-log", + "url", "uuid", + "zerocopy", "zeroize", ] @@ -3102,6 +3330,26 @@ dependencies = [ "serde_derive", ] +[[package]] +name = "rsa" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d0e5124fcb30e76a7e79bfee683a2746db83784b86289f6251b54b7950a0dfc" +dependencies = [ + "const-oid", + "digest", + "num-bigint-dig", + "num-integer", + "num-traits", + "pkcs1", + "pkcs8", + "rand_core", + "signature", + "spki", + "subtle", + "zeroize", +] + [[package]] name = "rusqlite" version = "0.32.1" @@ -3381,6 +3629,16 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "digest", + "rand_core", +] + [[package]] name = "simd-adler32" version = "0.3.7" @@ -3419,6 +3677,9 @@ name = "smallvec" version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" +dependencies = [ + "serde", +] [[package]] name = "smawk" @@ -3441,6 +3702,228 @@ name = "spin" version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +dependencies = [ + "lock_api", +] + +[[package]] +name = "spki" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der", +] + +[[package]] +name = "sqlformat" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7bba3a93db0cc4f7bdece8bb09e77e2e785c20bfebf79eb8340ed80708048790" +dependencies = [ + "nom", + "unicode_categories", +] + +[[package]] +name = "sqlx" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93334716a037193fac19df402f8571269c84a00852f6a7066b5d2616dcd64d3e" +dependencies = [ + "sqlx-core", + "sqlx-macros", + "sqlx-mysql", + "sqlx-postgres", + "sqlx-sqlite", +] + +[[package]] +name = "sqlx-core" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4d8060b456358185f7d50c55d9b5066ad956956fddec42ee2e8567134a8936e" +dependencies = [ + "atoi", + "byteorder", + "bytes", + "crc", + "crossbeam-queue", + "either", + "event-listener", + "futures-channel", + "futures-core", + "futures-intrusive", + "futures-io", + "futures-util", + "hashbrown 0.14.5", + "hashlink 0.9.1", + "hex", + "indexmap", + "log", + "memchr", + "once_cell", + "paste", + "percent-encoding", + "serde", + "serde_json", + "sha2", + "smallvec", + "sqlformat", + "thiserror 1.0.69", + "time", + "tracing", + "url", + "uuid", +] + +[[package]] +name = "sqlx-macros" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cac0692bcc9de3b073e8d747391827297e075c7710ff6276d9f7a1f3d58c6657" +dependencies = [ + "proc-macro2", + "quote", + "sqlx-core", + "sqlx-macros-core", + "syn", +] + +[[package]] +name = "sqlx-macros-core" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1804e8a7c7865599c9c79be146dc8a9fd8cc86935fa641d3ea58e5f0688abaa5" +dependencies = [ + "dotenvy", + "either", + "heck", + "hex", + "once_cell", + "proc-macro2", + "quote", + "serde", + "serde_json", + "sha2", + "sqlx-core", + "sqlx-mysql", + "sqlx-postgres", + "sqlx-sqlite", + "syn", + "tempfile", + "url", +] + +[[package]] +name = "sqlx-mysql" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64bb4714269afa44aef2755150a0fc19d756fb580a67db8885608cf02f47d06a" +dependencies = [ + "atoi", + "base64 0.22.1", + "bitflags 2.6.0", + "byteorder", + "bytes", + "crc", + "digest", + "dotenvy", + "either", + "futures-channel", + "futures-core", + "futures-io", + "futures-util", + "generic-array", + "hex", + "hkdf", + "hmac", + "itoa", + "log", + "md-5", + "memchr", + "once_cell", + "percent-encoding", + "rand", + "rsa", + "serde", + "sha1", + "sha2", + "smallvec", + "sqlx-core", + "stringprep", + "thiserror 1.0.69", + "time", + "tracing", + "uuid", + "whoami", +] + +[[package]] +name = "sqlx-postgres" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fa91a732d854c5d7726349bb4bb879bb9478993ceb764247660aee25f67c2f8" +dependencies = [ + "atoi", + "base64 0.22.1", + "bitflags 2.6.0", + "byteorder", + "crc", + "dotenvy", + "etcetera", + "futures-channel", + "futures-core", + "futures-io", + "futures-util", + "hex", + "hkdf", + "hmac", + "home", + "itoa", + "log", + "md-5", + "memchr", + "once_cell", + "rand", + "serde", + "serde_json", + "sha2", + "smallvec", + "sqlx-core", + "stringprep", + "thiserror 1.0.69", + "time", + "tracing", + "uuid", + "whoami", +] + +[[package]] +name = "sqlx-sqlite" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5b2cf34a45953bfd3daaf3db0f7a7878ab9b7a6b91b422d24a7a9e4c857b680" +dependencies = [ + "atoi", + "flume", + "futures-channel", + "futures-core", + "futures-executor", + "futures-intrusive", + "futures-util", + "libsqlite3-sys", + "log", + "percent-encoding", + "serde", + "serde_urlencoded", + "sqlx-core", + "time", + "tracing", + "url", + "uuid", +] [[package]] name = "stable_deref_trait" @@ -3467,6 +3950,17 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" +[[package]] +name = "stringprep" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b4df3d392d81bd458a8a621b8bffbd2302a12ffe288a9d931670948749463b1" +dependencies = [ + "unicode-bidi", + "unicode-normalization", + "unicode-properties", +] + [[package]] name = "strsim" version = "0.11.1" @@ -3834,6 +4328,7 @@ version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ + "log", "pin-project-lite", "tracing-attributes", "tracing-core", @@ -3954,6 +4449,12 @@ version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" +[[package]] +name = "unicode-bidi" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ab17db44d7388991a428b2ee655ce0c212e862eff1768a455c58f9aad6e7893" + [[package]] name = "unicode-ident" version = "1.0.13" @@ -3966,6 +4467,21 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f" +[[package]] +name = "unicode-normalization" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-properties" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e70f2a8b45122e719eb623c01822704c4e0907e7e426a05927e1a1cfff5b75d0" + [[package]] name = "unicode-segmentation" version = "1.12.0" @@ -3984,6 +4500,12 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd" +[[package]] +name = "unicode_categories" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e" + [[package]] name = "universal-hash" version = "0.5.1" @@ -4139,6 +4661,12 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "wasite" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" + [[package]] name = "wasm-bindgen" version = "0.2.95" @@ -4240,6 +4768,16 @@ dependencies = [ "rustls-pki-types", ] +[[package]] +name = "whoami" +version = "1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "372d5b87f58ec45c384ba03563b03544dc5fadc3983e434b286913f5b4a9bb6d" +dependencies = [ + "redox_syscall 0.5.7", + "wasite", +] + [[package]] name = "winapi" version = "0.3.9" diff --git a/libs/Cargo.toml b/libs/Cargo.toml index 8c30af54b..0fe2dd104 100644 --- a/libs/Cargo.toml +++ b/libs/Cargo.toml @@ -2,8 +2,6 @@ members = [ "./pavex*", "generate_from_path", - "pavex_cli_deps", - "pavexc_rustdoc_types", "persist_if_changed", "px_workspace_hack", ] @@ -104,6 +102,7 @@ serde_stacker = "0.1" sha2 = "0.10.8" similar = "2.6.0" smallvec = "1" +sqlx = { version = "0.8" } socket2 = "0.5.7" supports-color = "3.0.1" supports-hyperlinks = "3.0.0" diff --git a/libs/deny.toml b/libs/deny.toml index 011e95a90..be03bca0b 100644 --- a/libs/deny.toml +++ b/libs/deny.toml @@ -4,13 +4,10 @@ no-default-features = false [advisories] ignore = [ - # `yaml` crate is unmaintained, but we depend on it transitively via `config`, - # so no easy way to remove it. Since it isn't vulnerable, we'll ignore the advisory - # for now. - "RUSTSEC-2024-0320", - # `proc-macro-error` is unmaintained, but we depend on it transitively via `vergen-lib`. - # There is no runtime risk, so we'll ignore the advisory for now. - "RUSTSEC-2024-0370", + # `instant` crate is unmaintained, but we depend on it transitively, + # so no easy way to remove it until all intermediate crates get rid of it. + # Since it isn't vulnerable, we'll ignore the advisory for now. + "RUSTSEC-2024-0384", ] [licenses] diff --git a/libs/pavex_cli/src/command.rs b/libs/pavex_cli/src/command.rs index 9220997c3..5168e419f 100644 --- a/libs/pavex_cli/src/command.rs +++ b/libs/pavex_cli/src/command.rs @@ -110,7 +110,7 @@ pub enum Command { /// Optional. /// If provided, Pavex will serialize diagnostic information about /// the application to the specified path. - #[clap(long, value_parser)] + #[clap(long, env = "PAVEX_DIAGNOSTICS", value_parser)] diagnostics: Option, #[clap(long)] /// Verify that the generated server SDK is up-to-date. diff --git a/libs/pavex_session/src/id.rs b/libs/pavex_session/src/id.rs index 575a5811a..4c26d549a 100644 --- a/libs/pavex_session/src/id.rs +++ b/libs/pavex_session/src/id.rs @@ -6,10 +6,13 @@ /// /// # Format stability /// -/// From an API perspective, a session id is an opaque sequence of bytes. -/// Do **not** depend on the specifics of the underlying representation. -/// It may change between versions and those changes will not be considered -/// breaking changes. +/// The session ID is guaranteed to be a valid UUID. +/// The format of the UUID is not guaranteed to be stable across different versions of this library. +/// +/// It is recommended to treat the session ID as an opaque value in your application. +/// Knowing the format is primarily useful when implementing custom session storage backends, as +/// it allows you to leverage optimizations in your data store that are specific to the UUID format +/// (e.g. a dedicated data type, such as `UUID` in PostgreSQL). pub struct SessionId(uuid::Uuid); impl SessionId { @@ -18,4 +21,9 @@ impl SessionId { pub fn random() -> Self { Self(uuid::Uuid::new_v4()) } + + /// Returns the inner `uuid::Uuid` value. + pub fn inner(&self) -> uuid::Uuid { + self.0 + } } diff --git a/libs/pavex_session/src/session_.rs b/libs/pavex_session/src/session_.rs index fefbbfe74..cb15ec89f 100644 --- a/libs/pavex_session/src/session_.rs +++ b/libs/pavex_session/src/session_.rs @@ -1,4 +1,5 @@ use super::state::errors::{ServerGetError, ServerSetError, SyncError, ValueDeserializationError}; +use anyhow::Context; use errors::{FinalizeError, ValueSerializationError}; use pavex::cookie::{RemovalCookie, ResponseCookie}; use serde::de::DeserializeOwned; @@ -277,7 +278,7 @@ impl<'session> ClientSessionStateMut<'session> { pub fn set( &mut self, key: String, - value: T + value: T, ) -> Result, serde_json::Error> { let value = serde_json::to_value(value)?; Ok(self.set_value(key, value)) @@ -309,7 +310,10 @@ impl<'session> ClientSessionStateMut<'session> { /// /// If the key exists, the removed value is returned. /// If the removed value cannot be serialized, an error is returned. - pub fn remove(&mut self, key: &str) -> Result, serde_json::Error> { + pub fn remove( + &mut self, + key: &str, + ) -> Result, serde_json::Error> { self.remove_value(key) .map(|value| serde_json::from_value(value)) .transpose() @@ -447,9 +451,11 @@ impl<'session, 'store> ServerSessionState<'session, 'store> { /// If the key exists, the removed value is returned. /// If the removed value cannot be serialized, an error is returned. pub async fn remove(&mut self, key: &str) -> Result, LoadError> { - self.remove_value(key).await? + self.remove_value(key) + .await? .map(serde_json::from_value) .transpose() + .context("Failed to deserialize the removed value.") .map_err(LoadError::DeserializationError) } diff --git a/libs/pavex_session/src/store_.rs b/libs/pavex_session/src/store_.rs index da22bae6a..703a5c78c 100644 --- a/libs/pavex_session/src/store_.rs +++ b/libs/pavex_session/src/store_.rs @@ -1,7 +1,10 @@ use crate::SessionId; -use errors::{ChangeIdError, CreateError, DeleteError, LoadError, UpdateError, UpdateTtlError}; +use errors::{ + ChangeIdError, CreateError, DeleteError, DeleteExpiredError, LoadError, UpdateError, + UpdateTtlError, +}; use serde_json::Value; -use std::{borrow::Cow, collections::HashMap}; +use std::{borrow::Cow, collections::HashMap, num::NonZeroUsize}; /// Where server-side session records are stored. /// @@ -78,6 +81,14 @@ impl SessionStore { ) -> Result<(), ChangeIdError> { self.0.change_id(old_id, new_id).await } + + /// Deletes expired session records from the store. + pub async fn delete_expired( + &self, + batch_size: Option, + ) -> Result { + self.0.delete_expired(batch_size).await + } } #[async_trait::async_trait(?Send)] @@ -118,6 +129,30 @@ pub trait SessionStorageBackend: std::fmt::Debug + Send + Sync { /// /// The server-side state is left unchanged. async fn change_id(&self, old_id: &SessionId, new_id: &SessionId) -> Result<(), ChangeIdError>; + + /// Deletes expired session records from the store. + /// + /// If `batch_size` is provided, the query will delete at most `batch_size` expired sessions. + /// In either case, if successful, the method returns the number of expired sessions that + /// have been deleted. + /// + /// # When should you delete in batches? + /// + /// If there are a lot of expired sessions in the database, deleting them all at once can + /// cause performance issues. By deleting in batches, you can limit the number of sessions + /// deleted in a single query, reducing the impact. + /// + /// # Do I need to call this method? + /// + /// It depends on the storage backend you are using. Some backends (e.g. Redis) have + /// built-in support for expiring keys, so you may not need to call this method at all. + /// + /// If you're adding support for a new backend that has built-in support for expiring keys, + /// you can simply return `Ok(0)` from this method. + async fn delete_expired( + &self, + batch_size: Option, + ) -> Result; } /// A server-side session record that's going to be stored in the @@ -201,7 +236,7 @@ pub mod errors { pub enum LoadError { #[error("Failed to deserialize the session state.")] /// Failed to deserialize the session state. - DeserializationError(#[from] serde_json::Error), + DeserializationError(#[source] anyhow::Error), /// Something else went wrong when loading the session record. #[error("Something went wrong when loading the session record.")] Other(#[source] anyhow::Error), @@ -234,6 +269,11 @@ pub mod errors { Other(#[source] anyhow::Error), } + /// The error returned by [`SessionStorageBackend::delete_expired`][super::SessionStorageBackend::delete_expired]. + #[derive(Debug, thiserror::Error)] + #[error("Something went wrong when deleting expired sessions")] + pub struct DeleteExpiredError(#[from] anyhow::Error); + #[derive(Debug, thiserror::Error)] #[error("There is no session with the given id")] /// There is no session with the given ID. diff --git a/libs/pavex_session_memory_store/src/lib.rs b/libs/pavex_session_memory_store/src/lib.rs index 646c83434..b46bab137 100644 --- a/libs/pavex_session_memory_store/src/lib.rs +++ b/libs/pavex_session_memory_store/src/lib.rs @@ -1,13 +1,13 @@ //! An in-memory session store for `pavex_session`, geared towards testing and local development. -use std::{collections::HashMap, sync::Arc, time::Duration}; +use std::{collections::HashMap, num::NonZeroUsize, sync::Arc, time::Duration}; use time::OffsetDateTime; use tokio::sync::{Mutex, MutexGuard}; use pavex_session::{ store::{ errors::{ - ChangeIdError, CreateError, DeleteError, DuplicateIdError, LoadError, UnknownIdError, - UpdateError, UpdateTtlError, + ChangeIdError, CreateError, DeleteError, DeleteExpiredError, DuplicateIdError, + LoadError, UnknownIdError, UpdateError, UpdateTtlError, }, SessionRecord, SessionRecordRef, SessionStorageBackend, }, @@ -22,7 +22,11 @@ use pavex_session::{ /// This store won't persist data between server restarts. /// It also won't synchronize data between multiple server instances. /// It is primarily intended for testing and local development. -pub struct SessionMemoryStore(Arc>>); +pub struct InMemorySessionStore(Arc>>); + +#[doc(hidden)] +// Here for backwards compatibility. +pub type SessionStoreMemory = InMemorySessionStore; #[derive(Debug)] struct StoreRecord { @@ -35,7 +39,7 @@ impl StoreRecord { } } -impl SessionMemoryStore { +impl InMemorySessionStore { /// Creates a new (empty) in-memory session store. pub fn new() -> Self { Self(Arc::new(Mutex::new(HashMap::new()))) @@ -72,7 +76,7 @@ impl SessionMemoryStore { } #[async_trait::async_trait(?Send)] -impl SessionStorageBackend for SessionMemoryStore { +impl SessionStorageBackend for InMemorySessionStore { /// Creates a new session record in the store using the provided ID. #[tracing::instrument(name = "Create server-side session record", level = tracing::Level::TRACE, skip_all)] async fn create( @@ -174,4 +178,30 @@ impl SessionStorageBackend for SessionMemoryStore { guard.insert(*new_id, record); Ok(()) } + + /// Delete all expired records from the store. + #[tracing::instrument(name = "Delete expired records", level = tracing::Level::TRACE, skip_all)] + async fn delete_expired( + &self, + batch_size: Option, + ) -> Result { + let mut guard = self.0.lock().await; + let now = time::OffsetDateTime::now_utc(); + let mut stale_ids = Vec::new(); + for (id, record) in guard.iter() { + if record.deadline <= now { + stale_ids.push(*id); + if let Some(batch_size) = batch_size { + if stale_ids.len() >= batch_size.get() { + break; + } + } + } + } + let num_deleted = stale_ids.len(); + for id in stale_ids { + guard.remove(&id); + } + Ok(num_deleted) + } } diff --git a/libs/pavex_session_sqlx/Cargo.toml b/libs/pavex_session_sqlx/Cargo.toml new file mode 100644 index 000000000..6cc63a1e8 --- /dev/null +++ b/libs/pavex_session_sqlx/Cargo.toml @@ -0,0 +1,29 @@ +[package] +name = "pavex_session_sqlx" +edition.workspace = true +repository.workspace = true +homepage.workspace = true +license.workspace = true +version.workspace = true + +[features] +default = [] +postgres = ["sqlx/postgres"] + +[package.metadata.docs.rs] +all-features = true + +[dependencies] +pavex_session = { version = "0.1.53", path = "../pavex_session" } +time = { workspace = true, features = ["std"] } +serde_json = { workspace = true } +async-trait = { workspace = true } +tokio = { workspace = true, features = ["sync"] } +tracing = { workspace = true } +anyhow = { workspace = true } +sqlx = { workspace = true, features = ["uuid", "time"] } +px_workspace_hack = { version = "0.1", path = "../px_workspace_hack" } + +[dev-dependencies] +pavex_session_sqlx = { path = ".", version = "0.1.53", features = ["postgres"] } +pavex_tracing = { version = "0.1.53", path = "../pavex_tracing" } diff --git a/libs/pavex_session_sqlx/src/lib.rs b/libs/pavex_session_sqlx/src/lib.rs new file mode 100644 index 000000000..da1d97259 --- /dev/null +++ b/libs/pavex_session_sqlx/src/lib.rs @@ -0,0 +1,10 @@ +//! Storage backends for `pavex_session`, implemented using the `sqlx` crate. +//! +//! There is a dedicated feature flag for each supported database backend: +//! +//! - `postgres`: Support for PostgreSQL. + +#[cfg(feature = "postgres")] +mod postgres; +#[cfg(feature = "postgres")] +pub use postgres::PostgresSessionStore; diff --git a/libs/pavex_session_sqlx/src/postgres.rs b/libs/pavex_session_sqlx/src/postgres.rs new file mode 100644 index 000000000..f32addd41 --- /dev/null +++ b/libs/pavex_session_sqlx/src/postgres.rs @@ -0,0 +1,346 @@ +use std::{i64, num::NonZeroUsize, usize}; + +use sqlx::{ + postgres::{PgDatabaseError, PgQueryResult}, + PgPool, +}; + +use pavex_session::{ + store::{ + errors::{ + ChangeIdError, CreateError, DeleteError, DeleteExpiredError, DuplicateIdError, + LoadError, UnknownIdError, UpdateError, UpdateTtlError, + }, + SessionRecord, SessionRecordRef, SessionStorageBackend, + }, + SessionId, +}; + +#[derive(Debug, Clone)] +/// A server-side session store using Postgres as its backend. +/// +/// # Implementation details +/// +/// This store uses `sqlx` to interact with Postgres. +/// All session records are stored in a single table. You can use +/// [`migrate`](Self::migrate) to create the table and index +/// required by the store in the database. +/// Alternatively, you can use [`migration_query`](Self::migration_query) +/// to get the SQL query that creates the table and index in order to run it yourself +/// (e.g. as part of your database migration scripts). +pub struct PostgresSessionStore(sqlx::PgPool); + +impl PostgresSessionStore { + /// Creates a new Postgres session store instance. + /// + /// It requires a pool of Postgres connections to interact with the database + /// where the session records are stored. + pub fn new(pool: PgPool) -> Self { + Self(pool) + } + + /// Return the query used to create the sessions table and index. + /// + /// # Implementation details + /// + /// The query is designed to be idempotent, meaning it can be run multiple times + /// without causing any issues. If the table and index already exist, the query + /// does nothing. + /// + /// # Alternatives + /// + /// You can use this method to add the query to your database migration scripts. + /// Alternatively, you can use [`migrate`](Self::migrate) + /// to run the query directly on the database. + pub fn migration_query() -> &'static str { + "-- Create the sessions table if it doesn’t exist +CREATE TABLE IF NOT EXISTS sessions ( + id UUID PRIMARY KEY, + deadline TIMESTAMPTZ NOT NULL, + state JSONB NOT NULL +); + +-- Create the index on the deadline column if it doesn’t exist +DO $$ +BEGIN + IF NOT EXISTS ( + SELECT 1 FROM pg_indexes + WHERE schemaname = current_schema() + AND tablename = 'sessions' + AND indexname = 'idx_sessions_deadline' + ) THEN + CREATE INDEX idx_sessions_deadline ON sessions(deadline); + END IF; +END $$;" + } + + /// Create the sessions table and index in the database. + /// + /// This method is idempotent, meaning it can be called multiple times without + /// causing any issues. If the table and index already exist, this method does nothing. + /// + /// If you prefer to run the query yourself, rely on [`migration_query`](Self::migration_query) + /// to get the SQL that's being executed. + pub async fn migrate(&self) -> Result<(), sqlx::Error> { + use sqlx::Executor as _; + + self.0.execute(Self::migration_query()).await?; + Ok(()) + } +} + +#[async_trait::async_trait(?Send)] +impl SessionStorageBackend for PostgresSessionStore { + /// Creates a new session record in the store using the provided ID. + #[tracing::instrument(name = "Create server-side session record", level = tracing::Level::INFO, skip_all)] + async fn create( + &self, + id: &SessionId, + record: SessionRecordRef<'_>, + ) -> Result<(), CreateError> { + let deadline = time::OffsetDateTime::now_utc() + record.ttl; + let state = serde_json::to_value(record.state)?; + let query = sqlx::query( + "INSERT INTO sessions (id, deadline, state) \ + VALUES ($1, $2, $3) \ + ON CONFLICT (id) DO UPDATE \ + SET deadline = EXCLUDED.deadline, state = EXCLUDED.state \ + WHERE sessions.deadline < (now() AT TIME ZONE 'UTC')", + ) + .bind(id.inner()) + .bind(deadline) + .bind(state); + + match query.execute(&self.0).await { + // All good, we created the session record. + Ok(_) => Ok(()), + Err(e) => { + // Return the specialized error variant if the ID is already in use + if let Err(e) = as_duplicated_id_error(&e, id) { + Err(e.into()) + } else { + Err(CreateError::Other(e.into())) + } + } + } + } + + /// Update the state of an existing session in the store. + /// + /// It overwrites the existing record with the provided one. + #[tracing::instrument(name = "Update server-side session record", level = tracing::Level::INFO, skip_all)] + async fn update( + &self, + id: &SessionId, + record: SessionRecordRef<'_>, + ) -> Result<(), UpdateError> { + let new_deadline = time::OffsetDateTime::now_utc() + record.ttl; + let new_state = serde_json::to_value(record.state)?; + let query = sqlx::query( + "UPDATE sessions \ + SET deadline = $1, state = $2 \ + WHERE id = $3 AND deadline > (now() AT TIME ZONE 'UTC')", + ) + .bind(new_deadline) + .bind(new_state) + .bind(id.inner()); + + match query.execute(&self.0).await { + Ok(r) => as_unknown_id_error(&r, id).map_err(Into::into), + Err(e) => Err(UpdateError::Other(e.into())), + } + } + + /// Update the TTL of an existing session record in the store. + /// + /// It leaves the session state unchanged. + #[tracing::instrument(name = "Update TTL for server-side session record", level = tracing::Level::INFO, skip_all)] + async fn update_ttl( + &self, + id: &SessionId, + ttl: std::time::Duration, + ) -> Result<(), UpdateTtlError> { + let new_deadline = time::OffsetDateTime::now_utc() + ttl; + let query = sqlx::query( + "UPDATE sessions \ + SET deadline = $1 \ + WHERE id = $2 AND deadline > (now() AT TIME ZONE 'UTC')", + ) + .bind(new_deadline) + .bind(id.inner()); + match query.execute(&self.0).await { + Ok(r) => as_unknown_id_error(&r, id).map_err(Into::into), + Err(e) => Err(UpdateTtlError::Other(e.into())), + } + } + + /// Loads an existing session record from the store using the provided ID. + /// + /// If a session with the given ID exists, it is returned. If the session + /// does not exist or has been invalidated (e.g., expired), `None` is + /// returned. + #[tracing::instrument(name = "Load server-side session record", level = tracing::Level::INFO, skip_all)] + async fn load(&self, session_id: &SessionId) -> Result, LoadError> { + let row = sqlx::query( + "SELECT deadline, state \ + FROM sessions \ + WHERE id = $1 AND deadline > (now() AT TIME ZONE 'UTC')", + ) + .bind(session_id.inner()) + .fetch_optional(&self.0) + .await + .map_err(|e| LoadError::Other(e.into()))?; + row.map(|r| { + use anyhow::Context as _; + use sqlx::Row as _; + + let deadline: time::OffsetDateTime = r + .try_get(0) + .context("Failed to deserialize the retrieved session deadline") + .map_err(LoadError::DeserializationError)?; + let state: serde_json::Value = r + .try_get(1) + .context("Failed to deserialize the retrieved session state") + .map_err(LoadError::DeserializationError)?; + let ttl = deadline - time::OffsetDateTime::now_utc(); + Ok(SessionRecord { + // This conversion only fails if the duration is negative, which should not happen + ttl: ttl.try_into().unwrap_or(std::time::Duration::ZERO), + state: serde_json::from_value(state) + .context("Failed to deserialize the retrieved session state") + .map_err(LoadError::DeserializationError)?, + }) + }) + .transpose() + } + + /// Deletes a session record from the store using the provided ID. + /// + /// If the session exists, it is removed from the store. + #[tracing::instrument(name = "Delete server-side session record", level = tracing::Level::INFO, skip_all)] + async fn delete(&self, id: &SessionId) -> Result<(), DeleteError> { + let query = sqlx::query( + "DELETE FROM sessions \ + WHERE id = $1 AND deadline > (now() AT TIME ZONE 'UTC')", + ) + .bind(id.inner()); + match query.execute(&self.0).await { + Ok(r) => as_unknown_id_error(&r, id).map_err(Into::into), + Err(e) => Err(DeleteError::Other(e.into())), + } + } + + /// Change the session id associated with an existing session record. + /// + /// The server-side state is left unchanged. + #[tracing::instrument(name = "Change id for server-side session record", level = tracing::Level::INFO, skip_all)] + async fn change_id(&self, old_id: &SessionId, new_id: &SessionId) -> Result<(), ChangeIdError> { + let query = sqlx::query( + "UPDATE sessions \ + SET id = $1 \ + WHERE id = $2 AND deadline > (now() AT TIME ZONE 'UTC')", + ) + .bind(new_id.inner()) + .bind(old_id.inner()); + match query.execute(&self.0).await { + Ok(r) => as_unknown_id_error(&r, old_id).map_err(Into::into), + Err(e) => { + if let Err(e) = as_duplicated_id_error(&e, new_id) { + Err(e.into()) + } else { + Err(ChangeIdError::Other(e.into())) + } + } + } + } + + /// Delete expired sessions from the database. + /// + /// If `batch_size` is provided, the query will delete at most `batch_size` expired sessions. + /// In either case, if successful, the method returns the number of expired sessions that + /// have been deleted. + /// + /// # When should you delete in batches? + /// + /// If there are a lot of expired sessions in the database, deleting them all at once can + /// cause performance issues. By deleting in batches, you can limit the number of sessions + /// deleted in a single query, reducing the impact. + /// + /// # Example + /// + /// Delete expired sessions in batches of 1000: + /// + /// ```no_run + /// use pavex_session::SessionStore; + /// use pavex_session_sqlx::PostgresSessionStore; + /// use pavex_tracing::fields::{ + /// error_details, + /// error_message, + /// ERROR_DETAILS, + /// ERROR_MESSAGE + /// }; + /// use std::time::Duration; + /// + /// # async fn delete_expired_sessions(pool: sqlx::PgPool) { + /// let backend = PostgresSessionStore::new(pool); + /// let store = SessionStore::new(backend); + /// let batch_size = Some(1000.try_into().unwrap()); + /// let batch_sleep = Duration::from_secs(60); + /// loop { + /// if let Err(e) = store.delete_expired(batch_size).await { + /// tracing::event!( + /// tracing::Level::ERROR, + /// { ERROR_MESSAGE } = error_message(&e), + /// { ERROR_DETAILS } = error_details(&e), + /// "Failed to delete a batch of expired sessions", + /// ); + /// } + /// tokio::time::sleep(batch_sleep).await; + /// } + /// # } + async fn delete_expired( + &self, + batch_size: Option, + ) -> Result { + let query = if let Some(batch_size) = batch_size { + let batch_size: i64 = batch_size.get().try_into().unwrap_or(i64::MAX); + sqlx::query("DELETE FROM sessions WHERE deadline < (now() AT TIME ZONE 'UTC') LIMIT $1") + .bind(batch_size as i64) + } else { + sqlx::query("DELETE FROM sessions WHERE deadline < (now() AT TIME ZONE 'UTC')") + }; + let r = query.execute(&self.0).await.map_err(|e| { + let e: anyhow::Error = e.into(); + e + })?; + Ok(r.rows_affected().try_into().unwrap_or(usize::MAX)) + } +} + +fn as_duplicated_id_error(e: &sqlx::Error, id: &SessionId) -> Result<(), DuplicateIdError> { + if let Some(e) = e.as_database_error() { + if let Some(e) = e.try_downcast_ref::() { + // Check if the error is due to a duplicate ID + // See https://www.postgresql.org/docs/current/errcodes-appendix.html + // for the list of error codes for Postgres + if e.code() == "23505" && e.column() == Some("id") { + return Err(DuplicateIdError { id: id.to_owned() }); + } + } + } + Ok(()) +} + +fn as_unknown_id_error(r: &PgQueryResult, id: &SessionId) -> Result<(), UnknownIdError> { + // Check if the session record was changed + if r.rows_affected() == 0 { + return Err(UnknownIdError { id: id.to_owned() }.into()); + } + // Sanity check + assert_eq!( + r.rows_affected(), + 1, + "More than one session record was affected, even though the session ID is used as primary key. Something is deeply wrong here!" + ); + Ok(()) +} diff --git a/libs/pavexc_cli/src/main.rs b/libs/pavexc_cli/src/main.rs index 209f8877d..1d0314054 100644 --- a/libs/pavexc_cli/src/main.rs +++ b/libs/pavexc_cli/src/main.rs @@ -113,14 +113,14 @@ enum Commands { blueprint: PathBuf, /// Optional. If provided, pavex will serialize diagnostic information about /// the application to the specified path. - #[clap(long, value_parser)] + #[clap(long, env = "PAVEXC_DIAGNOSTICS", value_parser)] diagnostics: Option, /// The path to the directory that will contain the manifest and the source code for the generated application crate. /// If the provided path is relative, it is interpreted as relative to the root of the current workspace. #[clap(short, long, value_parser)] output: PathBuf, #[clap(long)] - /// Verify that the generated server SDK is up-to-date. + /// Verify that the generated server SDK is up-to-date. /// If it isn't, `pavexc` will return an error without updating /// the server SDK code. check: bool, diff --git a/libs/px_workspace_hack/Cargo.toml b/libs/px_workspace_hack/Cargo.toml index 494896cac..0e9c94d7f 100644 --- a/libs/px_workspace_hack/Cargo.toml +++ b/libs/px_workspace_hack/Cargo.toml @@ -19,22 +19,28 @@ license.workspace = true [dependencies] ahash = { version = "0.8" } aho-corasick = { version = "1" } +base64 = { version = "0.22" } +bitflags = { version = "2", default-features = false, features = ["serde"] } byteorder = { version = "1" } clap = { version = "4", features = ["derive", "env"] } clap_builder = { version = "4", default-features = false, features = ["color", "env", "help", "std", "suggestions", "usage"] } console = { version = "0.15" } +crossbeam-utils = { version = "0.8" } crypto-common = { version = "0.1", default-features = false, features = ["getrandom", "std"] } deranged = { version = "0.3", default-features = false, features = ["powerfmt", "serde", "std"] } digest = { version = "0.10", features = ["mac", "std"] } +either = { version = "1", features = ["serde"] } fixedbitset = { version = "0.4" } form_urlencoded = { version = "1" } futures-channel = { version = "0.3", features = ["sink"] } futures-core = { version = "0.3" } +futures-io = { version = "0.3" } futures-sink = { version = "0.3" } futures-util = { version = "0.3", features = ["channel", "io", "sink"] } getrandom = { version = "0.2", default-features = false, features = ["std"] } hashbrown = { version = "0.14" } hmac = { version = "0.12", default-features = false, features = ["reset"] } +idna = { version = "1", default-features = false, features = ["compiled_data", "std"] } indexmap = { version = "2", features = ["serde"] } log = { version = "0.4", default-features = false, features = ["std"] } memchr = { version = "2" } @@ -44,14 +50,18 @@ percent-encoding = { version = "2" } petgraph = { version = "0.6", default-features = false, features = ["graphmap", "stable_graph"] } proc-macro2 = { version = "1", features = ["span-locations"] } quote = { version = "1" } +rand = { version = "0.8" } regex = { version = "1" } regex-automata = { version = "0.4", default-features = false, features = ["dfa-onepass", "hybrid", "meta", "nfa", "perf", "unicode"] } regex-syntax = { version = "0.8" } reqwest = { version = "0.12", default-features = false, features = ["json", "rustls-tls"] } -serde = { version = "1", features = ["alloc", "derive"] } -serde_json = { version = "1", features = ["unbounded_depth"] } +serde = { version = "1", features = ["alloc", "derive", "rc"] } +serde_json = { version = "1", features = ["raw_value", "unbounded_depth"] } sha2 = { version = "0.10" } -smallvec = { version = "1", default-features = false, features = ["const_new"] } +smallvec = { version = "1", default-features = false, features = ["const_new", "serde"] } +sqlx = { version = "0.8", features = ["postgres", "time", "uuid"] } +sqlx-core = { version = "0.8", features = ["any", "json", "migrate", "offline", "time", "uuid"] } +sqlx-postgres = { version = "0.8", default-features = false, features = ["any", "json", "migrate", "offline", "time", "uuid"] } stable_deref_trait = { version = "1" } subtle = { version = "2" } syn = { version = "2", features = ["extra-traits", "fold", "full", "visit", "visit-mut"] } @@ -59,32 +69,40 @@ time = { version = "0.3", features = ["formatting", "local-offset", "macros", "p tokio = { version = "1", features = ["fs", "io-util", "macros", "net", "rt", "sync", "time"] } toml = { version = "0.8", features = ["preserve_order"] } toml_edit = { version = "0.22", features = ["serde"] } -tracing = { version = "0.1" } +tracing = { version = "0.1", features = ["log"] } tracing-core = { version = "0.1" } tracing-log = { version = "0.2" } +url = { version = "2" } uuid = { version = "1", features = ["fast-rng", "serde", "v4", "v7"] } +zerocopy = { version = "0.7", features = ["derive", "simd"] } zeroize = { version = "1", features = ["zeroize_derive"] } [build-dependencies] ahash = { version = "0.8" } aho-corasick = { version = "1" } +base64 = { version = "0.22" } +bitflags = { version = "2", default-features = false, features = ["serde"] } byteorder = { version = "1" } cc = { version = "1", default-features = false, features = ["parallel"] } clap = { version = "4", features = ["derive", "env"] } clap_builder = { version = "4", default-features = false, features = ["color", "env", "help", "std", "suggestions", "usage"] } console = { version = "0.15" } +crossbeam-utils = { version = "0.8" } crypto-common = { version = "0.1", default-features = false, features = ["getrandom", "std"] } deranged = { version = "0.3", default-features = false, features = ["powerfmt", "serde", "std"] } digest = { version = "0.10", features = ["mac", "std"] } +either = { version = "1", features = ["serde"] } fixedbitset = { version = "0.4" } form_urlencoded = { version = "1" } futures-channel = { version = "0.3", features = ["sink"] } futures-core = { version = "0.3" } +futures-io = { version = "0.3" } futures-sink = { version = "0.3" } futures-util = { version = "0.3", features = ["channel", "io", "sink"] } getrandom = { version = "0.2", default-features = false, features = ["std"] } hashbrown = { version = "0.14" } hmac = { version = "0.12", default-features = false, features = ["reset"] } +idna = { version = "1", default-features = false, features = ["compiled_data", "std"] } indexmap = { version = "2", features = ["serde"] } log = { version = "0.4", default-features = false, features = ["std"] } memchr = { version = "2" } @@ -94,14 +112,20 @@ percent-encoding = { version = "2" } petgraph = { version = "0.6", default-features = false, features = ["graphmap", "stable_graph"] } proc-macro2 = { version = "1", features = ["span-locations"] } quote = { version = "1" } +rand = { version = "0.8" } regex = { version = "1" } regex-automata = { version = "0.4", default-features = false, features = ["dfa-onepass", "hybrid", "meta", "nfa", "perf", "unicode"] } regex-syntax = { version = "0.8" } reqwest = { version = "0.12", default-features = false, features = ["json", "rustls-tls"] } -serde = { version = "1", features = ["alloc", "derive"] } -serde_json = { version = "1", features = ["unbounded_depth"] } +serde = { version = "1", features = ["alloc", "derive", "rc"] } +serde_json = { version = "1", features = ["raw_value", "unbounded_depth"] } sha2 = { version = "0.10" } -smallvec = { version = "1", default-features = false, features = ["const_new"] } +smallvec = { version = "1", default-features = false, features = ["const_new", "serde"] } +sqlx = { version = "0.8", features = ["postgres", "time", "uuid"] } +sqlx-core = { version = "0.8", features = ["any", "json", "migrate", "offline", "time", "uuid"] } +sqlx-macros = { version = "0.8", features = ["derive", "json", "macros", "migrate", "postgres", "time", "uuid"] } +sqlx-macros-core = { version = "0.8", features = ["derive", "json", "macros", "migrate", "postgres", "time", "uuid"] } +sqlx-postgres = { version = "0.8", default-features = false, features = ["any", "json", "migrate", "offline", "time", "uuid"] } stable_deref_trait = { version = "1" } subtle = { version = "2" } syn = { version = "2", features = ["extra-traits", "fold", "full", "visit", "visit-mut"] } @@ -110,10 +134,12 @@ time-macros = { version = "0.2", default-features = false, features = ["formatti tokio = { version = "1", features = ["fs", "io-util", "macros", "net", "rt", "sync", "time"] } toml = { version = "0.8", features = ["preserve_order"] } toml_edit = { version = "0.22", features = ["serde"] } -tracing = { version = "0.1" } +tracing = { version = "0.1", features = ["log"] } tracing-core = { version = "0.1" } tracing-log = { version = "0.2" } +url = { version = "2" } uuid = { version = "1", features = ["fast-rng", "serde", "v4", "v7"] } +zerocopy = { version = "0.7", features = ["derive", "simd"] } zeroize = { version = "1", features = ["zeroize_derive"] } ### END HAKARI SECTION