diff --git a/.github/workflows/publish-to-pages.yaml b/.github/workflows/publish-to-pages.yaml new file mode 100644 index 000000000..56cbb1bd4 --- /dev/null +++ b/.github/workflows/publish-to-pages.yaml @@ -0,0 +1,45 @@ +name: publish to github pages + +on: + push: + # Trigger when there is a new commit on main branch + branches: [ main ] + # also trigger when a new release tag is added to the repo + tags: + - "v*" + +# Cancel already running jobs +concurrency: + group: publish_to_pages_${{ github.head_ref }} + cancel-in-progress: true + +# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages +permissions: + contents: read + pages: write + id-token: write + +jobs: + build: + strategy: + matrix: + include: + - name: Publish website to Github Pages + runner: ubuntu-latest + environment: + name: github-pages + url: ${{ steps.setup_pages.outputs.base_url }} + name: ${{ matrix.name }} + runs-on: ${{ matrix.runner }} + steps: + - uses: actions/checkout@v4 + - name: Build website + run: cargo run -p website + - name: Setup Pages + uses: actions/configure-pages@v4 + - name: Upload pages + uses: actions/upload-pages-artifact@v3 + with: + path: 'website/root' + - name: Deploy pages + uses: actions/deploy-pages@v4 diff --git a/.gitignore b/.gitignore index 7b69c6476..ba7ca1f2f 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,8 @@ /.project /docs/book /docs/mdbook_bin +/website/root +/website/shotover_repo_for_docs /shotover-proxy/build/packages /some_local_file /test-helpers/src/connection/kafka/node/node_modules \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 038791f70..c563e037a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "addr2line" @@ -75,9 +75,9 @@ dependencies = [ [[package]] name = "allocator-api2" -version = "0.2.19" +version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "611cc2ae7d2e242c457e4be7f97036b8ad9ca152b499f53faf99b1ed8fc2553f" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" [[package]] name = "android-tzdata" @@ -151,9 +151,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.93" +version = "1.0.94" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c95c10ba0b00a02636238b814946408b1322d5ac4760326e6fb8ec956d85775" +checksum = "c1fd03a028ef38ba2276dce7e33fcd6369c158a1bca17946c4b1b701891c1ff7" [[package]] name = "arc-swap" @@ -163,9 +163,9 @@ checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457" [[package]] name = "async-compression" -version = "0.4.17" +version = "0.4.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cb8f1d480b0ea3783ab015936d2a55c87e219676f0c0b7dec61494043f21857" +checksum = "df895a515f70646414f4b45c0b79082783b80552b373a68283012928df56f522" dependencies = [ "flate2", "futures-core", @@ -182,7 +182,7 @@ checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -217,7 +217,7 @@ checksum = "99e1aca718ea7b89985790c94aad72d77533063fe00bc497bb79a7c2dae6a661" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -361,9 +361,9 @@ dependencies = [ [[package]] name = "aws-sdk-sts" -version = "1.49.0" +version = "1.50.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53dcf5e7d9bd1517b8b998e170e650047cea8a2b85fe1835abe3210713e541b7" +checksum = "6ada54e5f26ac246dc79727def52f7f8ed38915cb47781e2a72213957dc3a7d5" dependencies = [ "aws-credential-types", "aws-runtime", @@ -397,7 +397,7 @@ dependencies = [ "hex", "hmac", "http 0.2.12", - "http 1.1.0", + "http 1.2.0", "once_cell", "percent-encoding", "sha2", @@ -457,9 +457,9 @@ dependencies = [ [[package]] name = "aws-smithy-runtime" -version = "1.7.3" +version = "1.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be28bd063fa91fd871d131fc8b68d7cd4c5fa0869bea68daca50dcb1cbd76be2" +checksum = "9f20685047ca9d6f17b994a07f629c813f08b5bce65523e47124879e60103d45" dependencies = [ "aws-smithy-async", "aws-smithy-http", @@ -492,7 +492,7 @@ dependencies = [ "aws-smithy-types", "bytes", "http 0.2.12", - "http 1.1.0", + "http 1.2.0", "pin-project-lite", "tokio", "tracing", @@ -510,7 +510,7 @@ dependencies = [ "bytes-utils", "futures-core", "http 0.2.12", - "http 1.1.0", + "http 1.2.0", "http-body 0.4.6", "http-body 1.0.1", "http-body-util", @@ -571,18 +571,18 @@ dependencies = [ [[package]] name = "axum" -version = "0.7.7" +version = "0.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "504e3947307ac8326a5437504c517c4b56716c9d98fac0028c2acc7ca47d70ae" +checksum = "edca88bc138befd0323b20752846e6587272d3b03b0343c8ea28a6f819e6e71f" dependencies = [ "async-trait", "axum-core", "bytes", "futures-util", - "http 1.1.0", + "http 1.2.0", "http-body 1.0.1", "http-body-util", - "hyper 1.5.0", + "hyper 1.5.1", "hyper-util", "itoa", "matchit", @@ -592,7 +592,7 @@ dependencies = [ "pin-project-lite", "rustversion", "serde", - "sync_wrapper 1.0.1", + "sync_wrapper 1.0.2", "tokio", "tower", "tower-layer", @@ -609,13 +609,13 @@ dependencies = [ "async-trait", "bytes", "futures-util", - "http 1.1.0", + "http 1.2.0", "http-body 1.0.1", "http-body-util", "mime", "pin-project-lite", "rustversion", - "sync_wrapper 1.0.1", + "sync_wrapper 1.0.2", "tower-layer", "tower-service", "tracing", @@ -679,6 +679,15 @@ version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" +[[package]] +name = "basic-toml" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "823388e228f614e9558c6804262db37960ec8821856535f5c3f59913140558f8" +dependencies = [ + "serde", +] + [[package]] name = "bcrypt-pbkdf" version = "0.10.0" @@ -755,9 +764,9 @@ checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" [[package]] name = "bytemuck" -version = "1.19.0" +version = "1.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8334215b81e418a0a7bdb8ef0849474f40bb10c8b71f1c4ed315cff49f32494d" +checksum = "8b37c88a63ffd85d15b406896cc343916d7cf57838a847b3a6f2ca5d39a5695a" dependencies = [ "bytemuck_derive", ] @@ -770,7 +779,7 @@ checksum = "bcfcc3cd946cb52f0bbfdbbcfa2f4e24f75ebb6c0e1002f7c25904fada18b9ec" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -781,9 +790,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.8.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ac0150caa2ae65ca5bd83f25c7de183dea78d4d366469f148435e2acfbad0da" +checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b" dependencies = [ "serde", ] @@ -800,9 +809,9 @@ dependencies = [ [[package]] name = "cached" -version = "0.53.1" +version = "0.54.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4d73155ae6b28cf5de4cfc29aeb02b8a1c6dab883cb015d15cd514e42766846" +checksum = "9718806c4a2fe9e8a56fd736f97b340dd10ed1be8ed733ed50449f351dc33cae" dependencies = [ "ahash", "async-trait", @@ -811,7 +820,7 @@ dependencies = [ "futures", "hashbrown 0.14.5", "once_cell", - "thiserror", + "thiserror 1.0.69", "tokio", "web-time", ] @@ -825,7 +834,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -845,9 +854,9 @@ dependencies = [ [[package]] name = "cargo-platform" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24b1f0365a6c6bb4020cd05806fd0d33c44d38046b8bd7f0e40814b9763cabfc" +checksum = "e35af189006b9c0f00a064685c727031e3ed2d8020f7ba284d78cc2671bd36ea" dependencies = [ "serde", ] @@ -863,7 +872,21 @@ dependencies = [ "semver", "serde", "serde_json", - "thiserror", + "thiserror 1.0.69", +] + +[[package]] +name = "cargo_metadata" +version = "0.19.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8769706aad5d996120af43197bf46ef6ad0fda35216b4505f926a365a232d924" +dependencies = [ + "camino", + "cargo-platform", + "semver", + "serde", + "serde_json", + "thiserror 2.0.4", ] [[package]] @@ -899,14 +922,14 @@ dependencies = [ "chrono", "crc32fast", "derivative", - "derive_more 1.0.0", + "derive_more", "float_eq", "integer-encoding", "itertools 0.13.0", "lz4_flex", "num-bigint", "snap", - "thiserror", + "thiserror 1.0.69", "time", "uuid", ] @@ -928,9 +951,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.1.37" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40545c26d092346d8a8dab71ee48e7685a7a9cba76e634790c215b41a4a7b4cf" +checksum = "f34d93e62b03caf570cccc334cbc6c2fceca82f39211051345108adcba3eebdc" dependencies = [ "jobserver", "libc", @@ -939,24 +962,23 @@ dependencies = [ [[package]] name = "cdrs-tokio" -version = "8.1.3" +version = "8.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be8840d17b05de2dd9a96df0f38fc7d7341da32db1682f083ab8016ce4311bac" +checksum = "35fa999539d7c5f3f86ecb9c215802514cf1457436610dd3205c326bf8226fc6" dependencies = [ "arc-swap", "atomic", "bytemuck", - "bytes", "cassandra-protocol", "derivative", - "derive_more 0.99.18", + "derive_more", "futures", "fxhash", - "itertools 0.12.1", + "itertools 0.13.0", "lazy_static", "rand", "serde_json", - "thiserror", + "thiserror 2.0.4", "tokio", "tracing", "uuid", @@ -1065,9 +1087,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.20" +version = "4.5.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b97f376d85a664d5837dbae44bf546e6477a679ff6610010f17276f686d867e8" +checksum = "69371e34337c4c984bbe322360c2547210bf632eb2814bbe78a6e87a2935bd2b" dependencies = [ "clap_builder", "clap_derive", @@ -1075,9 +1097,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.20" +version = "4.5.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19bc80abd44e4bed93ca373a0704ccbd1b710dc5749406201bb018272808dc54" +checksum = "6e24c1b4099818523236a8ca881d2b45db98dadfb4625cf6608c12069fcbbde1" dependencies = [ "anstream", "anstyle", @@ -1094,14 +1116,14 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] name = "clap_lex" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" +checksum = "afb84c814227b90d6895e01398aee0d8033c00e7466aca416fb6a8e0eb19d8a7" [[package]] name = "clipboard-win" @@ -1114,9 +1136,9 @@ dependencies = [ [[package]] name = "cmake" -version = "0.1.51" +version = "0.1.52" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb1e43aa7fd152b1f968787f7dbcdeb306d1867ff373c69955211876c053f91a" +checksum = "c682c223677e0e5b6b7f63a64b9351844c3f1b1678a68b7ee617e30fb082620e" dependencies = [ "cc", ] @@ -1194,12 +1216,6 @@ version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" -[[package]] -name = "convert_case" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" - [[package]] name = "cookie-factory" version = "0.3.2" @@ -1225,6 +1241,16 @@ dependencies = [ "libc", ] +[[package]] +name = "core-foundation" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b55271e5c8c478ad3f38ad24ef34923091e0548492a266d19b3c0b4d82574c63" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "core-foundation-sys" version = "0.8.7" @@ -1233,9 +1259,9 @@ checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "cpufeatures" -version = "0.2.14" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0" +checksum = "16b80225097f2e5ae4e7179dd2266824648f3e2f49d9134d584b76389d31c4c3" dependencies = [ "libc", ] @@ -1362,15 +1388,6 @@ 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" @@ -1460,7 +1477,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -1500,7 +1517,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -1511,7 +1528,7 @@ checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ "darling_core", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -1579,19 +1596,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "derive_more" -version = "0.99.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f33878137e4dafd7fa914ad4e259e18a4e8e532b9617a2d0150262bf53abfce" -dependencies = [ - "convert_case", - "proc-macro2", - "quote", - "rustc_version", - "syn 2.0.87", -] - [[package]] name = "derive_more" version = "1.0.0" @@ -1609,7 +1613,7 @@ checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", "unicode-xid", ] @@ -1622,6 +1626,12 @@ dependencies = [ "cipher", ] +[[package]] +name = "devserver_lib" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edf215dbb8cb1409cca7645aaed35f9e39fb0a21855bba1ac48bc0334903bf66" + [[package]] name = "diff" version = "0.1.13" @@ -1648,7 +1658,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -1681,7 +1691,7 @@ name = "ec2-cargo" version = "0.1.0" dependencies = [ "aws-throwaway", - "cargo_metadata", + "cargo_metadata 0.19.1", "clap", "shell-quote", "shellfish", @@ -1795,12 +1805,12 @@ dependencies = [ [[package]] name = "errno" -version = "0.3.9" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -1854,9 +1864,9 @@ checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" [[package]] name = "flate2" -version = "1.0.34" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1b589b4dc103969ad3cf85c950899926ec64300a1a46d76c03a6072957036f0" +checksum = "c936bfdafb507ebbf50b8074c54fa31c5be9a1e7e5f467dd659697041407d07c" dependencies = [ "crc32fast", "miniz_oxide", @@ -1864,9 +1874,9 @@ dependencies = [ [[package]] name = "float-cmp" -version = "0.9.0" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98de4bbd547a563b716d8dfa9aad1cb19bfab00f4fa09a6a4ed21dbcf44ce9c4" +checksum = "b09cf3155332e944990140d967ff5eceb70df778b34f77d8075db46e4704e6d8" dependencies = [ "num-traits", ] @@ -1915,15 +1925,14 @@ dependencies = [ [[package]] name = "fred" -version = "9.4.0" +version = "10.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cdd5378252ea124b712e0ac55147d26ae3af575883b34b8423091a4c719606b" +checksum = "9dfdd0e46d87d0e8fc1e6636a5dd3b9a5c708722e9662df289ba62a8c198a721" dependencies = [ "arc-swap", "async-trait", "bytes", "bytes-utils", - "crossbeam-queue", "float-cmp", "fred-macros", "futures", @@ -1931,10 +1940,10 @@ dependencies = [ "parking_lot", "rand", "redis-protocol", - "rustls 0.23.18", - "rustls-native-certs 0.7.3", + "rustls 0.23.19", + "rustls-native-certs 0.8.1", "semver", - "socket2 0.5.7", + "socket2 0.5.8", "tokio", "tokio-rustls 0.26.0", "tokio-stream", @@ -1951,7 +1960,7 @@ checksum = "1458c6e22d36d61507034d5afecc64f105c1d39712b7ac6ec3b352c423f715cc" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -2016,7 +2025,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -2083,8 +2092,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", + "js-sys", "libc", "wasi", + "wasm-bindgen", ] [[package]] @@ -2152,7 +2163,7 @@ dependencies = [ "futures-sink", "futures-util", "http 0.2.12", - "indexmap 2.6.0", + "indexmap 2.7.0", "slab", "tokio", "tokio-util", @@ -2161,17 +2172,17 @@ dependencies = [ [[package]] name = "h2" -version = "0.4.6" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "524e8ac6999421f49a846c2d4411f337e53497d8ec55d67753beffa43c5d9205" +checksum = "ccae279728d634d083c00f6099cb58f01cc99c145b84b8be2f6c74618d79922e" dependencies = [ "atomic-waker", "bytes", "fnv", "futures-core", "futures-sink", - "http 1.1.0", - "indexmap 2.6.0", + "http 1.2.0", + "indexmap 2.7.0", "slab", "tokio", "tokio-util", @@ -2206,9 +2217,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.15.1" +version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a9bfc1af68b1726ea47d3d5109de126281def866b33970e10fbab11b5dafab3" +checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" dependencies = [ "foldhash", ] @@ -2219,12 +2230,6 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" -[[package]] -name = "hermit-abi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" - [[package]] name = "hermit-abi" version = "0.4.0" @@ -2289,9 +2294,9 @@ dependencies = [ [[package]] name = "http" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" +checksum = "f16ca2af56261c99fba8bac40a10251ce8188205a4c448fbb745a2e4daa76fea" dependencies = [ "bytes", "fnv", @@ -2316,7 +2321,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ "bytes", - "http 1.1.0", + "http 1.2.0", ] [[package]] @@ -2327,7 +2332,7 @@ checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" dependencies = [ "bytes", "futures-util", - "http 1.1.0", + "http 1.2.0", "http-body 1.0.1", "pin-project-lite", ] @@ -2344,6 +2349,15 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" +[[package]] +name = "humansize" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6cb51c9a029ddc91b07a787f1d86b53ccfa49b0e86688c946ebe8d3555685dd7" +dependencies = [ + "libm", +] + [[package]] name = "hyper" version = "0.14.31" @@ -2361,7 +2375,7 @@ dependencies = [ "httpdate", "itoa", "pin-project-lite", - "socket2 0.5.7", + "socket2 0.5.8", "tokio", "tower-service", "tracing", @@ -2370,15 +2384,15 @@ dependencies = [ [[package]] name = "hyper" -version = "1.5.0" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbbff0a806a4728c99295b254c8838933b5b082d75e3cb70c8dab21fdfbcfa9a" +checksum = "97818827ef4f364230e16705d4706e2897df2bb60617d6ca15d598025a3c481f" dependencies = [ "bytes", "futures-channel", "futures-util", - "h2 0.4.6", - "http 1.1.0", + "h2 0.4.7", + "http 1.2.0", "http-body 1.0.1", "httparse", "httpdate", @@ -2412,10 +2426,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08afdbb5c31130e3034af566421053ab03787c640246a446327f550d11bcb333" dependencies = [ "futures-util", - "http 1.1.0", - "hyper 1.5.0", + "http 1.2.0", + "hyper 1.5.1", "hyper-util", - "rustls 0.23.18", + "rustls 0.23.19", "rustls-pki-types", "tokio", "tokio-rustls 0.26.0", @@ -2431,7 +2445,7 @@ checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" dependencies = [ "bytes", "http-body-util", - "hyper 1.5.0", + "hyper 1.5.1", "hyper-util", "native-tls", "tokio", @@ -2448,11 +2462,11 @@ dependencies = [ "bytes", "futures-channel", "futures-util", - "http 1.1.0", + "http 1.2.0", "http-body 1.0.1", - "hyper 1.5.0", + "hyper 1.5.1", "pin-project-lite", - "socket2 0.5.7", + "socket2 0.5.8", "tokio", "tower-service", "tracing", @@ -2596,7 +2610,7 @@ checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -2639,12 +2653,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.6.0" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" +checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f" dependencies = [ "equivalent", - "hashbrown 0.15.1", + "hashbrown 0.15.2", "serde", ] @@ -2682,7 +2696,7 @@ version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "261f68e344040fbd0edea105bef17c66edf46f984ddb1115b775ce31be948f4b" dependencies = [ - "hermit-abi 0.4.0", + "hermit-abi", "libc", "windows-sys 0.52.0", ] @@ -2722,9 +2736,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.11" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" +checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" [[package]] name = "j4rs" @@ -2785,10 +2799,11 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.72" +version = "0.3.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a88f1bda2bd75b0452a14784937d796722fdebfe50df998aeb3f0b7603019a9" +checksum = "a865e038f7f6ed956f788f0d7d60c541fff74c7bd74272c5d4cf15c63743e705" dependencies = [ + "once_cell", "wasm-bindgen", ] @@ -2802,7 +2817,7 @@ dependencies = [ "bytes", "crc", "crc32c", - "indexmap 2.6.0", + "indexmap 2.7.0", "paste", "uuid", ] @@ -2818,15 +2833,15 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.162" +version = "0.2.167" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18d287de67fe55fd7e1581fe933d965a5a9477b38e949cfa9f8574ef01506398" +checksum = "09d6582e104315a817dff97f75133544b2e094ee22447d2acf4a74e189ba06fc" [[package]] name = "libloading" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4" +checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34" dependencies = [ "cfg-if", "windows-targets 0.52.6", @@ -2858,9 +2873,9 @@ checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" [[package]] name = "litemap" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "643cb0b8d4fcc284004d5fd0d67ccf61dfffadb7f75e1e71bc420f4688a3a704" +checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104" [[package]] name = "lock_api" @@ -2916,9 +2931,9 @@ checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "metrics" -version = "0.24.0" +version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ae428771d17306715c5091d446327d1cfdedc82185c65ba8423ab404e45bf10" +checksum = "7a7deb012b3b2767169ff203fadb4c6b0b82b947512e5eb9e0b78c2e186ad9e3" dependencies = [ "ahash", "portable-atomic", @@ -2931,11 +2946,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85b6f8152da6d7892ff1b7a1c0fa3f435e92b5918ad67035c3bb432111d9a29b" dependencies = [ "base64 0.22.1", - "indexmap 2.6.0", + "indexmap 2.7.0", "metrics", "metrics-util", "quanta", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -2946,7 +2961,7 @@ checksum = "15b482df36c13dd1869d73d14d28cd4855fbd6cfc32294bee109908a9f4a4ed7" dependencies = [ "crossbeam-epoch", "crossbeam-utils", - "hashbrown 0.15.1", + "hashbrown 0.15.2", "metrics", "quanta", "sketches-ddsketch", @@ -2958,6 +2973,16 @@ version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" +[[package]] +name = "mime_guess" +version = "2.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e" +dependencies = [ + "mime", + "unicase", +] + [[package]] name = "minimal-lexical" version = "0.2.1" @@ -2975,11 +3000,10 @@ dependencies = [ [[package]] name = "mio" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" +checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" dependencies = [ - "hermit-abi 0.3.9", "libc", "wasi", "windows-sys 0.52.0", @@ -2997,7 +3021,7 @@ dependencies = [ "openssl-probe", "openssl-sys", "schannel", - "security-framework", + "security-framework 2.11.1", "security-framework-sys", "tempfile", ] @@ -3143,23 +3167,23 @@ dependencies = [ [[package]] name = "num_enum" -version = "0.5.11" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f646caf906c20226733ed5b1374287eb97e3c2a5c227ce668c1f2ce20ae57c9" +checksum = "4e613fc340b2220f734a8595782c551f1250e969d87d3be1ae0579e8d4065179" dependencies = [ "num_enum_derive", ] [[package]] name = "num_enum_derive" -version = "0.5.11" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcbff9bc912032c62bf65ef1d5aea88983b420f4f839db1e9b0c281a25c9c799" +checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56" dependencies = [ - "proc-macro-crate 1.3.1", + "proc-macro-crate", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.90", ] [[package]] @@ -3232,7 +3256,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -3243,9 +3267,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-src" -version = "300.4.0+3.4.0" +version = "300.4.1+3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a709e02f2b4aca747929cca5ed248880847c650233cf8b8cdc48f40aaf4898a6" +checksum = "faa4eac4138c62414b5622d1b31c5c304f34b406b013c079c2bbc652fdd6678c" dependencies = [ "cc", ] @@ -3520,9 +3544,9 @@ dependencies = [ [[package]] name = "portable-atomic" -version = "1.9.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc9c68a3f6da06753e9335d63e27f6b9754dd1920d941135b7ea8224f141adb2" +checksum = "280dc24453071f1b63954171985a0b0d30058d287960968b9b2aca264c8d4ee6" [[package]] name = "powerfmt" @@ -3564,30 +3588,20 @@ dependencies = [ "elliptic-curve", ] -[[package]] -name = "proc-macro-crate" -version = "1.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" -dependencies = [ - "once_cell", - "toml_edit 0.19.15", -] - [[package]] name = "proc-macro-crate" version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b" dependencies = [ - "toml_edit 0.22.22", + "toml_edit", ] [[package]] name = "proc-macro2" -version = "1.0.89" +version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e" +checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" dependencies = [ "unicode-ident", ] @@ -3621,37 +3635,40 @@ dependencies = [ [[package]] name = "quinn" -version = "0.11.5" +version = "0.11.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c7c5fdde3cdae7203427dc4f0a68fe0ed09833edc525a03456b153b79828684" +checksum = "62e96808277ec6f97351a2380e6c25114bc9e67037775464979f3037c92d05ef" dependencies = [ "bytes", "pin-project-lite", "quinn-proto", "quinn-udp", "rustc-hash", - "rustls 0.23.18", - "socket2 0.5.7", - "thiserror", + "rustls 0.23.19", + "socket2 0.5.8", + "thiserror 2.0.4", "tokio", "tracing", ] [[package]] name = "quinn-proto" -version = "0.11.8" +version = "0.11.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fadfaed2cd7f389d0161bb73eeb07b7b78f8691047a6f3e73caaeae55310a4a6" +checksum = "a2fe5ef3495d7d2e377ff17b1a8ce2ee2ec2a18cde8b6ad6619d65d0701c135d" dependencies = [ "bytes", + "getrandom", "rand", "ring", "rustc-hash", - "rustls 0.23.18", + "rustls 0.23.19", + "rustls-pki-types", "slab", - "thiserror", + "thiserror 2.0.4", "tinyvec", "tracing", + "web-time", ] [[package]] @@ -3663,7 +3680,7 @@ dependencies = [ "cfg_aliases 0.2.1", "libc", "once_cell", - "socket2 0.5.7", + "socket2 0.5.8", "tracing", "windows-sys 0.59.0", ] @@ -3790,9 +3807,9 @@ dependencies = [ [[package]] name = "rdkafka-sys" -version = "4.7.0+2.3.0" +version = "4.8.0+2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55e0d2f9ba6253f6ec72385e453294f8618e9e15c2c6aba2a5c01ccf9622d615" +checksum = "ced38182dc436b3d9df0c77976f37a67134df26b050df1f0006688e46fc4c8be" dependencies = [ "cmake", "libc", @@ -3826,9 +3843,9 @@ dependencies = [ [[package]] name = "redis-protocol" -version = "5.0.1" +version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65deb7c9501fbb2b6f812a30d59c0253779480853545153a51d8e9e444ddc99f" +checksum = "9cdba59219406899220fc4cdfd17a95191ba9c9afb719b5fa5a083d63109a9f1" dependencies = [ "bytes", "bytes-utils", @@ -3855,7 +3872,7 @@ checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.4.8", + "regex-automata 0.4.9", "regex-syntax 0.8.5", ] @@ -3870,9 +3887,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.8" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" dependencies = [ "aho-corasick", "memchr", @@ -3915,11 +3932,11 @@ dependencies = [ "encoding_rs", "futures-core", "futures-util", - "h2 0.4.6", - "http 1.1.0", + "h2 0.4.7", + "http 1.2.0", "http-body 1.0.1", "http-body-util", - "hyper 1.5.0", + "hyper 1.5.1", "hyper-rustls 0.27.3", "hyper-tls", "hyper-util", @@ -3932,13 +3949,13 @@ dependencies = [ "percent-encoding", "pin-project-lite", "quinn", - "rustls 0.23.18", + "rustls 0.23.19", "rustls-pemfile 2.2.0", "rustls-pki-types", "serde", "serde_json", "serde_urlencoded", - "sync_wrapper 1.0.1", + "sync_wrapper 1.0.2", "system-configuration", "tokio", "tokio-native-tls", @@ -3978,11 +3995,52 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "rinja" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3dc4940d00595430b3d7d5a01f6222b5e5b51395d1120bdb28d854bb8abb17a5" +dependencies = [ + "humansize", + "itoa", + "percent-encoding", + "rinja_derive", +] + +[[package]] +name = "rinja_derive" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d9ed0146aef6e2825f1b1515f074510549efba38d71f4554eec32eb36ba18b" +dependencies = [ + "basic-toml", + "memchr", + "mime", + "mime_guess", + "proc-macro2", + "quote", + "rinja_parser", + "rustc-hash", + "serde", + "syn 2.0.90", +] + +[[package]] +name = "rinja_parser" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93f9a866e2e00a7a1fb27e46e9e324a6f7c0e7edc4543cae1d38f4e4a100c610" +dependencies = [ + "memchr", + "nom", + "serde", +] + [[package]] name = "rsa" -version = "0.9.6" +version = "0.9.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d0e5124fcb30e76a7e79bfee683a2746db83784b86289f6251b54b7950a0dfc" +checksum = "47c75d7c5c6b673e58bf54d8544a9f432e3a925b0e80f7cd3602ab5c50c55519" dependencies = [ "const-oid", "digest", @@ -4019,13 +4077,13 @@ checksum = "c5e1711e7d14f74b12a58411c542185ef7fb7f2e7f8ee6e2940a883628522b42" dependencies = [ "cfg-if", "glob", - "proc-macro-crate 3.2.0", + "proc-macro-crate", "proc-macro2", "quote", "regex", "relative-path", "rustc_version", - "syn 2.0.87", + "syn 2.0.90", "unicode-ident", ] @@ -4037,7 +4095,7 @@ checksum = "b3a8fb4672e840a587a66fc577a5491375df51ddb88f2a2c2a792598c326fe14" dependencies = [ "quote", "rand", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -4079,7 +4137,7 @@ dependencies = [ "ssh-encoding", "ssh-key", "subtle", - "thiserror", + "thiserror 1.0.69", "tokio", ] @@ -4137,7 +4195,7 @@ dependencies = [ "spki", "ssh-encoding", "ssh-key", - "thiserror", + "thiserror 1.0.69", "tokio", "tokio-stream", "typenum", @@ -4152,9 +4210,9 @@ checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" [[package]] name = "rustc-hash" -version = "2.0.0" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "583034fd73374156e66797ed8e5b0d5690409c9226b22d87cb7f19821c05d152" +checksum = "c7fb8039b3032c191086b10f11f319a6e99e1e82889c5cc6046f515c9db1d497" [[package]] name = "rustc_version" @@ -4167,9 +4225,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.40" +version = "0.38.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99e4ea3e1cdc4b559b8e5650f9c8e5998e3e5c1343b4eaf034565f32318d63c0" +checksum = "d7f649912bc1495e167a6edee79151c84b1bad49748cb4f1f1167f459f6224f6" dependencies = [ "bitflags", "errno", @@ -4192,9 +4250,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.18" +version = "0.23.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c9cc1d47e243d655ace55ed38201c19ae02c148ae56412ab8750e8f0166ab7f" +checksum = "934b404430bb06b3fae2cba809eb45a1ab1aecd64491213d7c3301b88393f8d1" dependencies = [ "log", "once_cell", @@ -4214,33 +4272,19 @@ dependencies = [ "openssl-probe", "rustls-pemfile 1.0.4", "schannel", - "security-framework", + "security-framework 2.11.1", ] [[package]] name = "rustls-native-certs" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5bfb394eeed242e909609f56089eecfe5fda225042e8b171791b9c95f5931e5" -dependencies = [ - "openssl-probe", - "rustls-pemfile 2.2.0", - "rustls-pki-types", - "schannel", - "security-framework", -] - -[[package]] -name = "rustls-native-certs" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcaf18a4f2be7326cd874a5fa579fae794320a0f388d365dca7e480e55f83f8a" +checksum = "7fcff2dd52b58a8d98a70243663a0d234c4e2b79235637849d15913394a247d3" dependencies = [ "openssl-probe", - "rustls-pemfile 2.2.0", "rustls-pki-types", "schannel", - "security-framework", + "security-framework 3.0.1", ] [[package]] @@ -4266,6 +4310,9 @@ name = "rustls-pki-types" version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "16f1201b3c9a7ee8039bcadc17b7e605e2945b27eee7631788c1bd2b0643674b" +dependencies = [ + "web-time", +] [[package]] name = "rustls-webpki" @@ -4356,9 +4403,9 @@ dependencies = [ [[package]] name = "schannel" -version = "0.1.26" +version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01227be5826fa0690321a2ba6c5cd57a19cf3f6a09e76973b58e61de6ab9d1c1" +checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" dependencies = [ "windows-sys 0.59.0", ] @@ -4415,8 +4462,8 @@ dependencies = [ "scylla-macros", "smallvec", "snap", - "socket2 0.5.7", - "thiserror", + "socket2 0.5.8", + "thiserror 1.0.69", "tokio", "tokio-openssl", "tracing", @@ -4435,7 +4482,7 @@ dependencies = [ "lz4_flex", "scylla-macros", "snap", - "thiserror", + "thiserror 1.0.69", "tokio", "uuid", ] @@ -4449,7 +4496,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -4473,7 +4520,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" dependencies = [ "bitflags", - "core-foundation", + "core-foundation 0.9.4", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1415a607e92bec364ea2cf9264646dcce0f91e6d65281bd6f2819cca3bf39c8" +dependencies = [ + "bitflags", + "core-foundation 0.10.0", "core-foundation-sys", "libc", "security-framework-sys", @@ -4500,29 +4560,29 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.214" +version = "1.0.215" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f55c3193aca71c12ad7890f1785d2b73e1b9f63a0bbc353c08ef26fe03fc56b5" +checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.214" +version = "1.0.215" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de523f781f095e28fa605cdce0f8307e451cc0fd14e2eb4cd2e98a355b147766" +checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] name = "serde_json" -version = "1.0.132" +version = "1.0.133" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d726bfaff4b320266d395898905d0eba0345aae23b54aee3a737e260fd46db03" +checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377" dependencies = [ "itoa", "memchr", @@ -4552,7 +4612,7 @@ dependencies = [ "chrono", "hex", "indexmap 1.9.3", - "indexmap 2.6.0", + "indexmap 2.7.0", "serde", "serde_derive", "serde_json", @@ -4569,7 +4629,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -4578,7 +4638,7 @@ version = "0.9.34+deprecated" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" dependencies = [ - "indexmap 2.6.0", + "indexmap 2.7.0", "itoa", "ryu", "serde", @@ -4637,7 +4697,7 @@ dependencies = [ "async-trait", "cfg-if", "rustyline", - "thiserror", + "thiserror 1.0.69", "yansi", ] @@ -4681,7 +4741,7 @@ dependencies = [ "governor", "hex", "hex-literal", - "http 1.1.0", + "http 1.2.0", "httparse", "itertools 0.13.0", "kafka-protocol", @@ -4695,14 +4755,14 @@ dependencies = [ "pretty_assertions", "rand", "redis-protocol", - "rustls 0.23.18", + "rustls 0.23.19", "rustls-pemfile 2.2.0", "rustls-pki-types", "sasl", "serde", "serde_json", "serde_yaml", - "thiserror", + "thiserror 2.0.4", "tokio", "tokio-rustls 0.26.0", "tokio-stream", @@ -4820,9 +4880,9 @@ dependencies = [ [[package]] name = "socket2" -version = "0.5.7" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" +checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8" dependencies = [ "libc", "windows-sys 0.52.0", @@ -4941,7 +5001,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -4973,9 +5033,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.87" +version = "2.0.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d" +checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31" dependencies = [ "proc-macro2", "quote", @@ -4990,9 +5050,9 @@ checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" [[package]] name = "sync_wrapper" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394" +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" dependencies = [ "futures-core", ] @@ -5005,7 +5065,7 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -5015,7 +5075,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" dependencies = [ "bitflags", - "core-foundation", + "core-foundation 0.9.4", "system-configuration-sys", ] @@ -5053,7 +5113,7 @@ dependencies = [ "cdrs-tokio", "docker-compose-runner", "futures-util", - "http 1.1.0", + "http 1.2.0", "itertools 0.13.0", "j4rs", "openssl", @@ -5063,7 +5123,7 @@ dependencies = [ "rdkafka", "redis", "reqwest", - "rustls 0.23.18", + "rustls 0.23.19", "rustls-pemfile 2.2.0", "rustls-pki-types", "scylla", @@ -5085,7 +5145,16 @@ version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" dependencies = [ - "thiserror-impl", + "thiserror-impl 1.0.69", +] + +[[package]] +name = "thiserror" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f49a1853cf82743e3b7950f77e0f4d622ca36cf4317cba00c767838bac8d490" +dependencies = [ + "thiserror-impl 2.0.4", ] [[package]] @@ -5096,7 +5165,18 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8381894bb3efe0c4acac3ded651301ceee58a15d47c2e34885ed1908ad667061" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", ] [[package]] @@ -5111,9 +5191,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.36" +version = "0.3.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" +checksum = "35e7868883861bd0e56d9ac6efcaaca0d6d5d82a2a7ec8209ff492c07cf37b21" dependencies = [ "deranged", "itoa", @@ -5132,9 +5212,9 @@ checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" [[package]] name = "time-macros" -version = "0.2.18" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" +checksum = "2834e6017e3e5e4b9834939793b282bc03b37a3336245fa820e35e233e2a85de" dependencies = [ "num-conv", "time-core", @@ -5177,9 +5257,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.41.1" +version = "1.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22cfb5bee7a6a52939ca9224d6ac897bb669134078daa8735560897f69de4d33" +checksum = "5cec9b21b0450273377fc97bd4c33a8acffc8c996c987a7c5b319a0083707551" dependencies = [ "backtrace", "bytes", @@ -5188,7 +5268,7 @@ dependencies = [ "parking_lot", "pin-project-lite", "signal-hook-registry", - "socket2 0.5.7", + "socket2 0.5.8", "tokio-macros", "windows-sys 0.52.0", ] @@ -5200,7 +5280,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0581e13b120b43f94b33fac60d6d7b37327e1dddad1b422b72b8dfbda0a453cd" dependencies = [ "anyhow", - "cargo_metadata", + "cargo_metadata 0.18.1", "chrono", "itertools 0.13.0", "nix 0.29.0", @@ -5231,7 +5311,7 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -5271,7 +5351,7 @@ version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" dependencies = [ - "rustls 0.23.18", + "rustls 0.23.19", "rustls-pki-types", "tokio", ] @@ -5295,8 +5375,8 @@ checksum = "edc5f74e248dc973e0dbb7b74c7e0d6fcc301c694ff50049504004ef4d0cdcd9" dependencies = [ "futures-util", "log", - "rustls 0.23.18", - "rustls-native-certs 0.8.0", + "rustls 0.23.19", + "rustls-native-certs 0.8.1", "rustls-pki-types", "tokio", "tokio-rustls 0.26.0", @@ -5322,26 +5402,15 @@ version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" -[[package]] -name = "toml_edit" -version = "0.19.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" -dependencies = [ - "indexmap 2.6.0", - "toml_datetime", - "winnow 0.5.40", -] - [[package]] name = "toml_edit" version = "0.22.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" dependencies = [ - "indexmap 2.6.0", + "indexmap 2.7.0", "toml_datetime", - "winnow 0.6.20", + "winnow", ] [[package]] @@ -5373,9 +5442,9 @@ checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" [[package]] name = "tracing" -version = "0.1.40" +version = "0.1.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" dependencies = [ "pin-project-lite", "tracing-attributes", @@ -5389,27 +5458,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3566e8ce28cc0a3fe42519fc80e6b4c943cc4c8cef275620eb8dac2d3d4e06cf" dependencies = [ "crossbeam-channel", - "thiserror", + "thiserror 1.0.69", "time", "tracing-subscriber", ] [[package]] name = "tracing-attributes" -version = "0.1.27" +version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] name = "tracing-core" -version = "0.1.32" +version = "0.1.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" dependencies = [ "once_cell", "valuable", @@ -5428,9 +5497,9 @@ dependencies = [ [[package]] name = "tracing-serde" -version = "0.1.3" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc6b213177105856957181934e4920de57730fc69bf42c37ee5bb664d406d9e1" +checksum = "704b1aeb7be0d0a84fc9828cae51dab5970fee5088f83d1dd7ee6f6246fc6ff1" dependencies = [ "serde", "tracing-core", @@ -5438,9 +5507,9 @@ dependencies = [ [[package]] name = "tracing-subscriber" -version = "0.3.18" +version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" +checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008" dependencies = [ "matchers", "nu-ansi-term 0.46.0", @@ -5493,14 +5562,14 @@ dependencies = [ "byteorder", "bytes", "data-encoding", - "http 1.1.0", + "http 1.2.0", "httparse", "log", "rand", - "rustls 0.23.18", + "rustls 0.23.19", "rustls-pki-types", "sha1", - "thiserror", + "thiserror 1.0.69", "utf-8", ] @@ -5547,14 +5616,20 @@ checksum = "70b20a22c42c8f1cd23ce5e34f165d4d37038f5b663ad20fb6adbdf029172483" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] +[[package]] +name = "unicase" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e51b68083f157f853b6379db119d1c1be0e6e4dec98101079dec41f6f5cf6df" + [[package]] name = "unicode-ident" -version = "1.0.13" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" +checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" [[package]] name = "unicode-segmentation" @@ -5598,9 +5673,9 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "url" -version = "2.5.3" +version = "2.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d157f1b96d14500ffdc1f10ba712e780825526c03d9a49b4d0324b0d9113ada" +checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" dependencies = [ "form_urlencoded", "idna", @@ -5710,9 +5785,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.95" +version = "0.2.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e" +checksum = "d15e63b4482863c109d70a7b8706c1e364eb6ea449b201a76c5b89cedcec2d5c" dependencies = [ "cfg-if", "once_cell", @@ -5721,36 +5796,37 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.95" +version = "0.2.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358" +checksum = "8d36ef12e3aaca16ddd3f67922bc63e48e953f126de60bd33ccc0101ef9998cd" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.45" +version = "0.4.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc7ec4f8827a71586374db3e87abdb5a2bb3a15afed140221307c3ec06b1f63b" +checksum = "9dfaf8f50e5f293737ee323940c7d8b08a66a95a419223d9f41610ca08b0833d" dependencies = [ "cfg-if", "js-sys", + "once_cell", "wasm-bindgen", "web-sys", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.95" +version = "0.2.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56" +checksum = "705440e08b42d3e4b36de7d66c944be628d579796b8090bfa3471478a2260051" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -5758,28 +5834,28 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.95" +version = "0.2.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" +checksum = "98c9ae5a76e46f4deecd0f0255cc223cfa18dc9b261213b8aa0c7b36f61b3f1d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.95" +version = "0.2.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d" +checksum = "6ee99da9c5ba11bd675621338ef6fa52296b76b83305e9b6e5c77d4c286d6d49" [[package]] name = "web-sys" -version = "0.3.72" +version = "0.3.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6488b90108c040df0fe62fa815cbdee25124641df01814dd7282749234c6112" +checksum = "a98bc3c33f0fe7e59ad7cd041b89034fa82a7c2d4365ca538dda6cdaf513863c" dependencies = [ "js-sys", "wasm-bindgen", @@ -5797,13 +5873,25 @@ dependencies = [ [[package]] name = "webpki-roots" -version = "0.26.6" +version = "0.26.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "841c67bff177718f1d4dfefde8d8f0e78f9b6589319ba88312f567fc5841a958" +checksum = "5d642ff16b7e79272ae451b7322067cdc17cadf68c23264be9d94a32319efe7e" dependencies = [ "rustls-pki-types", ] +[[package]] +name = "website" +version = "0.1.0" +dependencies = [ + "anyhow", + "clap", + "devserver_lib", + "rinja", + "semver", + "subprocess", +] + [[package]] name = "winapi" version = "0.3.9" @@ -6048,15 +6136,6 @@ dependencies = [ "tokio", ] -[[package]] -name = "winnow" -version = "0.5.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" -dependencies = [ - "memchr", -] - [[package]] name = "winnow" version = "0.6.20" @@ -6107,9 +6186,9 @@ dependencies = [ [[package]] name = "yoke" -version = "0.7.4" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c5b1314b079b0930c31e3af543d8ee1757b1951ae1e1565ec704403a7240ca5" +checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" dependencies = [ "serde", "stable_deref_trait", @@ -6119,13 +6198,13 @@ dependencies = [ [[package]] name = "yoke-derive" -version = "0.7.4" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28cc31741b18cb6f1d5ff12f5b7523e3d6eb0852bbbad19d73905511d9849b95" +checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", "synstructure", ] @@ -6147,27 +6226,27 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] name = "zerofrom" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91ec111ce797d0e0784a1116d0ddcdbea84322cd79e5d5ad173daeba4f93ab55" +checksum = "cff3ee08c995dee1859d998dea82f7374f2826091dd9cd47def953cae446cd2e" dependencies = [ "zerofrom-derive", ] [[package]] name = "zerofrom-derive" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ea7b4a3637ea8669cedf0f1fd5c286a17f3de97b8dd5a70a6c167a1730e63a5" +checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", "synstructure", ] @@ -6196,5 +6275,5 @@ checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] diff --git a/Cargo.toml b/Cargo.toml index 366e90819..be69dde5f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,6 +6,7 @@ members = [ "custom-transforms-example", "ec2-cargo", "windsock-cloud-docker", + "website", ] resolver = "2" @@ -43,7 +44,7 @@ rcgen = "0.13.0" subprocess = "0.2.7" chacha20poly1305 = { version = "0.10.0", features = ["std"] } csv = "1.2.0" -redis-protocol = { version = "5.0.0", features = ["bytes"] } +redis-protocol = { version = "6.0.0", features = ["bytes"] } bincode = "1.3.1" futures = "0.3" hex = "0.4.3" diff --git a/README.md b/README.md index b6a3e4f23..a2fe6f8ce 100644 --- a/README.md +++ b/README.md @@ -8,12 +8,12 @@ ## Documentation -For full documentation please go to [https://docs.shotover.io/](https://docs.shotover.io/shotover-blog/docs/user-guide/introduction.html) +For full documentation please go to [https://shotover.io/docs/latest](https://shotover.io/docs/latest/user-guide/introduction.html) ## Building Shotover is supported on Linux and macOS. -To build Shotover from source please refer to [the contributing documentation](https://docs.shotover.io/shotover-blog/docs/contributing.html) +To build Shotover from source please refer to [the contributing documentation](https://shotover.io/docs/latest/dev-docs/contributing.html) ## What is Shotover? diff --git a/custom-transforms-example/config/docker-compose.yaml b/custom-transforms-example/config/docker-compose.yaml index 24483c51f..f8891e78b 100644 --- a/custom-transforms-example/config/docker-compose.yaml +++ b/custom-transforms-example/config/docker-compose.yaml @@ -1,8 +1,8 @@ services: - redis-one: - image: library/redis:5.0.9 + valkey-one: + image: bitnami/valkey:7.2.5-debian-12-r9 ports: - "1111:6379" - volumes: - - ./redis.conf:/usr/local/etc/redis/redis.conf - command: [ "redis-server", "/usr/local/etc/redis/redis.conf" ] + environment: + ALLOW_EMPTY_PASSWORD: "yes" + VALKEY_TLS_ENABLED: "no" diff --git a/docs/src/SUMMARY.md b/docs/src/SUMMARY.md index 2e704bfab..a6cb0c44c 100644 --- a/docs/src/SUMMARY.md +++ b/docs/src/SUMMARY.md @@ -11,9 +11,9 @@ - [Sources](./sources.md) - [Transforms](./transforms.md) - [Examples]() - - [Redis Cluster]() - - [Unaware client](./examples/redis-clustering-unaware.md) - - [Aware client](./examples/redis-clustering-aware.md) + - [Valkey Cluster]() + - [Unaware client](./examples/valkey-clustering-unaware.md) + - [Aware client](./examples/valkey-clustering-aware.md) - [Cassandra Cluster]() - [Shotover sidecars](./examples/cassandra-cluster-shotover-sidecar.md) - [Contributing](./dev-docs/contributing.md) diff --git a/docs/src/examples/redis-clustering-aware.md b/docs/src/examples/redis-clustering-aware.md deleted file mode 100644 index c78e31039..000000000 --- a/docs/src/examples/redis-clustering-aware.md +++ /dev/null @@ -1,123 +0,0 @@ -# Redis Clustering with cluster aware client - -The following guide shows you how to configure Shotover to support proxying Redis cluster *aware* clients to [Redis cluster](https://redis.io/topics/cluster-spec). - -## Overview - -In this example, we will be connecting to a Redis cluster that has the following topology: - -* `172.16.1.2:6379` -* `172.16.1.3:6379` -* `172.16.1.4:6379` -* `172.16.1.5:6379` -* `172.16.1.6:6379` -* `172.16.1.7:6379` - -Shotover will be deployed as a sidecar to each node in the Redis cluster, listening on `6380`. Use the following [docker-compose.yaml](https://github.com/shotover/shotover-examples/blob/main/redis-cluster-1-1/docker-compose.yaml) to run the Redis cluster and Shotover sidecars. - -```console -curl -L https://raw.githubusercontent.com/shotover/shotover-examples/main/redis-cluster-1-1/docker-compose.yaml --output docker-compose.yaml -``` - -Below we can see an example of a Redis node and it's Shotover sidecar. Notice they are running on the same network address (`172.16.1.2`) and the present directory is being mounted to allow Shotover to access the config and topology files. - -```YAML - -redis-node-0: - image: bitnami/redis-cluster:6.2.12-debian-11-r26 - networks: - cluster_subnet: - ipv4_address: 172.16.1.2 - environment: - - 'ALLOW_EMPTY_PASSWORD=yes' - - 'REDIS_NODES=redis-node-0 redis-node-1 redis-node-2' - -shotover-0: - restart: always - depends_on: - - redis-node-0 - image: shotover/shotover-proxy - network_mode: "service:redis-node-0" - volumes: - - type: bind - source: $PWD - target: /config - -``` - -In this example we will use `redis-benchmark` with cluster mode enabled as our Redis cluster aware client application. - -## Configuration - -First we will modify our `topology.yaml` file to have a single Redis source. This will: - -* Define how Shotover listens for incoming connections from our client application (`redis-benchmark`). -* Configure Shotover to connect to the Redis node via our defined remote address. -* Configure Shotover to rewrite all Redis ports with our Shotover port when the cluster aware driver is talking to the cluster, through Shotover. -* Connect our Redis Source to our Redis cluster sink (transform). - -```yaml ---- -sources: - - Redis: - name: "redis" - listen_addr: "0.0.0.0:6380" - chain: - - RedisClusterPortsRewrite: - new_port: 6380 - - RedisSinkSingle: - remote_address: "0.0.0.0:6379" - connect_timeout_ms: 3000 -``` - -Modify an existing `topology.yaml` or create a new one and place the above example as the file's contents. - -You will also need a [config.yaml](https://raw.githubusercontent.com/shotover/shotover-examples/main/redis-cluster-1-1/config.yaml) to run Shotover. - -```shell -curl -L https://raw.githubusercontent.com/shotover/shotover-examples/main/redis-cluster-1-1/config.yaml --output config.yaml -``` - -## Starting - -We can now start the services with: - -```shell -docker-compose up -d -``` - -## Testing - -With everything now up and running, we can test out our client application. Let's start it up! - -First we will run `redis-benchmark` directly on our cluster. - -```console -redis-benchmark -h 172.16.1.2 -p 6379 -t set,get --cluster -``` - -If everything works correctly you should see the following, along with the benchmark results which have been omitted for brevity. Notice all traffic is going through the Redis port on `6379`. - -```console -Cluster has 3 master nodes: - -Master 0: d5eaf45804215f80cfb661928c1a84e1da7406a9 172.16.1.3:6379 -Master 1: d774cd063e430d34a71bceaab851d7744134e22f 172.16.1.2:6379 -Master 2: 04b301f1b165d81d5fb86e50312e9cc4898cbcce 172.16.1.4:6379 -``` - -Now run it again but on the Shotover port this time. - -```console -redis-benchmark -h 172.16.1.2 -p 6380 -t set,get --cluster -``` - -You should see the following, notice that all traffic is going through Shotover on `6380` instead of the Redis port of `6379`: - -```console -Cluster has 3 master nodes: - -Master 0: 04b301f1b165d81d5fb86e50312e9cc4898cbcce 172.16.1.4:6380 -Master 1: d5eaf45804215f80cfb661928c1a84e1da7406a9 172.16.1.3:6380 -Master 2: d774cd063e430d34a71bceaab851d7744134e22f 172.16.1.2:6380 -``` diff --git a/docs/src/examples/redis-clustering-unaware.md b/docs/src/examples/redis-clustering-unaware.md deleted file mode 100644 index e80498caf..000000000 --- a/docs/src/examples/redis-clustering-unaware.md +++ /dev/null @@ -1,187 +0,0 @@ -# Redis Clustering - -The following guide shows you how to configure Shotover Proxy to support transparently proxying Redis cluster _unaware_ clients to a [Redis cluster](https://redis.io/topics/cluster-spec). - -## General Configuration - -First you need to setup a Redis cluster and Shotover. - -The easiest way to do this is with this example [docker-compose.yaml](https://github.com/shotover/shotover-examples/blob/main/redis-cluster-1-many/docker-compose.yaml) -You should first inspect the `docker-compose.yaml` to understand what the cluster looks like and how its exposed to the network. - -Then run: - -```shell -curl -L https://raw.githubusercontent.com/shotover/shotover-examples/main/redis-cluster-1-many/docker-compose.yaml --output docker-compose.yaml -``` - -Alternatively you could spin up a hosted Redis cluster on [any cloud provider that provides it](https://www.instaclustr.com/products/managed-redis). -This more accurately reflects a real production use but will take a bit more setup. -And reduce the docker-compose.yaml to just the shotover part - -```yaml -services: - shotover-0: - networks: - cluster_subnet: - ipv4_address: 172.16.1.9 - image: shotover/shotover-proxy:v0.1.10 - volumes: - - .:/config -networks: - cluster_subnet: - name: cluster_subnet - driver: bridge - ipam: - driver: default - config: - - subnet: 172.16.1.0/24 - gateway: 172.16.1.1 -``` - -## Shotover Configuration - -```yaml ---- -sources: - - Redis: - name: "redis" - # define where shotover listens for incoming connections from our client application (`redis-benchmark`). - listen_addr: "0.0.0.0:6379" - chain: - # configure Shotover to connect to the Redis cluster via our defined contact points - - RedisSinkCluster: - first_contact_points: - - "172.16.1.2:6379" - - "172.16.1.3:6379" - - "172.16.1.4:6379" - - "172.16.1.5:6379" - - "172.16.1.6:6379" - - "172.16.1.7:6379" - connect_timeout_ms: 3000 -``` - -Modify an existing `topology.yaml` or create a new one and place the above example as the file's contents. - -If you didnt use the standard `docker-compose.yaml` setup then you will need to change `first_contact_points` to point to the Redis instances you used. - -You will also need a [config.yaml](https://raw.githubusercontent.com/shotover/shotover-examples/main/redis-cluster-1-1/config.yaml) to run Shotover. - -```shell -curl -L https://raw.githubusercontent.com/shotover/shotover-examples/main/redis-cluster-1-1/config.yaml --output config.yaml -``` - -## Starting - -We can now start the services with: - -```shell -docker-compose up -d -``` - -## Testing - -With your Redis Cluster and Shotover now up and running, we can test out our client application. Let's start it up! - -```console -redis-benchmark -h 172.16.1.9 -t set,get -``` - -Running against local containerised Redis instances on a Ryzen 9 3900X we get the following: - -```console -user@demo ~$ redis-benchmark -t set,get -====== SET ====== - 100000 requests completed in 0.69 seconds - 50 parallel clients - 3 bytes payload - keep alive: 1 - host configuration "save": - host configuration "appendonly": - multi-thread: no - -Latency by percentile distribution: -0.000% <= 0.079 milliseconds (cumulative count 2) -50.000% <= 0.215 milliseconds (cumulative count 51352) -75.000% <= 0.231 milliseconds (cumulative count 79466) -87.500% <= 0.247 milliseconds (cumulative count 91677) -93.750% <= 0.255 milliseconds (cumulative count 94319) -96.875% <= 0.271 milliseconds (cumulative count 97011) -98.438% <= 0.303 milliseconds (cumulative count 98471) -99.219% <= 0.495 milliseconds (cumulative count 99222) -99.609% <= 0.615 milliseconds (cumulative count 99613) -99.805% <= 0.719 milliseconds (cumulative count 99806) -99.902% <= 0.791 milliseconds (cumulative count 99908) -99.951% <= 0.919 milliseconds (cumulative count 99959) -99.976% <= 0.967 milliseconds (cumulative count 99976) -99.988% <= 0.991 milliseconds (cumulative count 99992) -99.994% <= 1.007 milliseconds (cumulative count 99995) -99.997% <= 1.015 milliseconds (cumulative count 99998) -99.998% <= 1.023 milliseconds (cumulative count 99999) -99.999% <= 1.031 milliseconds (cumulative count 100000) -100.000% <= 1.031 milliseconds (cumulative count 100000) - -Cumulative distribution of latencies: -0.007% <= 0.103 milliseconds (cumulative count 7) -33.204% <= 0.207 milliseconds (cumulative count 33204) -98.471% <= 0.303 milliseconds (cumulative count 98471) -99.044% <= 0.407 milliseconds (cumulative count 99044) -99.236% <= 0.503 milliseconds (cumulative count 99236) -99.571% <= 0.607 milliseconds (cumulative count 99571) -99.793% <= 0.703 milliseconds (cumulative count 99793) -99.926% <= 0.807 milliseconds (cumulative count 99926) -99.949% <= 0.903 milliseconds (cumulative count 99949) -99.995% <= 1.007 milliseconds (cumulative count 99995) -100.000% <= 1.103 milliseconds (cumulative count 100000) - -Summary: - throughput summary: 144092.22 requests per second - latency summary (msec): - avg min p50 p95 p99 max - 0.222 0.072 0.215 0.263 0.391 1.031 -====== GET ====== - 100000 requests completed in 0.69 seconds - 50 parallel clients - 3 bytes payload - keep alive: 1 - host configuration "save": - host configuration "appendonly": - multi-thread: no - -Latency by percentile distribution: -0.000% <= 0.079 milliseconds (cumulative count 1) -50.000% <= 0.215 milliseconds (cumulative count 64586) -75.000% <= 0.223 milliseconds (cumulative count 77139) -87.500% <= 0.239 milliseconds (cumulative count 90521) -93.750% <= 0.255 milliseconds (cumulative count 94985) -96.875% <= 0.287 milliseconds (cumulative count 97262) -98.438% <= 0.311 milliseconds (cumulative count 98588) -99.219% <= 0.367 milliseconds (cumulative count 99232) -99.609% <= 0.495 milliseconds (cumulative count 99613) -99.805% <= 0.583 milliseconds (cumulative count 99808) -99.902% <= 0.631 milliseconds (cumulative count 99913) -99.951% <= 0.647 milliseconds (cumulative count 99955) -99.976% <= 0.663 milliseconds (cumulative count 99978) -99.988% <= 0.679 milliseconds (cumulative count 99990) -99.994% <= 0.703 milliseconds (cumulative count 99995) -99.997% <= 0.711 milliseconds (cumulative count 99997) -99.998% <= 0.751 milliseconds (cumulative count 99999) -99.999% <= 0.775 milliseconds (cumulative count 100000) -100.000% <= 0.775 milliseconds (cumulative count 100000) - -Cumulative distribution of latencies: -0.009% <= 0.103 milliseconds (cumulative count 9) -48.520% <= 0.207 milliseconds (cumulative count 48520) -98.179% <= 0.303 milliseconds (cumulative count 98179) -99.358% <= 0.407 milliseconds (cumulative count 99358) -99.626% <= 0.503 milliseconds (cumulative count 99626) -99.867% <= 0.607 milliseconds (cumulative count 99867) -99.995% <= 0.703 milliseconds (cumulative count 99995) -100.000% <= 0.807 milliseconds (cumulative count 100000) - -Summary: - throughput summary: 143884.89 requests per second - latency summary (msec): - avg min p50 p95 p99 max - 0.214 0.072 0.215 0.263 0.335 0.775 -``` diff --git a/docs/src/examples/valkey-clustering-aware.md b/docs/src/examples/valkey-clustering-aware.md new file mode 100644 index 000000000..60547be85 --- /dev/null +++ b/docs/src/examples/valkey-clustering-aware.md @@ -0,0 +1,123 @@ +# Valkey Clustering with cluster aware client + +The following guide shows you how to configure Shotover to support proxying Valkey cluster *aware* clients to [Valkey cluster](https://valkey.io/topics/cluster-spec). + +## Overview + +In this example, we will be connecting to a Valkey cluster that has the following topology: + +* `172.16.1.2:6379` +* `172.16.1.3:6379` +* `172.16.1.4:6379` +* `172.16.1.5:6379` +* `172.16.1.6:6379` +* `172.16.1.7:6379` + +Shotover will be deployed as a sidecar to each node in the Valkey cluster, listening on `6380`. Use the following [docker-compose.yaml](https://github.com/shotover/shotover-examples/blob/main/valkey-cluster-1-1/docker-compose.yaml) to run the Valkey cluster and Shotover sidecars. + +```console +curl -L https://raw.githubusercontent.com/shotover/shotover-examples/main/valkey-cluster-1-1/docker-compose.yaml --output docker-compose.yaml +``` + +Below we can see an example of a Valkey node and it's Shotover sidecar. Notice they are running on the same network address (`172.16.1.2`) and the present directory is being mounted to allow Shotover to access the config and topology files. + +```YAML + +valkey-node-0: + image: bitnami/valkey-cluster:7.2.5-debian-12-r4 + networks: + cluster_subnet: + ipv4_address: 172.16.1.2 + environment: + - 'ALLOW_EMPTY_PASSWORD=yes' + - 'VALKEY_NODES=valkey-node-0 valkey-node-1 valkey-node-2' + +shotover-0: + restart: always + depends_on: + - valkey-node-0 + image: shotover/shotover-proxy + network_mode: "service:valkey-node-0" + volumes: + - type: bind + source: $PWD + target: /config + +``` + +In this example we will use `valkey-benchmark` with cluster mode enabled as our Valkey cluster aware client application. + +## Configuration + +First we will modify our `topology.yaml` file to have a single Valkey source. This will: + +* Define how Shotover listens for incoming connections from our client application (`valkey-benchmark`). +* Configure Shotover to connect to the Valkey node via our defined remote address. +* Configure Shotover to rewrite all Valkey ports with our Shotover port when the cluster aware driver is talking to the cluster, through Shotover. +* Connect our Valkey Source to our Valkey cluster sink (transform). + +```yaml +--- +sources: + - Valkey: + name: "valkey" + listen_addr: "0.0.0.0:6380" + chain: + - ValkeyClusterPortsRewrite: + new_port: 6380 + - ValkeySinkSingle: + remote_address: "0.0.0.0:6379" + connect_timeout_ms: 3000 +``` + +Modify an existing `topology.yaml` or create a new one and place the above example as the file's contents. + +You will also need a [config.yaml](https://raw.githubusercontent.com/shotover/shotover-examples/main/valkey-cluster-1-1/config.yaml) to run Shotover. + +```shell +curl -L https://raw.githubusercontent.com/shotover/shotover-examples/main/valkey-cluster-1-1/config.yaml --output config.yaml +``` + +## Starting + +We can now start the services with: + +```shell +docker-compose up -d +``` + +## Testing + +With everything now up and running, we can test out our client application. Let's start it up! + +First we will run `valkey-benchmark` directly on our cluster. + +```console +valkey-benchmark -h 172.16.1.2 -p 6379 -t set,get --cluster +``` + +If everything works correctly you should see the following, along with the benchmark results which have been omitted for brevity. Notice all traffic is going through the Valkey port on `6379`. + +```console +Cluster has 3 master nodes: + +Master 0: d5eaf45804215f80cfb661928c1a84e1da7406a9 172.16.1.3:6379 +Master 1: d774cd063e430d34a71bceaab851d7744134e22f 172.16.1.2:6379 +Master 2: 04b301f1b165d81d5fb86e50312e9cc4898cbcce 172.16.1.4:6379 +``` + +Now run it again but on the Shotover port this time. + +```console +valkey-benchmark -h 172.16.1.2 -p 6380 -t set,get --cluster +``` + +You should see the following, notice that all traffic is going through Shotover on `6380` instead of the Valkey port of `6379`: + +```console +Cluster has 3 master nodes: + +Master 0: 04b301f1b165d81d5fb86e50312e9cc4898cbcce 172.16.1.4:6380 +Master 1: d5eaf45804215f80cfb661928c1a84e1da7406a9 172.16.1.3:6380 +Master 2: d774cd063e430d34a71bceaab851d7744134e22f 172.16.1.2:6380 +``` diff --git a/docs/src/examples/valkey-clustering-unaware.md b/docs/src/examples/valkey-clustering-unaware.md new file mode 100644 index 000000000..140d1a108 --- /dev/null +++ b/docs/src/examples/valkey-clustering-unaware.md @@ -0,0 +1,88 @@ +# Valkey Clustering + +The following guide shows you how to configure Shotover Proxy to support transparently proxying Valkey cluster _unaware_ clients to a [Valkey cluster](https://valkey.io/topics/cluster-spec). + +## General Configuration + +First you need to setup a Valkey cluster and Shotover. + +The easiest way to do this is with this example [docker-compose.yaml](https://github.com/shotover/shotover-examples/blob/main/valkey-cluster-1-many/docker-compose.yaml) +You should first inspect the `docker-compose.yaml` to understand what the cluster looks like and how its exposed to the network. + +Then run: + +```shell +curl -L https://raw.githubusercontent.com/shotover/shotover-examples/main/valkey-cluster-1-many/docker-compose.yaml --output docker-compose.yaml +``` + +Alternatively you could spin up a hosted Valkey cluster on [any cloud provider that provides it](https://www.instaclustr.com/products/managed-valkey). +This more accurately reflects a real production use but will take a bit more setup. +And reduce the docker-compose.yaml to just the shotover part + +```yaml +services: + shotover-0: + networks: + cluster_subnet: + ipv4_address: 172.16.1.9 + image: shotover/shotover-proxy:v0.1.10 + volumes: + - .:/config +networks: + cluster_subnet: + name: cluster_subnet + driver: bridge + ipam: + driver: default + config: + - subnet: 172.16.1.0/24 + gateway: 172.16.1.1 +``` + +## Shotover Configuration + +```yaml +--- +sources: + - Valkey: + name: "valkey" + # define where shotover listens for incoming connections from our client application (`valkey-benchmark`). + listen_addr: "0.0.0.0:6379" + chain: + # configure Shotover to connect to the Valkey cluster via our defined contact points + - ValkeySinkCluster: + first_contact_points: + - "172.16.1.2:6379" + - "172.16.1.3:6379" + - "172.16.1.4:6379" + - "172.16.1.5:6379" + - "172.16.1.6:6379" + - "172.16.1.7:6379" + connect_timeout_ms: 3000 +``` + +Modify an existing `topology.yaml` or create a new one and place the above example as the file's contents. + +If you didnt use the standard `docker-compose.yaml` setup then you will need to change `first_contact_points` to point to the Valkey instances you used. + +You will also need a [config.yaml](https://raw.githubusercontent.com/shotover/shotover-examples/main/valkey-cluster-1-1/config.yaml) to run Shotover. + +```shell +curl -L https://raw.githubusercontent.com/shotover/shotover-examples/main/valkey-cluster-1-1/config.yaml --output config.yaml +``` + +## Starting + +We can now start the services with: + +```shell +docker-compose up -d +``` + +## Testing + +With your Valkey Cluster and Shotover now up and running, we can test out our client application. Let's start it up! + +```console +valkey-benchmark -h 172.16.1.9 -t set,get +``` diff --git a/docs/src/user-guide/getting-started.md b/docs/src/user-guide/getting-started.md index b4055883a..cf495a5ee 100644 --- a/docs/src/user-guide/getting-started.md +++ b/docs/src/user-guide/getting-started.md @@ -17,4 +17,4 @@ To see Shotover's command line arguments run: `./shotover-proxy --help` Full `topology.yaml` examples configured for a specific use case: -* [Redis clustering](../examples/redis-clustering-unaware.md) +* [valkey clustering](../examples/valkey-clustering-unaware.md) diff --git a/docs/src/user-guide/introduction.md b/docs/src/user-guide/introduction.md index fd1e79e48..5c473af0b 100644 --- a/docs/src/user-guide/introduction.md +++ b/docs/src/user-guide/introduction.md @@ -22,7 +22,7 @@ Shotover aims to make these challenges simpler by providing a point where data l Longer term, Shotover can also leverage the same capability to make operational tasks easier to solve a number of other challenges that come with working multiple databases. Some of these include: * Data encryption at the field level, with a common key management scheme between databases. -* Routing the same data to databases that provide different query capabilities or performance characteristics (e.g. indexing data in Redis in Elasticsearch, easy caching of DynamoDB data in Redis). +* Routing the same data to databases that provide different query capabilities or performance characteristics (e.g. indexing data in Valkey in Elasticsearch, easy caching of DynamoDB data in Valkey). * Routing/replicating data across regions for databases that don't support it natively or the functionality is gated behind proprietary "open-core" implementations. * A common audit and AuthZ/AuthN point for SOX/PCI/HIPAA compliance. @@ -38,18 +38,11 @@ Shotover prioritises the following principals in the order listed: Shotover provides a set of predefined transforms that can modify, route and control queries from any number of sources to a similar number of sinks. As the user you can construct chains of these transforms to achieve the behaviour required. Each chain can then be attached to a "source" that speaks the native protocol of you chosen database. The transform chain will process each request with access to a unified/simplified representation of a generic query, the original raw query and optionally (for SQL like protocols) a parsed AST representing the query. - - Shotover proxy currently supports the following protocols as sources: -* Cassandra (CQLv4) -* Redis (RESP2) +* Cassandra (CQL4 + CQL5) +* Valkey/Redis (RESP2) +* Kafka (Kafka Wire Protocol) ## Shotover performance diff --git a/ec2-cargo/Cargo.toml b/ec2-cargo/Cargo.toml index a4bfa895b..dc225243a 100644 --- a/ec2-cargo/Cargo.toml +++ b/ec2-cargo/Cargo.toml @@ -14,5 +14,5 @@ tracing-subscriber.workspace = true aws-throwaway.workspace = true tracing-appender.workspace = true shellfish = { version = "0.10.0", features = ["async"] } -cargo_metadata = "0.18.0" +cargo_metadata = "0.19.0" shell-quote.workspace = true diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 7df8e1f93..53e53ab08 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,4 +1,4 @@ [toolchain] -channel = "1.82" -components = [ "rustfmt", "clippy" ] -targets = [ "aarch64-unknown-linux-gnu" ] +channel = "1.83" +components = ["rustfmt", "clippy"] +targets = ["aarch64-unknown-linux-gnu"] diff --git a/shotover-proxy/Cargo.toml b/shotover-proxy/Cargo.toml index ca1c74cc0..8c5f8d992 100644 --- a/shotover-proxy/Cargo.toml +++ b/shotover-proxy/Cargo.toml @@ -37,7 +37,7 @@ rand.workspace = true async-trait.workspace = true tracing-subscriber.workspace = true tracing-appender.workspace = true -fred = { version = "9.0.3", features = ["enable-rustls-ring"] } +fred = { version = "10.0.0", features = ["enable-rustls-ring"] } tokio-bin-process.workspace = true rustls-pemfile = "2.0.0" rustls-pki-types = "1.1.0" diff --git a/shotover-proxy/benches/windsock/valkey/bench.rs b/shotover-proxy/benches/windsock/valkey/bench.rs index 9261d95c5..c191f321c 100644 --- a/shotover-proxy/benches/windsock/valkey/bench.rs +++ b/shotover-proxy/benches/windsock/valkey/bench.rs @@ -357,7 +357,7 @@ impl Bench for ValkeyBench { // only one string field so we just directly store the value in resources let address = resources; - let mut config = RedisConfig::from_url(address).unwrap(); + let mut config = Config::from_url(address).unwrap(); if let Encryption::Tls = self.encryption { let private_key = load_private_key("tests/test-configs/valkey/tls/certs/localhost.key").unwrap(); @@ -372,7 +372,7 @@ impl Bench for ValkeyBench { .into(), ); } - let client = Arc::new(RedisClient::new(config, None, None, None)); + let client = Arc::new(Client::new(config, None, None, None)); // connect to the server, returning a handle to the task that drives the connection let shutdown_handle = client.connect(); @@ -444,7 +444,7 @@ fn load_ca(path: &str) -> Result { #[derive(Clone)] struct BenchTaskValkey { - client: Arc, + client: Arc, operation: ValkeyOperation, } diff --git a/shotover-proxy/config/topology.yaml b/shotover-proxy/config/topology.yaml index 66fa99b1a..81deea19f 100644 --- a/shotover-proxy/config/topology.yaml +++ b/shotover-proxy/config/topology.yaml @@ -1,19 +1,19 @@ -# For an overview of topology configuration: https://docs.shotover.io/user-guide/configuration/#topologyyaml +# For an overview of topology configuration: https://shotover.io/docs/latest/user-guide/configuration/#topologyyaml --- # The list of sources. sources: # The source, change from Valkey to the source type of the database protocol you are receiving messages in. - # For a list of possible sources: https://docs.shotover.io/sources + # For a list of possible sources: https://shotover.io/docs/latest/sources - Valkey: name: "valkey" listen_addr: "127.0.0.1:6379" chain: # A DebugPrinter transform, reports an INFO log for every message that passes through this transform. # You should delete this transform and add as many other transforms in this chain as you need. - # For a list of possible transforms: https://docs.shotover.io/transforms/#transforms_1 + # For a list of possible transforms: https://shotover.io/docs/latest/transforms/#transforms-1 - DebugPrinter # A NullSink transform, drops all messages it receives. # You will want to replace this with a sink transform to send the message to a database. - # For a list of possible transforms: https://docs.shotover.io/transforms/#transforms_1 + # For a list of possible transforms: https://shotover.io/docs/latest/transforms/#transforms-1 - NullSink diff --git a/shotover-proxy/tests/test-configs/cassandra/valkey-cache/docker-compose.yaml b/shotover-proxy/tests/test-configs/cassandra/valkey-cache/docker-compose.yaml index fc0ee6f37..a09aaa327 100644 --- a/shotover-proxy/tests/test-configs/cassandra/valkey-cache/docker-compose.yaml +++ b/shotover-proxy/tests/test-configs/cassandra/valkey-cache/docker-compose.yaml @@ -1,8 +1,12 @@ services: - redis-one: - image: library/redis:5.0.9 + valkey-one: + image: bitnami/valkey:7.2.5-debian-12-r9 ports: - "6379:6379" + environment: + ALLOW_EMPTY_PASSWORD: "yes" + VALKEY_TLS_ENABLED: "no" + cassandra-one: image: shotover/cassandra-test:4.0.6-r1 ports: diff --git a/shotover-proxy/tests/test-configs/log-to-file/docker-compose.yaml b/shotover-proxy/tests/test-configs/log-to-file/docker-compose.yaml index 7acef8da1..f8891e78b 100644 --- a/shotover-proxy/tests/test-configs/log-to-file/docker-compose.yaml +++ b/shotover-proxy/tests/test-configs/log-to-file/docker-compose.yaml @@ -1,5 +1,8 @@ services: - redis-one: - image: library/redis:5.0.9 + valkey-one: + image: bitnami/valkey:7.2.5-debian-12-r9 ports: - "1111:6379" + environment: + ALLOW_EMPTY_PASSWORD: "yes" + VALKEY_TLS_ENABLED: "no" diff --git a/shotover-proxy/tests/transforms/log_to_file.rs b/shotover-proxy/tests/transforms/log_to_file.rs index 55cd96085..76ab14462 100644 --- a/shotover-proxy/tests/transforms/log_to_file.rs +++ b/shotover-proxy/tests/transforms/log_to_file.rs @@ -20,20 +20,14 @@ async fn log_to_file() { "*4\r\n$6\r\nCLIENT\r\n$7\r\nSETINFO\r\n$8\r\nLIB-NAME\r\n$8\r\nredis-rs\r\n", ); let response = std::fs::read("message-log/1/responses/message1.bin").unwrap(); - assert_eq_string( - &response, - "-ERR Unknown subcommand or wrong number of arguments for 'SETINFO'. Try CLIENT HELP\r\n", - ); + assert_eq_string(&response, "+OK\r\n"); let request = std::fs::read("message-log/1/requests/message2.bin").unwrap(); assert_eq_string( &request, "*4\r\n$6\r\nCLIENT\r\n$7\r\nSETINFO\r\n$7\r\nLIB-VER\r\n$6\r\n0.24.0\r\n", ); let response = std::fs::read("message-log/1/responses/message2.bin").unwrap(); - assert_eq_string( - &response, - "-ERR Unknown subcommand or wrong number of arguments for 'SETINFO'. Try CLIENT HELP\r\n", - ); + assert_eq_string(&response, "+OK\r\n"); // SET sent by command assert_ok(redis::cmd("SET").arg("foo").arg(42), &mut connection).await; diff --git a/shotover-proxy/tests/valkey_int_tests/basic_driver_tests.rs b/shotover-proxy/tests/valkey_int_tests/basic_driver_tests.rs index b0f16acf7..1ff5c3367 100644 --- a/shotover-proxy/tests/valkey_int_tests/basic_driver_tests.rs +++ b/shotover-proxy/tests/valkey_int_tests/basic_driver_tests.rs @@ -1,7 +1,7 @@ use crate::valkey_int_tests::assert::*; use crate::CONNECTION_REFUSED_OS_ERROR; use bytes::BytesMut; -use fred::clients::RedisClient; +use fred::clients::Client; use fred::interfaces::ClientLike; use futures::{Future, StreamExt}; use pretty_assertions::assert_eq; @@ -1283,7 +1283,7 @@ pub async fn test_dr_auth() { /// at least one driver handles this as we expect. /// Fred is used here as redis-rs sends an unconfigurable `CLIENT SETINFO` command and ignores the result on connection init. /// This results in the error message being completely dropped with redis-rs. -pub async fn test_trigger_transform_failure_driver(client: &RedisClient) { +pub async fn test_trigger_transform_failure_driver(client: &Client) { assert_eq!( // fred sends a `CLIENT` command on startup to which shotover will reply with an error client.wait_for_connect().await.unwrap_err().details(), @@ -1292,9 +1292,6 @@ pub async fn test_trigger_transform_failure_driver(client: &RedisClient) { } /// A raw variant of this test case is provided so that we can make a strong assertion about the way shotover handles this case. -/// -/// CAREFUL: This lacks any kind of check that shotover is ready, -/// so make sure shotover_manager.redis_connection is run on 6379 before calling this. pub async fn test_trigger_transform_failure_raw() { // Send invalid valkey command // To correctly handle this shotover should close the connection @@ -1305,7 +1302,7 @@ pub async fn test_trigger_transform_failure_raw() { connection.write_all(b"*1\r\n$4\r\nping\r\n").await.unwrap(); assert_eq!( - read_redis_message(&mut connection).await, + read_valkey_message(&mut connection).await, ValkeyFrame::Error(format!("ERR Internal shotover (or custom transform) bug: Chain failed to send and/or receive messages, the connection will now be closed. Caused by: 0: ValkeySinkSingle transform failed 1: Failed to connect to destination 127.0.0.1:1111 2: Connection refused (os error {CONNECTION_REFUSED_OS_ERROR})").into()) ); @@ -1319,7 +1316,7 @@ pub async fn test_trigger_transform_failure_raw() { assert_eq!(amount, 0); } -async fn read_redis_message(connection: &mut TcpStream) -> ValkeyFrame { +async fn read_valkey_message(connection: &mut TcpStream) -> ValkeyFrame { let mut buffer = BytesMut::new(); loop { if let Ok(Some((result, len))) = @@ -1336,8 +1333,6 @@ async fn read_redis_message(connection: &mut TcpStream) -> ValkeyFrame { } } -/// CAREFUL: This lacks any kind of check that shotover is ready, -/// so make sure shotover_manager.redis_connection is run on 6379 before calling this. pub async fn test_invalid_frame() { // Send invalid valkey command // To correctly handle this shotover should close the connection @@ -1346,7 +1341,7 @@ pub async fn test_invalid_frame() { .unwrap(); connection - .write_all(b"invalid_redis_frame\r\n") + .write_all(b"invalid_valkey_frame\r\n") .await .unwrap(); diff --git a/shotover-proxy/tests/valkey_int_tests/mod.rs b/shotover-proxy/tests/valkey_int_tests/mod.rs index a4eaaa0a7..d57a73c3a 100644 --- a/shotover-proxy/tests/valkey_int_tests/mod.rs +++ b/shotover-proxy/tests/valkey_int_tests/mod.rs @@ -1,8 +1,8 @@ use crate::{shotover_process, CONNECTION_REFUSED_OS_ERROR}; use basic_driver_tests::*; -use fred::clients::RedisClient; +use fred::clients::Client; use fred::interfaces::ClientLike; -use fred::types::RedisConfig; +use fred::prelude::Config; use pretty_assertions::assert_eq; use redis::aio::Connection; use redis::Commands; @@ -50,11 +50,11 @@ async fn passthrough_standard() { } #[tokio::test(flavor = "multi_thread")] -async fn passthrough_redis_down() { +async fn passthrough_valkey_down() { let shotover = shotover_process("tests/test-configs/valkey/passthrough/topology.yaml") .start() .await; - let client = RedisClient::new(RedisConfig::default(), None, None, None); + let client = Client::new(Config::default(), None, None, None); { let _shutdown_handle = client.connect(); diff --git a/shotover/Cargo.toml b/shotover/Cargo.toml index 3f6df96f9..a37e3e191 100644 --- a/shotover/Cargo.toml +++ b/shotover/Cargo.toml @@ -52,7 +52,7 @@ axum = { version = "0.7", default-features = false, features = ["tokio", "tracin pretty-hex = "0.4.0" tokio-stream = "0.1.2" derivative = "2.1.1" -cached = { version = "0.53", features = ["async"], optional = true } +cached = { version = "0.54", features = ["async"], optional = true } governor = { version = "0.7", default-features = false, features = ["std", "jitter", "quanta"] } nonzero_ext = "0.3.0" version-compare = { version = "0.2", optional = true } @@ -79,7 +79,7 @@ typetag.workspace = true tokio-tungstenite = "0.24.0" # Error handling -thiserror = "1.0" +thiserror = "2.0" anyhow.workspace = true backtrace = "0.3.66" backtrace-ext = "0.2" diff --git a/shotover/src/codec/valkey.rs b/shotover/src/codec/valkey.rs index 0c36a4472..58ae010d3 100644 --- a/shotover/src/codec/valkey.rs +++ b/shotover/src/codec/valkey.rs @@ -238,7 +238,7 @@ impl Encoder for ValkeyEncoder { } Encodable::Frame(frame) => { let item = frame.into_valkey().unwrap(); - extend_encode(dst, &item) + extend_encode(dst, &item, false) .map(|_| ()) .map_err(|e| anyhow!("Valkey encoding error: {} - {:#?}", e, item)) } diff --git a/shotover/src/config/topology.rs b/shotover/src/config/topology.rs index 3530a85d4..b8016085b 100644 --- a/shotover/src/config/topology.rs +++ b/shotover/src/config/topology.rs @@ -180,7 +180,7 @@ foo source: * flush_when_millis_since_last_flush But none of them were provided. - Check https://docs.shotover.io/transforms.html#coalesce for more information. + Check https://shotover.io/docs/latest/transforms.html#coalesce for more information. "#; let error = run_test_topology_valkey(vec![ diff --git a/shotover/src/frame/mod.rs b/shotover/src/frame/mod.rs index 71f7317ea..098a4a59b 100644 --- a/shotover/src/frame/mod.rs +++ b/shotover/src/frame/mod.rs @@ -60,7 +60,7 @@ impl MessageType { #[cfg(feature = "cassandra")] MessageType::Cassandra => "cql", #[cfg(feature = "valkey")] - MessageType::Valkey => "redis", + MessageType::Valkey => "valkey", #[cfg(feature = "kafka")] MessageType::Kafka => "kafka", #[cfg(feature = "opensearch")] diff --git a/shotover/src/lib.rs b/shotover/src/lib.rs index 63037e559..04dcbfe72 100644 --- a/shotover/src/lib.rs +++ b/shotover/src/lib.rs @@ -57,7 +57,7 @@ If we absolutely need unsafe code, it should be isolated within a separate small not(feature = "opensearch"), ))] compile_error!( - "At least one protocol feature must be enabled, e.g. `cassandra`, `redis`, `kafka` or `opensearch`" + "At least one protocol feature must be enabled, e.g. `cassandra`, `valkey`, `kafka` or `opensearch`" ); pub mod codec; diff --git a/shotover/src/transforms/cassandra/sink_cluster/token_ring.rs b/shotover/src/transforms/cassandra/sink_cluster/token_ring.rs index f0a57b5ef..873be7701 100644 --- a/shotover/src/transforms/cassandra/sink_cluster/token_ring.rs +++ b/shotover/src/transforms/cassandra/sink_cluster/token_ring.rs @@ -57,7 +57,7 @@ impl TokenRing { nodes: &'a [CassandraNode], token_from_key: Murmur3Token, keyspace: &'a KeyspaceMetadata, - ) -> impl Iterator + '_ { + ) -> impl Iterator + 'a { let mut racks_used = vec![]; self.ring_range(token_from_key) .filter(move |host_id| { diff --git a/shotover/src/transforms/coalesce.rs b/shotover/src/transforms/coalesce.rs index 33bc2084c..2007ba8b1 100644 --- a/shotover/src/transforms/coalesce.rs +++ b/shotover/src/transforms/coalesce.rs @@ -66,7 +66,7 @@ impl TransformBuilder for Coalesce { " * flush_when_millis_since_last_flush".into(), "".into(), " But none of them were provided.".into(), - " Check https://docs.shotover.io/transforms.html#coalesce for more information." + " Check https://shotover.io/docs/latest/transforms.html#coalesce for more information." .into(), ] } else { diff --git a/shotover/src/transforms/kafka/sink_cluster/mod.rs b/shotover/src/transforms/kafka/sink_cluster/mod.rs index c2c9e0748..ed470fd96 100644 --- a/shotover/src/transforms/kafka/sink_cluster/mod.rs +++ b/shotover/src/transforms/kafka/sink_cluster/mod.rs @@ -3993,7 +3993,7 @@ fn random_broker_id(nodes: &[KafkaNode], rng: &mut SmallRng) -> BrokerId { struct FormatTopicName<'a>(&'a TopicName, &'a Uuid); -impl<'a> std::fmt::Display for FormatTopicName<'a> { +impl std::fmt::Display for FormatTopicName<'_> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { if self.0.is_empty() { write!(f, "topic with id {}", self.1) diff --git a/shotover/src/transforms/mod.rs b/shotover/src/transforms/mod.rs index eb9973204..786772acb 100644 --- a/shotover/src/transforms/mod.rs +++ b/shotover/src/transforms/mod.rs @@ -166,7 +166,7 @@ pub struct ChainState<'a> { /// [`Wrapper`] will not (cannot) bring the current list of transforms that it needs to traverse with it /// This is purely to make it convenient to clone all the data within Wrapper rather than it's transform /// state. -impl<'a> Clone for ChainState<'a> { +impl Clone for ChainState<'_> { fn clone(&self) -> Self { ChainState { requests: self.requests.clone(), diff --git a/website/Cargo.toml b/website/Cargo.toml new file mode 100644 index 000000000..48b30ef5b --- /dev/null +++ b/website/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "website" +version = "0.1.0" +edition = "2021" +license = "Apache-2.0" +publish = false + +[dependencies] +subprocess.workspace = true +anyhow.workspace = true +rinja = "0.3.5" +semver = "1.0.23" +devserver_lib = { version = "0.4.2", default-features = false } +clap.workspace = true \ No newline at end of file diff --git a/website/assets/arrow_right.png b/website/assets/arrow_right.png new file mode 100644 index 000000000..73996a40b Binary files /dev/null and b/website/assets/arrow_right.png differ diff --git a/website/assets/favicon.ico b/website/assets/favicon.ico new file mode 100644 index 000000000..5ef343f58 Binary files /dev/null and b/website/assets/favicon.ico differ diff --git a/website/assets/logo.png b/website/assets/logo.png new file mode 100644 index 000000000..9324350b2 Binary files /dev/null and b/website/assets/logo.png differ diff --git a/website/assets/style.css b/website/assets/style.css new file mode 100644 index 000000000..173544286 --- /dev/null +++ b/website/assets/style.css @@ -0,0 +1,2081 @@ +:root { + --vp-c-white: #ffffff; + --vp-c-white-soft: #f9f9f9; + --vp-c-white-mute: #f1f1f1; + --vp-c-black: #1a1a1a; + --vp-c-black-pure: #000000; + --vp-c-black-soft: #242424; + --vp-c-black-mute: #2f2f2f; + --vp-c-gray: #8e8e8e; + --vp-c-gray-light-1: #aeaeae; + --vp-c-gray-light-2: #c7c7c7; + --vp-c-gray-light-3: #d1d1d1; + --vp-c-gray-light-4: #e5e5e5; + --vp-c-gray-light-5: #f2f2f2; + --vp-c-gray-dark-1: #636363; + --vp-c-gray-dark-2: #484848; + --vp-c-gray-dark-3: #3a3a3a; + --vp-c-gray-dark-4: #282828; + --vp-c-gray-dark-5: #202020; + --vp-c-divider-light-1: rgba(60, 60, 60, .29); + --vp-c-divider-light-2: rgba(60, 60, 60, .12); + --vp-c-divider-dark-1: rgba(84, 84, 84, .65); + --vp-c-divider-dark-2: rgba(84, 84, 84, .48); + --vp-c-text-light-1: var(--vp-c-indigo); + --vp-c-text-light-2: rgba(60, 60, 60, .7); + --vp-c-text-light-3: rgba(60, 60, 60, .33); + --vp-c-text-light-4: rgba(60, 60, 60, .18); + --vp-c-text-dark-1: rgba(255, 255, 255, .87); + --vp-c-text-dark-2: rgba(235, 235, 235, .6); + --vp-c-text-dark-3: rgba(235, 235, 235, .38); + --vp-c-text-dark-4: rgba(235, 235, 235, .18); + --vp-c-indigo: #213547; + --vp-c-indigo-soft: #476582; + --vp-c-indigo-light: #aac8e4; + --vp-c-indigo-lighter: #c9def1; + --vp-c-indigo-dark: #1d2f3f; + --vp-c-indigo-darker: #14212e; + --vp-c-green: #42b883; + --vp-c-green-light: #42d392; + --vp-c-green-lighter: #35eb9a; + --vp-c-green-dark: #33a06f; + --vp-c-green-darker: #155f3e; + --vp-c-green-dimm-1: rgba(66, 184, 131, .5); + --vp-c-green-dimm-2: rgba(66, 184, 131, .25); + --vp-c-green-dimm-3: rgba(66, 184, 131, .05); + --vp-c-yellow: #ffc517; + --vp-c-yellow-light: #fcd253; + --vp-c-yellow-lighter: #fcfc7c; + --vp-c-yellow-dark: #e0ad15; + --vp-c-yellow-darker: #ad850e; + --vp-c-yellow-dimm-1: rgba(255, 197, 23, .5); + --vp-c-yellow-dimm-2: rgba(255, 197, 23, .25); + --vp-c-yellow-dimm-3: rgba(255, 197, 23, .05); + --vp-c-red: #ed3c50; + --vp-c-red-light: #f54e82; + --vp-c-red-lighter: #fd1d7c; + --vp-c-red-dark: #cd2d3f; + --vp-c-red-darker: #ab2131; + --vp-c-red-dimm-1: rgba(237, 60, 80, .5); + --vp-c-red-dimm-2: rgba(237, 60, 80, .25); + --vp-c-red-dimm-3: rgba(237, 60, 80, .05) +} + +:root { + --vp-c-bg: var(--vp-c-white); + --vp-c-bg-soft: var(--vp-c-white-soft); + --vp-c-bg-mute: var(--vp-c-white-mute); + --vp-c-bg-alt: var(--vp-c-white-soft); + --vp-c-divider: var(--vp-c-divider-light-1); + --vp-c-divider-light: var(--vp-c-divider-light-2); + --vp-c-divider-inverse: var(--vp-c-divider-dark-1); + --vp-c-divider-inverse-light: var(--vp-c-divider-dark-2); + --vp-c-text-1: var(--vp-c-text-light-1); + --vp-c-text-2: var(--vp-c-text-light-2); + --vp-c-text-3: var(--vp-c-text-light-3); + --vp-c-text-4: var(--vp-c-text-light-4); + --vp-c-text-inverse-1: var(--vp-c-text-dark-1); + --vp-c-text-inverse-2: var(--vp-c-text-dark-2); + --vp-c-text-inverse-3: var(--vp-c-text-dark-3); + --vp-c-text-inverse-4: var(--vp-c-text-dark-4); + --vp-c-text-code: var(--vp-c-indigo-soft); + --vp-c-brand: var(--vp-c-green); + --vp-c-brand-light: var(--vp-c-green-light); + --vp-c-brand-lighter: var(--vp-c-green-lighter); + --vp-c-brand-dark: var(--vp-c-green-dark); + --vp-c-brand-darker: var(--vp-c-green-darker); + --vp-c-sponsor: #fd1d7c +} + +@media (prefers-color-scheme: dark) { + + :root { + --vp-c-bg: var(--vp-c-black-soft); + --vp-c-bg-soft: var(--vp-c-black-mute); + --vp-c-bg-mute: var(--vp-c-gray-dark-3); + --vp-c-bg-alt: var(--vp-c-black); + --vp-c-divider: var(--vp-c-divider-dark-1); + --vp-c-divider-light: var(--vp-c-divider-dark-2); + --vp-c-divider-inverse: var(--vp-c-divider-light-1); + --vp-c-divider-inverse-light: var(--vp-c-divider-light-2); + --vp-c-text-1: var(--vp-c-text-dark-1); + --vp-c-text-2: var(--vp-c-text-dark-2); + --vp-c-text-3: var(--vp-c-text-dark-3); + --vp-c-text-4: var(--vp-c-text-dark-4); + --vp-c-text-inverse-1: var(--vp-c-text-light-1); + --vp-c-text-inverse-2: var(--vp-c-text-light-2); + --vp-c-text-inverse-3: var(--vp-c-text-light-3); + --vp-c-text-inverse-4: var(--vp-c-text-light-4); + --vp-c-text-code: var(--vp-c-indigo-lighter) + } +} + +:root { + --vp-font-family-base: "Inter var experimental", "Inter var", "Inter", ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Helvetica, Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; + --vp-font-family-mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace +} + +:root { + --vp-shadow-1: 0 1px 2px rgba(0, 0, 0, .04), 0 1px 2px rgba(0, 0, 0, .06); + --vp-shadow-2: 0 3px 12px rgba(0, 0, 0, .07), 0 1px 4px rgba(0, 0, 0, .07); + --vp-shadow-3: 0 12px 32px rgba(0, 0, 0, .1), 0 2px 6px rgba(0, 0, 0, .08); + --vp-shadow-4: 0 14px 44px rgba(0, 0, 0, .12), 0 3px 9px rgba(0, 0, 0, .12); + --vp-shadow-5: 0 18px 56px rgba(0, 0, 0, .16), 0 4px 12px rgba(0, 0, 0, .16) +} + +:root { + --vp-z-index-local-nav: 10; + --vp-z-index-nav: 20; + --vp-z-index-layout-top: 30; + --vp-z-index-backdrop: 40; + --vp-z-index-sidebar: 50; + --vp-z-index-footer: 60 +} + +:root { + --vp-layout-max-width: 1440px +} + +:root { + --vp-nav-height: var(--vp-nav-height-mobile); + --vp-nav-height-mobile: 56px; + --vp-nav-height-desktop: 72px +} + +@media (min-width: 960px) { + :root { + --vp-nav-height: var(--vp-nav-height-desktop) + } +} + +:root { + --vp-sidebar-width: 272px +} + +:root { + --vp-home-hero-name-color: var(--vp-c-brand); + --vp-home-hero-name-background: transparent; + --vp-home-hero-image-background-image: none; + --vp-home-hero-image-filter: none +} + +*, +:before, +:after { + box-sizing: border-box +} + +html { + line-height: 1.4; + font-size: 16px; + -webkit-text-size-adjust: 100% +} + +body { + margin: 0; + width: 100%; + min-width: 320px; + min-height: 100vh; + line-height: 24px; + font-family: var(--vp-font-family-base); + font-size: 16px; + font-weight: 400; + color: var(--vp-c-text-1); + background-color: var(--vp-c-bg); + direction: ltr; + font-synthesis: none; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale +} + +main { + display: block +} + +h1, +h2, +h3, +h4, +h5, +h6 { + margin: 0; + line-height: 24px; + font-size: 16px; + font-weight: 400 +} + +p { + margin: 0 +} + +strong, +b { + font-weight: 600 +} + +a, +area, +button, +[role=button], +input, +label, +select, +summary, +textarea { + touch-action: manipulation +} + +a { + color: inherit; +} + +blockquote { + margin: 0 +} + +pre, +code, +kbd, +samp { + font-family: var(--vp-font-family-mono) +} + +img, +svg, +video, +canvas, +audio, +iframe, +embed, +object { + display: block +} + +figure { + margin: 0 +} + +img, +video { + max-width: 100%; + height: auto +} + +button, +input, +optgroup, +select, +textarea { + border: 0; + padding: 0; + line-height: inherit; + color: inherit +} + +input:focus, +textarea:focus, +select:focus { + outline: none +} + +table { + border-collapse: collapse +} + +input { + background-color: transparent +} + +input:-ms-input-placeholder, +textarea:-ms-input-placeholder { + color: var(--vp-c-text-3) +} + +input::-ms-input-placeholder, +textarea::-ms-input-placeholder { + color: var(--vp-c-text-3) +} + +input::placeholder, +textarea::placeholder { + color: var(--vp-c-text-3) +} + +textarea { + resize: vertical +} + +select { + -webkit-appearance: none +} + +fieldset { + margin: 0; + padding: 0 +} + +h1, +h2, +h3, +h4, +h5, +h6, +p { + overflow-wrap: break-word +} + +vite-error-overlay { + z-index: 9999 +} + +.visually-hidden { + position: absolute; + width: 1px; + height: 1px; + white-space: nowrap; + clip: rect(0 0 0 0); + clip-path: inset(50%); + overflow: hidden +} + + +.VPSkipLink[data-v-151f2593] { + top: 8px; + left: 8px; + padding: 8px 16px; + z-index: 999; + border-radius: 8px; + font-size: 12px; + font-weight: 700; + text-decoration: none; + color: var(--vp-c-brand); + box-shadow: var(--vp-shadow-3); + background-color: var(--vp-c-bg) +} + +.VPSkipLink[data-v-151f2593]:focus { + height: auto; + width: auto; + clip: auto; + clip-path: none +} + +@media (prefers-color-scheme: dark) { + .VPSkipLink[data-v-151f2593] { + color: var(--vp-c-green) + } +} + +@media (min-width: 1280px) { + .VPSkipLink[data-v-151f2593] { + top: 14px; + left: 16px + } +} + +.VPNavBarTitle[data-v-d5925166] { + flex-shrink: 0; + border-bottom: 1px solid transparent +} + +@media (min-width: 960px) { + .VPNavBarTitle.has-sidebar[data-v-d5925166] { + margin-right: 32px; + width: calc(var(--vp-sidebar-width) - 64px); + border-bottom-color: var(--vp-c-divider-light); + background-color: var(--vp-c-bg-alt) + } +} + +.title[data-v-d5925166] { + display: flex; + align-items: center; + width: 100%; + height: var(--vp-nav-height); + font-size: 16px; + font-weight: 600; + color: var(--vp-c-text-1); + transition: opacity .25s +} + +.title[data-v-d5925166]:hover { + opacity: .6 +} + +@media (min-width: 960px) { + .title[data-v-d5925166] { + flex-shrink: 0 + } +} + +[data-v-d5925166] .logo { + margin-right: 8px; + height: 24px +} + + +@keyframes fade-in { + 0% { + opacity: 0 + } + + to { + opacity: 1 + } +} + +.VPNavBarMenuLink[data-v-47a2263e] { + display: flex; + align-items: center; + padding: 0 12px; + line-height: var(--vp-nav-height-mobile); + font-size: 14px; + font-weight: 500; + color: var(--vp-c-text-1); + transition: color .25s +} + +.VPNavBarMenuLink.active[data-v-47a2263e], +.VPNavBarMenuLink[data-v-47a2263e]:hover { + color: var(--vp-c-brand) +} + +@media (min-width: 1280px) { + .VPNavBarMenuLink[data-v-47a2263e] { + line-height: var(--vp-nav-height-desktop) + } +} + +.link[data-v-e8e0fb1d] { + display: block; + border-radius: 6px; + padding: 0 12px; + line-height: 32px; + font-size: 14px; + font-weight: 500; + color: var(--vp-c-text-1); + white-space: nowrap; + transition: background-color .25s, color .25s +} + +.link[data-v-e8e0fb1d]:hover { + color: var(--vp-c-brand); + background-color: var(--vp-c-bg-mute) +} + +@media (prefers-color-scheme: dark) { + .link[data-v-e8e0fb1d]:hover { + background-color: var(--vp-c-bg-soft) + } +} + +.link.active[data-v-e8e0fb1d] { + color: var(--vp-c-brand) +} + + +.title[data-v-9ca52130] { + padding: 0 12px; + line-height: 32px; + font-size: 14px; + font-weight: 600; + color: var(--vp-c-text-2); + transition: color .25s +} + +.text[data-v-6ffb57d3] { + display: flex; + align-items: center; + line-height: var(--vp-nav-height-mobile); + font-size: 14px; + font-weight: 500; + color: var(--vp-c-text-1); + transition: color .25s +} + +@media (min-width: 960px) { + .text[data-v-6ffb57d3] { + line-height: var(--vp-nav-height-desktop) + } +} + +.menu[data-v-6ffb57d3] { + position: absolute; + top: calc(var(--vp-nav-height-mobile) / 2 + 20px); + right: 0; + opacity: 0; + visibility: hidden; + transition: opacity .25s, visibility .25s, transform .25s +} + +@media (min-width: 960px) { + .menu[data-v-6ffb57d3] { + top: calc(var(--vp-nav-height-desktop) / 2 + 20px) + } +} + +.VPNavBarMenu[data-v-f83db6ba] { + display: none +} + +@media (min-width: 768px) { + .VPNavBarMenu[data-v-f83db6ba] { + display: flex + } +} + +.title[data-v-db824e91] { + padding: 0 24px 0 12px; + line-height: 32px; + font-size: 14px; + font-weight: 700; + color: var(--vp-c-text-1) +} + +.check[data-v-eba7420e] { + position: absolute; + top: 1px; + left: 1px; + width: 18px; + height: 18px; + border-radius: 50%; + background-color: var(--vp-c-white); + box-shadow: var(--vp-shadow-1); + transition: transform .25s +} + +@media (prefers-color-scheme: dark) { + .check[data-v-eba7420e] { + background-color: var(--vp-c-black) + } +} + + +.container[data-v-e5dd9c1c] { + position: relative; + width: 16px; + height: 14px; + overflow: hidden +} + +.VPNavBar[data-v-6f1d18b5] { + position: relative; + border-bottom: 1px solid var(--vp-c-divider-light); + padding: 0 8px 0 24px; + height: var(--vp-nav-height-mobile); + transition: border-color .5s, background-color .5s; + pointer-events: none +} + +@media (min-width: 768px) { + .VPNavBar[data-v-6f1d18b5] { + padding: 0 32px + } +} + +@media (min-width: 960px) { + .VPNavBar[data-v-6f1d18b5] { + height: var(--vp-nav-height-desktop); + border-bottom: 0 + } + + .VPNavBar.has-sidebar .content[data-v-6f1d18b5] { + margin-right: -32px; + padding-right: 32px; + -webkit-backdrop-filter: saturate(50%) blur(8px); + backdrop-filter: saturate(50%) blur(8px); + background: rgba(255, 255, 255, .7) + } + + @media (prefers-color-scheme: dark) { + .VPNavBar.has-sidebar .content[data-v-6f1d18b5] { + background: rgba(36, 36, 36, .7) + } + } + + @supports not (backdrop-filter: saturate(50%) blur(8px)) { + .VPNavBar.has-sidebar .content[data-v-6f1d18b5] { + background: rgba(255, 255, 255, .95) + } + + @media (prefers-color-scheme: dark) { + VPNavBar.has-sidebar .content[data-v-6f1d18b5] { + background: rgba(36, 36, 36, .95) + } + } + } +} + +.container[data-v-6f1d18b5] { + display: flex; + justify-content: space-between; + margin: 0 auto; + max-width: calc(var(--vp-layout-max-width) - 64px); + pointer-events: none +} + +.container[data-v-6f1d18b5] * { + pointer-events: auto +} + +.content[data-v-6f1d18b5] { + display: flex; + justify-content: flex-end; + align-items: center; + flex-grow: 1 +} + +.title[data-v-7478538b] { + line-height: 32px; + font-size: 13px; + font-weight: 700; + color: var(--vp-c-text-2); + transition: color .25s +} + + +.text[data-v-7bc19822] { + line-height: 24px; + font-size: 12px; + font-weight: 500; + color: var(--vp-c-text-2); + transition: color .5s +} + +.title[data-v-6bfcad30] { + display: flex; + align-items: center; + font-size: 14px; + font-weight: 500; + color: var(--vp-c-text-1) +} + +.list[data-v-6bfcad30] { + padding: 4px 0 0 24px +} + +.link[data-v-6bfcad30] { + line-height: 32px; + font-size: 13px; + color: var(--vp-c-text-1) +} + +.container[data-v-4a289eba] { + margin: 0 auto; + padding: 24px 0 96px; + max-width: 288px +} + +.VPNav[data-v-a50780ff] { + position: relative; + top: var(--vp-layout-top-height, 0px); + left: 0; + z-index: var(--vp-z-index-nav); + width: 100%; + pointer-events: none +} + +@media (min-width: 960px) { + .VPNav[data-v-a50780ff] { + position: fixed + } + + .VPNav.no-sidebar[data-v-a50780ff] { + -webkit-backdrop-filter: saturate(50%) blur(8px); + backdrop-filter: saturate(50%) blur(8px); + background: rgba(255, 255, 255, .7) + } + + @media (prefers-color-scheme: dark) { + .VPNav.no-sidebar[data-v-a50780ff] { + background: rgba(36, 36, 36, .7) + } + } + + @supports not (backdrop-filter: saturate(50%) blur(8px)) { + .VPNav.no-sidebar[data-v-a50780ff] { + background: rgba(255, 255, 255, .95) + } + + @media (prefers-color-scheme: dark) { + .VPNav.no-sidebar[data-v-a50780ff] { + background: rgba(36, 36, 36, .95) + } + } + } +} + +.VPLocalNav[data-v-b6162a8b] { + position: sticky; + top: 0; + left: 0; + z-index: var(--vp-z-index-local-nav); + display: flex; + justify-content: space-between; + align-items: center; + border-bottom: 1px solid var(--vp-c-divider-light); + width: 100%; + background-color: var(--vp-c-bg); + transition: border-color .5s, background-color .5s; + padding-top: var(--vp-layout-top-height, 0px) +} + +@media (min-width: 960px) { + .VPLocalNav[data-v-b6162a8b] { + display: none + } +} + +.menu[data-v-b6162a8b] { + display: flex; + align-items: center; + padding: 12px 24px 11px; + line-height: 24px; + font-size: 12px; + font-weight: 500; + color: var(--vp-c-text-2); + transition: color .5s +} + +.menu[data-v-b6162a8b]:hover { + color: var(--vp-c-text-1); + transition: color .25s +} + +@media (min-width: 768px) { + .menu[data-v-b6162a8b] { + padding: 0 32px + } +} + +.link[data-v-36b976d1] { + display: block; + margin: 4px 0; + color: var(--vp-c-text-2); + transition: color .5s +} + +.link[data-v-36b976d1]:hover { + color: var(--vp-c-text-1) +} + +.link.active[data-v-36b976d1] { + color: var(--vp-c-brand) +} + +.link-text[data-v-36b976d1] { + line-height: 20px; + font-size: 14px; + font-weight: 500 +} + +.link-text.light[data-v-36b976d1] { + font-size: 13px; + font-weight: 400 +} + +.title[data-v-6e45c352] { + display: flex; + justify-content: space-between; + align-items: flex-start; + z-index: 2 +} + +.title-text[data-v-6e45c352] { + padding-top: 6px; + padding-bottom: 6px; + line-height: 20px; + font-size: 14px; + font-weight: 700; + color: var(--vp-c-text-1) +} + +.action[data-v-6e45c352] { + display: none; + position: relative; + margin-right: -8px; + border-radius: 4px; + width: 32px; + height: 32px; + color: var(--vp-c-text-3); + transition: color .25s +} + +.title:hover .action[data-v-6e45c352] { + color: var(--vp-c-text-2) +} + +.nav[data-v-a186aa16] { + outline: 0 +} + +.container[data-v-0a0d4301] { + display: flex; + flex-direction: column; + margin: 0 auto; + max-width: 1152px +} + +@media (min-width: 960px) { + .container[data-v-0a0d4301] { + flex-direction: row + } +} + +.main[data-v-0a0d4301] { + position: relative; + z-index: 10; + order: 2; + flex-grow: 1; + flex-shrink: 0 +} + +@media (min-width: 960px) { + .main[data-v-0a0d4301] { + order: 1; + width: calc((100% / 3) * 2) + } + +} + +.name[data-v-0a0d4301], +.text[data-v-0a0d4301] { + max-width: 392px; + letter-spacing: -.4px; + line-height: 40px; + font-size: 32px; + font-weight: 700; + white-space: pre-wrap +} + +.name[data-v-0a0d4301] { + color: var(--vp-home-hero-name-color) +} + +.clip[data-v-0a0d4301] { + background: var(--vp-home-hero-name-background); + -webkit-background-clip: text; + background-clip: text; + -webkit-text-fill-color: var(--vp-home-hero-name-color) +} + +@media (min-width: 640px) { + + .name[data-v-0a0d4301], + .text[data-v-0a0d4301] { + max-width: 576px; + line-height: 56px; + font-size: 48px + } +} + +@media (min-width: 960px) { + + .name[data-v-0a0d4301], + .text[data-v-0a0d4301] { + line-height: 64px; + font-size: 56px + } + +} + +.tagline[data-v-0a0d4301] { + padding-top: 8px; + max-width: 392px; + line-height: 28px; + font-size: 18px; + font-weight: 500; + white-space: pre-wrap; + color: var(--vp-c-text-2) +} + +@media (min-width: 640px) { + .tagline[data-v-0a0d4301] { + padding-top: 12px; + max-width: 576px; + line-height: 32px; + font-size: 20px + } +} + +@media (min-width: 960px) { + .tagline[data-v-0a0d4301] { + line-height: 36px; + font-size: 24px + } +} + +.actions[data-v-0a0d4301] { + display: flex; + flex-wrap: wrap; + margin: -6px; + padding-top: 24px +} + +@media (min-width: 640px) { + .actions[data-v-0a0d4301] { + padding-top: 32px + } +} + +.action[data-v-0a0d4301] { + flex-shrink: 0; + padding: 6px +} + +.image[data-v-0a0d4301] { + order: 1; + margin: -76px -24px -48px +} + +@media (min-width: 640px) { + .image[data-v-0a0d4301] { + margin: -108px -24px -48px + } +} + +@media (min-width: 960px) { + .image[data-v-0a0d4301] { + flex-grow: 1; + order: 2; + margin: 0; + min-height: 100% + } +} + +.image-container[data-v-0a0d4301] { + position: relative; + margin: 0 auto; + width: 320px; + height: 320px +} + +@media (min-width: 640px) { + .image-container[data-v-0a0d4301] { + width: 392px; + height: 392px + } +} + +@media (min-width: 960px) { + .image-container[data-v-0a0d4301] { + display: flex; + justify-content: center; + align-items: center; + width: 100%; + height: 100%; + transform: translate(-32px, -32px) + } +} + +[data-v-0a0d4301] .image-src { + position: absolute; + top: 50%; + left: 50%; + max-width: 192px; + transform: translate(-50%, -50%) +} + +@media (min-width: 640px) { + [data-v-0a0d4301] .image-src { + max-width: 256px + } +} + +@media (min-width: 960px) { + [data-v-0a0d4301] .image-src { + max-width: 320px + } +} + +.VPFeature[data-v-b8147458] { + display: block; + border: 1px solid var(--vp-c-bg-soft); + border-radius: 12px; + height: 100%; + background-color: var(--vp-c-bg-soft); + transition: border-color .25s, background-color .25s +} + +.VPFeature.link[data-v-b8147458]:hover { + border-color: var(--vp-c-brand); + background-color: var(--vp-c-bg) +} + +@media (prefers-color-scheme: dark) { + .VPFeature.link[data-v-b8147458]:hover { + background-color: var(--vp-c-bg-mute) + } +} + +.box[data-v-b8147458] { + display: flex; + flex-direction: column; + padding: 24px; + height: 100% +} + +.title[data-v-b8147458] { + line-height: 24px; + font-size: 16px; + font-weight: 600 +} + +.details[data-v-b8147458] { + flex-grow: 1; + padding-top: 8px; + line-height: 24px; + font-size: 14px; + font-weight: 500; + color: var(--vp-c-text-2) +} + +.link-text[data-v-b8147458] { + padding-top: 8px +} + +.link-text-value[data-v-b8147458] { + display: flex; + align-items: center; + font-size: 14px; + font-weight: 500; + color: var(--vp-c-brand); + transition: color .25s +} + +.VPFeature.link:hover .link-text-value[data-v-b8147458] { + color: var(--vp-c-brand-dark) +} + +.VPFeatures[data-v-69662dc1] { + position: relative; + padding: 0 24px +} + +@media (min-width: 640px) { + .VPFeatures[data-v-69662dc1] { + padding: 0 48px + } +} + +@media (min-width: 960px) { + .VPFeatures[data-v-69662dc1] { + padding: 0 64px + } +} + +.container[data-v-69662dc1] { + margin: 0 auto; + max-width: 1152px +} + +.VPHome[data-v-1db23833] { + padding-bottom: 96px +} + +@media (min-width: 768px) { + .VPHome[data-v-1db23833] { + padding-bottom: 128px + } +} + +.root[data-v-1188541a] { + position: relative; + z-index: 1 +} + +.nested[data-v-1188541a] { + padding-left: 13px +} + +.outline-link[data-v-1188541a] { + display: block; + line-height: 28px; + color: var(--vp-c-text-2); + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + transition: color .5s +} + +.outline-link[data-v-1188541a]:hover, +.outline-link.active[data-v-1188541a] { + color: var(--vp-c-text-1); + transition: color .25s +} + +.outline-link.nested[data-v-1188541a] { + padding-left: 13px +} + +.content[data-v-2865c0b0] { + position: relative; + border-left: 1px solid var(--vp-c-divider-light); + padding-left: 16px; + font-size: 13px; + font-weight: 500 +} + +.outline-marker[data-v-2865c0b0] { + position: absolute; + top: 32px; + left: -1px; + z-index: 0; + opacity: 0; + width: 1px; + height: 18px; + background-color: var(--vp-c-brand); + transition: top .25s cubic-bezier(0, 1, .5, 1), background-color .5s, opacity .25s +} + +.outline-title[data-v-2865c0b0] { + letter-spacing: .4px; + line-height: 28px; + font-size: 13px; + font-weight: 600 +} + + +.spacer[data-v-afc4c1a1] { + flex-grow: 1 +} + +.title[data-v-21f75714] { + display: block; + line-height: 20px; + font-size: 14px; + font-weight: 500; + color: var(--vp-c-brand); + transition: color .25s +} + + +.container[data-v-cfb513e0] { + margin: 0 auto; + width: 100% +} + +.aside[data-v-cfb513e0] { + position: relative; + display: none; + order: 2; + flex-grow: 1; + padding-left: 32px; + width: 100%; + max-width: 256px +} + +.aside-container[data-v-cfb513e0] { + position: sticky; + top: 0; + margin-top: calc((var(--vp-nav-height-desktop) + var(--vp-layout-top-height, 0px)) * -1 - 32px); + padding-top: calc(var(--vp-nav-height-desktop) + var(--vp-layout-top-height, 0px) + 32px); + height: 100vh; + overflow-x: hidden; + overflow-y: auto; + scrollbar-width: none +} + +.aside-container[data-v-cfb513e0]::-webkit-scrollbar { + display: none +} + +.aside-curtain[data-v-cfb513e0] { + position: fixed; + bottom: 0; + z-index: 10; + width: 224px; + height: 32px; + background: linear-gradient(transparent, var(--vp-c-bg) 70%) +} + +.aside-content[data-v-cfb513e0] { + display: flex; + flex-direction: column; + min-height: calc(100vh - (var(--vp-nav-height-desktop) + var(--vp-layout-top-height, 0px) + 32px)); + padding-bottom: 32px +} + +.content[data-v-cfb513e0] { + position: relative; + margin: 0 auto; + width: 100% +} + +@media (min-width: 960px) { + .content[data-v-cfb513e0] { + padding: 0 32px 128px + } +} + +@media (min-width: 1280px) { + .content[data-v-cfb513e0] { + order: 1; + margin: 0; + min-width: 640px + } +} + +.content-container[data-v-cfb513e0] { + margin: 0 auto +} + +.VPContent[data-v-d981fe29] { + flex-grow: 1; + flex-shrink: 0; + margin: var(--vp-layout-top-height, 0px) auto 0; + width: 100% +} + +.VPContent.is-home[data-v-d981fe29] { + width: 100%; + max-width: 100% +} + +.VPContent.has-sidebar[data-v-d981fe29] { + margin: 0 +} + +@media (min-width: 960px) { + .VPContent[data-v-d981fe29] { + padding-top: var(--vp-nav-height) + } + + .VPContent.has-sidebar[data-v-d981fe29] { + margin: var(--vp-layout-top-height, 0px) 0 0; + padding-left: var(--vp-sidebar-width) + } +} + +@media (min-width: 1440px) { + .VPContent.has-sidebar[data-v-d981fe29] { + padding-right: calc((100vw - var(--vp-layout-max-width)) / 2); + padding-left: calc((100vw - var(--vp-layout-max-width)) / 2 + var(--vp-sidebar-width)) + } +} + +.VPFooter[data-v-9f24cc86] { + position: relative; + z-index: var(--vp-z-index-footer); + border-top: 1px solid var(--vp-c-divider-light); + padding: 32px 24px; + background-color: var(--vp-c-bg) +} + +.VPFooter.has-sidebar[data-v-9f24cc86] { + display: none +} + +@media (min-width: 768px) { + .VPFooter[data-v-9f24cc86] { + padding: 32px + } +} + +.container[data-v-9f24cc86] { + margin: 0 auto; + max-width: var(--vp-layout-max-width); + text-align: center +} + +.message[data-v-9f24cc86], +.copyright[data-v-9f24cc86] { + line-height: 24px; + font-size: 14px; + font-weight: 500; + color: var(--vp-c-text-2) +} + +.message[data-v-9f24cc86] { + order: 2 +} + +.copyright[data-v-9f24cc86] { + order: 1 +} + +.Layout[data-v-f44a984a] { + display: flex; + flex-direction: column; + min-height: 100vh +} + +.title[data-v-95656537] { + padding-top: 12px; + letter-spacing: 2px; + line-height: 20px; + font-size: 20px; + font-weight: 700 +} + +.divider[data-v-95656537] { + margin: 24px auto 18px; + width: 64px; + height: 1px; + background-color: var(--vp-c-divider) +} + +.quote[data-v-95656537] { + margin: 0 auto; + max-width: 256px; + font-size: 14px; + font-weight: 500; + color: var(--vp-c-text-2) +} + +.action[data-v-95656537] { + padding-top: 20px +} + +.link[data-v-95656537] { + display: inline-block; + border: 1px solid var(--vp-c-brand); + border-radius: 16px; + padding: 3px 16px; + font-size: 14px; + font-weight: 500; + color: var(--vp-c-brand); + transition: border-color .25s, color .25s +} + +.link[data-v-95656537]:hover { + border-color: var(--vp-c-brand-dark); + color: var(--vp-c-brand-dark) +} + +.container[data-v-247c88bc] { + margin: 0 auto; + max-width: 1152px +} + +.message[data-v-247c88bc] { + margin: 0 auto; + padding-top: 10px; + max-width: 320px; + text-align: center; + line-height: 24px; + font-size: 16px; + font-weight: 500; + color: var(--vp-c-text-2) +} + +.action[data-v-247c88bc] { + padding-top: 40px; + text-align: center +} + +.title[data-v-bf2cbdac] { + letter-spacing: 0; + line-height: 44px; + font-size: 36px; + font-weight: 500 +} + +@media (min-width: 768px) { + .title[data-v-bf2cbdac] { + letter-spacing: -.5px; + line-height: 56px; + font-size: 48px + } +} + +.title[data-v-be0f7349] { + position: relative; + margin: 0 auto; + max-width: 1152px; + text-align: center; + color: var(--vp-c-text-2) +} + +.title-line[data-v-be0f7349] { + position: absolute; + top: 16px; + left: 0; + width: 100%; + height: 1px; + background-color: var(--vp-c-divider-light) +} + +.title-text[data-v-be0f7349] { + position: relative; + display: inline-block; + padding: 0 24px; + letter-spacing: 0; + line-height: 32px; + font-size: 20px; + font-weight: 500; + background-color: var(--vp-c-bg) +} + +.data[data-v-89ac5bf1] { + text-align: center +} + +.desc[data-v-89ac5bf1] { + margin: 0 auto +} + +.links[data-v-89ac5bf1] { + display: flex; + justify-content: center; + height: 56px +} + +.container[data-v-04685dce] { + display: grid; + gap: 24px; + margin: 0 auto; + max-width: 1152px +} + +:root { + --vp-c-brand: #2355CB; + --vp-c-brand-dark: #2355CB; + --vp-c-black-soft: #000000; + --vp-c-text-light-1: #000000; + --vp-c-text-dark-1: #ffffff; + --landing-fade: #D8E1F8; + --vp-layout-max-width: 1340px; + --vp-font-family-base: "Plus Jakarta Sans", "Inter var experimental", "Inter var", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif +} + +@media (prefers-color-scheme: dark) { + :root { + --landing-fade: #1a1b21 + } +} + +@media (prefers-color-scheme: dark) { + .VPNav.no-sidebar { + background-color: var(--vp-c-black-soft) !important + } +} + +.VPNavBarMenuLink.active { + font-weight: 700 +} + +.VPLink.link.active .link-text { + color: var(--vp-c-brand) !important +} + +.VPLink.link .link-text { + font-size: 16px +} + +::-webkit-scrollbar { + display: none +} + +.f-left { + float: left +} + +.f-right { + float: right +} + +.mt-1 { + margin-top: 15px +} + +.mt-2 { + margin-top: 25px +} + +.mt-5 { + margin-top: 50px +} + +.mt-6 { + margin-top: 60px +} + +.mt-7 { + margin-top: 70px +} + +.mt-15 { + margin-top: 150px +} + +.mb-1 { + margin-bottom: 10px +} + +.mb-2 { + margin-bottom: 20px +} + +.mb-3 { + margin-bottom: 30px +} + +.mb-4 { + margin-bottom: 40px +} + +.mb-6 { + margin-bottom: 60px +} + +.mb-8 { + margin-bottom: 80px +} + +.mb-11 { + margin-bottom: 110px +} + +.mb-18 { + margin-bottom: 180px +} + +.mb-22 { + margin-bottom: 220px +} + +.mb-24 { + margin-bottom: 240px +} + +.ml-20 { + margin-left: 40px +} + +.w-100 { + width: 100% +} + +.w-85 { + width: 85% +} + +.w-80 { + width: 80% +} + +.w-65 { + width: 65% +} + +.w-60 { + width: 60% +} + +.w-57 { + width: 57% +} + +.w-55 { + width: 55% +} + +.w-50 { + width: 50% +} + +.w-45 { + width: 45% +} + +.w-43 { + width: 43% +} + +.w-40 { + width: 40% +} + +.w-15 { + width: 15% +} + +.p-130 { + padding: 0 130px +} + +.p-105 { + padding: 0 105px +} + +.p-90 { + padding: 0 90px +} + +.p-50 { + padding: 0 50px +} + +.pl-130 { + padding-left: 130px +} + +.pl-6 { + padding-left: 60px +} + +.pr-2 { + padding-right: 20px +} + +.pb-5 { + padding-bottom: 50px +} + +.px-2 { + padding: 0 20px +} + +.text-left { + text-align: left +} + +.c-brand { + color: var(--vp-c-brand) !important +} + +.c-brand-light { + color: #56bced !important +} + +.shotover-title { + font-size: 150px; + font-weight: 600; + line-height: 160px; + margin-top: 110px +} + +.shotover-subtitle { + font-size: 37.5px; + font-weight: 700; + line-height: 60px; + margin-left: 7px; + margin-bottom: 16px +} + +.landing-title { + font-size: 75px; + font-weight: 600; + line-height: 88px +} + +.landing-title-img { + width: calc(100% - 40px) +} + +.shotover-motto { + font-size: 20.5px; + font-weight: 400; + margin-left: 6px; + margin-bottom: 44px +} + +.landing-action-btn { + text-decoration: none; + font-weight: 600; + font-size: 21px; + padding: 12px 57px; + margin-left: 3px; + color: var(--vp-c-brand); + box-shadow: 0 5px 6px #2355cb40; + border-radius: 50px; + border: 2px solid transparent; + background: linear-gradient(var(--vp-c-bg), var(--vp-c-bg)) padding-box, linear-gradient(to right, var(--vp-c-brand), #56BCED) border-box +} + +.landing-action-btn-text { + background-color: var(--vp-c-brand); + background-image: linear-gradient(to right, var(--vp-c-brand), #56BCED); + background-size: 100%; + background-repeat: repeat; + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; +} + +.landing-description-title { + background-color: var(--vp-c-brand); + background-image: linear-gradient(90deg, #2355CB 0%, #56BCED 60%); + background-size: 100%; + background-repeat: repeat; + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + font-size: 80px; + font-weight: 600; + line-height: 89px +} + +.landing-description { + font-size: 21px; + font-weight: 400; + line-height: 26px +} + +.landing-docs-title { + width: 45%; + font-size: 55px; + font-weight: 600; + line-height: 66px; + color: #c8d4f2; + margin-bottom: 25px +} + +.docs-container { + text-align: center +} + +.docs-block { + text-decoration: none; + display: block; + float: left; + width: calc(33% - 50px); + max-width: 500px; + border: 2px solid var(--vp-c-brand); + border-radius: 40px; + padding: 33px 50px; + margin-left: 25px; + margin-right: 25px +} + +.docs-block:hover { + background-color: var(--vp-c-brand); + color: var(--vp-c-bg) +} + +.doc-name { + font-weight: 700; + font-size: 37px; + text-align: left; + line-height: 47px +} + +.doc-desc { + color: #9c9a9a; + font-weight: 400; + font-size: 21px; + line-height: 27px; + height: 250px +} + +.doc-action-btn { + color: var(--vp-c-brand); + background-color: var(--vp-c-text-dark-1); + border: 2px solid var(--vp-c-brand); + border-radius: 50px; + padding: 10px 30px; + font-weight: 500 +} + +.doc-arrow { + margin-top: 1px; + margin-left: 14px; + width: 22px +} + +.landing-problems { + background: linear-gradient(180deg, var(--vp-c-bg) 0%, var(--landing-fade) 35%, var(--landing-fade) 75%, var(--vp-c-bg) 100%) +} + +.landing-problems-title { + width: 70%; + font-size: 78px; + font-weight: 600; + line-height: 92px +} + +.problems-description { + font-size: 26px; + font-weight: 400; + line-height: 34px +} + +.problem-card { + color: var(--vp-c-text-dark-1); + width: calc(50% - 17px); + height: 300px; + border-radius: 40px; + padding: 40px 50px; + font-size: 25px; + line-height: 35px; + font-weight: 400; + margin-bottom: 17px; + margin-left: 8.5px; + margin-right: 8.5px; + position: relative +} + +.pointer-text { + width: 240px; + position: absolute; + top: 3px; + left: 80px +} + +.no-scroll-y { + overflow-y: hidden !important +} + +.footer-nav { + padding-top: 15px +} + +.footer-link { + float: left; + width: 100%; + margin-bottom: 8px; + font-weight: 500; + color: var(--vp-c-text-1) !important +} + +.footer-link:hover { + color: var(--vp-c-brand) !important +} + +.copyright-section a { + float: left; + font-size: 24px; + font-weight: 600 +} + +.copyright-section a span { + margin-top: 6.5px; + margin-right: 15px; + float: left +} + +.copyright-section img { + float: left; + width: 80px; + font-size: 24px; + font-weight: 600 +} + +.copyright-section .copyright { + font-weight: 400; + font-size: 12px; + line-height: 16px; + color: #717171 !important; + width: 90%; + max-width: 674px +} + + +@media (max-width: 768px) { + .p-130 { + padding: 20px !important + } + + .footer { + text-align: center !important + } + + .footer .copyright-section { + width: 100% !important; + margin-bottom: 20px; + position: relative + } + + .footer .copyright { + width: 100% !important; + max-width: 100% !important + } + + .footer .footer-nav { + width: 100% !important + } + + .footer a.mb-3 { + width: 202px; + position: absolute; + left: 50%; + transform: translate(-50%) + } + + .footer .copyright-section .f-left.w-100 { + margin-top: 55px + } + + .landing-description-title, + .landing-docs-title, + .landing-problems-title, + .landing-title { + text-align: center + } + + .landing-docs-title { + max-width: 100% !important + } + + .landing-title, + .landing-description.w-50 { + width: 100% + } + + .landing-description, + .problems-description { + text-align: justify + } + + .w-65.problems-description, + .w-50.problems-description { + width: 100% + } + + .problem-card { + width: 100%; + margin-top: 0 !important; + margin-left: 0; + margin-right: 0; + padding: 20px 30px + } + + .problem-card .w-80, + .landing-deploy .landing-description.w-80 { + width: 100% + } + + .landing-deploy .p-50 { + padding: 0 + } + + .landing-main-title { + text-align: center + } + + .landing-main-title .w-55 { + width: 100% + } + + .landing-main-title .w-45 { + display: none + } +} + +@media (max-width: 928px) { + .p-130 { + padding: 20px !important + } + + .pl-130 { + padding-left: 20px !important; + padding-right: 20px !important + } + + .p-105 { + padding: 20px !important + } + + .p-90 { + padding-left: 0; + padding-right: 0 + } +} + +@media (max-width: 1100px) { + .landing-deploy .w-45 { + width: 100%; + margin-bottom: 20px + } + + .landing-deploy .w-55 { + width: 100% + } +} + +@media (max-width: 1235px) { + .p-90 { + padding-left: 0; + padding-right: 0 + } + + .w-43 { + width: 100% + } + + .pr-2 { + padding-right: 0 + } + + .w-57 { + width: 100% + } + + .mb-sm-1 { + margin-bottom: 10px + } + + .landing-problems-title { + width: 100% + } + + .landing-deploy .w-40 { + width: 100% + } +} + +@media (max-width: 1360px) { + .docs-block { + width: 100%; + max-width: 100%; + margin-bottom: 30px; + margin-left: 0; + margin-right: 0 + } +} + +@media (min-width: 1236px) and (max-width: 1376px) { + .landing-problems-title { + width: 80% + } +} + +@media (max-width: 1487px) { + .landing-docs-title { + width: 100%; + max-width: 675px + } + + .problem-card { + padding: 20px 30px + } + + .problem-card .w-80 { + width: 100% + } + + .shotover-title { + font-size: 75px; + line-height: 85px + } + + .shotover-subtitle { + font-size: 30px; + line-height: 52px + } + + .landing-description-title { + font-size: 60px; + line-height: 69px + } + + .landing-docs-title { + font-size: 45px; + line-height: 56px + } + + .doc-name { + font-size: 32px; + line-height: 42px + } + + .landing-problems-title { + font-size: 45px; + line-height: 60px + } + + .landing-title { + font-size: 55px; + line-height: 70px + } +} \ No newline at end of file diff --git a/website/assets/title_image.png b/website/assets/title_image.png new file mode 100644 index 000000000..70314fbde Binary files /dev/null and b/website/assets/title_image.png differ diff --git a/website/readme.md b/website/readme.md new file mode 100644 index 000000000..e9d0f7007 --- /dev/null +++ b/website/readme.md @@ -0,0 +1,6 @@ +# Shotover website + +This tool generates the shotover website. +To test the website locally, run the command: `cargo run -p website -- --serve` + +The website is hosted via github actions at the domain: diff --git a/website/src/cli.rs b/website/src/cli.rs new file mode 100644 index 000000000..411979141 --- /dev/null +++ b/website/src/cli.rs @@ -0,0 +1,10 @@ +use clap::Parser; + +/// Generates the shotover website. +#[derive(Parser, Clone)] +#[clap()] +pub struct Args { + /// As well as generating the site, serve the contents of the site over http. + #[clap(long)] + pub serve: bool, +} diff --git a/website/src/docs.rs b/website/src/docs.rs new file mode 100644 index 000000000..8a85adf27 --- /dev/null +++ b/website/src/docs.rs @@ -0,0 +1,84 @@ +use crate::run_command; +use anyhow::Result; +use rinja::Template; +use std::{fs::create_dir_all, path::Path}; + +pub fn generate_all_docs(current_dir: &Path) -> Result<()> { + let root = current_dir.join("website").join("root"); + println!("Generating main"); + create_dir_all(root.join("docs")).unwrap(); + build_docs( + current_dir, + Path::new("docs"), + &root.join("docs").join("main"), + ); + + // ensure repo exists and is up to date + let repo_path = Path::new("website").join("shotover_repo_for_docs"); + if repo_path.exists() { + run_command(&repo_path, "git", &["fetch"])?; + } else { + run_command( + ".", + "git", + &[ + "clone", + "https://github.com/shotover/shotover-proxy", + repo_path.to_str().unwrap(), + ], + )?; + } + + let versions = crate::version_tags::get_versions_of_repo(&repo_path); + + let docs = DocsTemplate { + versions: versions.iter().map(|x| x.semver_range.clone()).collect(), + }; + std::fs::write(root.join("docs").join("index.html"), docs.render().unwrap()).unwrap(); + + for version in &versions { + println!("Generating {}", version.tag); + run_command(&repo_path, "git", &["checkout", &version.tag])?; + + build_docs( + current_dir, + &repo_path.join("docs"), + &root.join("docs").join(&version.semver_range), + ) + } + + if let Some(version) = versions.first() { + println!("Generating latest"); + run_command(&repo_path, "git", &["checkout", &version.tag])?; + + build_docs( + current_dir, + &repo_path.join("docs"), + &root.join("docs").join("latest"), + ) + } + + Ok(()) +} + +fn build_docs(current_dir: &Path, in_path: &Path, out_path: &Path) { + let temp_docs_dir = current_dir.join("target").join("temp_docs_build"); + std::fs::remove_dir_all(&temp_docs_dir).ok(); + run_command( + in_path, + "mdbook", + &["build", "--dest-dir", temp_docs_dir.to_str().unwrap()], + ) + .ok(); + + std::fs::remove_dir_all(out_path).ok(); + std::fs::rename(temp_docs_dir.join("html"), out_path).unwrap(); + + std::fs::remove_dir_all(&temp_docs_dir).ok(); +} + +#[derive(Template)] +#[template(path = "docs.html")] +struct DocsTemplate { + versions: Vec, +} diff --git a/website/src/main.rs b/website/src/main.rs new file mode 100644 index 000000000..bac343d70 --- /dev/null +++ b/website/src/main.rs @@ -0,0 +1,99 @@ +use anyhow::{anyhow, Result}; +use clap::Parser; +use cli::Args; +use rinja::Template; +use std::{path::Path, process::Command}; +use subprocess::{Exec, Redirection}; + +mod cli; +mod docs; +mod version_tags; + +fn main() { + // Set standard path to root of repo so this always runs in the same directory, regardless of where the user ran it from. + let current_dir = Path::new(env!("CARGO_MANIFEST_DIR")).parent().unwrap(); + std::env::set_current_dir(current_dir).unwrap(); + + let args = Args::parse(); + + println!("Ensuring mdbook is installed"); + // TODO: Once mdbook starts doing macos aarch64 binary releases we should download the release directly instead of compiling. + // https://github.com/rust-lang/mdBook/pull/2500 + if !Command::new("cargo") + .args(["install", "mdbook", "--version", "0.4.43"]) + .status() + .unwrap() + .success() + { + return; + } + + let root = current_dir.join("website").join("root"); + std::fs::remove_dir_all(&root).ok(); + std::fs::create_dir_all(&root).unwrap(); + + // copy assets + let dest_assets = root.join("assets"); + std::fs::create_dir_all(&dest_assets).unwrap(); + for file in std::fs::read_dir("website/assets").unwrap() { + let file = file.unwrap(); + std::fs::copy(file.path(), dest_assets.join(file.file_name())).unwrap(); + } + // browsers expect to find the file here. + std::fs::rename( + "website/root/assets/favicon.ico", + "website/root/favicon.ico", + ) + .unwrap(); + + // generate landing page + std::fs::write(root.join("index.html"), Landing {}.render().unwrap()).unwrap(); + + if let Err(err) = docs::generate_all_docs(current_dir) { + println!("{err}"); + return; + } + + if args.serve { + println!("Hosting website at: http://localhost:8000"); + + devserver_lib::run( + "localhost", + 8000, + current_dir.join("website").join("root").to_str().unwrap(), + false, + "", + ); + } else { + let out = current_dir.join("website").join("root"); + println!( + "Succesfully generated website at: file://{}", + out.to_str().unwrap() + ); + } +} + +pub fn run_command(dir: impl AsRef, command: &str, args: &[&str]) -> Result { + let data = Exec::cmd(command) + .args(args) + .cwd(dir) + .stdout(Redirection::Pipe) + .stderr(Redirection::Merge) + .capture()?; + + if data.exit_status.success() { + Ok(data.stdout_str()) + } else { + Err(anyhow!( + "command {} {:?} exited with {:?} and output:\n{}", + command, + args, + data.exit_status, + data.stdout_str() + )) + } +} + +#[derive(Template)] +#[template(path = "landing.html")] +struct Landing {} diff --git a/website/src/version_tags.rs b/website/src/version_tags.rs new file mode 100644 index 000000000..9df0f732f --- /dev/null +++ b/website/src/version_tags.rs @@ -0,0 +1,60 @@ +use crate::run_command; +use semver::Version; +use std::path::Path; + +pub struct VersionTag { + /// e.g. "v0.1.1" + pub tag: String, + /// e.g. "0.1.x" + pub semver_range: String, + /// e.g. 0.1.1 + pub version: Version, +} + +impl VersionTag { + fn new(tag: &str) -> Option { + let version = Version::parse(tag.strip_prefix("v")?).ok()?; + + // ignore any prerelease or otherwise unusual tags + if !version.pre.is_empty() || !version.build.is_empty() { + return None; + } + + let semver_range = if version.major != 0 { + format!("{}.Y.Z", version.major) + } else { + format!("0.{}.Z", version.minor) + }; + Some(VersionTag { + tag: tag.to_owned(), + version, + semver_range, + }) + } +} + +pub fn get_versions_of_repo(repo_path: &Path) -> Vec { + let mut versions: Vec = run_command(repo_path, "git", &["tag"]) + .unwrap() + .lines() + .filter_map(VersionTag::new) + .filter(|x| x.version >= Version::new(0, 1, 0)) + .collect(); + + // reverse sort the list of versions + versions.sort_by_key(|x| x.version.clone()); + versions.reverse(); + + // Filter out any versions with duplicate semver range, keeping the first item. + // Keeping the first items leaves us with the most recent item due to the previous reverse sort. + let mut known = vec![]; + versions.retain(|version| { + let any_known = known + .iter() + .any(|known_range| &version.semver_range == known_range); + known.push(version.semver_range.clone()); + !any_known + }); + + versions +} diff --git a/website/templates/base.html b/website/templates/base.html new file mode 100644 index 000000000..51604e7f0 --- /dev/null +++ b/website/templates/base.html @@ -0,0 +1,56 @@ + + + + + + + {% block title %} {{ title }} {% endblock %} + {% block head %}{% endblock %} + + + + +
+
Skip to content + +
+
+
+ +
+ +
+
+
+
+
+
+
+
+
+ {% block content %}

Placeholder content

{% endblock %} +
+ +
+
+
+
+
+
+ + + \ No newline at end of file diff --git a/website/templates/docs.html b/website/templates/docs.html new file mode 100644 index 000000000..ca8142e6f --- /dev/null +++ b/website/templates/docs.html @@ -0,0 +1,22 @@ +{% extends "base.html" %} + +{% block title %} +Shotover Documentation Index +{% endblock %} + +{% block content %} +
+
+

Documentation for current and historical versions of shotover is hosted below:

+ + +
+
+ + +{% endblock %} \ No newline at end of file diff --git a/website/templates/landing.html b/website/templates/landing.html new file mode 100644 index 000000000..b9a14c408 --- /dev/null +++ b/website/templates/landing.html @@ -0,0 +1,97 @@ +{% extends "base.html" %} + +{% block title %} +Shotover Proxy +{% endblock %} + +{% block content %} +
+
+

Shotover

+

L7 data layer proxy + +

+

Get + started +
+
+
+
+
+

What is Shotover?

+
+
+

Shotover is a high performance, configurable + and extensible L7 data-layer proxy for controlling, managing and modifying + the flow of database requests in transit. It can be used to solve many + different operational and interoperability challenges by transparently + intercepting and transforming queries. It is transparent in the sense that + it can be plugged into your architecture without requiring application + change.

+
+
+ +
+

What problems does Shotover solve?

+

More broadly, Shotover is designed to be + used for a very wide ranging class of problems where it is useful to + transparently intercept a database call and redirect it. This allows you to + change the behaviour of running applications at the infrastructure level without + change to the application code itself. Some examples where we envisage Shotover + could be deployed include:

+
+
+ Moving very large or very hot + tenants/customers/keys to a separate data store by intercepting and + redirecting queries for those particular keys +
+
Dual + writing and/or query translation to allow the underlying storage + technology to be changed
+
Adding auditing, encryption or other security + measures
+
+ As an alternative to Change Data Capture + technology to send writes to a message stream such as Apache + Kafka +
+
+
+
+
+

Name

+

Shotover refers to the + Shotover (Kimi-ākau) river in Otago, New Zealand - close to Queenstown and + eventually flowing into Lake Wakatipu via the Kawarau River, it's famous for + white water rafting, bungy-jumping, fast rapids and jet boating.

+
+
+{% endblock %} \ No newline at end of file