├── .dockerignore ├── .env.example ├── .github └── workflows │ ├── build.yml │ ├── ci.yml │ └── release.yml ├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── Dockerfile ├── LICENSE ├── README.md ├── action.yml ├── action ├── main.mjs ├── post.mjs └── util.mjs ├── icon.png ├── renovate.json ├── src ├── app_settings.rs ├── lib.rs ├── main.rs ├── routes │ ├── artifacts.rs │ ├── events.rs │ ├── health_check.rs │ └── mod.rs ├── startup.rs ├── storage.rs └── telemetry.rs └── tests └── e2e ├── artifacts.rs ├── health_check.rs ├── helpers.rs └── main.rs /.dockerignore: -------------------------------------------------------------------------------- 1 | .git 2 | .github 3 | *.log 4 | /target -------------------------------------------------------------------------------- /.env.example: -------------------------------------------------------------------------------- 1 | #################################### 2 | # Optional 3 | #################################### 4 | S3_ACCESS_KEY="ACCESS_KEY_FROM_MINIO" 5 | S3_SECRET_KEY="SECRET_KEY_FROM_MINIO" 6 | S3_ENDPOINT="http://localhost:9000" 7 | 8 | #################################### 9 | # Optional but with defaults 10 | #################################### 11 | # Bucket name defaults to "turbo" 12 | S3_BUCKET_NAME="YOUR_BUCKET_NAME" 13 | # Region defaults to "eu-central-1" 14 | S3_REGION="eu-central-1" 15 | # Defaults to "false" 16 | S3_USE_PATH_STYLE=true 17 | # Defaults to 8000 18 | PORT=8000 19 | # Path for writing logs to a file 20 | LOGS_DIRECTORY="/tmp/decay_logs" 21 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build binary 2 | on: 3 | # workflow_dispatch: 4 | # inputs: {} 5 | pull_request: 6 | concurrency: 7 | group: ${{ github.ref }} 8 | cancel-in-progress: false 9 | 10 | jobs: 11 | build: 12 | name: Build 13 | runs-on: ubuntu-latest 14 | steps: 15 | - name: Checkout code 16 | uses: actions/checkout@v4 17 | 18 | - name: Set up Docker Buildx 19 | uses: docker/setup-buildx-action@v3 20 | 21 | - name: build binary 22 | run: docker build -t rust_build . 23 | 24 | - name: create temp container 25 | run: docker create --name dist rust_build 26 | 27 | - name: copy binary 28 | run: | 29 | mkdir out && \ 30 | docker cp dist:app/target/x86_64-unknown-linux-musl/release/decay out/decay 31 | 32 | - uses: actions/upload-artifact@v4 33 | with: 34 | name: binaries 35 | path: | 36 | out/decay 37 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: "CI Checks" 2 | on: 3 | push: 4 | branches: 5 | - main 6 | pull_request: 7 | 8 | jobs: 9 | lint: 10 | name: lint 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v4 14 | # Ensure rustfmt is installed and setup problem matcher 15 | - uses: actions-rust-lang/setup-rust-toolchain@v1 16 | with: 17 | components: rustfmt 18 | - name: Rustfmt Check 19 | uses: actions-rust-lang/rustfmt@v1 20 | 21 | - name: Run Clippy 22 | env: 23 | RUSTFLAGS: "-Dwarnings" 24 | run: cargo clippy 25 | 26 | test: 27 | name: test 28 | runs-on: ubuntu-latest 29 | steps: 30 | - uses: actions/checkout@v4 31 | - uses: actions-rust-lang/setup-rust-toolchain@v1 32 | - run: cargo test --all-features 33 | env: 34 | S3_ACCESS_KEY: some-access-key 35 | S3_SECRET_KEY: some-secret-key 36 | S3_REGION: eu-central-1 37 | S3_BUCKET_NAME: turbo 38 | S3_ENDPOINT: "http://localhost:9000" 39 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release new tag 2 | on: 3 | workflow_dispatch: 4 | inputs: 5 | semver: 6 | description: "The SemVer value used by this release" 7 | type: string 8 | required: true 9 | 10 | concurrency: 11 | group: ${{ github.ref }} 12 | cancel-in-progress: false 13 | 14 | permissions: "write-all" 15 | 16 | jobs: 17 | release: 18 | name: Release Turbo Cache Server 19 | runs-on: ubuntu-latest 20 | 21 | steps: 22 | - name: Checkout repository 23 | uses: actions/checkout@v4 24 | 25 | - name: Branch sanity check 26 | if: github.ref != 'refs/heads/main' 27 | run: | 28 | echo "Releases should only run from the main branch" 29 | exit 1 30 | 31 | - name: Update version on Cargo.toml 32 | run: | 33 | sed -i "s/^version = \".*\"/version = \"${{ github.event.inputs.semver }}\"/" Cargo.toml 34 | cat Cargo.toml 35 | 36 | - name: build binary 37 | run: docker build -t rust_build . 38 | 39 | - name: create temp container to copy binary from 40 | run: docker create --name dist rust_build 41 | 42 | # Copy binary from the Docker container and put 43 | # it within the `action` directory before commiting the new tag. 44 | # This makes the binary available directly from the tag 45 | # when using this repo as a Github Action, without requiring 46 | # an extra binary download from somewhere else (Github Releases?) 47 | # leading to a faster pipeline. 48 | - name: copy binary 49 | run: | 50 | docker cp dist:app/target/x86_64-unknown-linux-musl/release/decay action/decay 51 | chmod +x action/decay 52 | - name: Commit new binary 53 | run: | 54 | git config --global user.name "${GITHUB_ACTOR}" 55 | git config --global user.email "${GITHUB_ACTOR}@users.noreply.github.com" 56 | git add action/decay 57 | git commit -am "Release ${{ github.event.inputs.semver }}" 58 | git tag -a ${{ github.event.inputs.semver }} -m "Release ${{ github.event.inputs.semver }}" 59 | - name: Push new tag 60 | run: git push origin ${{ github.event.inputs.semver }} 61 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # IDEs 2 | .vscode 3 | .idea 4 | 5 | .DS_Store 6 | # Build output 7 | /target 8 | *.log 9 | .env 10 | db 11 | s3_data 12 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 4 4 | 5 | [[package]] 6 | name = "actix-codec" 7 | version = "0.5.2" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "5f7b0a21988c1bf877cf4759ef5ddaac04c1c9fe808c9142ecb78ba97d97a28a" 10 | dependencies = [ 11 | "bitflags", 12 | "bytes", 13 | "futures-core", 14 | "futures-sink", 15 | "memchr", 16 | "pin-project-lite", 17 | "tokio", 18 | "tokio-util", 19 | "tracing", 20 | ] 21 | 22 | [[package]] 23 | name = "actix-http" 24 | version = "3.11.0" 25 | source = "registry+https://github.com/rust-lang/crates.io-index" 26 | checksum = "44dfe5c9e0004c623edc65391dfd51daa201e7e30ebd9c9bedf873048ec32bc2" 27 | dependencies = [ 28 | "actix-codec", 29 | "actix-rt", 30 | "actix-service", 31 | "actix-utils", 32 | "base64", 33 | "bitflags", 34 | "brotli", 35 | "bytes", 36 | "bytestring", 37 | "derive_more", 38 | "encoding_rs", 39 | "flate2", 40 | "foldhash", 41 | "futures-core", 42 | "h2 0.3.26", 43 | "http 0.2.12", 44 | "httparse", 45 | "httpdate", 46 | "itoa", 47 | "language-tags", 48 | "local-channel", 49 | "mime", 50 | "percent-encoding", 51 | "pin-project-lite", 52 | "rand", 53 | "sha1", 54 | "smallvec", 55 | "tokio", 56 | "tokio-util", 57 | "tracing", 58 | "zstd", 59 | ] 60 | 61 | [[package]] 62 | name = "actix-macros" 63 | version = "0.2.4" 64 | source = "registry+https://github.com/rust-lang/crates.io-index" 65 | checksum = "e01ed3140b2f8d422c68afa1ed2e85d996ea619c988ac834d255db32138655cb" 66 | dependencies = [ 67 | "quote", 68 | "syn", 69 | ] 70 | 71 | [[package]] 72 | name = "actix-router" 73 | version = "0.5.3" 74 | source = "registry+https://github.com/rust-lang/crates.io-index" 75 | checksum = "13d324164c51f63867b57e73ba5936ea151b8a41a1d23d1031eeb9f70d0236f8" 76 | dependencies = [ 77 | "bytestring", 78 | "cfg-if", 79 | "http 0.2.12", 80 | "regex", 81 | "regex-lite", 82 | "serde", 83 | "tracing", 84 | ] 85 | 86 | [[package]] 87 | name = "actix-rt" 88 | version = "2.10.0" 89 | source = "registry+https://github.com/rust-lang/crates.io-index" 90 | checksum = "24eda4e2a6e042aa4e55ac438a2ae052d3b5da0ecf83d7411e1a368946925208" 91 | dependencies = [ 92 | "futures-core", 93 | "tokio", 94 | ] 95 | 96 | [[package]] 97 | name = "actix-server" 98 | version = "2.6.0" 99 | source = "registry+https://github.com/rust-lang/crates.io-index" 100 | checksum = "a65064ea4a457eaf07f2fba30b4c695bf43b721790e9530d26cb6f9019ff7502" 101 | dependencies = [ 102 | "actix-rt", 103 | "actix-service", 104 | "actix-utils", 105 | "futures-core", 106 | "futures-util", 107 | "mio", 108 | "socket2", 109 | "tokio", 110 | "tracing", 111 | ] 112 | 113 | [[package]] 114 | name = "actix-service" 115 | version = "2.0.2" 116 | source = "registry+https://github.com/rust-lang/crates.io-index" 117 | checksum = "3b894941f818cfdc7ccc4b9e60fa7e53b5042a2e8567270f9147d5591893373a" 118 | dependencies = [ 119 | "futures-core", 120 | "paste", 121 | "pin-project-lite", 122 | ] 123 | 124 | [[package]] 125 | name = "actix-utils" 126 | version = "3.0.1" 127 | source = "registry+https://github.com/rust-lang/crates.io-index" 128 | checksum = "88a1dcdff1466e3c2488e1cb5c36a71822750ad43839937f85d2f4d9f8b705d8" 129 | dependencies = [ 130 | "local-waker", 131 | "pin-project-lite", 132 | ] 133 | 134 | [[package]] 135 | name = "actix-web" 136 | version = "4.11.0" 137 | source = "registry+https://github.com/rust-lang/crates.io-index" 138 | checksum = "a597b77b5c6d6a1e1097fddde329a83665e25c5437c696a3a9a4aa514a614dea" 139 | dependencies = [ 140 | "actix-codec", 141 | "actix-http", 142 | "actix-macros", 143 | "actix-router", 144 | "actix-rt", 145 | "actix-server", 146 | "actix-service", 147 | "actix-utils", 148 | "actix-web-codegen", 149 | "bytes", 150 | "bytestring", 151 | "cfg-if", 152 | "cookie", 153 | "derive_more", 154 | "encoding_rs", 155 | "foldhash", 156 | "futures-core", 157 | "futures-util", 158 | "impl-more", 159 | "itoa", 160 | "language-tags", 161 | "log", 162 | "mime", 163 | "once_cell", 164 | "pin-project-lite", 165 | "regex", 166 | "regex-lite", 167 | "serde", 168 | "serde_json", 169 | "serde_urlencoded", 170 | "smallvec", 171 | "socket2", 172 | "time", 173 | "tracing", 174 | "url", 175 | ] 176 | 177 | [[package]] 178 | name = "actix-web-codegen" 179 | version = "4.3.0" 180 | source = "registry+https://github.com/rust-lang/crates.io-index" 181 | checksum = "f591380e2e68490b5dfaf1dd1aa0ebe78d84ba7067078512b4ea6e4492d622b8" 182 | dependencies = [ 183 | "actix-router", 184 | "proc-macro2", 185 | "quote", 186 | "syn", 187 | ] 188 | 189 | [[package]] 190 | name = "addr2line" 191 | version = "0.24.2" 192 | source = "registry+https://github.com/rust-lang/crates.io-index" 193 | checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" 194 | dependencies = [ 195 | "gimli", 196 | ] 197 | 198 | [[package]] 199 | name = "adler2" 200 | version = "2.0.0" 201 | source = "registry+https://github.com/rust-lang/crates.io-index" 202 | checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" 203 | 204 | [[package]] 205 | name = "ahash" 206 | version = "0.8.11" 207 | source = "registry+https://github.com/rust-lang/crates.io-index" 208 | checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" 209 | dependencies = [ 210 | "cfg-if", 211 | "getrandom 0.2.15", 212 | "once_cell", 213 | "version_check", 214 | "zerocopy 0.7.35", 215 | ] 216 | 217 | [[package]] 218 | name = "aho-corasick" 219 | version = "1.1.3" 220 | source = "registry+https://github.com/rust-lang/crates.io-index" 221 | checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" 222 | dependencies = [ 223 | "memchr", 224 | ] 225 | 226 | [[package]] 227 | name = "alloc-no-stdlib" 228 | version = "2.0.4" 229 | source = "registry+https://github.com/rust-lang/crates.io-index" 230 | checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3" 231 | 232 | [[package]] 233 | name = "alloc-stdlib" 234 | version = "0.2.2" 235 | source = "registry+https://github.com/rust-lang/crates.io-index" 236 | checksum = "94fb8275041c72129eb51b7d0322c29b8387a0386127718b096429201a5d6ece" 237 | dependencies = [ 238 | "alloc-no-stdlib", 239 | ] 240 | 241 | [[package]] 242 | name = "assert-json-diff" 243 | version = "2.0.2" 244 | source = "registry+https://github.com/rust-lang/crates.io-index" 245 | checksum = "47e4f2b81832e72834d7518d8487a0396a28cc408186a2e8854c0f98011faf12" 246 | dependencies = [ 247 | "serde", 248 | "serde_json", 249 | ] 250 | 251 | [[package]] 252 | name = "async-trait" 253 | version = "0.1.83" 254 | source = "registry+https://github.com/rust-lang/crates.io-index" 255 | checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" 256 | dependencies = [ 257 | "proc-macro2", 258 | "quote", 259 | "syn", 260 | ] 261 | 262 | [[package]] 263 | name = "atomic-waker" 264 | version = "1.1.2" 265 | source = "registry+https://github.com/rust-lang/crates.io-index" 266 | checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" 267 | 268 | [[package]] 269 | name = "attohttpc" 270 | version = "0.28.2" 271 | source = "registry+https://github.com/rust-lang/crates.io-index" 272 | checksum = "412b79ce053cef36eda52c25664b45ec92a21769488e20d5a8bf0b3c9e1a28cb" 273 | dependencies = [ 274 | "http 1.2.0", 275 | "log", 276 | "native-tls", 277 | "serde", 278 | "serde_json", 279 | "url", 280 | ] 281 | 282 | [[package]] 283 | name = "autocfg" 284 | version = "1.4.0" 285 | source = "registry+https://github.com/rust-lang/crates.io-index" 286 | checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" 287 | 288 | [[package]] 289 | name = "aws-creds" 290 | version = "0.37.0" 291 | source = "registry+https://github.com/rust-lang/crates.io-index" 292 | checksum = "7f84143206b9c72b3c5cb65415de60c7539c79cd1559290fddec657939131be0" 293 | dependencies = [ 294 | "attohttpc", 295 | "home", 296 | "log", 297 | "quick-xml", 298 | "rust-ini", 299 | "serde", 300 | "thiserror", 301 | "time", 302 | "url", 303 | ] 304 | 305 | [[package]] 306 | name = "aws-region" 307 | version = "0.25.5" 308 | source = "registry+https://github.com/rust-lang/crates.io-index" 309 | checksum = "e9aed3f9c7eac9be28662fdb3b0f4d1951e812f7c64fed4f0327ba702f459b3b" 310 | dependencies = [ 311 | "thiserror", 312 | ] 313 | 314 | [[package]] 315 | name = "backtrace" 316 | version = "0.3.74" 317 | source = "registry+https://github.com/rust-lang/crates.io-index" 318 | checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" 319 | dependencies = [ 320 | "addr2line", 321 | "cfg-if", 322 | "libc", 323 | "miniz_oxide", 324 | "object", 325 | "rustc-demangle", 326 | "windows-targets 0.52.6", 327 | ] 328 | 329 | [[package]] 330 | name = "base64" 331 | version = "0.22.1" 332 | source = "registry+https://github.com/rust-lang/crates.io-index" 333 | checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" 334 | 335 | [[package]] 336 | name = "bitflags" 337 | version = "2.6.0" 338 | source = "registry+https://github.com/rust-lang/crates.io-index" 339 | checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" 340 | 341 | [[package]] 342 | name = "block-buffer" 343 | version = "0.10.4" 344 | source = "registry+https://github.com/rust-lang/crates.io-index" 345 | checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" 346 | dependencies = [ 347 | "generic-array", 348 | ] 349 | 350 | [[package]] 351 | name = "brotli" 352 | version = "8.0.1" 353 | source = "registry+https://github.com/rust-lang/crates.io-index" 354 | checksum = "9991eea70ea4f293524138648e41ee89b0b2b12ddef3b255effa43c8056e0e0d" 355 | dependencies = [ 356 | "alloc-no-stdlib", 357 | "alloc-stdlib", 358 | "brotli-decompressor", 359 | ] 360 | 361 | [[package]] 362 | name = "brotli-decompressor" 363 | version = "5.0.0" 364 | source = "registry+https://github.com/rust-lang/crates.io-index" 365 | checksum = "874bb8112abecc98cbd6d81ea4fa7e94fb9449648c93cc89aa40c81c24d7de03" 366 | dependencies = [ 367 | "alloc-no-stdlib", 368 | "alloc-stdlib", 369 | ] 370 | 371 | [[package]] 372 | name = "bumpalo" 373 | version = "3.16.0" 374 | source = "registry+https://github.com/rust-lang/crates.io-index" 375 | checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" 376 | 377 | [[package]] 378 | name = "byteorder" 379 | version = "1.5.0" 380 | source = "registry+https://github.com/rust-lang/crates.io-index" 381 | checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" 382 | 383 | [[package]] 384 | name = "bytes" 385 | version = "1.9.0" 386 | source = "registry+https://github.com/rust-lang/crates.io-index" 387 | checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b" 388 | 389 | [[package]] 390 | name = "bytestring" 391 | version = "1.4.0" 392 | source = "registry+https://github.com/rust-lang/crates.io-index" 393 | checksum = "e465647ae23b2823b0753f50decb2d5a86d2bb2cac04788fafd1f80e45378e5f" 394 | dependencies = [ 395 | "bytes", 396 | ] 397 | 398 | [[package]] 399 | name = "cc" 400 | version = "1.2.16" 401 | source = "registry+https://github.com/rust-lang/crates.io-index" 402 | checksum = "be714c154be609ec7f5dad223a33bf1482fff90472de28f7362806e6d4832b8c" 403 | dependencies = [ 404 | "jobserver", 405 | "libc", 406 | "shlex", 407 | ] 408 | 409 | [[package]] 410 | name = "cfg-if" 411 | version = "1.0.0" 412 | source = "registry+https://github.com/rust-lang/crates.io-index" 413 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 414 | 415 | [[package]] 416 | name = "const-random" 417 | version = "0.1.18" 418 | source = "registry+https://github.com/rust-lang/crates.io-index" 419 | checksum = "87e00182fe74b066627d63b85fd550ac2998d4b0bd86bfed477a0ae4c7c71359" 420 | dependencies = [ 421 | "const-random-macro", 422 | ] 423 | 424 | [[package]] 425 | name = "const-random-macro" 426 | version = "0.1.16" 427 | source = "registry+https://github.com/rust-lang/crates.io-index" 428 | checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e" 429 | dependencies = [ 430 | "getrandom 0.2.15", 431 | "once_cell", 432 | "tiny-keccak", 433 | ] 434 | 435 | [[package]] 436 | name = "cookie" 437 | version = "0.16.2" 438 | source = "registry+https://github.com/rust-lang/crates.io-index" 439 | checksum = "e859cd57d0710d9e06c381b550c06e76992472a8c6d527aecd2fc673dcc231fb" 440 | dependencies = [ 441 | "percent-encoding", 442 | "time", 443 | "version_check", 444 | ] 445 | 446 | [[package]] 447 | name = "core-foundation" 448 | version = "0.9.4" 449 | source = "registry+https://github.com/rust-lang/crates.io-index" 450 | checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" 451 | dependencies = [ 452 | "core-foundation-sys", 453 | "libc", 454 | ] 455 | 456 | [[package]] 457 | name = "core-foundation-sys" 458 | version = "0.8.7" 459 | source = "registry+https://github.com/rust-lang/crates.io-index" 460 | checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" 461 | 462 | [[package]] 463 | name = "cpufeatures" 464 | version = "0.2.16" 465 | source = "registry+https://github.com/rust-lang/crates.io-index" 466 | checksum = "16b80225097f2e5ae4e7179dd2266824648f3e2f49d9134d584b76389d31c4c3" 467 | dependencies = [ 468 | "libc", 469 | ] 470 | 471 | [[package]] 472 | name = "crc32fast" 473 | version = "1.4.2" 474 | source = "registry+https://github.com/rust-lang/crates.io-index" 475 | checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" 476 | dependencies = [ 477 | "cfg-if", 478 | ] 479 | 480 | [[package]] 481 | name = "crossbeam-channel" 482 | version = "0.5.15" 483 | source = "registry+https://github.com/rust-lang/crates.io-index" 484 | checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" 485 | dependencies = [ 486 | "crossbeam-utils", 487 | ] 488 | 489 | [[package]] 490 | name = "crossbeam-utils" 491 | version = "0.8.21" 492 | source = "registry+https://github.com/rust-lang/crates.io-index" 493 | checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" 494 | 495 | [[package]] 496 | name = "crunchy" 497 | version = "0.2.2" 498 | source = "registry+https://github.com/rust-lang/crates.io-index" 499 | checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" 500 | 501 | [[package]] 502 | name = "crypto-common" 503 | version = "0.1.6" 504 | source = "registry+https://github.com/rust-lang/crates.io-index" 505 | checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" 506 | dependencies = [ 507 | "generic-array", 508 | "typenum", 509 | ] 510 | 511 | [[package]] 512 | name = "deadpool" 513 | version = "0.10.0" 514 | source = "registry+https://github.com/rust-lang/crates.io-index" 515 | checksum = "fb84100978c1c7b37f09ed3ce3e5f843af02c2a2c431bae5b19230dad2c1b490" 516 | dependencies = [ 517 | "async-trait", 518 | "deadpool-runtime", 519 | "num_cpus", 520 | "tokio", 521 | ] 522 | 523 | [[package]] 524 | name = "deadpool-runtime" 525 | version = "0.1.4" 526 | source = "registry+https://github.com/rust-lang/crates.io-index" 527 | checksum = "092966b41edc516079bdf31ec78a2e0588d1d0c08f78b91d8307215928642b2b" 528 | 529 | [[package]] 530 | name = "decay" 531 | version = "0.0.0" 532 | dependencies = [ 533 | "actix-web", 534 | "dotenv", 535 | "futures", 536 | "openssl", 537 | "reqwest", 538 | "rust-s3", 539 | "serde", 540 | "tokio", 541 | "tracing", 542 | "tracing-appender", 543 | "tracing-bunyan-formatter", 544 | "tracing-log 0.2.0", 545 | "tracing-subscriber", 546 | "wiremock", 547 | ] 548 | 549 | [[package]] 550 | name = "deranged" 551 | version = "0.3.11" 552 | source = "registry+https://github.com/rust-lang/crates.io-index" 553 | checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" 554 | dependencies = [ 555 | "powerfmt", 556 | "serde", 557 | ] 558 | 559 | [[package]] 560 | name = "derive_more" 561 | version = "2.0.1" 562 | source = "registry+https://github.com/rust-lang/crates.io-index" 563 | checksum = "093242cf7570c207c83073cf82f79706fe7b8317e98620a47d5be7c3d8497678" 564 | dependencies = [ 565 | "derive_more-impl", 566 | ] 567 | 568 | [[package]] 569 | name = "derive_more-impl" 570 | version = "2.0.1" 571 | source = "registry+https://github.com/rust-lang/crates.io-index" 572 | checksum = "bda628edc44c4bb645fbe0f758797143e4e07926f7ebf4e9bdfbd3d2ce621df3" 573 | dependencies = [ 574 | "proc-macro2", 575 | "quote", 576 | "syn", 577 | "unicode-xid", 578 | ] 579 | 580 | [[package]] 581 | name = "digest" 582 | version = "0.10.7" 583 | source = "registry+https://github.com/rust-lang/crates.io-index" 584 | checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" 585 | dependencies = [ 586 | "block-buffer", 587 | "crypto-common", 588 | "subtle", 589 | ] 590 | 591 | [[package]] 592 | name = "displaydoc" 593 | version = "0.2.5" 594 | source = "registry+https://github.com/rust-lang/crates.io-index" 595 | checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" 596 | dependencies = [ 597 | "proc-macro2", 598 | "quote", 599 | "syn", 600 | ] 601 | 602 | [[package]] 603 | name = "dlv-list" 604 | version = "0.5.2" 605 | source = "registry+https://github.com/rust-lang/crates.io-index" 606 | checksum = "442039f5147480ba31067cb00ada1adae6892028e40e45fc5de7b7df6dcc1b5f" 607 | dependencies = [ 608 | "const-random", 609 | ] 610 | 611 | [[package]] 612 | name = "dotenv" 613 | version = "0.15.0" 614 | source = "registry+https://github.com/rust-lang/crates.io-index" 615 | checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f" 616 | 617 | [[package]] 618 | name = "encoding_rs" 619 | version = "0.8.35" 620 | source = "registry+https://github.com/rust-lang/crates.io-index" 621 | checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" 622 | dependencies = [ 623 | "cfg-if", 624 | ] 625 | 626 | [[package]] 627 | name = "equivalent" 628 | version = "1.0.1" 629 | source = "registry+https://github.com/rust-lang/crates.io-index" 630 | checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" 631 | 632 | [[package]] 633 | name = "errno" 634 | version = "0.3.10" 635 | source = "registry+https://github.com/rust-lang/crates.io-index" 636 | checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" 637 | dependencies = [ 638 | "libc", 639 | "windows-sys 0.59.0", 640 | ] 641 | 642 | [[package]] 643 | name = "fastrand" 644 | version = "2.3.0" 645 | source = "registry+https://github.com/rust-lang/crates.io-index" 646 | checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" 647 | 648 | [[package]] 649 | name = "flate2" 650 | version = "1.0.35" 651 | source = "registry+https://github.com/rust-lang/crates.io-index" 652 | checksum = "c936bfdafb507ebbf50b8074c54fa31c5be9a1e7e5f467dd659697041407d07c" 653 | dependencies = [ 654 | "crc32fast", 655 | "miniz_oxide", 656 | ] 657 | 658 | [[package]] 659 | name = "fnv" 660 | version = "1.0.7" 661 | source = "registry+https://github.com/rust-lang/crates.io-index" 662 | checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" 663 | 664 | [[package]] 665 | name = "foldhash" 666 | version = "0.1.4" 667 | source = "registry+https://github.com/rust-lang/crates.io-index" 668 | checksum = "a0d2fde1f7b3d48b8395d5f2de76c18a528bd6a9cdde438df747bfcba3e05d6f" 669 | 670 | [[package]] 671 | name = "foreign-types" 672 | version = "0.3.2" 673 | source = "registry+https://github.com/rust-lang/crates.io-index" 674 | checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" 675 | dependencies = [ 676 | "foreign-types-shared", 677 | ] 678 | 679 | [[package]] 680 | name = "foreign-types-shared" 681 | version = "0.1.1" 682 | source = "registry+https://github.com/rust-lang/crates.io-index" 683 | checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" 684 | 685 | [[package]] 686 | name = "form_urlencoded" 687 | version = "1.2.1" 688 | source = "registry+https://github.com/rust-lang/crates.io-index" 689 | checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" 690 | dependencies = [ 691 | "percent-encoding", 692 | ] 693 | 694 | [[package]] 695 | name = "futures" 696 | version = "0.3.31" 697 | source = "registry+https://github.com/rust-lang/crates.io-index" 698 | checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" 699 | dependencies = [ 700 | "futures-channel", 701 | "futures-core", 702 | "futures-executor", 703 | "futures-io", 704 | "futures-sink", 705 | "futures-task", 706 | "futures-util", 707 | ] 708 | 709 | [[package]] 710 | name = "futures-channel" 711 | version = "0.3.31" 712 | source = "registry+https://github.com/rust-lang/crates.io-index" 713 | checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" 714 | dependencies = [ 715 | "futures-core", 716 | "futures-sink", 717 | ] 718 | 719 | [[package]] 720 | name = "futures-core" 721 | version = "0.3.31" 722 | source = "registry+https://github.com/rust-lang/crates.io-index" 723 | checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" 724 | 725 | [[package]] 726 | name = "futures-executor" 727 | version = "0.3.31" 728 | source = "registry+https://github.com/rust-lang/crates.io-index" 729 | checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" 730 | dependencies = [ 731 | "futures-core", 732 | "futures-task", 733 | "futures-util", 734 | ] 735 | 736 | [[package]] 737 | name = "futures-io" 738 | version = "0.3.31" 739 | source = "registry+https://github.com/rust-lang/crates.io-index" 740 | checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" 741 | 742 | [[package]] 743 | name = "futures-macro" 744 | version = "0.3.31" 745 | source = "registry+https://github.com/rust-lang/crates.io-index" 746 | checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" 747 | dependencies = [ 748 | "proc-macro2", 749 | "quote", 750 | "syn", 751 | ] 752 | 753 | [[package]] 754 | name = "futures-sink" 755 | version = "0.3.31" 756 | source = "registry+https://github.com/rust-lang/crates.io-index" 757 | checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" 758 | 759 | [[package]] 760 | name = "futures-task" 761 | version = "0.3.31" 762 | source = "registry+https://github.com/rust-lang/crates.io-index" 763 | checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" 764 | 765 | [[package]] 766 | name = "futures-util" 767 | version = "0.3.31" 768 | source = "registry+https://github.com/rust-lang/crates.io-index" 769 | checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" 770 | dependencies = [ 771 | "futures-channel", 772 | "futures-core", 773 | "futures-io", 774 | "futures-macro", 775 | "futures-sink", 776 | "futures-task", 777 | "memchr", 778 | "pin-project-lite", 779 | "pin-utils", 780 | "slab", 781 | ] 782 | 783 | [[package]] 784 | name = "generic-array" 785 | version = "0.14.7" 786 | source = "registry+https://github.com/rust-lang/crates.io-index" 787 | checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" 788 | dependencies = [ 789 | "typenum", 790 | "version_check", 791 | ] 792 | 793 | [[package]] 794 | name = "gethostname" 795 | version = "0.2.3" 796 | source = "registry+https://github.com/rust-lang/crates.io-index" 797 | checksum = "c1ebd34e35c46e00bb73e81363248d627782724609fe1b6396f553f68fe3862e" 798 | dependencies = [ 799 | "libc", 800 | "winapi", 801 | ] 802 | 803 | [[package]] 804 | name = "getrandom" 805 | version = "0.2.15" 806 | source = "registry+https://github.com/rust-lang/crates.io-index" 807 | checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" 808 | dependencies = [ 809 | "cfg-if", 810 | "libc", 811 | "wasi 0.11.0+wasi-snapshot-preview1", 812 | ] 813 | 814 | [[package]] 815 | name = "getrandom" 816 | version = "0.3.1" 817 | source = "registry+https://github.com/rust-lang/crates.io-index" 818 | checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8" 819 | dependencies = [ 820 | "cfg-if", 821 | "libc", 822 | "wasi 0.13.3+wasi-0.2.2", 823 | "windows-targets 0.52.6", 824 | ] 825 | 826 | [[package]] 827 | name = "gimli" 828 | version = "0.31.1" 829 | source = "registry+https://github.com/rust-lang/crates.io-index" 830 | checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" 831 | 832 | [[package]] 833 | name = "h2" 834 | version = "0.3.26" 835 | source = "registry+https://github.com/rust-lang/crates.io-index" 836 | checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" 837 | dependencies = [ 838 | "bytes", 839 | "fnv", 840 | "futures-core", 841 | "futures-sink", 842 | "futures-util", 843 | "http 0.2.12", 844 | "indexmap", 845 | "slab", 846 | "tokio", 847 | "tokio-util", 848 | "tracing", 849 | ] 850 | 851 | [[package]] 852 | name = "h2" 853 | version = "0.4.7" 854 | source = "registry+https://github.com/rust-lang/crates.io-index" 855 | checksum = "ccae279728d634d083c00f6099cb58f01cc99c145b84b8be2f6c74618d79922e" 856 | dependencies = [ 857 | "atomic-waker", 858 | "bytes", 859 | "fnv", 860 | "futures-core", 861 | "futures-sink", 862 | "http 1.2.0", 863 | "indexmap", 864 | "slab", 865 | "tokio", 866 | "tokio-util", 867 | "tracing", 868 | ] 869 | 870 | [[package]] 871 | name = "hashbrown" 872 | version = "0.14.5" 873 | source = "registry+https://github.com/rust-lang/crates.io-index" 874 | checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" 875 | 876 | [[package]] 877 | name = "hashbrown" 878 | version = "0.15.2" 879 | source = "registry+https://github.com/rust-lang/crates.io-index" 880 | checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" 881 | 882 | [[package]] 883 | name = "hermit-abi" 884 | version = "0.3.9" 885 | source = "registry+https://github.com/rust-lang/crates.io-index" 886 | checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" 887 | 888 | [[package]] 889 | name = "hex" 890 | version = "0.4.3" 891 | source = "registry+https://github.com/rust-lang/crates.io-index" 892 | checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" 893 | 894 | [[package]] 895 | name = "hmac" 896 | version = "0.12.1" 897 | source = "registry+https://github.com/rust-lang/crates.io-index" 898 | checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" 899 | dependencies = [ 900 | "digest", 901 | ] 902 | 903 | [[package]] 904 | name = "home" 905 | version = "0.5.11" 906 | source = "registry+https://github.com/rust-lang/crates.io-index" 907 | checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf" 908 | dependencies = [ 909 | "windows-sys 0.59.0", 910 | ] 911 | 912 | [[package]] 913 | name = "http" 914 | version = "0.2.12" 915 | source = "registry+https://github.com/rust-lang/crates.io-index" 916 | checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" 917 | dependencies = [ 918 | "bytes", 919 | "fnv", 920 | "itoa", 921 | ] 922 | 923 | [[package]] 924 | name = "http" 925 | version = "1.2.0" 926 | source = "registry+https://github.com/rust-lang/crates.io-index" 927 | checksum = "f16ca2af56261c99fba8bac40a10251ce8188205a4c448fbb745a2e4daa76fea" 928 | dependencies = [ 929 | "bytes", 930 | "fnv", 931 | "itoa", 932 | ] 933 | 934 | [[package]] 935 | name = "http-body" 936 | version = "0.4.6" 937 | source = "registry+https://github.com/rust-lang/crates.io-index" 938 | checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" 939 | dependencies = [ 940 | "bytes", 941 | "http 0.2.12", 942 | "pin-project-lite", 943 | ] 944 | 945 | [[package]] 946 | name = "http-body" 947 | version = "1.0.1" 948 | source = "registry+https://github.com/rust-lang/crates.io-index" 949 | checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" 950 | dependencies = [ 951 | "bytes", 952 | "http 1.2.0", 953 | ] 954 | 955 | [[package]] 956 | name = "http-body-util" 957 | version = "0.1.2" 958 | source = "registry+https://github.com/rust-lang/crates.io-index" 959 | checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" 960 | dependencies = [ 961 | "bytes", 962 | "futures-util", 963 | "http 1.2.0", 964 | "http-body 1.0.1", 965 | "pin-project-lite", 966 | ] 967 | 968 | [[package]] 969 | name = "httparse" 970 | version = "1.9.5" 971 | source = "registry+https://github.com/rust-lang/crates.io-index" 972 | checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946" 973 | 974 | [[package]] 975 | name = "httpdate" 976 | version = "1.0.3" 977 | source = "registry+https://github.com/rust-lang/crates.io-index" 978 | checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" 979 | 980 | [[package]] 981 | name = "hyper" 982 | version = "0.14.32" 983 | source = "registry+https://github.com/rust-lang/crates.io-index" 984 | checksum = "41dfc780fdec9373c01bae43289ea34c972e40ee3c9f6b3c8801a35f35586ce7" 985 | dependencies = [ 986 | "bytes", 987 | "futures-channel", 988 | "futures-core", 989 | "futures-util", 990 | "http 0.2.12", 991 | "http-body 0.4.6", 992 | "httparse", 993 | "httpdate", 994 | "itoa", 995 | "pin-project-lite", 996 | "socket2", 997 | "tokio", 998 | "tower-service", 999 | "tracing", 1000 | "want", 1001 | ] 1002 | 1003 | [[package]] 1004 | name = "hyper" 1005 | version = "1.6.0" 1006 | source = "registry+https://github.com/rust-lang/crates.io-index" 1007 | checksum = "cc2b571658e38e0c01b1fdca3bbbe93c00d3d71693ff2770043f8c29bc7d6f80" 1008 | dependencies = [ 1009 | "bytes", 1010 | "futures-channel", 1011 | "futures-util", 1012 | "h2 0.4.7", 1013 | "http 1.2.0", 1014 | "http-body 1.0.1", 1015 | "httparse", 1016 | "httpdate", 1017 | "itoa", 1018 | "pin-project-lite", 1019 | "smallvec", 1020 | "tokio", 1021 | "want", 1022 | ] 1023 | 1024 | [[package]] 1025 | name = "hyper-rustls" 1026 | version = "0.27.4" 1027 | source = "registry+https://github.com/rust-lang/crates.io-index" 1028 | checksum = "f6884a48c6826ec44f524c7456b163cebe9e55a18d7b5e307cb4f100371cc767" 1029 | dependencies = [ 1030 | "futures-util", 1031 | "http 1.2.0", 1032 | "hyper 1.6.0", 1033 | "hyper-util", 1034 | "rustls", 1035 | "rustls-pki-types", 1036 | "tokio", 1037 | "tokio-rustls", 1038 | "tower-service", 1039 | ] 1040 | 1041 | [[package]] 1042 | name = "hyper-tls" 1043 | version = "0.5.0" 1044 | source = "registry+https://github.com/rust-lang/crates.io-index" 1045 | checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" 1046 | dependencies = [ 1047 | "bytes", 1048 | "hyper 0.14.32", 1049 | "native-tls", 1050 | "tokio", 1051 | "tokio-native-tls", 1052 | ] 1053 | 1054 | [[package]] 1055 | name = "hyper-tls" 1056 | version = "0.6.0" 1057 | source = "registry+https://github.com/rust-lang/crates.io-index" 1058 | checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" 1059 | dependencies = [ 1060 | "bytes", 1061 | "http-body-util", 1062 | "hyper 1.6.0", 1063 | "hyper-util", 1064 | "native-tls", 1065 | "tokio", 1066 | "tokio-native-tls", 1067 | "tower-service", 1068 | ] 1069 | 1070 | [[package]] 1071 | name = "hyper-util" 1072 | version = "0.1.13" 1073 | source = "registry+https://github.com/rust-lang/crates.io-index" 1074 | checksum = "b1c293b6b3d21eca78250dc7dbebd6b9210ec5530e038cbfe0661b5c47ab06e8" 1075 | dependencies = [ 1076 | "base64", 1077 | "bytes", 1078 | "futures-channel", 1079 | "futures-core", 1080 | "futures-util", 1081 | "http 1.2.0", 1082 | "http-body 1.0.1", 1083 | "hyper 1.6.0", 1084 | "ipnet", 1085 | "libc", 1086 | "percent-encoding", 1087 | "pin-project-lite", 1088 | "socket2", 1089 | "system-configuration", 1090 | "tokio", 1091 | "tower-service", 1092 | "tracing", 1093 | "windows-registry", 1094 | ] 1095 | 1096 | [[package]] 1097 | name = "icu_collections" 1098 | version = "1.5.0" 1099 | source = "registry+https://github.com/rust-lang/crates.io-index" 1100 | checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" 1101 | dependencies = [ 1102 | "displaydoc", 1103 | "yoke", 1104 | "zerofrom", 1105 | "zerovec", 1106 | ] 1107 | 1108 | [[package]] 1109 | name = "icu_locid" 1110 | version = "1.5.0" 1111 | source = "registry+https://github.com/rust-lang/crates.io-index" 1112 | checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" 1113 | dependencies = [ 1114 | "displaydoc", 1115 | "litemap", 1116 | "tinystr", 1117 | "writeable", 1118 | "zerovec", 1119 | ] 1120 | 1121 | [[package]] 1122 | name = "icu_locid_transform" 1123 | version = "1.5.0" 1124 | source = "registry+https://github.com/rust-lang/crates.io-index" 1125 | checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" 1126 | dependencies = [ 1127 | "displaydoc", 1128 | "icu_locid", 1129 | "icu_locid_transform_data", 1130 | "icu_provider", 1131 | "tinystr", 1132 | "zerovec", 1133 | ] 1134 | 1135 | [[package]] 1136 | name = "icu_locid_transform_data" 1137 | version = "1.5.0" 1138 | source = "registry+https://github.com/rust-lang/crates.io-index" 1139 | checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" 1140 | 1141 | [[package]] 1142 | name = "icu_normalizer" 1143 | version = "1.5.0" 1144 | source = "registry+https://github.com/rust-lang/crates.io-index" 1145 | checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" 1146 | dependencies = [ 1147 | "displaydoc", 1148 | "icu_collections", 1149 | "icu_normalizer_data", 1150 | "icu_properties", 1151 | "icu_provider", 1152 | "smallvec", 1153 | "utf16_iter", 1154 | "utf8_iter", 1155 | "write16", 1156 | "zerovec", 1157 | ] 1158 | 1159 | [[package]] 1160 | name = "icu_normalizer_data" 1161 | version = "1.5.0" 1162 | source = "registry+https://github.com/rust-lang/crates.io-index" 1163 | checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" 1164 | 1165 | [[package]] 1166 | name = "icu_properties" 1167 | version = "1.5.1" 1168 | source = "registry+https://github.com/rust-lang/crates.io-index" 1169 | checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" 1170 | dependencies = [ 1171 | "displaydoc", 1172 | "icu_collections", 1173 | "icu_locid_transform", 1174 | "icu_properties_data", 1175 | "icu_provider", 1176 | "tinystr", 1177 | "zerovec", 1178 | ] 1179 | 1180 | [[package]] 1181 | name = "icu_properties_data" 1182 | version = "1.5.0" 1183 | source = "registry+https://github.com/rust-lang/crates.io-index" 1184 | checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" 1185 | 1186 | [[package]] 1187 | name = "icu_provider" 1188 | version = "1.5.0" 1189 | source = "registry+https://github.com/rust-lang/crates.io-index" 1190 | checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" 1191 | dependencies = [ 1192 | "displaydoc", 1193 | "icu_locid", 1194 | "icu_provider_macros", 1195 | "stable_deref_trait", 1196 | "tinystr", 1197 | "writeable", 1198 | "yoke", 1199 | "zerofrom", 1200 | "zerovec", 1201 | ] 1202 | 1203 | [[package]] 1204 | name = "icu_provider_macros" 1205 | version = "1.5.0" 1206 | source = "registry+https://github.com/rust-lang/crates.io-index" 1207 | checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" 1208 | dependencies = [ 1209 | "proc-macro2", 1210 | "quote", 1211 | "syn", 1212 | ] 1213 | 1214 | [[package]] 1215 | name = "idna" 1216 | version = "1.0.3" 1217 | source = "registry+https://github.com/rust-lang/crates.io-index" 1218 | checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" 1219 | dependencies = [ 1220 | "idna_adapter", 1221 | "smallvec", 1222 | "utf8_iter", 1223 | ] 1224 | 1225 | [[package]] 1226 | name = "idna_adapter" 1227 | version = "1.2.0" 1228 | source = "registry+https://github.com/rust-lang/crates.io-index" 1229 | checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" 1230 | dependencies = [ 1231 | "icu_normalizer", 1232 | "icu_properties", 1233 | ] 1234 | 1235 | [[package]] 1236 | name = "impl-more" 1237 | version = "0.1.8" 1238 | source = "registry+https://github.com/rust-lang/crates.io-index" 1239 | checksum = "aae21c3177a27788957044151cc2800043d127acaa460a47ebb9b84dfa2c6aa0" 1240 | 1241 | [[package]] 1242 | name = "indexmap" 1243 | version = "2.7.0" 1244 | source = "registry+https://github.com/rust-lang/crates.io-index" 1245 | checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f" 1246 | dependencies = [ 1247 | "equivalent", 1248 | "hashbrown 0.15.2", 1249 | ] 1250 | 1251 | [[package]] 1252 | name = "ipnet" 1253 | version = "2.10.1" 1254 | source = "registry+https://github.com/rust-lang/crates.io-index" 1255 | checksum = "ddc24109865250148c2e0f3d25d4f0f479571723792d3802153c60922a4fb708" 1256 | 1257 | [[package]] 1258 | name = "iri-string" 1259 | version = "0.7.8" 1260 | source = "registry+https://github.com/rust-lang/crates.io-index" 1261 | checksum = "dbc5ebe9c3a1a7a5127f920a418f7585e9e758e911d0466ed004f393b0e380b2" 1262 | dependencies = [ 1263 | "memchr", 1264 | "serde", 1265 | ] 1266 | 1267 | [[package]] 1268 | name = "itoa" 1269 | version = "1.0.14" 1270 | source = "registry+https://github.com/rust-lang/crates.io-index" 1271 | checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" 1272 | 1273 | [[package]] 1274 | name = "jobserver" 1275 | version = "0.1.32" 1276 | source = "registry+https://github.com/rust-lang/crates.io-index" 1277 | checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" 1278 | dependencies = [ 1279 | "libc", 1280 | ] 1281 | 1282 | [[package]] 1283 | name = "js-sys" 1284 | version = "0.3.77" 1285 | source = "registry+https://github.com/rust-lang/crates.io-index" 1286 | checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" 1287 | dependencies = [ 1288 | "once_cell", 1289 | "wasm-bindgen", 1290 | ] 1291 | 1292 | [[package]] 1293 | name = "language-tags" 1294 | version = "0.3.2" 1295 | source = "registry+https://github.com/rust-lang/crates.io-index" 1296 | checksum = "d4345964bb142484797b161f473a503a434de77149dd8c7427788c6e13379388" 1297 | 1298 | [[package]] 1299 | name = "lazy_static" 1300 | version = "1.5.0" 1301 | source = "registry+https://github.com/rust-lang/crates.io-index" 1302 | checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" 1303 | 1304 | [[package]] 1305 | name = "libc" 1306 | version = "0.2.172" 1307 | source = "registry+https://github.com/rust-lang/crates.io-index" 1308 | checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" 1309 | 1310 | [[package]] 1311 | name = "linux-raw-sys" 1312 | version = "0.4.14" 1313 | source = "registry+https://github.com/rust-lang/crates.io-index" 1314 | checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" 1315 | 1316 | [[package]] 1317 | name = "litemap" 1318 | version = "0.7.4" 1319 | source = "registry+https://github.com/rust-lang/crates.io-index" 1320 | checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104" 1321 | 1322 | [[package]] 1323 | name = "local-channel" 1324 | version = "0.1.5" 1325 | source = "registry+https://github.com/rust-lang/crates.io-index" 1326 | checksum = "b6cbc85e69b8df4b8bb8b89ec634e7189099cea8927a276b7384ce5488e53ec8" 1327 | dependencies = [ 1328 | "futures-core", 1329 | "futures-sink", 1330 | "local-waker", 1331 | ] 1332 | 1333 | [[package]] 1334 | name = "local-waker" 1335 | version = "0.1.4" 1336 | source = "registry+https://github.com/rust-lang/crates.io-index" 1337 | checksum = "4d873d7c67ce09b42110d801813efbc9364414e356be9935700d368351657487" 1338 | 1339 | [[package]] 1340 | name = "lock_api" 1341 | version = "0.4.12" 1342 | source = "registry+https://github.com/rust-lang/crates.io-index" 1343 | checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" 1344 | dependencies = [ 1345 | "autocfg", 1346 | "scopeguard", 1347 | ] 1348 | 1349 | [[package]] 1350 | name = "log" 1351 | version = "0.4.22" 1352 | source = "registry+https://github.com/rust-lang/crates.io-index" 1353 | checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" 1354 | 1355 | [[package]] 1356 | name = "matchers" 1357 | version = "0.1.0" 1358 | source = "registry+https://github.com/rust-lang/crates.io-index" 1359 | checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" 1360 | dependencies = [ 1361 | "regex-automata 0.1.10", 1362 | ] 1363 | 1364 | [[package]] 1365 | name = "maybe-async" 1366 | version = "0.2.10" 1367 | source = "registry+https://github.com/rust-lang/crates.io-index" 1368 | checksum = "5cf92c10c7e361d6b99666ec1c6f9805b0bea2c3bd8c78dc6fe98ac5bd78db11" 1369 | dependencies = [ 1370 | "proc-macro2", 1371 | "quote", 1372 | "syn", 1373 | ] 1374 | 1375 | [[package]] 1376 | name = "md5" 1377 | version = "0.7.0" 1378 | source = "registry+https://github.com/rust-lang/crates.io-index" 1379 | checksum = "490cc448043f947bae3cbee9c203358d62dbee0db12107a74be5c30ccfd09771" 1380 | 1381 | [[package]] 1382 | name = "memchr" 1383 | version = "2.7.4" 1384 | source = "registry+https://github.com/rust-lang/crates.io-index" 1385 | checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" 1386 | 1387 | [[package]] 1388 | name = "mime" 1389 | version = "0.3.17" 1390 | source = "registry+https://github.com/rust-lang/crates.io-index" 1391 | checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" 1392 | 1393 | [[package]] 1394 | name = "minidom" 1395 | version = "0.15.2" 1396 | source = "registry+https://github.com/rust-lang/crates.io-index" 1397 | checksum = "f45614075738ce1b77a1768912a60c0227525971b03e09122a05b8a34a2a6278" 1398 | dependencies = [ 1399 | "rxml", 1400 | ] 1401 | 1402 | [[package]] 1403 | name = "miniz_oxide" 1404 | version = "0.8.2" 1405 | source = "registry+https://github.com/rust-lang/crates.io-index" 1406 | checksum = "4ffbe83022cedc1d264172192511ae958937694cd57ce297164951b8b3568394" 1407 | dependencies = [ 1408 | "adler2", 1409 | ] 1410 | 1411 | [[package]] 1412 | name = "mio" 1413 | version = "1.0.3" 1414 | source = "registry+https://github.com/rust-lang/crates.io-index" 1415 | checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" 1416 | dependencies = [ 1417 | "libc", 1418 | "log", 1419 | "wasi 0.11.0+wasi-snapshot-preview1", 1420 | "windows-sys 0.52.0", 1421 | ] 1422 | 1423 | [[package]] 1424 | name = "native-tls" 1425 | version = "0.2.12" 1426 | source = "registry+https://github.com/rust-lang/crates.io-index" 1427 | checksum = "a8614eb2c83d59d1c8cc974dd3f920198647674a0a035e1af1fa58707e317466" 1428 | dependencies = [ 1429 | "libc", 1430 | "log", 1431 | "openssl", 1432 | "openssl-probe", 1433 | "openssl-sys", 1434 | "schannel", 1435 | "security-framework", 1436 | "security-framework-sys", 1437 | "tempfile", 1438 | ] 1439 | 1440 | [[package]] 1441 | name = "nu-ansi-term" 1442 | version = "0.46.0" 1443 | source = "registry+https://github.com/rust-lang/crates.io-index" 1444 | checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" 1445 | dependencies = [ 1446 | "overload", 1447 | "winapi", 1448 | ] 1449 | 1450 | [[package]] 1451 | name = "num-conv" 1452 | version = "0.1.0" 1453 | source = "registry+https://github.com/rust-lang/crates.io-index" 1454 | checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" 1455 | 1456 | [[package]] 1457 | name = "num_cpus" 1458 | version = "1.16.0" 1459 | source = "registry+https://github.com/rust-lang/crates.io-index" 1460 | checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" 1461 | dependencies = [ 1462 | "hermit-abi", 1463 | "libc", 1464 | ] 1465 | 1466 | [[package]] 1467 | name = "object" 1468 | version = "0.36.5" 1469 | source = "registry+https://github.com/rust-lang/crates.io-index" 1470 | checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e" 1471 | dependencies = [ 1472 | "memchr", 1473 | ] 1474 | 1475 | [[package]] 1476 | name = "once_cell" 1477 | version = "1.21.3" 1478 | source = "registry+https://github.com/rust-lang/crates.io-index" 1479 | checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" 1480 | 1481 | [[package]] 1482 | name = "openssl" 1483 | version = "0.10.73" 1484 | source = "registry+https://github.com/rust-lang/crates.io-index" 1485 | checksum = "8505734d46c8ab1e19a1dce3aef597ad87dcb4c37e7188231769bd6bd51cebf8" 1486 | dependencies = [ 1487 | "bitflags", 1488 | "cfg-if", 1489 | "foreign-types", 1490 | "libc", 1491 | "once_cell", 1492 | "openssl-macros", 1493 | "openssl-sys", 1494 | ] 1495 | 1496 | [[package]] 1497 | name = "openssl-macros" 1498 | version = "0.1.1" 1499 | source = "registry+https://github.com/rust-lang/crates.io-index" 1500 | checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" 1501 | dependencies = [ 1502 | "proc-macro2", 1503 | "quote", 1504 | "syn", 1505 | ] 1506 | 1507 | [[package]] 1508 | name = "openssl-probe" 1509 | version = "0.1.5" 1510 | source = "registry+https://github.com/rust-lang/crates.io-index" 1511 | checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" 1512 | 1513 | [[package]] 1514 | name = "openssl-src" 1515 | version = "300.4.1+3.4.0" 1516 | source = "registry+https://github.com/rust-lang/crates.io-index" 1517 | checksum = "faa4eac4138c62414b5622d1b31c5c304f34b406b013c079c2bbc652fdd6678c" 1518 | dependencies = [ 1519 | "cc", 1520 | ] 1521 | 1522 | [[package]] 1523 | name = "openssl-sys" 1524 | version = "0.9.109" 1525 | source = "registry+https://github.com/rust-lang/crates.io-index" 1526 | checksum = "90096e2e47630d78b7d1c20952dc621f957103f8bc2c8359ec81290d75238571" 1527 | dependencies = [ 1528 | "cc", 1529 | "libc", 1530 | "openssl-src", 1531 | "pkg-config", 1532 | "vcpkg", 1533 | ] 1534 | 1535 | [[package]] 1536 | name = "ordered-multimap" 1537 | version = "0.7.3" 1538 | source = "registry+https://github.com/rust-lang/crates.io-index" 1539 | checksum = "49203cdcae0030493bad186b28da2fa25645fa276a51b6fec8010d281e02ef79" 1540 | dependencies = [ 1541 | "dlv-list", 1542 | "hashbrown 0.14.5", 1543 | ] 1544 | 1545 | [[package]] 1546 | name = "overload" 1547 | version = "0.1.1" 1548 | source = "registry+https://github.com/rust-lang/crates.io-index" 1549 | checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" 1550 | 1551 | [[package]] 1552 | name = "parking_lot" 1553 | version = "0.12.3" 1554 | source = "registry+https://github.com/rust-lang/crates.io-index" 1555 | checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" 1556 | dependencies = [ 1557 | "lock_api", 1558 | "parking_lot_core", 1559 | ] 1560 | 1561 | [[package]] 1562 | name = "parking_lot_core" 1563 | version = "0.9.10" 1564 | source = "registry+https://github.com/rust-lang/crates.io-index" 1565 | checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" 1566 | dependencies = [ 1567 | "cfg-if", 1568 | "libc", 1569 | "redox_syscall", 1570 | "smallvec", 1571 | "windows-targets 0.52.6", 1572 | ] 1573 | 1574 | [[package]] 1575 | name = "paste" 1576 | version = "1.0.15" 1577 | source = "registry+https://github.com/rust-lang/crates.io-index" 1578 | checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" 1579 | 1580 | [[package]] 1581 | name = "percent-encoding" 1582 | version = "2.3.1" 1583 | source = "registry+https://github.com/rust-lang/crates.io-index" 1584 | checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" 1585 | 1586 | [[package]] 1587 | name = "pin-project-lite" 1588 | version = "0.2.15" 1589 | source = "registry+https://github.com/rust-lang/crates.io-index" 1590 | checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" 1591 | 1592 | [[package]] 1593 | name = "pin-utils" 1594 | version = "0.1.0" 1595 | source = "registry+https://github.com/rust-lang/crates.io-index" 1596 | checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" 1597 | 1598 | [[package]] 1599 | name = "pkg-config" 1600 | version = "0.3.31" 1601 | source = "registry+https://github.com/rust-lang/crates.io-index" 1602 | checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" 1603 | 1604 | [[package]] 1605 | name = "powerfmt" 1606 | version = "0.2.0" 1607 | source = "registry+https://github.com/rust-lang/crates.io-index" 1608 | checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" 1609 | 1610 | [[package]] 1611 | name = "ppv-lite86" 1612 | version = "0.2.20" 1613 | source = "registry+https://github.com/rust-lang/crates.io-index" 1614 | checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" 1615 | dependencies = [ 1616 | "zerocopy 0.7.35", 1617 | ] 1618 | 1619 | [[package]] 1620 | name = "proc-macro2" 1621 | version = "1.0.92" 1622 | source = "registry+https://github.com/rust-lang/crates.io-index" 1623 | checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" 1624 | dependencies = [ 1625 | "unicode-ident", 1626 | ] 1627 | 1628 | [[package]] 1629 | name = "quick-xml" 1630 | version = "0.32.0" 1631 | source = "registry+https://github.com/rust-lang/crates.io-index" 1632 | checksum = "1d3a6e5838b60e0e8fa7a43f22ade549a37d61f8bdbe636d0d7816191de969c2" 1633 | dependencies = [ 1634 | "memchr", 1635 | "serde", 1636 | ] 1637 | 1638 | [[package]] 1639 | name = "quote" 1640 | version = "1.0.37" 1641 | source = "registry+https://github.com/rust-lang/crates.io-index" 1642 | checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" 1643 | dependencies = [ 1644 | "proc-macro2", 1645 | ] 1646 | 1647 | [[package]] 1648 | name = "rand" 1649 | version = "0.9.0" 1650 | source = "registry+https://github.com/rust-lang/crates.io-index" 1651 | checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94" 1652 | dependencies = [ 1653 | "rand_chacha", 1654 | "rand_core", 1655 | "zerocopy 0.8.23", 1656 | ] 1657 | 1658 | [[package]] 1659 | name = "rand_chacha" 1660 | version = "0.9.0" 1661 | source = "registry+https://github.com/rust-lang/crates.io-index" 1662 | checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" 1663 | dependencies = [ 1664 | "ppv-lite86", 1665 | "rand_core", 1666 | ] 1667 | 1668 | [[package]] 1669 | name = "rand_core" 1670 | version = "0.9.3" 1671 | source = "registry+https://github.com/rust-lang/crates.io-index" 1672 | checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" 1673 | dependencies = [ 1674 | "getrandom 0.3.1", 1675 | ] 1676 | 1677 | [[package]] 1678 | name = "redox_syscall" 1679 | version = "0.5.8" 1680 | source = "registry+https://github.com/rust-lang/crates.io-index" 1681 | checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834" 1682 | dependencies = [ 1683 | "bitflags", 1684 | ] 1685 | 1686 | [[package]] 1687 | name = "regex" 1688 | version = "1.11.1" 1689 | source = "registry+https://github.com/rust-lang/crates.io-index" 1690 | checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" 1691 | dependencies = [ 1692 | "aho-corasick", 1693 | "memchr", 1694 | "regex-automata 0.4.9", 1695 | "regex-syntax 0.8.5", 1696 | ] 1697 | 1698 | [[package]] 1699 | name = "regex-automata" 1700 | version = "0.1.10" 1701 | source = "registry+https://github.com/rust-lang/crates.io-index" 1702 | checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" 1703 | dependencies = [ 1704 | "regex-syntax 0.6.29", 1705 | ] 1706 | 1707 | [[package]] 1708 | name = "regex-automata" 1709 | version = "0.4.9" 1710 | source = "registry+https://github.com/rust-lang/crates.io-index" 1711 | checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" 1712 | dependencies = [ 1713 | "aho-corasick", 1714 | "memchr", 1715 | "regex-syntax 0.8.5", 1716 | ] 1717 | 1718 | [[package]] 1719 | name = "regex-lite" 1720 | version = "0.1.6" 1721 | source = "registry+https://github.com/rust-lang/crates.io-index" 1722 | checksum = "53a49587ad06b26609c52e423de037e7f57f20d53535d66e08c695f347df952a" 1723 | 1724 | [[package]] 1725 | name = "regex-syntax" 1726 | version = "0.6.29" 1727 | source = "registry+https://github.com/rust-lang/crates.io-index" 1728 | checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" 1729 | 1730 | [[package]] 1731 | name = "regex-syntax" 1732 | version = "0.8.5" 1733 | source = "registry+https://github.com/rust-lang/crates.io-index" 1734 | checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" 1735 | 1736 | [[package]] 1737 | name = "reqwest" 1738 | version = "0.12.18" 1739 | source = "registry+https://github.com/rust-lang/crates.io-index" 1740 | checksum = "e98ff6b0dbbe4d5a37318f433d4fc82babd21631f194d370409ceb2e40b2f0b5" 1741 | dependencies = [ 1742 | "base64", 1743 | "bytes", 1744 | "encoding_rs", 1745 | "futures-core", 1746 | "h2 0.4.7", 1747 | "http 1.2.0", 1748 | "http-body 1.0.1", 1749 | "http-body-util", 1750 | "hyper 1.6.0", 1751 | "hyper-rustls", 1752 | "hyper-tls 0.6.0", 1753 | "hyper-util", 1754 | "ipnet", 1755 | "js-sys", 1756 | "log", 1757 | "mime", 1758 | "native-tls", 1759 | "once_cell", 1760 | "percent-encoding", 1761 | "pin-project-lite", 1762 | "rustls-pki-types", 1763 | "serde", 1764 | "serde_json", 1765 | "serde_urlencoded", 1766 | "sync_wrapper", 1767 | "tokio", 1768 | "tokio-native-tls", 1769 | "tower", 1770 | "tower-http", 1771 | "tower-service", 1772 | "url", 1773 | "wasm-bindgen", 1774 | "wasm-bindgen-futures", 1775 | "web-sys", 1776 | ] 1777 | 1778 | [[package]] 1779 | name = "ring" 1780 | version = "0.17.13" 1781 | source = "registry+https://github.com/rust-lang/crates.io-index" 1782 | checksum = "70ac5d832aa16abd7d1def883a8545280c20a60f523a370aa3a9617c2b8550ee" 1783 | dependencies = [ 1784 | "cc", 1785 | "cfg-if", 1786 | "getrandom 0.2.15", 1787 | "libc", 1788 | "untrusted", 1789 | "windows-sys 0.52.0", 1790 | ] 1791 | 1792 | [[package]] 1793 | name = "rust-ini" 1794 | version = "0.21.1" 1795 | source = "registry+https://github.com/rust-lang/crates.io-index" 1796 | checksum = "4e310ef0e1b6eeb79169a1171daf9abcb87a2e17c03bee2c4bb100b55c75409f" 1797 | dependencies = [ 1798 | "cfg-if", 1799 | "ordered-multimap", 1800 | "trim-in-place", 1801 | ] 1802 | 1803 | [[package]] 1804 | name = "rust-s3" 1805 | version = "0.35.1" 1806 | source = "registry+https://github.com/rust-lang/crates.io-index" 1807 | checksum = "c3df3f353b1f4209dcf437d777cda90279c397ab15a0cd6fd06bd32c88591533" 1808 | dependencies = [ 1809 | "async-trait", 1810 | "aws-creds", 1811 | "aws-region", 1812 | "base64", 1813 | "bytes", 1814 | "cfg-if", 1815 | "futures", 1816 | "hex", 1817 | "hmac", 1818 | "http 0.2.12", 1819 | "hyper 0.14.32", 1820 | "hyper-tls 0.5.0", 1821 | "log", 1822 | "maybe-async", 1823 | "md5", 1824 | "minidom", 1825 | "native-tls", 1826 | "percent-encoding", 1827 | "quick-xml", 1828 | "serde", 1829 | "serde_derive", 1830 | "serde_json", 1831 | "sha2", 1832 | "thiserror", 1833 | "time", 1834 | "tokio", 1835 | "tokio-native-tls", 1836 | "tokio-stream", 1837 | "url", 1838 | ] 1839 | 1840 | [[package]] 1841 | name = "rustc-demangle" 1842 | version = "0.1.24" 1843 | source = "registry+https://github.com/rust-lang/crates.io-index" 1844 | checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" 1845 | 1846 | [[package]] 1847 | name = "rustix" 1848 | version = "0.38.42" 1849 | source = "registry+https://github.com/rust-lang/crates.io-index" 1850 | checksum = "f93dc38ecbab2eb790ff964bb77fa94faf256fd3e73285fd7ba0903b76bedb85" 1851 | dependencies = [ 1852 | "bitflags", 1853 | "errno", 1854 | "libc", 1855 | "linux-raw-sys", 1856 | "windows-sys 0.59.0", 1857 | ] 1858 | 1859 | [[package]] 1860 | name = "rustls" 1861 | version = "0.23.20" 1862 | source = "registry+https://github.com/rust-lang/crates.io-index" 1863 | checksum = "5065c3f250cbd332cd894be57c40fa52387247659b14a2d6041d121547903b1b" 1864 | dependencies = [ 1865 | "once_cell", 1866 | "rustls-pki-types", 1867 | "rustls-webpki", 1868 | "subtle", 1869 | "zeroize", 1870 | ] 1871 | 1872 | [[package]] 1873 | name = "rustls-pki-types" 1874 | version = "1.10.1" 1875 | source = "registry+https://github.com/rust-lang/crates.io-index" 1876 | checksum = "d2bf47e6ff922db3825eb750c4e2ff784c6ff8fb9e13046ef6a1d1c5401b0b37" 1877 | 1878 | [[package]] 1879 | name = "rustls-webpki" 1880 | version = "0.102.8" 1881 | source = "registry+https://github.com/rust-lang/crates.io-index" 1882 | checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" 1883 | dependencies = [ 1884 | "ring", 1885 | "rustls-pki-types", 1886 | "untrusted", 1887 | ] 1888 | 1889 | [[package]] 1890 | name = "rustversion" 1891 | version = "1.0.20" 1892 | source = "registry+https://github.com/rust-lang/crates.io-index" 1893 | checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2" 1894 | 1895 | [[package]] 1896 | name = "rxml" 1897 | version = "0.9.1" 1898 | source = "registry+https://github.com/rust-lang/crates.io-index" 1899 | checksum = "a98f186c7a2f3abbffb802984b7f1dfd65dac8be1aafdaabbca4137f53f0dff7" 1900 | dependencies = [ 1901 | "bytes", 1902 | "rxml_validation", 1903 | "smartstring", 1904 | ] 1905 | 1906 | [[package]] 1907 | name = "rxml_validation" 1908 | version = "0.9.1" 1909 | source = "registry+https://github.com/rust-lang/crates.io-index" 1910 | checksum = "22a197350ece202f19a166d1ad6d9d6de145e1d2a8ef47db299abe164dbd7530" 1911 | 1912 | [[package]] 1913 | name = "ryu" 1914 | version = "1.0.18" 1915 | source = "registry+https://github.com/rust-lang/crates.io-index" 1916 | checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" 1917 | 1918 | [[package]] 1919 | name = "schannel" 1920 | version = "0.1.27" 1921 | source = "registry+https://github.com/rust-lang/crates.io-index" 1922 | checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" 1923 | dependencies = [ 1924 | "windows-sys 0.59.0", 1925 | ] 1926 | 1927 | [[package]] 1928 | name = "scopeguard" 1929 | version = "1.2.0" 1930 | source = "registry+https://github.com/rust-lang/crates.io-index" 1931 | checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" 1932 | 1933 | [[package]] 1934 | name = "security-framework" 1935 | version = "2.11.1" 1936 | source = "registry+https://github.com/rust-lang/crates.io-index" 1937 | checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" 1938 | dependencies = [ 1939 | "bitflags", 1940 | "core-foundation", 1941 | "core-foundation-sys", 1942 | "libc", 1943 | "security-framework-sys", 1944 | ] 1945 | 1946 | [[package]] 1947 | name = "security-framework-sys" 1948 | version = "2.13.0" 1949 | source = "registry+https://github.com/rust-lang/crates.io-index" 1950 | checksum = "1863fd3768cd83c56a7f60faa4dc0d403f1b6df0a38c3c25f44b7894e45370d5" 1951 | dependencies = [ 1952 | "core-foundation-sys", 1953 | "libc", 1954 | ] 1955 | 1956 | [[package]] 1957 | name = "serde" 1958 | version = "1.0.219" 1959 | source = "registry+https://github.com/rust-lang/crates.io-index" 1960 | checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" 1961 | dependencies = [ 1962 | "serde_derive", 1963 | ] 1964 | 1965 | [[package]] 1966 | name = "serde_derive" 1967 | version = "1.0.219" 1968 | source = "registry+https://github.com/rust-lang/crates.io-index" 1969 | checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" 1970 | dependencies = [ 1971 | "proc-macro2", 1972 | "quote", 1973 | "syn", 1974 | ] 1975 | 1976 | [[package]] 1977 | name = "serde_json" 1978 | version = "1.0.133" 1979 | source = "registry+https://github.com/rust-lang/crates.io-index" 1980 | checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377" 1981 | dependencies = [ 1982 | "itoa", 1983 | "memchr", 1984 | "ryu", 1985 | "serde", 1986 | ] 1987 | 1988 | [[package]] 1989 | name = "serde_urlencoded" 1990 | version = "0.7.1" 1991 | source = "registry+https://github.com/rust-lang/crates.io-index" 1992 | checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" 1993 | dependencies = [ 1994 | "form_urlencoded", 1995 | "itoa", 1996 | "ryu", 1997 | "serde", 1998 | ] 1999 | 2000 | [[package]] 2001 | name = "sha1" 2002 | version = "0.10.6" 2003 | source = "registry+https://github.com/rust-lang/crates.io-index" 2004 | checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" 2005 | dependencies = [ 2006 | "cfg-if", 2007 | "cpufeatures", 2008 | "digest", 2009 | ] 2010 | 2011 | [[package]] 2012 | name = "sha2" 2013 | version = "0.10.8" 2014 | source = "registry+https://github.com/rust-lang/crates.io-index" 2015 | checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" 2016 | dependencies = [ 2017 | "cfg-if", 2018 | "cpufeatures", 2019 | "digest", 2020 | ] 2021 | 2022 | [[package]] 2023 | name = "sharded-slab" 2024 | version = "0.1.7" 2025 | source = "registry+https://github.com/rust-lang/crates.io-index" 2026 | checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" 2027 | dependencies = [ 2028 | "lazy_static", 2029 | ] 2030 | 2031 | [[package]] 2032 | name = "shlex" 2033 | version = "1.3.0" 2034 | source = "registry+https://github.com/rust-lang/crates.io-index" 2035 | checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" 2036 | 2037 | [[package]] 2038 | name = "signal-hook-registry" 2039 | version = "1.4.2" 2040 | source = "registry+https://github.com/rust-lang/crates.io-index" 2041 | checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" 2042 | dependencies = [ 2043 | "libc", 2044 | ] 2045 | 2046 | [[package]] 2047 | name = "slab" 2048 | version = "0.4.9" 2049 | source = "registry+https://github.com/rust-lang/crates.io-index" 2050 | checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" 2051 | dependencies = [ 2052 | "autocfg", 2053 | ] 2054 | 2055 | [[package]] 2056 | name = "smallvec" 2057 | version = "1.13.2" 2058 | source = "registry+https://github.com/rust-lang/crates.io-index" 2059 | checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" 2060 | 2061 | [[package]] 2062 | name = "smartstring" 2063 | version = "1.0.1" 2064 | source = "registry+https://github.com/rust-lang/crates.io-index" 2065 | checksum = "3fb72c633efbaa2dd666986505016c32c3044395ceaf881518399d2f4127ee29" 2066 | dependencies = [ 2067 | "autocfg", 2068 | "static_assertions", 2069 | "version_check", 2070 | ] 2071 | 2072 | [[package]] 2073 | name = "socket2" 2074 | version = "0.5.10" 2075 | source = "registry+https://github.com/rust-lang/crates.io-index" 2076 | checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" 2077 | dependencies = [ 2078 | "libc", 2079 | "windows-sys 0.52.0", 2080 | ] 2081 | 2082 | [[package]] 2083 | name = "stable_deref_trait" 2084 | version = "1.2.0" 2085 | source = "registry+https://github.com/rust-lang/crates.io-index" 2086 | checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" 2087 | 2088 | [[package]] 2089 | name = "static_assertions" 2090 | version = "1.1.0" 2091 | source = "registry+https://github.com/rust-lang/crates.io-index" 2092 | checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" 2093 | 2094 | [[package]] 2095 | name = "subtle" 2096 | version = "2.6.1" 2097 | source = "registry+https://github.com/rust-lang/crates.io-index" 2098 | checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" 2099 | 2100 | [[package]] 2101 | name = "syn" 2102 | version = "2.0.90" 2103 | source = "registry+https://github.com/rust-lang/crates.io-index" 2104 | checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31" 2105 | dependencies = [ 2106 | "proc-macro2", 2107 | "quote", 2108 | "unicode-ident", 2109 | ] 2110 | 2111 | [[package]] 2112 | name = "sync_wrapper" 2113 | version = "1.0.2" 2114 | source = "registry+https://github.com/rust-lang/crates.io-index" 2115 | checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" 2116 | dependencies = [ 2117 | "futures-core", 2118 | ] 2119 | 2120 | [[package]] 2121 | name = "synstructure" 2122 | version = "0.13.1" 2123 | source = "registry+https://github.com/rust-lang/crates.io-index" 2124 | checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" 2125 | dependencies = [ 2126 | "proc-macro2", 2127 | "quote", 2128 | "syn", 2129 | ] 2130 | 2131 | [[package]] 2132 | name = "system-configuration" 2133 | version = "0.6.1" 2134 | source = "registry+https://github.com/rust-lang/crates.io-index" 2135 | checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" 2136 | dependencies = [ 2137 | "bitflags", 2138 | "core-foundation", 2139 | "system-configuration-sys", 2140 | ] 2141 | 2142 | [[package]] 2143 | name = "system-configuration-sys" 2144 | version = "0.6.0" 2145 | source = "registry+https://github.com/rust-lang/crates.io-index" 2146 | checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4" 2147 | dependencies = [ 2148 | "core-foundation-sys", 2149 | "libc", 2150 | ] 2151 | 2152 | [[package]] 2153 | name = "tempfile" 2154 | version = "3.14.0" 2155 | source = "registry+https://github.com/rust-lang/crates.io-index" 2156 | checksum = "28cce251fcbc87fac86a866eeb0d6c2d536fc16d06f184bb61aeae11aa4cee0c" 2157 | dependencies = [ 2158 | "cfg-if", 2159 | "fastrand", 2160 | "once_cell", 2161 | "rustix", 2162 | "windows-sys 0.59.0", 2163 | ] 2164 | 2165 | [[package]] 2166 | name = "thiserror" 2167 | version = "1.0.69" 2168 | source = "registry+https://github.com/rust-lang/crates.io-index" 2169 | checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" 2170 | dependencies = [ 2171 | "thiserror-impl", 2172 | ] 2173 | 2174 | [[package]] 2175 | name = "thiserror-impl" 2176 | version = "1.0.69" 2177 | source = "registry+https://github.com/rust-lang/crates.io-index" 2178 | checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" 2179 | dependencies = [ 2180 | "proc-macro2", 2181 | "quote", 2182 | "syn", 2183 | ] 2184 | 2185 | [[package]] 2186 | name = "thread_local" 2187 | version = "1.1.8" 2188 | source = "registry+https://github.com/rust-lang/crates.io-index" 2189 | checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" 2190 | dependencies = [ 2191 | "cfg-if", 2192 | "once_cell", 2193 | ] 2194 | 2195 | [[package]] 2196 | name = "time" 2197 | version = "0.3.37" 2198 | source = "registry+https://github.com/rust-lang/crates.io-index" 2199 | checksum = "35e7868883861bd0e56d9ac6efcaaca0d6d5d82a2a7ec8209ff492c07cf37b21" 2200 | dependencies = [ 2201 | "deranged", 2202 | "itoa", 2203 | "num-conv", 2204 | "powerfmt", 2205 | "serde", 2206 | "time-core", 2207 | "time-macros", 2208 | ] 2209 | 2210 | [[package]] 2211 | name = "time-core" 2212 | version = "0.1.2" 2213 | source = "registry+https://github.com/rust-lang/crates.io-index" 2214 | checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" 2215 | 2216 | [[package]] 2217 | name = "time-macros" 2218 | version = "0.2.19" 2219 | source = "registry+https://github.com/rust-lang/crates.io-index" 2220 | checksum = "2834e6017e3e5e4b9834939793b282bc03b37a3336245fa820e35e233e2a85de" 2221 | dependencies = [ 2222 | "num-conv", 2223 | "time-core", 2224 | ] 2225 | 2226 | [[package]] 2227 | name = "tiny-keccak" 2228 | version = "2.0.2" 2229 | source = "registry+https://github.com/rust-lang/crates.io-index" 2230 | checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" 2231 | dependencies = [ 2232 | "crunchy", 2233 | ] 2234 | 2235 | [[package]] 2236 | name = "tinystr" 2237 | version = "0.7.6" 2238 | source = "registry+https://github.com/rust-lang/crates.io-index" 2239 | checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" 2240 | dependencies = [ 2241 | "displaydoc", 2242 | "zerovec", 2243 | ] 2244 | 2245 | [[package]] 2246 | name = "tokio" 2247 | version = "1.45.1" 2248 | source = "registry+https://github.com/rust-lang/crates.io-index" 2249 | checksum = "75ef51a33ef1da925cea3e4eb122833cb377c61439ca401b770f54902b806779" 2250 | dependencies = [ 2251 | "backtrace", 2252 | "bytes", 2253 | "libc", 2254 | "mio", 2255 | "parking_lot", 2256 | "pin-project-lite", 2257 | "signal-hook-registry", 2258 | "socket2", 2259 | "tokio-macros", 2260 | "windows-sys 0.52.0", 2261 | ] 2262 | 2263 | [[package]] 2264 | name = "tokio-macros" 2265 | version = "2.5.0" 2266 | source = "registry+https://github.com/rust-lang/crates.io-index" 2267 | checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" 2268 | dependencies = [ 2269 | "proc-macro2", 2270 | "quote", 2271 | "syn", 2272 | ] 2273 | 2274 | [[package]] 2275 | name = "tokio-native-tls" 2276 | version = "0.3.1" 2277 | source = "registry+https://github.com/rust-lang/crates.io-index" 2278 | checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" 2279 | dependencies = [ 2280 | "native-tls", 2281 | "tokio", 2282 | ] 2283 | 2284 | [[package]] 2285 | name = "tokio-rustls" 2286 | version = "0.26.1" 2287 | source = "registry+https://github.com/rust-lang/crates.io-index" 2288 | checksum = "5f6d0975eaace0cf0fcadee4e4aaa5da15b5c079146f2cffb67c113be122bf37" 2289 | dependencies = [ 2290 | "rustls", 2291 | "tokio", 2292 | ] 2293 | 2294 | [[package]] 2295 | name = "tokio-stream" 2296 | version = "0.1.17" 2297 | source = "registry+https://github.com/rust-lang/crates.io-index" 2298 | checksum = "eca58d7bba4a75707817a2c44174253f9236b2d5fbd055602e9d5c07c139a047" 2299 | dependencies = [ 2300 | "futures-core", 2301 | "pin-project-lite", 2302 | "tokio", 2303 | ] 2304 | 2305 | [[package]] 2306 | name = "tokio-util" 2307 | version = "0.7.13" 2308 | source = "registry+https://github.com/rust-lang/crates.io-index" 2309 | checksum = "d7fcaa8d55a2bdd6b83ace262b016eca0d79ee02818c5c1bcdf0305114081078" 2310 | dependencies = [ 2311 | "bytes", 2312 | "futures-core", 2313 | "futures-sink", 2314 | "pin-project-lite", 2315 | "tokio", 2316 | ] 2317 | 2318 | [[package]] 2319 | name = "tower" 2320 | version = "0.5.2" 2321 | source = "registry+https://github.com/rust-lang/crates.io-index" 2322 | checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" 2323 | dependencies = [ 2324 | "futures-core", 2325 | "futures-util", 2326 | "pin-project-lite", 2327 | "sync_wrapper", 2328 | "tokio", 2329 | "tower-layer", 2330 | "tower-service", 2331 | ] 2332 | 2333 | [[package]] 2334 | name = "tower-http" 2335 | version = "0.6.4" 2336 | source = "registry+https://github.com/rust-lang/crates.io-index" 2337 | checksum = "0fdb0c213ca27a9f57ab69ddb290fd80d970922355b83ae380b395d3986b8a2e" 2338 | dependencies = [ 2339 | "bitflags", 2340 | "bytes", 2341 | "futures-util", 2342 | "http 1.2.0", 2343 | "http-body 1.0.1", 2344 | "iri-string", 2345 | "pin-project-lite", 2346 | "tower", 2347 | "tower-layer", 2348 | "tower-service", 2349 | ] 2350 | 2351 | [[package]] 2352 | name = "tower-layer" 2353 | version = "0.3.3" 2354 | source = "registry+https://github.com/rust-lang/crates.io-index" 2355 | checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" 2356 | 2357 | [[package]] 2358 | name = "tower-service" 2359 | version = "0.3.3" 2360 | source = "registry+https://github.com/rust-lang/crates.io-index" 2361 | checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" 2362 | 2363 | [[package]] 2364 | name = "tracing" 2365 | version = "0.1.41" 2366 | source = "registry+https://github.com/rust-lang/crates.io-index" 2367 | checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" 2368 | dependencies = [ 2369 | "log", 2370 | "pin-project-lite", 2371 | "tracing-attributes", 2372 | "tracing-core", 2373 | ] 2374 | 2375 | [[package]] 2376 | name = "tracing-appender" 2377 | version = "0.2.3" 2378 | source = "registry+https://github.com/rust-lang/crates.io-index" 2379 | checksum = "3566e8ce28cc0a3fe42519fc80e6b4c943cc4c8cef275620eb8dac2d3d4e06cf" 2380 | dependencies = [ 2381 | "crossbeam-channel", 2382 | "thiserror", 2383 | "time", 2384 | "tracing-subscriber", 2385 | ] 2386 | 2387 | [[package]] 2388 | name = "tracing-attributes" 2389 | version = "0.1.28" 2390 | source = "registry+https://github.com/rust-lang/crates.io-index" 2391 | checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" 2392 | dependencies = [ 2393 | "proc-macro2", 2394 | "quote", 2395 | "syn", 2396 | ] 2397 | 2398 | [[package]] 2399 | name = "tracing-bunyan-formatter" 2400 | version = "0.3.10" 2401 | source = "registry+https://github.com/rust-lang/crates.io-index" 2402 | checksum = "2d637245a0d8774bd48df6482e086c59a8b5348a910c3b0579354045a9d82411" 2403 | dependencies = [ 2404 | "ahash", 2405 | "gethostname", 2406 | "log", 2407 | "serde", 2408 | "serde_json", 2409 | "time", 2410 | "tracing", 2411 | "tracing-core", 2412 | "tracing-log 0.1.4", 2413 | "tracing-subscriber", 2414 | ] 2415 | 2416 | [[package]] 2417 | name = "tracing-core" 2418 | version = "0.1.33" 2419 | source = "registry+https://github.com/rust-lang/crates.io-index" 2420 | checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" 2421 | dependencies = [ 2422 | "once_cell", 2423 | "valuable", 2424 | ] 2425 | 2426 | [[package]] 2427 | name = "tracing-log" 2428 | version = "0.1.4" 2429 | source = "registry+https://github.com/rust-lang/crates.io-index" 2430 | checksum = "f751112709b4e791d8ce53e32c4ed2d353565a795ce84da2285393f41557bdf2" 2431 | dependencies = [ 2432 | "log", 2433 | "once_cell", 2434 | "tracing-core", 2435 | ] 2436 | 2437 | [[package]] 2438 | name = "tracing-log" 2439 | version = "0.2.0" 2440 | source = "registry+https://github.com/rust-lang/crates.io-index" 2441 | checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" 2442 | dependencies = [ 2443 | "log", 2444 | "once_cell", 2445 | "tracing-core", 2446 | ] 2447 | 2448 | [[package]] 2449 | name = "tracing-subscriber" 2450 | version = "0.3.19" 2451 | source = "registry+https://github.com/rust-lang/crates.io-index" 2452 | checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008" 2453 | dependencies = [ 2454 | "matchers", 2455 | "nu-ansi-term", 2456 | "once_cell", 2457 | "regex", 2458 | "sharded-slab", 2459 | "smallvec", 2460 | "thread_local", 2461 | "tracing", 2462 | "tracing-core", 2463 | "tracing-log 0.2.0", 2464 | ] 2465 | 2466 | [[package]] 2467 | name = "trim-in-place" 2468 | version = "0.1.7" 2469 | source = "registry+https://github.com/rust-lang/crates.io-index" 2470 | checksum = "343e926fc669bc8cde4fa3129ab681c63671bae288b1f1081ceee6d9d37904fc" 2471 | 2472 | [[package]] 2473 | name = "try-lock" 2474 | version = "0.2.5" 2475 | source = "registry+https://github.com/rust-lang/crates.io-index" 2476 | checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" 2477 | 2478 | [[package]] 2479 | name = "typenum" 2480 | version = "1.17.0" 2481 | source = "registry+https://github.com/rust-lang/crates.io-index" 2482 | checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" 2483 | 2484 | [[package]] 2485 | name = "unicode-ident" 2486 | version = "1.0.14" 2487 | source = "registry+https://github.com/rust-lang/crates.io-index" 2488 | checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" 2489 | 2490 | [[package]] 2491 | name = "unicode-xid" 2492 | version = "0.2.6" 2493 | source = "registry+https://github.com/rust-lang/crates.io-index" 2494 | checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" 2495 | 2496 | [[package]] 2497 | name = "untrusted" 2498 | version = "0.9.0" 2499 | source = "registry+https://github.com/rust-lang/crates.io-index" 2500 | checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" 2501 | 2502 | [[package]] 2503 | name = "url" 2504 | version = "2.5.4" 2505 | source = "registry+https://github.com/rust-lang/crates.io-index" 2506 | checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" 2507 | dependencies = [ 2508 | "form_urlencoded", 2509 | "idna", 2510 | "percent-encoding", 2511 | ] 2512 | 2513 | [[package]] 2514 | name = "utf16_iter" 2515 | version = "1.0.5" 2516 | source = "registry+https://github.com/rust-lang/crates.io-index" 2517 | checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" 2518 | 2519 | [[package]] 2520 | name = "utf8_iter" 2521 | version = "1.0.4" 2522 | source = "registry+https://github.com/rust-lang/crates.io-index" 2523 | checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" 2524 | 2525 | [[package]] 2526 | name = "valuable" 2527 | version = "0.1.0" 2528 | source = "registry+https://github.com/rust-lang/crates.io-index" 2529 | checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" 2530 | 2531 | [[package]] 2532 | name = "vcpkg" 2533 | version = "0.2.15" 2534 | source = "registry+https://github.com/rust-lang/crates.io-index" 2535 | checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" 2536 | 2537 | [[package]] 2538 | name = "version_check" 2539 | version = "0.9.5" 2540 | source = "registry+https://github.com/rust-lang/crates.io-index" 2541 | checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" 2542 | 2543 | [[package]] 2544 | name = "want" 2545 | version = "0.3.1" 2546 | source = "registry+https://github.com/rust-lang/crates.io-index" 2547 | checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" 2548 | dependencies = [ 2549 | "try-lock", 2550 | ] 2551 | 2552 | [[package]] 2553 | name = "wasi" 2554 | version = "0.11.0+wasi-snapshot-preview1" 2555 | source = "registry+https://github.com/rust-lang/crates.io-index" 2556 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" 2557 | 2558 | [[package]] 2559 | name = "wasi" 2560 | version = "0.13.3+wasi-0.2.2" 2561 | source = "registry+https://github.com/rust-lang/crates.io-index" 2562 | checksum = "26816d2e1a4a36a2940b96c5296ce403917633dff8f3440e9b236ed6f6bacad2" 2563 | dependencies = [ 2564 | "wit-bindgen-rt", 2565 | ] 2566 | 2567 | [[package]] 2568 | name = "wasm-bindgen" 2569 | version = "0.2.100" 2570 | source = "registry+https://github.com/rust-lang/crates.io-index" 2571 | checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" 2572 | dependencies = [ 2573 | "cfg-if", 2574 | "once_cell", 2575 | "rustversion", 2576 | "wasm-bindgen-macro", 2577 | ] 2578 | 2579 | [[package]] 2580 | name = "wasm-bindgen-backend" 2581 | version = "0.2.100" 2582 | source = "registry+https://github.com/rust-lang/crates.io-index" 2583 | checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" 2584 | dependencies = [ 2585 | "bumpalo", 2586 | "log", 2587 | "proc-macro2", 2588 | "quote", 2589 | "syn", 2590 | "wasm-bindgen-shared", 2591 | ] 2592 | 2593 | [[package]] 2594 | name = "wasm-bindgen-futures" 2595 | version = "0.4.50" 2596 | source = "registry+https://github.com/rust-lang/crates.io-index" 2597 | checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61" 2598 | dependencies = [ 2599 | "cfg-if", 2600 | "js-sys", 2601 | "once_cell", 2602 | "wasm-bindgen", 2603 | "web-sys", 2604 | ] 2605 | 2606 | [[package]] 2607 | name = "wasm-bindgen-macro" 2608 | version = "0.2.100" 2609 | source = "registry+https://github.com/rust-lang/crates.io-index" 2610 | checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" 2611 | dependencies = [ 2612 | "quote", 2613 | "wasm-bindgen-macro-support", 2614 | ] 2615 | 2616 | [[package]] 2617 | name = "wasm-bindgen-macro-support" 2618 | version = "0.2.100" 2619 | source = "registry+https://github.com/rust-lang/crates.io-index" 2620 | checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" 2621 | dependencies = [ 2622 | "proc-macro2", 2623 | "quote", 2624 | "syn", 2625 | "wasm-bindgen-backend", 2626 | "wasm-bindgen-shared", 2627 | ] 2628 | 2629 | [[package]] 2630 | name = "wasm-bindgen-shared" 2631 | version = "0.2.100" 2632 | source = "registry+https://github.com/rust-lang/crates.io-index" 2633 | checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" 2634 | dependencies = [ 2635 | "unicode-ident", 2636 | ] 2637 | 2638 | [[package]] 2639 | name = "web-sys" 2640 | version = "0.3.77" 2641 | source = "registry+https://github.com/rust-lang/crates.io-index" 2642 | checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" 2643 | dependencies = [ 2644 | "js-sys", 2645 | "wasm-bindgen", 2646 | ] 2647 | 2648 | [[package]] 2649 | name = "winapi" 2650 | version = "0.3.9" 2651 | source = "registry+https://github.com/rust-lang/crates.io-index" 2652 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 2653 | dependencies = [ 2654 | "winapi-i686-pc-windows-gnu", 2655 | "winapi-x86_64-pc-windows-gnu", 2656 | ] 2657 | 2658 | [[package]] 2659 | name = "winapi-i686-pc-windows-gnu" 2660 | version = "0.4.0" 2661 | source = "registry+https://github.com/rust-lang/crates.io-index" 2662 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 2663 | 2664 | [[package]] 2665 | name = "winapi-x86_64-pc-windows-gnu" 2666 | version = "0.4.0" 2667 | source = "registry+https://github.com/rust-lang/crates.io-index" 2668 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 2669 | 2670 | [[package]] 2671 | name = "windows-link" 2672 | version = "0.1.0" 2673 | source = "registry+https://github.com/rust-lang/crates.io-index" 2674 | checksum = "6dccfd733ce2b1753b03b6d3c65edf020262ea35e20ccdf3e288043e6dd620e3" 2675 | 2676 | [[package]] 2677 | name = "windows-registry" 2678 | version = "0.4.0" 2679 | source = "registry+https://github.com/rust-lang/crates.io-index" 2680 | checksum = "4286ad90ddb45071efd1a66dfa43eb02dd0dfbae1545ad6cc3c51cf34d7e8ba3" 2681 | dependencies = [ 2682 | "windows-result", 2683 | "windows-strings", 2684 | "windows-targets 0.53.0", 2685 | ] 2686 | 2687 | [[package]] 2688 | name = "windows-result" 2689 | version = "0.3.1" 2690 | source = "registry+https://github.com/rust-lang/crates.io-index" 2691 | checksum = "06374efe858fab7e4f881500e6e86ec8bc28f9462c47e5a9941a0142ad86b189" 2692 | dependencies = [ 2693 | "windows-link", 2694 | ] 2695 | 2696 | [[package]] 2697 | name = "windows-strings" 2698 | version = "0.3.1" 2699 | source = "registry+https://github.com/rust-lang/crates.io-index" 2700 | checksum = "87fa48cc5d406560701792be122a10132491cff9d0aeb23583cc2dcafc847319" 2701 | dependencies = [ 2702 | "windows-link", 2703 | ] 2704 | 2705 | [[package]] 2706 | name = "windows-sys" 2707 | version = "0.52.0" 2708 | source = "registry+https://github.com/rust-lang/crates.io-index" 2709 | checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" 2710 | dependencies = [ 2711 | "windows-targets 0.52.6", 2712 | ] 2713 | 2714 | [[package]] 2715 | name = "windows-sys" 2716 | version = "0.59.0" 2717 | source = "registry+https://github.com/rust-lang/crates.io-index" 2718 | checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" 2719 | dependencies = [ 2720 | "windows-targets 0.52.6", 2721 | ] 2722 | 2723 | [[package]] 2724 | name = "windows-targets" 2725 | version = "0.52.6" 2726 | source = "registry+https://github.com/rust-lang/crates.io-index" 2727 | checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" 2728 | dependencies = [ 2729 | "windows_aarch64_gnullvm 0.52.6", 2730 | "windows_aarch64_msvc 0.52.6", 2731 | "windows_i686_gnu 0.52.6", 2732 | "windows_i686_gnullvm 0.52.6", 2733 | "windows_i686_msvc 0.52.6", 2734 | "windows_x86_64_gnu 0.52.6", 2735 | "windows_x86_64_gnullvm 0.52.6", 2736 | "windows_x86_64_msvc 0.52.6", 2737 | ] 2738 | 2739 | [[package]] 2740 | name = "windows-targets" 2741 | version = "0.53.0" 2742 | source = "registry+https://github.com/rust-lang/crates.io-index" 2743 | checksum = "b1e4c7e8ceaaf9cb7d7507c974735728ab453b67ef8f18febdd7c11fe59dca8b" 2744 | dependencies = [ 2745 | "windows_aarch64_gnullvm 0.53.0", 2746 | "windows_aarch64_msvc 0.53.0", 2747 | "windows_i686_gnu 0.53.0", 2748 | "windows_i686_gnullvm 0.53.0", 2749 | "windows_i686_msvc 0.53.0", 2750 | "windows_x86_64_gnu 0.53.0", 2751 | "windows_x86_64_gnullvm 0.53.0", 2752 | "windows_x86_64_msvc 0.53.0", 2753 | ] 2754 | 2755 | [[package]] 2756 | name = "windows_aarch64_gnullvm" 2757 | version = "0.52.6" 2758 | source = "registry+https://github.com/rust-lang/crates.io-index" 2759 | checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" 2760 | 2761 | [[package]] 2762 | name = "windows_aarch64_gnullvm" 2763 | version = "0.53.0" 2764 | source = "registry+https://github.com/rust-lang/crates.io-index" 2765 | checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" 2766 | 2767 | [[package]] 2768 | name = "windows_aarch64_msvc" 2769 | version = "0.52.6" 2770 | source = "registry+https://github.com/rust-lang/crates.io-index" 2771 | checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" 2772 | 2773 | [[package]] 2774 | name = "windows_aarch64_msvc" 2775 | version = "0.53.0" 2776 | source = "registry+https://github.com/rust-lang/crates.io-index" 2777 | checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" 2778 | 2779 | [[package]] 2780 | name = "windows_i686_gnu" 2781 | version = "0.52.6" 2782 | source = "registry+https://github.com/rust-lang/crates.io-index" 2783 | checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" 2784 | 2785 | [[package]] 2786 | name = "windows_i686_gnu" 2787 | version = "0.53.0" 2788 | source = "registry+https://github.com/rust-lang/crates.io-index" 2789 | checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" 2790 | 2791 | [[package]] 2792 | name = "windows_i686_gnullvm" 2793 | version = "0.52.6" 2794 | source = "registry+https://github.com/rust-lang/crates.io-index" 2795 | checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" 2796 | 2797 | [[package]] 2798 | name = "windows_i686_gnullvm" 2799 | version = "0.53.0" 2800 | source = "registry+https://github.com/rust-lang/crates.io-index" 2801 | checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" 2802 | 2803 | [[package]] 2804 | name = "windows_i686_msvc" 2805 | version = "0.52.6" 2806 | source = "registry+https://github.com/rust-lang/crates.io-index" 2807 | checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" 2808 | 2809 | [[package]] 2810 | name = "windows_i686_msvc" 2811 | version = "0.53.0" 2812 | source = "registry+https://github.com/rust-lang/crates.io-index" 2813 | checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" 2814 | 2815 | [[package]] 2816 | name = "windows_x86_64_gnu" 2817 | version = "0.52.6" 2818 | source = "registry+https://github.com/rust-lang/crates.io-index" 2819 | checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" 2820 | 2821 | [[package]] 2822 | name = "windows_x86_64_gnu" 2823 | version = "0.53.0" 2824 | source = "registry+https://github.com/rust-lang/crates.io-index" 2825 | checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" 2826 | 2827 | [[package]] 2828 | name = "windows_x86_64_gnullvm" 2829 | version = "0.52.6" 2830 | source = "registry+https://github.com/rust-lang/crates.io-index" 2831 | checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" 2832 | 2833 | [[package]] 2834 | name = "windows_x86_64_gnullvm" 2835 | version = "0.53.0" 2836 | source = "registry+https://github.com/rust-lang/crates.io-index" 2837 | checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" 2838 | 2839 | [[package]] 2840 | name = "windows_x86_64_msvc" 2841 | version = "0.52.6" 2842 | source = "registry+https://github.com/rust-lang/crates.io-index" 2843 | checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" 2844 | 2845 | [[package]] 2846 | name = "windows_x86_64_msvc" 2847 | version = "0.53.0" 2848 | source = "registry+https://github.com/rust-lang/crates.io-index" 2849 | checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" 2850 | 2851 | [[package]] 2852 | name = "wiremock" 2853 | version = "0.6.3" 2854 | source = "registry+https://github.com/rust-lang/crates.io-index" 2855 | checksum = "101681b74cd87b5899e87bcf5a64e83334dd313fcd3053ea72e6dba18928e301" 2856 | dependencies = [ 2857 | "assert-json-diff", 2858 | "async-trait", 2859 | "base64", 2860 | "deadpool", 2861 | "futures", 2862 | "http 1.2.0", 2863 | "http-body-util", 2864 | "hyper 1.6.0", 2865 | "hyper-util", 2866 | "log", 2867 | "once_cell", 2868 | "regex", 2869 | "serde", 2870 | "serde_json", 2871 | "tokio", 2872 | "url", 2873 | ] 2874 | 2875 | [[package]] 2876 | name = "wit-bindgen-rt" 2877 | version = "0.33.0" 2878 | source = "registry+https://github.com/rust-lang/crates.io-index" 2879 | checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c" 2880 | dependencies = [ 2881 | "bitflags", 2882 | ] 2883 | 2884 | [[package]] 2885 | name = "write16" 2886 | version = "1.0.0" 2887 | source = "registry+https://github.com/rust-lang/crates.io-index" 2888 | checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" 2889 | 2890 | [[package]] 2891 | name = "writeable" 2892 | version = "0.5.5" 2893 | source = "registry+https://github.com/rust-lang/crates.io-index" 2894 | checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" 2895 | 2896 | [[package]] 2897 | name = "yoke" 2898 | version = "0.7.5" 2899 | source = "registry+https://github.com/rust-lang/crates.io-index" 2900 | checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" 2901 | dependencies = [ 2902 | "serde", 2903 | "stable_deref_trait", 2904 | "yoke-derive", 2905 | "zerofrom", 2906 | ] 2907 | 2908 | [[package]] 2909 | name = "yoke-derive" 2910 | version = "0.7.5" 2911 | source = "registry+https://github.com/rust-lang/crates.io-index" 2912 | checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" 2913 | dependencies = [ 2914 | "proc-macro2", 2915 | "quote", 2916 | "syn", 2917 | "synstructure", 2918 | ] 2919 | 2920 | [[package]] 2921 | name = "zerocopy" 2922 | version = "0.7.35" 2923 | source = "registry+https://github.com/rust-lang/crates.io-index" 2924 | checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" 2925 | dependencies = [ 2926 | "byteorder", 2927 | "zerocopy-derive 0.7.35", 2928 | ] 2929 | 2930 | [[package]] 2931 | name = "zerocopy" 2932 | version = "0.8.23" 2933 | source = "registry+https://github.com/rust-lang/crates.io-index" 2934 | checksum = "fd97444d05a4328b90e75e503a34bad781f14e28a823ad3557f0750df1ebcbc6" 2935 | dependencies = [ 2936 | "zerocopy-derive 0.8.23", 2937 | ] 2938 | 2939 | [[package]] 2940 | name = "zerocopy-derive" 2941 | version = "0.7.35" 2942 | source = "registry+https://github.com/rust-lang/crates.io-index" 2943 | checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" 2944 | dependencies = [ 2945 | "proc-macro2", 2946 | "quote", 2947 | "syn", 2948 | ] 2949 | 2950 | [[package]] 2951 | name = "zerocopy-derive" 2952 | version = "0.8.23" 2953 | source = "registry+https://github.com/rust-lang/crates.io-index" 2954 | checksum = "6352c01d0edd5db859a63e2605f4ea3183ddbd15e2c4a9e7d32184df75e4f154" 2955 | dependencies = [ 2956 | "proc-macro2", 2957 | "quote", 2958 | "syn", 2959 | ] 2960 | 2961 | [[package]] 2962 | name = "zerofrom" 2963 | version = "0.1.5" 2964 | source = "registry+https://github.com/rust-lang/crates.io-index" 2965 | checksum = "cff3ee08c995dee1859d998dea82f7374f2826091dd9cd47def953cae446cd2e" 2966 | dependencies = [ 2967 | "zerofrom-derive", 2968 | ] 2969 | 2970 | [[package]] 2971 | name = "zerofrom-derive" 2972 | version = "0.1.5" 2973 | source = "registry+https://github.com/rust-lang/crates.io-index" 2974 | checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808" 2975 | dependencies = [ 2976 | "proc-macro2", 2977 | "quote", 2978 | "syn", 2979 | "synstructure", 2980 | ] 2981 | 2982 | [[package]] 2983 | name = "zeroize" 2984 | version = "1.8.1" 2985 | source = "registry+https://github.com/rust-lang/crates.io-index" 2986 | checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" 2987 | 2988 | [[package]] 2989 | name = "zerovec" 2990 | version = "0.10.4" 2991 | source = "registry+https://github.com/rust-lang/crates.io-index" 2992 | checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" 2993 | dependencies = [ 2994 | "yoke", 2995 | "zerofrom", 2996 | "zerovec-derive", 2997 | ] 2998 | 2999 | [[package]] 3000 | name = "zerovec-derive" 3001 | version = "0.10.3" 3002 | source = "registry+https://github.com/rust-lang/crates.io-index" 3003 | checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" 3004 | dependencies = [ 3005 | "proc-macro2", 3006 | "quote", 3007 | "syn", 3008 | ] 3009 | 3010 | [[package]] 3011 | name = "zstd" 3012 | version = "0.13.2" 3013 | source = "registry+https://github.com/rust-lang/crates.io-index" 3014 | checksum = "fcf2b778a664581e31e389454a7072dab1647606d44f7feea22cd5abb9c9f3f9" 3015 | dependencies = [ 3016 | "zstd-safe", 3017 | ] 3018 | 3019 | [[package]] 3020 | name = "zstd-safe" 3021 | version = "7.2.1" 3022 | source = "registry+https://github.com/rust-lang/crates.io-index" 3023 | checksum = "54a3ab4db68cea366acc5c897c7b4d4d1b8994a9cd6e6f841f8964566a419059" 3024 | dependencies = [ 3025 | "zstd-sys", 3026 | ] 3027 | 3028 | [[package]] 3029 | name = "zstd-sys" 3030 | version = "2.0.13+zstd.1.5.6" 3031 | source = "registry+https://github.com/rust-lang/crates.io-index" 3032 | checksum = "38ff0f21cfee8f97d94cef41359e0c89aa6113028ab0291aa8ca0038995a95aa" 3033 | dependencies = [ 3034 | "cc", 3035 | "pkg-config", 3036 | ] 3037 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "decay" 3 | edition = "2024" 4 | rust-version = "1.86" 5 | version = "0.0.0" 6 | authors = ["Bruno Paulino "] 7 | license = "MIT" 8 | repository = "https://github.com/brunojppb/turbo-cache-server" 9 | readme = "README.md" 10 | 11 | [lib] 12 | path = "src/lib.rs" 13 | 14 | [[bin]] 15 | path = "src/main.rs" 16 | name = "decay" 17 | 18 | [dependencies] 19 | actix-web = "4" 20 | dotenv = "0.15.0" 21 | rust-s3 = "0.35" 22 | serde = { version = "1.0", features = ["derive"] } 23 | tokio = { version = "1", features = ["macros", "rt-multi-thread"] } 24 | tracing = { version = "0.1", features = ["log"] } 25 | tracing-appender = "0.2" 26 | tracing-subscriber = { version = "0.3", features = ["registry", "env-filter"] } 27 | tracing-log = "0.2" 28 | tracing-bunyan-formatter = "0.3" 29 | futures = "0.3" 30 | openssl = { version = "0.10", features = ["vendored"] } 31 | 32 | [dev-dependencies] 33 | reqwest = "0.12" 34 | wiremock = "0.6" 35 | 36 | 37 | [profile.release] 38 | # For more details on smaller binary size, see: 39 | # https://github.com/johnthagen/min-sized-rust/blob/094d314f0c28f7e4bffeb0b0258f71cb303bd91a/README.md 40 | strip = true # Automatically strip symbols from the binary to reduce binary size 41 | opt-level = "z" # Optimize for size. 42 | lto = true 43 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # To make Decay compatible with differnt linux distributions, 2 | # let's cross-compile using musl so the binary is statically linked with the right dependencies 3 | # See: https://users.rust-lang.org/t/unable-to-run-compiled-program/88441/5 4 | # See: https://github.com/rust-cross/rust-musl-cross 5 | # See: https://hub.docker.com/layers/messense/rust-musl-cross/x86_64-musl/images/sha256-7ef452f6c731535a716e3f5a5d255fbe9720f35e992c9dee7d477e58542cfaf5?context=explore 6 | FROM messense/rust-musl-cross@sha256:7ef452f6c731535a716e3f5a5d255fbe9720f35e992c9dee7d477e58542cfaf5 as builder 7 | WORKDIR /app 8 | COPY . /app 9 | # See: https://github.com/rust-lang/rustup/issues/1167#issuecomment-367061388 10 | RUN rm -frv ~/.rustup/toolchains/* 11 | RUN rustup show \ 12 | && rustup update \ 13 | && rustup target add x86_64-unknown-linux-musl \ 14 | && rustc --version 15 | RUN cargo build --verbose --release 16 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Bruno Paulino 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |


Turbo engine

2 |

Turbo Cache Server

3 |

4 | Turborepo remote cache server, API-compliant as a GitHub Action with S3-compatible storage support. 5 |

6 | 7 | ### How can I use this in my monorepo? 8 | 9 | Make sure that you have an S3-compatible storage available. We currently tested 10 | with: 11 | 12 | - [Amazon S3](https://aws.amazon.com/s3/) 13 | - [Cloudflare R2](https://www.cloudflare.com/en-gb/developer-platform/r2/) 14 | - [Minio Object Storage](https://min.io/) 15 | 16 | You can use the Turbo Cache Server as a **GitHub Action**. Here is how: 17 | 18 | 1. In your workflow files, add the following global environment variables: 19 | 20 | ```yml 21 | env: 22 | TURBO_API: "http://127.0.0.1:8585" 23 | TURBO_TEAM: "NAME_OF_YOUR_REPO_HERE" 24 | # The value of TURBO_TOKEN is irrelevant 25 | # as we don't perform any auth against the cache server 26 | # but it's still necessary for Turborepo 27 | TURBO_TOKEN: "turbo-token" 28 | ``` 29 | 30 | 1. In the same workflow file, after checking out your code, 31 | start the Turbo Cache Server in the background: 32 | 33 | ```yml 34 | - name: Checkout repository 35 | uses: actions/checkout@v4 36 | 37 | - name: Turborepo Cache Server 38 | uses: brunojppb/turbo-cache-server@1.0.3 39 | env: 40 | PORT: "8585" 41 | S3_ACCESS_KEY: ${{ secrets.S3_ACCESS_KEY }} 42 | S3_SECRET_KEY: ${{ secrets.S3_SECRET_KEY }} 43 | S3_ENDPOINT: ${{ secrets.S3_ENDPOINT }} 44 | S3_BUCKET_NAME: your-bucket-name-here 45 | # Region defaults to "eu-central-1" 46 | S3_REGION: "eu-central-1" 47 | # if your S3-compatible store does not support requests 48 | # like https://bucket.hostname.domain/. Setting `S3_USE_PATH_STYLE` 49 | # to true configures the S3 client to make requests like 50 | # https://hostname.domain/bucket instead. 51 | # Defaults to "false" 52 | S3_USE_PATH_STYLE: false 53 | # Max payload size for each cache object sent by Turborepo 54 | # Defaults to 100 MB 55 | # Requests larger than that, will get "HTTP 413: Entity Too Large" errors 56 | MAX_PAYLOAD_SIZE_IN_MB: "100" 57 | 58 | # Now you can run your turborepo tasks and rely on the cache server 59 | # available in the background to provide previously built artifacts (cache hits) 60 | # and let Turborepo upload new artifacts when there is a cache miss. 61 | - name: Run tasks 62 | run: turbo run test build typecheck 63 | ``` 64 | 65 | And that is all you need to use our remote cache server for Turborepo. As a 66 | reference, take a look at 67 | [this example workflow file](https://github.com/brunojppb/turbo-decay/blob/main/.github/workflows/ci.yml) 68 | for inspiration. 69 | 70 | > [!NOTE] 71 | > These environment variables are required by Turborepo so it can call 72 | > the Turbo Cache Server with the right HTTP body, headers and query strings. 73 | > These environment variables are necessary so the Turborepo binary can identify 74 | > the Remote Cache feature is enabled and can use them across all steps. You can 75 | > [read more about this here](https://turbo.build/repo/docs/ci#setup) on the 76 | > Turborepo official docs. 77 | 78 | ## How does that work? 79 | 80 | Turbo Cache Server is a tiny web server written in 81 | [Rust](https://www.rust-lang.org/) that uses any S3-compatible bucket as its 82 | storage layer for the artifacts generated by Turborepo. 83 | 84 | ### What happens when there is a cache hit? 85 | 86 | Here is a diagram showing how the Turbo Cache Server works within our actions 87 | during a cache hit: 88 | 89 | ```mermaid 90 | sequenceDiagram 91 | actor A as Developer 92 | participant B as GitHub 93 | participant C as GitHub Actions 94 | participant D as Turbo Cache Server 95 | participant E as S3 bucket 96 | A->>+B: Push new commit to GH.
Trigger PR Checks. 97 | B->>+C: Trigger CI pipeline 98 | C->>+D: turborepo cache server via
"use: turbo-cache-server@0.0.2" action 99 | Note right of C: Starts a server instance
in the background. 100 | D-->>-C: Turbo cache server ready 101 | C->>+D: Turborepo executes task
(e.g. test, build) 102 | Note right of C: Cache check on the Turbo cache server
for task hash "1wa2dr3" 103 | D->>+E: Get object with name "1wa2dr3" 104 | E-->>-D: object "1wa2dr3" exists 105 | D-->>-C: Cache hit for task "1wa2dr3" 106 | Note right of C: Replay logs and artifacts
for task 107 | C->>+D: Post-action: Shutdown Turbo Cache Server 108 | D-->>-C: Turbo Cache server terminates safely 109 | C-->>-B: CI pipline complete 110 | B-->>-A: PR Checks done 111 | ``` 112 | 113 | ### What happens when there is a cache miss? 114 | 115 | When a cache isn't yet available, the Turbo Cache Server will handle new uploads 116 | and store the artifacts in S3 as you can see in the following diagram: 117 | 118 | ```mermaid 119 | sequenceDiagram 120 | actor A as Developer 121 | participant B as GitHub 122 | participant C as GitHub Actions 123 | participant D as Turbo Cache Server 124 | participant E as S3 bucket 125 | A->>+B: Push new commit to GH.
Trigger PR Checks. 126 | B->>+C: Trigger CI pipeline 127 | C->>+D: turborepo cache server via
"use: turbo-cache-server@0.0.2" action 128 | Note right of C: Starts a server instance
in the background. 129 | D-->>-C: Turborepo cache server ready 130 | C->>+D: Turborepo executes build task 131 | Note right of C: Cache check on the server
for task hash "1wa2dr3" 132 | D->>+E: Get object with name "1wa2dr3" 133 | E-->>-D: object "1wa2dr3" DOES NOT exist 134 | D-->>-C: Cache miss for task "1wa2dr3" 135 | Note right of C: Turborepo executes task normaly 136 | C-->>C: Turborepo executes build task 137 | C->>+D: Turborepo uploads cache artifact
with hash "1wa2dr3" 138 | D->>+E: Put object with name "1wa2dr3" 139 | E->>-D: Object stored 140 | D-->>-C: Cache upload complete 141 | C->>+D: Post-action: Turbo Cache Server shutdown 142 | D-->>-C: Turbo Cache server terminates safely 143 | C-->>-B: CI pipline complete 144 | B-->>-A: PR Checks done 145 | ``` 146 | 147 | ## Development 148 | 149 | Turbo Cache Server requires [Rust](https://www.rust-lang.org/) 1.75 or above. To 150 | setup your environment, use the rustup script as recommended by the 151 | [Rust docs](https://www.rust-lang.org/learn/get-started): 152 | 153 | ```shell 154 | curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh 155 | ``` 156 | 157 | Now run the following command to run the web server locally: 158 | 159 | ```shell 160 | cargo run 161 | ``` 162 | 163 | ### Setting up your environment 164 | 165 | During local development, you might want to try the Turbo Dev Server locally 166 | against a JS monorepo. As it depends on a S3-compatible service for storing 167 | Turborepo artifacts, we recommend using [Minio](https://min.io/) with Docker 168 | with the following command: 169 | 170 | ```shell 171 | docker run \ 172 | -d \ 173 | -p 9000:9000 \ 174 | -p 9001:9001 \ 175 | --user $(id -u):$(id -g) \ 176 | --name minio1 \ 177 | -e "MINIO_ROOT_USER=minio" \ 178 | -e "MINIO_ROOT_PASSWORD=minio12345" \ 179 | -v ./s3_data:/data \ 180 | quay.io/minio/minio server /data --console-address ":9001" 181 | ``` 182 | 183 | #### Setting up environment variables 184 | 185 | Copy the `.env.example` file, rename it to `.env` and add the environment 186 | variables required. As we use Minio locally, just go to the 187 | [Web UI](http://localhost:9001) of Minio, create a bucket and generate 188 | credentials and copy it to the `.env` file. 189 | 190 | ### Tests 191 | 192 | To execute the test suite, run: 193 | 194 | ```shell 195 | cargo test 196 | ``` 197 | 198 | While running our end-to-end tests, you might run into the following error: 199 | 200 | ```log 201 | thread 'actix-server worker 9' panicked at /src/index.crates.io-6f17d22bba15001f/actix-server-2.4.0/src/worker.rs:404:34: 202 | called `Result::unwrap()` on an `Err` value: Os { code: 24, kind: Uncategorized, message: "Too many open files" } 203 | thread 'artifacts::list_team_artifacts_test' panicked at tests/e2e/artifacts.rs:81:29: 204 | Failed to request /v8/artifacts 205 | ``` 206 | 207 | This is likely due the the maximum number of open file descriptors defined for 208 | your user. Just run the following command to fix it: 209 | 210 | ```shell 211 | ulimit -n 1024 212 | ``` 213 | -------------------------------------------------------------------------------- /action.yml: -------------------------------------------------------------------------------- 1 | name: "Turbo Cache Server" 2 | description: "Turborepo remote cache server background process as Action" 3 | 4 | runs: 5 | using: "node20" 6 | main: "action/main.mjs" 7 | post: "action/post.mjs" 8 | -------------------------------------------------------------------------------- /action/main.mjs: -------------------------------------------------------------------------------- 1 | import { spawn } from 'node:child_process' 2 | import { resolve } from 'node:path' 3 | import { LOGS_DIR, DECAY_PID_KEY, saveState } from './util.mjs' 4 | 5 | const __dirname = new URL('.', import.meta.url).pathname 6 | const serverBinary = resolve(__dirname, './decay') 7 | 8 | const decayProcess = spawn(serverBinary, [], { 9 | detached: true, 10 | stdio: 'ignore', 11 | env: { 12 | ...process.env, 13 | LOGS_DIRECTORY: LOGS_DIR, 14 | }, 15 | }) 16 | 17 | decayProcess.unref() 18 | 19 | const pid = decayProcess.pid?.toString() 20 | 21 | console.log(` 22 | Turbo Cache Server running with pid: "${pid}" 23 | Web server logs are being written at "${LOGS_DIR}" 24 | `) 25 | 26 | saveState(DECAY_PID_KEY, pid) 27 | process.exit(0) 28 | -------------------------------------------------------------------------------- /action/post.mjs: -------------------------------------------------------------------------------- 1 | import * as fs from 'node:fs' 2 | import * as path from 'node:path' 3 | import { getState, LOGS_DIR, DECAY_PID_KEY, isProcessRunning, sleep } from './util.mjs' 4 | 5 | let pid = getState(DECAY_PID_KEY) 6 | 7 | if (typeof pid === 'undefined') { 8 | console.error(`${DECAY_PID_KEY} state could not be found. Exiting...`) 9 | process.exit(1) 10 | } 11 | 12 | pid = parseInt(pid) 13 | 14 | console.log(`Turbo Cache Server will be stopped on pid: ${pid}`) 15 | 16 | process.kill(pid, 'SIGTERM') 17 | 18 | const maxProcessCheckAttempts = 20 19 | const sleepTimeInMills = 500 20 | let killCounter = 0 21 | while (isProcessRunning(pid)) { 22 | if (killCounter >= maxProcessCheckAttempts) { 23 | console.error('Taking too long to stop. Killing it directly') 24 | process.kill(pid, 'SIGKILL') 25 | break 26 | } 27 | console.log(`Server is shutting down. Waiting ${sleepTimeInMills}ms...`) 28 | await sleep(sleepTimeInMills) 29 | killCounter = killCounter + 1 30 | } 31 | 32 | // Read logs and output it as-is so we can debug 33 | // any potential errors during the Turborepo remote cache API calls. 34 | // Logs are written on a "{crate_name}.log" file 35 | const logFile = path.resolve(LOGS_DIR, 'decay.log') 36 | console.log(`Reading Turbo Cache Server logs from ${logFile}`) 37 | const serverLogs = fs.readFileSync(logFile, { encoding: 'utf-8' }) 38 | console.log(serverLogs) 39 | 40 | process.exit(0) -------------------------------------------------------------------------------- /action/util.mjs: -------------------------------------------------------------------------------- 1 | import * as fs from 'node:fs' 2 | import * as os from 'node:os' 3 | import * as path from 'node:path' 4 | 5 | /** 6 | * Read state value from the Github injected values 7 | * @param {string} key 8 | * @returns 9 | */ 10 | export function getState(key) { 11 | const githubKey = `STATE_${key}` 12 | return process.env[githubKey] 13 | } 14 | 15 | /** 16 | * Append state to the Github state file 17 | * which can be read on subsequent Github Action commands 18 | * @param {string} key 19 | * @param {string} value 20 | */ 21 | export function saveState(key, value) { 22 | const state = `${key}=${value}` 23 | const stateFilePath = process.env.GITHUB_STATE 24 | if (typeof stateFilePath !== 'string') { 25 | throw new Error('GITHUB_STATE file not available') 26 | } 27 | fs.appendFileSync(stateFilePath, state) 28 | } 29 | 30 | /** 31 | * Check whether the given process ID is still running 32 | * @param {number} pid 33 | */ 34 | export function isProcessRunning(pid) { 35 | try { 36 | // If sig is 0, then no signal is sent, but existence and permission 37 | // checks are still performed; this can be used to check for the 38 | // existence of a process ID or process group ID that the caller is 39 | // permitted to signal. 40 | // See: https://man7.org/linux/man-pages/man2/kill.2.html 41 | return process.kill(pid, 0) 42 | } catch (error) { 43 | return error.code === 'EPERM' 44 | } 45 | } 46 | 47 | /** 48 | * Sleep for the given time in milliseconds 49 | * @param {number} timeInMills 50 | */ 51 | export function sleep(timeInMills) { 52 | return new Promise(resolve => setTimeout(resolve, timeInMills)) 53 | } 54 | 55 | export const LOGS_DIR = path.resolve(os.tmpdir(), 'decay_logs') 56 | export const DECAY_PID_KEY = 'DECAY_SERVER_PID' -------------------------------------------------------------------------------- /icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunojppb/turbo-cache-server/6c56322b968ffa326a4a09fbb7f2865aa9c2cf98/icon.png -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "extends": [ 4 | "config:recommended" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /src/app_settings.rs: -------------------------------------------------------------------------------- 1 | use std::env; 2 | 3 | #[derive(Clone)] 4 | pub struct AppSettings { 5 | pub port: u16, 6 | /// The maximum size allowed for payloads 7 | /// uploaded by Turborepo. Defaults to 100MB. 8 | pub max_payload_size_in_bytes: usize, 9 | pub s3_access_key: Option, 10 | pub s3_secret_key: Option, 11 | pub s3_endpoint: Option, 12 | /// if your S3-compatible store does not support requests 13 | /// like https://bucket.hostname.domain/. Setting `s3_use_path_style` 14 | /// to true configures the S3 client to make requests like 15 | /// https://hostname.domain/bucket instead. 16 | pub s3_use_path_style: bool, 17 | pub s3_region: String, 18 | pub s3_bucket_name: String, 19 | } 20 | 21 | pub fn get_settings() -> AppSettings { 22 | let port = env::var("PORT") 23 | .unwrap_or("8000".to_string()) 24 | .parse::() 25 | .expect("Could not read PORT from env"); 26 | 27 | let s3_access_key = env::var("S3_ACCESS_KEY").ok(); 28 | let s3_secret_key = env::var("S3_SECRET_KEY").ok(); 29 | let s3_region = env::var("S3_REGION").unwrap_or("eu-central-1".to_owned()); 30 | let s3_endpoint = env::var("S3_ENDPOINT").ok(); 31 | let s3_use_path_style = env::var("S3_USE_PATH_STYLE") 32 | .map(|v| v == "true" || v == "1") 33 | .unwrap_or(false); 34 | 35 | // by default,we scope Turborepo artifacts using the "TURBO_TEAM" name sent by turborepo 36 | // which creates a folder within the S3 bucket and uploads everything under that. 37 | let s3_bucket_name = env::var("S3_BUCKET_NAME").unwrap_or("turbo".to_owned()); 38 | 39 | let payload_in_mb = env::var("MAX_PAYLOAD_SIZE_IN_MB").unwrap_or("100".to_string()); 40 | 41 | let max_payload_size_in_bytes = payload_in_mb 42 | .parse::() 43 | .map(|size_in_mb| size_in_mb * 1024 * 1024) 44 | .unwrap_or_else(|_| { 45 | panic!( 46 | "Invalid value given for MAX_PAYLOAD_SIZE_IN_MB: \"{}\"", 47 | payload_in_mb 48 | ) 49 | }); 50 | 51 | AppSettings { 52 | port, 53 | max_payload_size_in_bytes, 54 | s3_access_key, 55 | s3_secret_key, 56 | s3_region, 57 | s3_endpoint, 58 | s3_bucket_name, 59 | s3_use_path_style, 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod app_settings; 2 | pub mod routes; 3 | pub mod startup; 4 | pub mod storage; 5 | pub mod telemetry; 6 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | use std::net::TcpListener; 2 | 3 | use decay::{ 4 | app_settings::get_settings, 5 | telemetry::{get_telemetry_subscriber, init_telemetry_subscriber}, 6 | }; 7 | 8 | const PKG_NAME: &str = env!("CARGO_PKG_NAME"); 9 | 10 | #[tokio::main] 11 | async fn main() -> Result<(), std::io::Error> { 12 | dotenv::dotenv().ok(); 13 | 14 | // Initialise our logger and telemetry stack 15 | // for entire lifecycle of our web server 16 | let subscriber = get_telemetry_subscriber(PKG_NAME, "info".into(), std::io::stdout); 17 | init_telemetry_subscriber(subscriber); 18 | 19 | let app_settings = get_settings(); 20 | let address = format!("127.0.0.1:{}", app_settings.port); 21 | let listener = TcpListener::bind(address)?; 22 | 23 | decay::startup::run(listener, app_settings)?.await 24 | } 25 | -------------------------------------------------------------------------------- /src/routes/artifacts.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashMap; 2 | 3 | use actix_web::{ 4 | HttpRequest, HttpResponse, Responder, 5 | web::{Bytes, Data, Query}, 6 | }; 7 | use futures::StreamExt; 8 | use serde::Serialize; 9 | 10 | use crate::storage::Storage; 11 | 12 | #[derive(Serialize)] 13 | struct Artifact { 14 | filename: String, 15 | } 16 | 17 | #[derive(Serialize)] 18 | struct PostTeamArtifactsResponse { 19 | hashes: Vec, 20 | } 21 | 22 | const EMPTY_HASHES: PostTeamArtifactsResponse = PostTeamArtifactsResponse { hashes: vec![] }; 23 | 24 | /// As of now, we do not need to list all artifacts for a given 25 | /// team. This seems to be an Admin endpoint for Vercel to map/reduce 26 | /// on the artifacts for a given team and report metrics. 27 | #[tracing::instrument(name = "List team artifacts", skip(req))] 28 | pub async fn post_list_team_artifacts(req: HttpRequest) -> impl Responder { 29 | let team = extract_team_from_req(&req); 30 | 31 | tracing::info!(team = team, "Listing team artifacts"); 32 | 33 | HttpResponse::Ok().json(&EMPTY_HASHES) 34 | } 35 | 36 | #[tracing::instrument(name = "Check artifact presence", skip(req, storage))] 37 | pub async fn head_check_file(req: HttpRequest, storage: Data) -> impl Responder { 38 | let artifact_info = match ArtifactRequest::from(&req) { 39 | Some(info) => info, 40 | None => return HttpResponse::NotFound().finish(), 41 | }; 42 | 43 | match storage.file_exists(&artifact_info.file_path()).await { 44 | true => HttpResponse::Ok().finish(), 45 | false => HttpResponse::NotFound().finish(), 46 | } 47 | } 48 | 49 | #[tracing::instrument(name = "Store turbo artifact", skip(storage, body))] 50 | pub async fn put_file(req: HttpRequest, storage: Data, body: Bytes) -> impl Responder { 51 | let artifact_info = match ArtifactRequest::from(&req) { 52 | Some(info) => info, 53 | None => return HttpResponse::BadRequest().finish(), 54 | }; 55 | match storage.put_file(&artifact_info.file_path(), &body).await { 56 | Ok(_) => { 57 | let artifact = Artifact { 58 | filename: artifact_info.hash.clone(), 59 | }; 60 | 61 | HttpResponse::Created().json(artifact) 62 | } 63 | Err(error) => { 64 | tracing::error!("Could not store file error={}", error); 65 | HttpResponse::BadRequest().finish() 66 | } 67 | } 68 | } 69 | 70 | #[tracing::instrument(name = "Read turbo artifact", skip(storage))] 71 | pub async fn get_file(req: HttpRequest, storage: Data) -> impl Responder { 72 | let artifact_info = match ArtifactRequest::from(&req) { 73 | Some(info) => info, 74 | None => return HttpResponse::NotFound().finish(), 75 | }; 76 | 77 | let Some(response) = storage.get_file(&artifact_info.file_path()).await else { 78 | return HttpResponse::NotFound().finish(); 79 | }; 80 | 81 | let stream = response.bytes.map(|maybe_chunk| match maybe_chunk { 82 | Ok(bytes) => Result::::Ok(bytes), 83 | Err(error) => { 84 | tracing::error!(error = error.to_string(), "Chunk stream error"); 85 | Result::::Err(actix_web::error::ErrorBadRequest( 86 | "Error while streaming artifact", 87 | )) 88 | } 89 | }); 90 | 91 | HttpResponse::Ok().streaming(stream) 92 | } 93 | 94 | fn extract_team_from_req(req: &HttpRequest) -> String { 95 | let query_string = Query::>::from_query(req.query_string()).unwrap(); 96 | let default_team_name = "no_team".to_owned(); 97 | query_string 98 | .get("slug") 99 | .or_else(|| query_string.get("teamId")) 100 | .unwrap_or(&default_team_name) 101 | .to_string() 102 | } 103 | 104 | struct ArtifactRequest { 105 | hash: String, 106 | team: String, 107 | } 108 | 109 | impl ArtifactRequest { 110 | /// File path as represented in the S3 storage 111 | fn file_path(&self) -> String { 112 | format!("/{}/{}", self.team, self.hash) 113 | } 114 | 115 | fn from(req: &HttpRequest) -> Option { 116 | let hash = match req.match_info().get("hash") { 117 | Some(h) => h.to_owned(), 118 | None => return None, 119 | }; 120 | 121 | let team = extract_team_from_req(req); 122 | 123 | Some(ArtifactRequest { hash, team }) 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /src/routes/events.rs: -------------------------------------------------------------------------------- 1 | use actix_web::{HttpResponse, Responder}; 2 | 3 | // @TODO: Turborepo post specific events for metrics 4 | // collections to this endpoint. For now, we just ignore it, 5 | // but would be interesting to gather these metrics 6 | #[tracing::instrument(name = "Record Turbo event")] 7 | pub async fn post_events() -> impl Responder { 8 | HttpResponse::Created().finish() 9 | } 10 | -------------------------------------------------------------------------------- /src/routes/health_check.rs: -------------------------------------------------------------------------------- 1 | use actix_web::{HttpResponse, Responder}; 2 | 3 | pub async fn health_check() -> impl Responder { 4 | HttpResponse::Ok().finish() 5 | } 6 | -------------------------------------------------------------------------------- /src/routes/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod artifacts; 2 | pub mod events; 3 | pub mod health_check; 4 | 5 | pub use artifacts::*; 6 | pub use events::*; 7 | pub use health_check::*; 8 | -------------------------------------------------------------------------------- /src/startup.rs: -------------------------------------------------------------------------------- 1 | use actix_web::{App, HttpServer, dev::Server, middleware::Logger, web}; 2 | use std::net::TcpListener; 3 | 4 | use crate::{ 5 | app_settings::AppSettings, 6 | routes::{ 7 | get_file, head_check_file, health_check, post_events, post_list_team_artifacts, put_file, 8 | }, 9 | storage::Storage, 10 | }; 11 | 12 | pub fn run(listener: TcpListener, app_settings: AppSettings) -> Result { 13 | let storage = Storage::new(&app_settings); 14 | let storage = web::Data::new(storage); 15 | let port = listener 16 | .local_addr() 17 | .expect("TCPListener should be valid") 18 | .port(); 19 | let server = HttpServer::new(move || { 20 | App::new() 21 | .wrap(Logger::default()) 22 | .route("/management/health", web::get().to(health_check)) 23 | .route("/v8/artifacts/status", web::get().to(health_check)) 24 | .route("/v8/artifacts", web::post().to(post_list_team_artifacts)) 25 | .route("/v8/artifacts/events", web::post().to(post_events)) 26 | .route("/v8/artifacts/{hash}", web::put().to(put_file)) 27 | .route("/v8/artifacts/{hash}", web::get().to(get_file)) 28 | .route("/v8/artifacts/{hash}", web::head().to(head_check_file)) 29 | .app_data(storage.clone()) 30 | .app_data(actix_web::web::PayloadConfig::new( 31 | app_settings.max_payload_size_in_bytes, 32 | )) 33 | }) 34 | .listen(listener)? 35 | .run(); 36 | 37 | tracing::info!(port = port, "Decay server started"); 38 | 39 | Ok(server) 40 | } 41 | -------------------------------------------------------------------------------- /src/storage.rs: -------------------------------------------------------------------------------- 1 | use s3::{Bucket, Region, creds::Credentials, request::ResponseDataStream}; 2 | 3 | use crate::app_settings::AppSettings; 4 | 5 | pub struct Storage { 6 | bucket: Box, 7 | } 8 | 9 | impl Storage { 10 | pub fn new(settings: &AppSettings) -> Self { 11 | let region = match &settings.s3_endpoint { 12 | Some(endpoint) => Region::Custom { 13 | endpoint: endpoint.clone(), 14 | region: settings.s3_region.clone(), 15 | }, 16 | None => settings 17 | .s3_region 18 | .parse() 19 | .expect("AWS region should be present"), 20 | }; 21 | 22 | let credentials = match (&settings.s3_access_key, &settings.s3_secret_key) { 23 | (Some(access_key), Some(secret_key)) => { 24 | Credentials::new(Some(access_key), Some(secret_key), None, None, None).unwrap() 25 | } 26 | // If your Credentials are handled via IAM policies and allow 27 | // your network to access S3 directly without any credentials setup 28 | // Then no need to setup credentials at all. Defaults should be fine 29 | _ => Credentials::default().expect("Could not use default AWS credentials"), 30 | }; 31 | 32 | let mut bucket = Bucket::new(&settings.s3_bucket_name, region, credentials) 33 | .expect("Could not create a S3 bucket"); 34 | 35 | if settings.s3_use_path_style { 36 | bucket.set_path_style() 37 | } 38 | 39 | Self { bucket } 40 | } 41 | 42 | /// Streams the file from the S3 bucket 43 | pub async fn get_file(&self, path: &str) -> Option { 44 | let maybe_file = self.bucket.get_object_stream(path).await; 45 | maybe_file.ok() 46 | } 47 | 48 | /// Stores the given data in the S3 bucket under the given path 49 | pub async fn put_file(&self, path: &str, data: &[u8]) -> Result<(), String> { 50 | match self.bucket.put_object(path, data).await { 51 | Ok(_response) => Ok(()), 52 | Err(e) => Err(format!("Could not upload file: {}", e)), 53 | } 54 | } 55 | 56 | /// Checks whether the given file path exists on the S3 bucket 57 | pub async fn file_exists(&self, path: &str) -> bool { 58 | self.bucket.head_object(path).await.is_ok() 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/telemetry.rs: -------------------------------------------------------------------------------- 1 | use std::env; 2 | 3 | use tracing::{Subscriber, subscriber::set_global_default}; 4 | use tracing_bunyan_formatter::{BunyanFormattingLayer, JsonStorageLayer}; 5 | use tracing_log::LogTracer; 6 | use tracing_subscriber::{ 7 | EnvFilter, 8 | fmt::{self, MakeWriter}, 9 | layer::SubscriberExt, 10 | }; 11 | 12 | pub fn get_telemetry_subscriber( 13 | name: &str, 14 | env_filter: String, 15 | sink: Sink, 16 | ) -> impl Subscriber + Send + Sync 17 | where 18 | Sink: for<'a> MakeWriter<'a> + Send + Sync + 'static, 19 | { 20 | let env_filter = 21 | EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new(env_filter)); 22 | let formatting_layer = BunyanFormattingLayer::new(name.into(), sink); 23 | 24 | // Only output logs to a file if the runtime has given an output path 25 | let maybe_file_layer = match env::var("LOGS_DIRECTORY") { 26 | Ok(logs_dir) => { 27 | let file_appender = 28 | tracing_appender::rolling::never(logs_dir, format!("{}.log", &name)); 29 | let file_layer = fmt::layer().with_writer(file_appender); 30 | Some(file_layer) 31 | } 32 | Err(_) => None, 33 | }; 34 | 35 | tracing_subscriber::registry() 36 | .with(env_filter) 37 | .with(JsonStorageLayer) 38 | .with(formatting_layer) 39 | .with(maybe_file_layer) 40 | } 41 | 42 | /// Initialise the telemetry stack by setting up the global 43 | /// default telemetry subscriber. The subscriber will handle log and tracing 44 | /// events based on the pre-configured layers. 45 | pub fn init_telemetry_subscriber(subscriber: impl Subscriber + Send + Sync) { 46 | LogTracer::init().expect("Could not set logger"); 47 | set_global_default(subscriber).expect("Failed to set subscriber"); 48 | } 49 | -------------------------------------------------------------------------------- /tests/e2e/artifacts.rs: -------------------------------------------------------------------------------- 1 | use wiremock::{ 2 | Mock, ResponseTemplate, 3 | matchers::{method, path}, 4 | }; 5 | 6 | use crate::helpers::{TurboArtifactFileMock, spawn_app}; 7 | 8 | #[tokio::test] 9 | async fn upload_artifact_to_s3_test() { 10 | let app = spawn_app().await; 11 | 12 | let client = reqwest::Client::new(); 13 | let file_mock = TurboArtifactFileMock::new(); 14 | 15 | Mock::given(path(format!( 16 | "/{}/{}/{}", 17 | app.bucket_name, file_mock.team, file_mock.file_hash 18 | ))) 19 | .and(method("PUT")) 20 | .respond_with(ResponseTemplate::new(201)) 21 | .mount(&app.storage_server) 22 | .await; 23 | 24 | let response = client 25 | .put(format!( 26 | "{}/v8/artifacts/{}?slug={}", 27 | &app.address, file_mock.file_hash, file_mock.team 28 | )) 29 | .header("Content-Type", "application/octet-stream") 30 | .body(file_mock.file_bytes.clone()) 31 | .send() 32 | .await 33 | .expect("Failed to POST artifact to the cache server"); 34 | 35 | let upload_req = &app.storage_server.received_requests().await.unwrap()[0]; 36 | 37 | // Make sure the uploaded binary is exactly what has been uploaded to S3 38 | assert!(upload_req.body == file_mock.file_bytes); 39 | assert!(response.status() == 201); 40 | } 41 | 42 | #[tokio::test] 43 | async fn download_artifact_from_s3_test() { 44 | let app = spawn_app().await; 45 | 46 | let client = reqwest::Client::new(); 47 | let file_mock = TurboArtifactFileMock::new(); 48 | 49 | Mock::given(path(format!( 50 | "/{}/{}/{}", 51 | app.bucket_name, file_mock.team, file_mock.file_hash 52 | ))) 53 | .and(method("GET")) 54 | .respond_with(ResponseTemplate::new(200).set_body_bytes(file_mock.file_bytes.clone())) 55 | .mount(&app.storage_server) 56 | .await; 57 | 58 | let response = client 59 | .get(format!( 60 | "{}/v8/artifacts/{}?slug={}", 61 | &app.address, file_mock.file_hash, file_mock.team 62 | )) 63 | .send() 64 | .await 65 | .expect("Failed to GET artifact from the cache server"); 66 | 67 | assert!(response.status() == 200); 68 | assert!(response.text().await.unwrap().as_bytes() == file_mock.file_bytes); 69 | } 70 | 71 | #[tokio::test] 72 | async fn list_team_artifacts_test() { 73 | let app = spawn_app().await; 74 | 75 | let client = reqwest::Client::new(); 76 | 77 | let response = client 78 | .post(format!("{}/v8/artifacts", &app.address)) 79 | .send() 80 | .await 81 | .unwrap_or_else(|_| panic!("Failed to request /v8/artifacts")); 82 | 83 | assert_eq!(response.status(), 200); 84 | } 85 | 86 | #[tokio::test] 87 | async fn artifact_exists_test() { 88 | let app = spawn_app().await; 89 | 90 | let client = reqwest::Client::new(); 91 | let file_mock = TurboArtifactFileMock::new(); 92 | 93 | mock_s3_head_req(&app, &file_mock, 200).await; 94 | 95 | let response = client 96 | .head(format!( 97 | "{}/v8/artifacts/{}?slug={}", 98 | &app.address, file_mock.file_hash, file_mock.team 99 | )) 100 | .send() 101 | .await 102 | .expect("Failed to HEAD and check artifact from Sake"); 103 | 104 | assert_eq!(response.status(), 200); 105 | } 106 | 107 | #[tokio::test] 108 | async fn artifact_does_not_exist_test() { 109 | let app = spawn_app().await; 110 | 111 | let client = reqwest::Client::new(); 112 | let file_mock = TurboArtifactFileMock::new(); 113 | 114 | mock_s3_head_req(&app, &file_mock, 404).await; 115 | 116 | let response = client 117 | .head(format!( 118 | "{}/v8/artifacts/{}?slug={}", 119 | &app.address, file_mock.file_hash, file_mock.team 120 | )) 121 | .send() 122 | .await 123 | .expect("Failed to HEAD and check artifact from Sake"); 124 | 125 | assert_eq!(response.status(), 404); 126 | } 127 | 128 | /// A head request must be performed to the S3 bucket 129 | /// to check whether the artifact exists 130 | async fn mock_s3_head_req( 131 | app: &crate::helpers::TestApp, 132 | file_mock: &crate::helpers::TurboArtifactFileMock, 133 | response_code: u16, 134 | ) { 135 | Mock::given(path(format!( 136 | "/{}/{}/{}", 137 | app.bucket_name, file_mock.team, file_mock.file_hash 138 | ))) 139 | .and(method("HEAD")) 140 | .respond_with(ResponseTemplate::new(response_code)) 141 | .mount(&app.storage_server) 142 | .await; 143 | } 144 | -------------------------------------------------------------------------------- /tests/e2e/health_check.rs: -------------------------------------------------------------------------------- 1 | use reqwest::Response; 2 | 3 | use crate::helpers::spawn_app; 4 | 5 | #[tokio::test] 6 | async fn health_check_test() { 7 | let app = spawn_app().await; 8 | 9 | let response = check_endpoint("/management/health", &app).await; 10 | 11 | assert!(response.status().is_success()); 12 | assert_eq!(Some(0), response.content_length()); 13 | } 14 | 15 | #[tokio::test] 16 | async fn turborepo_status_check_test() { 17 | let app = spawn_app().await; 18 | 19 | let response = check_endpoint("/v8/artifacts/status", &app).await; 20 | 21 | assert!(response.status().is_success()); 22 | assert_eq!(Some(0), response.content_length()); 23 | } 24 | 25 | async fn check_endpoint(endpoint: &str, app: &crate::helpers::TestApp) -> Response { 26 | let client = reqwest::Client::new(); 27 | 28 | client 29 | .get(format!("{}{}", &app.address, endpoint)) 30 | .send() 31 | .await 32 | .unwrap_or_else(|_| panic!("Failed to request {}", endpoint)) 33 | } 34 | -------------------------------------------------------------------------------- /tests/e2e/helpers.rs: -------------------------------------------------------------------------------- 1 | use decay::{ 2 | app_settings::get_settings, 3 | telemetry::{get_telemetry_subscriber, init_telemetry_subscriber}, 4 | }; 5 | use dotenv::dotenv; 6 | use std::net::TcpListener; 7 | use std::sync::LazyLock; 8 | 9 | use wiremock::MockServer; 10 | 11 | pub struct TestApp { 12 | /// Address where our app will be listening to HTTP requests. 13 | /// Commonly using 127.0.0.1 during local tests. 14 | pub address: String, 15 | /// Intercept and mock S3 provider APIs 16 | pub storage_server: MockServer, 17 | pub bucket_name: String, 18 | } 19 | 20 | #[allow(clippy::let_underscore_future)] 21 | pub async fn spawn_app() -> TestApp { 22 | dotenv().ok(); 23 | 24 | LazyLock::force(&TRACING); 25 | 26 | let storage_server = MockServer::start().await; 27 | 28 | let listener = TcpListener::bind("127.0.0.1:0").expect("Failed to bind to local address"); 29 | let port = listener.local_addr().unwrap().port(); 30 | let mut app_settings = get_settings(); 31 | let bucket_name = "mock_bucket".to_owned(); 32 | 33 | app_settings.s3_endpoint = Some(storage_server.uri()); 34 | app_settings.s3_use_path_style = true; 35 | app_settings.s3_bucket_name.clone_from(&bucket_name); 36 | 37 | let server = decay::startup::run(listener, app_settings).expect("Could not bind to listener"); 38 | let _ = tokio::spawn(server); 39 | 40 | let address = format!("http://127.0.0.1:{}", port); 41 | TestApp { 42 | address, 43 | storage_server, 44 | bucket_name, 45 | } 46 | } 47 | 48 | static TRACING: LazyLock<()> = LazyLock::new(|| { 49 | let subscriber_name = "test"; 50 | let filter_level = String::from("debug"); 51 | 52 | if std::env::var("TEST_LOG").is_ok() { 53 | let subscriber = get_telemetry_subscriber(subscriber_name, filter_level, std::io::stdout); 54 | init_telemetry_subscriber(subscriber); 55 | } else { 56 | let subscriber = get_telemetry_subscriber(subscriber_name, filter_level, std::io::sink); 57 | init_telemetry_subscriber(subscriber); 58 | } 59 | }); 60 | 61 | /// Helper mock for simulating arbitrary artifacts being 62 | /// uploaded from Turborepo to our cache server 63 | pub(crate) struct TurboArtifactFileMock { 64 | /// Hash generated by turborepo. used as a filename 65 | pub file_hash: String, 66 | /// Bytes representing the uploaded binary file 67 | pub file_bytes: Vec, 68 | /// Team given as the `slug` query string 69 | pub team: String, 70 | } 71 | 72 | impl TurboArtifactFileMock { 73 | pub(crate) fn new() -> Self { 74 | Self { 75 | file_hash: "mock-file-hash".to_owned(), 76 | file_bytes: Vec::from("file-content".as_bytes()), 77 | team: "mock-team".to_owned(), 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /tests/e2e/main.rs: -------------------------------------------------------------------------------- 1 | mod artifacts; 2 | mod health_check; 3 | mod helpers; 4 | --------------------------------------------------------------------------------