diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index f70e588..f0c0baa 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -179,6 +179,18 @@ jobs: echo "$HOME/.cargo/bin" >> $GITHUB_PATH fi + - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 + with: + node-version: "22.15.0" + + - name: Enable pnpm + run: | + corepack enable + corepack prepare pnpm@10.28.2 --activate + + - name: Install JS dependencies + run: pnpm install --ignore-scripts + - name: Install sha256sum (macOS ARM64) if: ${{ runner.os == 'macOS' && runner.arch == 'ARM64' }} shell: bash @@ -293,6 +305,18 @@ jobs: - run: chmod +x ~/.cargo/bin/dist + - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 + with: + node-version: "22.15.0" + + - name: Enable pnpm + run: | + corepack enable + corepack prepare pnpm@10.28.2 --activate + + - name: Install JS dependencies + run: pnpm install --ignore-scripts + - name: Fetch local artifacts uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index fa77085..6b2d321 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -29,6 +29,15 @@ jobs: uses: dtolnay/rust-toolchain@efa25f7f19611383d5b0ccf2d1c8914531636bf9 # master with: toolchain: 1.92.0 + - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 + with: + node-version: "22.15.0" + - name: Enable pnpm + run: | + corepack enable + corepack prepare pnpm@10.28.2 --activate + - name: Install JS dependencies + run: pnpm install --ignore-scripts - name: Run auth unit tests run: cargo test auth::tests -- --nocapture @@ -106,5 +115,14 @@ jobs: with: python-version: ${{ matrix.python-version }} - uses: astral-sh/setup-uv@d4b2f3b6ecc6e67c4457f6d3e41ec42d3d0fcb86 # v5.4.2 + - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 + with: + node-version: "22.15.0" + - name: Enable pnpm + run: | + corepack enable + corepack prepare pnpm@10.28.2 --activate + - name: Install JS dependencies + run: pnpm install --ignore-scripts - name: Run eval fixtures run: cargo test --test eval_fixtures diff --git a/Cargo.lock b/Cargo.lock index cefa77c..94284b6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8,7 +8,7 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f7b0a21988c1bf877cf4759ef5ddaac04c1c9fe808c9142ecb78ba97d97a28a" dependencies = [ - "bitflags", + "bitflags 2.13.0", "bytes", "futures-core", "futures-sink", @@ -21,23 +21,23 @@ dependencies = [ [[package]] name = "actix-http" -version = "3.12.0" +version = "3.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f860ee6746d0c5b682147b2f7f8ef036d4f92fe518251a3a35ffa3650eafdf0e" +checksum = "48e2faa3e7418ed780cca54829d32782a4008a077230f67457caa063415e99c2" dependencies = [ "actix-codec", "actix-rt", "actix-service", "actix-utils", "base64 0.22.1", - "bitflags", + "bitflags 2.13.0", "brotli", "bytes", "bytestring", "derive_more", "encoding_rs", "flate2", - "foldhash", + "foldhash 0.2.0", "futures-core", "h2", "http 0.2.12", @@ -49,8 +49,8 @@ dependencies = [ "mime", "percent-encoding", "pin-project-lite", - "rand 0.9.2", - "sha1", + "rand 0.10.2", + "sha1 0.11.0", "smallvec", "tokio", "tokio-util", @@ -65,7 +65,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e01ed3140b2f8d422c68afa1ed2e85d996ea619c988ac834d255db32138655cb" dependencies = [ "quote", - "syn", + "syn 2.0.118", ] [[package]] @@ -132,9 +132,9 @@ dependencies = [ [[package]] name = "actix-web" -version = "4.13.0" +version = "4.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff87453bc3b56e9b2b23c1cc0b1be8797184accf51d2abe0f8a33ec275d316bf" +checksum = "df09e2d9239703dd64056359c920c7f3fba6535ec61a0059e0f44e095ffe02b4" dependencies = [ "actix-codec", "actix-http", @@ -151,7 +151,7 @@ dependencies = [ "cookie", "derive_more", "encoding_rs", - "foldhash", + "foldhash 0.2.0", "futures-core", "futures-util", "impl-more", @@ -164,10 +164,10 @@ dependencies = [ "regex", "regex-lite", "serde", - "serde_json 1.0.149", + "serde_json 1.0.150", "serde_urlencoded", "smallvec", - "socket2 0.6.2", + "socket2 0.6.4", "time", "tracing", "url", @@ -182,7 +182,7 @@ dependencies = [ "actix-router", "proc-macro2", "quote", - "syn", + "syn 2.0.118", ] [[package]] @@ -191,6 +191,18 @@ version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" +[[package]] +name = "ahash" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" +dependencies = [ + "cfg-if", + "once_cell", + "version_check", + "zerocopy", +] + [[package]] name = "aho-corasick" version = "1.1.4" @@ -208,9 +220,9 @@ checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3" [[package]] name = "alloc-stdlib" -version = "0.2.2" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94fb8275041c72129eb51b7d0322c29b8387a0386127718b096429201a5d6ece" +checksum = "0e76a019e91224d279006ff972f1e984179a6e9feb050adba6ce8274aef23195" dependencies = [ "alloc-no-stdlib", ] @@ -232,9 +244,9 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.21" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a" +checksum = "824a212faf96e9acacdbd09febd34438f8f711fb84e09a8916013cd7815ca28d" dependencies = [ "anstyle", "anstyle-parse", @@ -247,15 +259,15 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.13" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" +checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000" [[package]] name = "anstyle-parse" -version = "0.2.7" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" +checksum = "52ce7f38b242319f7cabaa6813055467063ecdc9d355bbb4ce0c68908cd8130e" dependencies = [ "utf8parse", ] @@ -282,19 +294,43 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.102" +version = "1.0.103" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a4385e2e34eb35d6b3efe798b9eb88096925d87726c0798709bf56d9ed84af3" + +[[package]] +name = "approx" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cab112f0a86d568ea0e627cc1d6be74a1e9cd55214684db5561995f6dad897c6" +dependencies = [ + "num-traits", +] + +[[package]] +name = "ar_archive_writer" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" +checksum = "4087686b4b0a3427190bae57a1d9a478dbb2d40c5dc1bd6e2b6d797913bdd348" +dependencies = [ + "object", +] [[package]] name = "arc-swap" -version = "1.9.1" +version = "1.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a3a1fd6f75306b68087b831f025c712524bcb19aad54e557b1129cfa0a2b207" +checksum = "c049c0be4daef0b145cb3555416b3b8ef5b7888a38aea1a3a155801fe7b0810b" dependencies = [ "rustversion", ] +[[package]] +name = "ascii" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d92bec98840b8f03a5ff5413de5293bfcd8bf96467cf5452609f939ec6f5de16" + [[package]] name = "assert-json-diff" version = "2.0.2" @@ -302,14 +338,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "47e4f2b81832e72834d7518d8487a0396a28cc408186a2e8854c0f98011faf12" dependencies = [ "serde", - "serde_json 1.0.149", + "serde_json 1.0.150", ] [[package]] name = "assert_cmd" -version = "2.2.0" +version = "2.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a686bbee5efb88a82df0621b236e74d925f470e5445d3220a5648b892ec99c9" +checksum = "2aa3a22042e45de04255c7bf3626e239f450200fd0493c1e382263544b20aea6" dependencies = [ "anstyle", "bstr", @@ -320,11 +356,22 @@ dependencies = [ "wait-timeout", ] +[[package]] +name = "ast_node" +version = "5.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2eb025ef00a6da925cf40870b9c8d008526b6004ece399cb0974209720f0b194" +dependencies = [ + "quote", + "swc_macros_common", + "syn 2.0.118", +] + [[package]] name = "async-compression" -version = "0.4.41" +version = "0.4.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0f9ee0f6e02ffd7ad5816e9464499fba7b3effd01123b515c41d1697c43dad1" +checksum = "e79b3f8a79cccc2898f31920fc69f304859b3bd567490f75ebf51ae1c792a9ac" dependencies = [ "compression-codecs", "compression-core", @@ -340,7 +387,16 @@ checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.118", +] + +[[package]] +name = "atomic" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a89cbf775b137e9b968e67227ef7f775587cde3fd31b0d8599dbd0f598a48340" +dependencies = [ + "bytemuck", ] [[package]] @@ -349,11 +405,22 @@ version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" +[[package]] +name = "auto_impl" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffdcb70bdbc4d478427380519163274ac86e52916e10f0a8889adf0f96d3fee7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.118", +] + [[package]] name = "autocfg" -version = "1.5.0" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" +checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53" [[package]] name = "backoff" @@ -365,7 +432,7 @@ dependencies = [ "getrandom 0.2.17", "instant", "pin-project-lite", - "rand 0.8.5", + "rand 0.8.6", "tokio", ] @@ -387,6 +454,25 @@ version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" +[[package]] +name = "base64-simd" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "339abbe78e73178762e23bea9dfd08e697eb3f3301cd4be981c0f78ba5859195" +dependencies = [ + "outref", + "vsimd", +] + +[[package]] +name = "better_scoped_tls" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cd228125315b132eed175bf47619ac79b945b26e56b848ba203ae4ea8603609" +dependencies = [ + "scoped-tls", +] + [[package]] name = "big_serde_json" version = "0.1.0" @@ -396,11 +482,32 @@ dependencies = [ "ts-rs", ] +[[package]] +name = "bit-set" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" + [[package]] name = "bitflags" -version = "2.11.0" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" +checksum = "b4388bee8683e3d04af747c73422af53102d2bd24d9eadb6cbc100baef4b43f8" [[package]] name = "block-buffer" @@ -411,11 +518,20 @@ dependencies = [ "generic-array", ] +[[package]] +name = "block-buffer" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2f6c7dbe95a6ed67ad9f18e57daf93a2f034c524b99fd2b76d18fdfeb6660aa" +dependencies = [ + "hybrid-array", +] + [[package]] name = "bon" -version = "3.9.1" +version = "3.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f47dbe92550676ee653353c310dfb9cf6ba17ee70396e1f7cf0a2020ad49b2fe" +checksum = "a602c73c7b0148ec6d12af6fd5cc7a46e2eacc8878271a999abac56eed12f561" dependencies = [ "bon-macros", "rustversion", @@ -423,17 +539,17 @@ dependencies = [ [[package]] name = "bon-macros" -version = "3.9.1" +version = "3.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "519bd3116aeeb42d5372c29d982d16d0170d3d4a5ed85fc7dd91642ffff3c67c" +checksum = "6dee98b0db6a962de883bf5d20362dee4d7ca0d12fe39a7c6c73c844e1cd7c1f" dependencies = [ - "darling 0.23.0", + "darling", "ident_case", "prettyplease", "proc-macro2", "quote", "rustversion", - "syn", + "syn 2.0.118", ] [[package]] @@ -451,11 +567,11 @@ dependencies = [ "chrono", "crossbeam", "futures", - "indexmap 2.13.0", + "indexmap 2.14.0", "regex", "reqwest", "serde", - "serde_json 1.0.149", + "serde_json 1.0.150", "serde_repr", "thiserror 1.0.69", "tokio", @@ -466,9 +582,9 @@ dependencies = [ [[package]] name = "brotli" -version = "8.0.2" +version = "8.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bd8b9603c7aa97359dbd97ecf258968c95f3adddd6db2f7e7a5bef101c84560" +checksum = "5cc91aac060a7a1e25823bdccbfb6af1875b88f17c6daac97894eed8207166b3" dependencies = [ "alloc-no-stdlib", "alloc-stdlib", @@ -477,23 +593,32 @@ dependencies = [ [[package]] name = "brotli-decompressor" -version = "5.0.0" +version = "5.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "874bb8112abecc98cbd6d81ea4fa7e94fb9449648c93cc89aa40c81c24d7de03" +checksum = "3a32acac15fe1967bc3986b2a6347dffc965602354ea6f450ad07e8bfd253583" dependencies = [ "alloc-no-stdlib", "alloc-stdlib", ] +[[package]] +name = "bs58" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4" +dependencies = [ + "tinyvec", +] + [[package]] name = "bstr" -version = "1.12.1" +version = "1.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63044e1ae8e69f3b5a92c736ca6269b8d12fa7efe39bf34ddb06d102cf0e2cab" +checksum = "5cee35f73844aa3014bb606320a6c1f010249dbdf43342fe54b5a4f6a8ed4b79" dependencies = [ "memchr", "regex-automata", - "serde", + "serde_core", ] [[package]] @@ -523,16 +648,33 @@ dependencies = [ "lingua", "oauth2", "open", + "oxc_allocator", + "oxc_codegen", + "oxc_parser", + "oxc_semantic", + "oxc_span", + "oxc_transformer", "pathdiff", "predicates", "ratatui", "regex", "reqwest", "serde", - "serde_json 1.0.149", + "serde_json 1.0.150", "serde_path_to_error", "sha2", "strip-ansi-escapes", + "swc_atoms", + "swc_bundler", + "swc_common 21.0.2", + "swc_ecma_ast 23.0.1", + "swc_ecma_codegen", + "swc_ecma_loader", + "swc_ecma_parser", + "swc_ecma_transforms_base", + "swc_ecma_transforms_react", + "swc_ecma_transforms_typescript", + "swc_ecma_visit 22.0.0", "tempfile", "tokio", "toml", @@ -544,30 +686,49 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.20.2" +version = "3.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" +dependencies = [ + "allocator-api2", +] + +[[package]] +name = "by_address" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64fa3c856b712db6612c019f14756e64e4bcea13337a6b33b696333a9eaa2d06" + +[[package]] +name = "bytemuck" +version = "1.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" +checksum = "c8efb64bd706a16a1bdde310ae86b351e4d21550d98d056f22f8a7f7a2183fec" [[package]] name = "bytes" -version = "1.11.1" +version = "1.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" +checksum = "fc652a48c352aef3ea3aed32080501cf3ef6ed5da78602a020c991775b0aff04" [[package]] -name = "bytestring" -version = "1.5.0" +name = "bytes-str" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "113b4343b5f6617e7ad401ced8de3cc8b012e73a594347c307b90db3e9271289" +checksum = "577d2bf5650f8554d5a372af5ac93535110a0fc75b3e702bb853369febf227c2" dependencies = [ "bytes", + "serde", ] [[package]] -name = "cassowary" -version = "0.3.0" +name = "bytestring" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df8670b8c7b9dae1793364eafadf7239c40d669904660c5960d74cfd80b46a53" +checksum = "86566c496f2f47d9b8147a4c8b02ffdb69c919fe0c2b2e7195d22cbba0e635c9" +dependencies = [ + "bytes", +] [[package]] name = "castaway" @@ -580,9 +741,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.56" +version = "1.2.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aebf35691d1bfb0ac386a69bac2fde4dd276fb618cf8bf4f5318fe285e821bb2" +checksum = "f5d6cac793997bd970000024b2934968efe83b382de4fdcf4fcb46b6ee4ad996" dependencies = [ "find-msvc-tools", "jobserver", @@ -602,11 +763,22 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" +[[package]] +name = "chacha20" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d524456ba66e72eb8b115ff89e01e497f8e6d11d78b70b1aa13c0fbd97540a81" +dependencies = [ + "cfg-if", + "cpufeatures 0.3.0", + "rand_core 0.10.1", +] + [[package]] name = "chrono" -version = "0.4.44" +version = "0.4.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0" +checksum = "1aa79e62e7697b8e29b513a68abacf485adcd1fe8284a4316c5ae868e6633327" dependencies = [ "iana-time-zone", "js-sys", @@ -618,9 +790,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.60" +version = "4.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2797f34da339ce31042b27d23607e051786132987f595b02ba4f6a6dffb7030a" +checksum = "1ddb117e43bbf7dacf0a4190fef4d345b9bad68dfc649cb349e7d17d28428e51" dependencies = [ "clap_builder", "clap_derive", @@ -628,9 +800,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.60" +version = "4.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24a241312cea5059b13574bb9b3861cabf758b879c15190b37b6d6fd63ab6876" +checksum = "714a53001bf66416adb0e2ef5ac857140e7dc3a0c48fb28b2f10762fc4b5069f" dependencies = [ "anstream", "anstyle", @@ -640,27 +812,36 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.55" +version = "4.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a92793da1a46a5f2a02a6f4c46c6496b28c43638adea8306fcb0caa1634f24e5" +checksum = "f2ce8604710f6733aa641a2b3731eaa1e8b3d9973d5e3565da11800813f997a9" dependencies = [ "heck", "proc-macro2", "quote", - "syn", + "syn 2.0.118", ] [[package]] name = "clap_lex" -version = "1.0.0" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9" + +[[package]] +name = "cobs" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a822ea5bc7590f9d40f1ba12c0dc3c2760f3482c6984db1573ad11031420831" +checksum = "0fa961b519f0b462e3a3b4a34b64d119eeaca1d59af726fe450bbba07a9fc0a1" +dependencies = [ + "thiserror 2.0.18", +] [[package]] name = "colorchoice" -version = "1.0.4" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" +checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570" [[package]] name = "comfy-table" @@ -670,14 +851,27 @@ checksum = "958c5d6ecf1f214b4c2bbbbf6ab9523a864bd136dcf71a7e8904799acfe1ad47" dependencies = [ "crossterm 0.29.0", "unicode-segmentation", - "unicode-width 0.2.0", + "unicode-width 0.2.2", +] + +[[package]] +name = "compact_str" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f86b9c4c00838774a6d902ef931eff7470720c51d90c2e32cfe15dc304737b3f" +dependencies = [ + "castaway", + "cfg-if", + "itoa", + "ryu", + "static_assertions", ] [[package]] name = "compact_str" -version = "0.8.1" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b79c4069c6cad78e2e0cdfcbd26275770669fb39fd308a752dc110e83b9af32" +checksum = "9dfdd1c2274d9aa354115b09dc9a901d6c5576818cdf70d14cae2bdb47df00ab" dependencies = [ "castaway", "cfg-if", @@ -689,9 +883,9 @@ dependencies = [ [[package]] name = "compression-codecs" -version = "0.4.37" +version = "0.4.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb7b51a7d9c967fc26773061ba86150f19c50c0d65c887cb1fbe295fd16619b7" +checksum = "ce2548391e9c1929c21bf6aa2680af86fe4c1b33e6cea9ac1cfeec0bd11218cf" dependencies = [ "compression-core", "flate2", @@ -700,9 +894,9 @@ dependencies = [ [[package]] name = "compression-core" -version = "0.4.31" +version = "0.4.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75984efb6ed102a0d42db99afb6c1948f0380d1d91808d5529916e6c08b49d8d" +checksum = "cc14f565cf027a105f7a44ccf9e5b424348421a1d8952a8fc9d499d313107789" [[package]] name = "console" @@ -713,10 +907,16 @@ dependencies = [ "encode_unicode", "libc", "once_cell", - "unicode-width 0.2.0", + "unicode-width 0.2.2", "windows-sys 0.59.0", ] +[[package]] +name = "const-oid" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6ef517f0926dd24a1582492c791b6a4818a4d94e789a334894aa15b0d12f55c" + [[package]] name = "convert_case" version = "0.10.0" @@ -753,6 +953,12 @@ version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" +[[package]] +name = "cow-utils" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "417bef24afe1460300965a25ff4a24b8b45ad011948302ec221e8a0a81eb2c79" + [[package]] name = "cpufeatures" version = "0.2.17" @@ -762,6 +968,30 @@ dependencies = [ "libc", ] +[[package]] +name = "cpufeatures" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201" +dependencies = [ + "libc", +] + +[[package]] +name = "crc" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49fc9a695bca7f35f5f4c15cddc84415f66a74ea78eef08e90c5024f2b540e23" +dependencies = [ + "crc-catalog", +] + +[[package]] +name = "crc-catalog" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccaeedb56da03b09f598226e25e80088cb4cd25f316e6e4df7d695f0feeb1403" + [[package]] name = "crc32fast" version = "1.5.0" @@ -771,6 +1001,12 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "critical-section" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" + [[package]] name = "crossbeam" version = "0.8.4" @@ -786,18 +1022,18 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.5.15" +version = "0.5.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" +checksum = "d85363c37faeca707aef026efa9f3b34d077bce547e48f770770625c6013679e" dependencies = [ "crossbeam-utils", ] [[package]] name = "crossbeam-deque" -version = "0.8.6" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" +checksum = "5181e0de7b61eb03a81e347d6dd8797bae9da5146707b51077e2d71a54ec0ceb" dependencies = [ "crossbeam-epoch", "crossbeam-utils", @@ -805,27 +1041,27 @@ dependencies = [ [[package]] name = "crossbeam-epoch" -version = "0.9.18" +version = "0.9.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +checksum = "2d6914041f254d6e9176c01941b21115dcfb7089e55135a35411081bd106ef3f" dependencies = [ "crossbeam-utils", ] [[package]] name = "crossbeam-queue" -version = "0.3.12" +version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f58bbc28f91df819d0aa2a2c00cd19754769c2fad90579b3592b1c9ba7a3115" +checksum = "803d13fb3b09d88be9f4dbc29062c66b19bf7170867ceb746d2a8689bf6c7a26" dependencies = [ "crossbeam-utils", ] [[package]] name = "crossbeam-utils" -version = "0.8.21" +version = "0.8.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" +checksum = "61803da095bee82a81bb1a452ecc25d3b2f1416d1897eb86430c6159ef717c17" [[package]] name = "crossterm" @@ -833,7 +1069,7 @@ version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "829d955a0bb380ef178a640b91779e3987da38c9aea133b20614cfed8cdea9c6" dependencies = [ - "bitflags", + "bitflags 2.13.0", "crossterm_winapi", "mio", "parking_lot", @@ -849,11 +1085,15 @@ version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d8b9f2e4c67f833b660cdb0a3523065869fb35570177239812ed4c905aeff87b" dependencies = [ - "bitflags", + "bitflags 2.13.0", "crossterm_winapi", + "derive_more", "document-features", + "mio", "parking_lot", "rustix 1.1.4", + "signal-hook", + "signal-hook-mio", "winapi", ] @@ -877,37 +1117,32 @@ dependencies = [ ] [[package]] -name = "darling" -version = "0.21.3" +name = "crypto-common" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cdf337090841a411e2a7f3deb9187445851f91b309c0c0a29e05f74a00a48c0" +checksum = "ce6e4c961d6cd6c9a86db418387425e8bdeaf05b3c8bc1411e6dca4c252f1453" dependencies = [ - "darling_core 0.21.3", - "darling_macro 0.21.3", + "hybrid-array", ] [[package]] -name = "darling" -version = "0.23.0" +name = "csscolorparser" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25ae13da2f202d56bd7f91c25fba009e7717a1e4a1cc98a76d844b65ae912e9d" +checksum = "eb2a7d3066da2de787b7f032c736763eb7ae5d355f81a68bab2675a96008b0bf" dependencies = [ - "darling_core 0.23.0", - "darling_macro 0.23.0", + "lab", + "phf 0.11.3", ] [[package]] -name = "darling_core" -version = "0.21.3" +name = "darling" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1247195ecd7e3c85f83c8d2a366e4210d588e802133e1e355180a9870b517ea4" +checksum = "25ae13da2f202d56bd7f91c25fba009e7717a1e4a1cc98a76d844b65ae912e9d" dependencies = [ - "fnv", - "ident_case", - "proc-macro2", - "quote", - "strsim", - "syn", + "darling_core", + "darling_macro", ] [[package]] @@ -920,38 +1155,46 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn", + "syn 2.0.118", ] [[package]] name = "darling_macro" -version = "0.21.3" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81" +checksum = "ac3984ec7bd6cfa798e62b4a642426a5be0e68f9401cfc2a01e3fa9ea2fcdb8d" dependencies = [ - "darling_core 0.21.3", + "darling_core", "quote", - "syn", + "syn 2.0.118", ] [[package]] -name = "darling_macro" -version = "0.23.0" +name = "dashmap" +version = "6.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3984ec7bd6cfa798e62b4a642426a5be0e68f9401cfc2a01e3fa9ea2fcdb8d" +checksum = "e6361d5c062261c78a176addb82d4c821ae42bed6089de0e12603cd25de2059c" dependencies = [ - "darling_core 0.23.0", - "quote", - "syn", + "cfg-if", + "crossbeam-utils", + "hashbrown 0.14.5", + "lock_api", + "once_cell", + "parking_lot_core", ] +[[package]] +name = "deltae" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5729f5117e208430e437df2f4843f5e5952997175992d1414f94c57d61e270b4" + [[package]] name = "deranged" version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" dependencies = [ - "powerfmt", "serde_core", ] @@ -974,7 +1217,7 @@ dependencies = [ "proc-macro2", "quote", "rustc_version", - "syn", + "syn 2.0.118", "unicode-xid", ] @@ -1004,8 +1247,19 @@ version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ - "block-buffer", - "crypto-common", + "block-buffer 0.10.4", + "crypto-common 0.1.7", +] + +[[package]] +name = "digest" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1dd6dbb5841937940781866fa1281a1ff7bd3bf827091440879f9994983d5c2" +dependencies = [ + "block-buffer 0.12.1", + "const-oid", + "crypto-common 0.2.2", ] [[package]] @@ -1031,13 +1285,13 @@ dependencies = [ [[package]] name = "displaydoc" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +checksum = "1ac70aa55017e108007fbaf5aa0f54b021c98f92ff8af59d42eda9da96e3dd4f" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.118", ] [[package]] @@ -1055,6 +1309,18 @@ version = "0.15.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" +[[package]] +name = "dragonbox_ecma" +version = "0.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d742b56656e8b14d63e7ea9806597b1849ae25412584c8adf78c0f67bd985e66" + +[[package]] +name = "dragonbox_ecma" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd8e701084c37e7ef62d3f9e453b618130cbc0ef3573847785952a3ac3f746bf" + [[package]] name = "dunce" version = "1.0.5" @@ -1069,9 +1335,21 @@ checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555" [[package]] name = "either" -version = "1.15.0" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" +checksum = "91622ff5e7162018101f2fea40d6ebf4a78bbe5a49736a2020649edf9693679e" + +[[package]] +name = "embedded-io" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef1a6892d9eef45c8fa6b9e0086428a2cca8491aca8f787c534a3d6d0bcb3ced" + +[[package]] +name = "embedded-io" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d" [[package]] name = "encode_unicode" @@ -1105,26 +1383,74 @@ dependencies = [ ] [[package]] -name = "fastrand" -version = "2.3.0" +name = "euclid" +version = "0.22.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" +checksum = "f1a05365e3b1c6d1650318537c7460c6923f1abdd272ad6842baa2b509957a06" +dependencies = [ + "num-traits", +] [[package]] -name = "find-msvc-tools" -version = "0.1.9" +name = "fancy-regex" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" +checksum = "b95f7c0680e4142284cf8b22c14a476e87d61b004a3a0861872b32ef7ead40a2" +dependencies = [ + "bit-set", + "regex", +] [[package]] -name = "fixedbitset" -version = "0.5.7" +name = "fast-srgb8" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99" +checksum = "dd2e7510819d6fbf51a5545c8f922716ecfb14df168a3242f7d33e0239efe6a1" [[package]] -name = "flate2" -version = "1.1.9" +name = "fastrand" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6" + +[[package]] +name = "filedescriptor" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e40758ed24c9b2eeb76c35fb0aebc66c626084edd827e07e1552279814c6682d" +dependencies = [ + "libc", + "thiserror 1.0.69", + "winapi", +] + +[[package]] +name = "find-msvc-tools" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" + +[[package]] +name = "finl_unicode" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9844ddc3a6e533d62bba727eb6c28b5d360921d5175e9ff0f1e621a5c590a4d5" + +[[package]] +name = "fixedbitset" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" + +[[package]] +name = "fixedbitset" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99" + +[[package]] +name = "flate2" +version = "1.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c" dependencies = [ @@ -1153,6 +1479,12 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" +[[package]] +name = "foldhash" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" + [[package]] name = "form_urlencoded" version = "1.2.2" @@ -1162,6 +1494,16 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "from_variant" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5ff35a391aef949120a0340d690269b3d9f63460a6106e99bd07b961f345ea9" +dependencies = [ + "swc_macros_common", + "syn 2.0.118", +] + [[package]] name = "futures" version = "0.3.32" @@ -1218,7 +1560,7 @@ checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.118", ] [[package]] @@ -1289,24 +1631,23 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" dependencies = [ "cfg-if", - "js-sys", "libc", - "r-efi", + "r-efi 5.3.0", "wasip2", - "wasm-bindgen", ] [[package]] name = "getrandom" -version = "0.4.1" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "139ef39800118c7683f2fd3c98c1b23c09ae076556b435f8e9064ae108aaeeec" +checksum = "300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099" dependencies = [ "cfg-if", + "js-sys", "libc", - "r-efi", - "wasip2", - "wasip3", + "r-efi 6.0.0", + "rand_core 0.10.1", + "wasm-bindgen", ] [[package]] @@ -1327,7 +1668,7 @@ dependencies = [ "futures-sink", "futures-util", "http 0.2.12", - "indexmap 2.13.0", + "indexmap 2.14.0", "slab", "tokio", "tokio-util", @@ -1340,6 +1681,16 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +dependencies = [ + "ahash", + "allocator-api2", +] + [[package]] name = "hashbrown" version = "0.15.5" @@ -1347,8 +1698,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" dependencies = [ "allocator-api2", - "equivalent", - "foldhash", + "foldhash 0.1.5", ] [[package]] @@ -1356,6 +1706,22 @@ name = "hashbrown" version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash 0.2.0", +] + +[[package]] +name = "hashbrown" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash 0.2.0", +] [[package]] name = "heck" @@ -1363,12 +1729,32 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" +[[package]] +name = "hermit-abi" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" + [[package]] name = "hex" version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +[[package]] +name = "hstr" +version = "3.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83bb87e4b300d73412f6dcc7022ee7741452b51b155c2b06e5994d0770c2dbe2" +dependencies = [ + "hashbrown 0.14.5", + "new_debug_unreachable", + "once_cell", + "rustc-hash", + "serde", + "triomphe", +] + [[package]] name = "http" version = "0.2.12" @@ -1382,9 +1768,9 @@ dependencies = [ [[package]] name = "http" -version = "1.4.0" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a" +checksum = "6970f50e31d6fc17d3fa27329444bfa74e196cf62e95052a3f6fee181dba6425" dependencies = [ "bytes", "itoa", @@ -1397,7 +1783,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ "bytes", - "http 1.4.0", + "http 1.4.2", ] [[package]] @@ -1408,7 +1794,7 @@ checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" dependencies = [ "bytes", "futures-core", - "http 1.4.0", + "http 1.4.2", "http-body", "pin-project-lite", ] @@ -1425,22 +1811,30 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" +[[package]] +name = "hybrid-array" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "818356c5132c1fede50f837ca96afbe78ff42413047f4abb886217845e1b6c8c" +dependencies = [ + "typenum", +] + [[package]] name = "hyper" -version = "1.8.1" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ab2d4f250c3d7b1c9fcdff1cece94ea4e2dfbec68614f7b87cb205f24ca9d11" +checksum = "55281c53a1894c864990125767da440a4e630446785086f52523b20033b74498" dependencies = [ "atomic-waker", "bytes", "futures-channel", "futures-core", - "http 1.4.0", + "http 1.4.2", "http-body", "httparse", "itoa", "pin-project-lite", - "pin-utils", "smallvec", "tokio", "want", @@ -1448,16 +1842,15 @@ dependencies = [ [[package]] name = "hyper-rustls" -version = "0.27.7" +version = "0.27.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" +checksum = "33ca68d021ef39cf6463ab54c1d0f5daf03377b70561305bb89a8f83aab66e0f" dependencies = [ - "http 1.4.0", + "http 1.4.2", "hyper", "hyper-util", "rustls", "rustls-native-certs", - "rustls-pki-types", "tokio", "tokio-rustls", "tower-service", @@ -1474,14 +1867,14 @@ dependencies = [ "bytes", "futures-channel", "futures-util", - "http 1.4.0", + "http 1.4.2", "http-body", "hyper", "ipnet", "libc", "percent-encoding", "pin-project-lite", - "socket2 0.6.2", + "socket2 0.6.4", "tokio", "tower-service", "tracing", @@ -1513,12 +1906,13 @@ dependencies = [ [[package]] name = "icu_collections" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" +checksum = "2984d1cd16c883d7935b9e07e44071dca8d917fd52ecc02c04d5fa0b5a3f191c" dependencies = [ "displaydoc", "potential_utf", + "utf8_iter", "yoke", "zerofrom", "zerovec", @@ -1526,9 +1920,9 @@ dependencies = [ [[package]] name = "icu_locale_core" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" +checksum = "92219b62b3e2b4d88ac5119f8904c10f8f61bf7e95b640d25ba3075e6cac2c29" dependencies = [ "displaydoc", "litemap", @@ -1539,9 +1933,9 @@ dependencies = [ [[package]] name = "icu_normalizer" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" +checksum = "c56e5ee99d6e3d33bd91c5d85458b6005a22140021cc324cea84dd0e72cff3b4" dependencies = [ "icu_collections", "icu_normalizer_data", @@ -1553,15 +1947,15 @@ dependencies = [ [[package]] name = "icu_normalizer_data" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" +checksum = "da3be0ae77ea334f4da67c12f149704f19f81d1adf7c51cf482943e84a2bad38" [[package]] name = "icu_properties" -version = "2.1.2" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec" +checksum = "bee3b67d0ea5c2cca5003417989af8996f8604e34fb9ddf96208a033901e70de" dependencies = [ "icu_collections", "icu_locale_core", @@ -1573,15 +1967,15 @@ dependencies = [ [[package]] name = "icu_properties_data" -version = "2.1.2" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af" +checksum = "8e2bbb201e0c04f7b4b3e14382af113e17ba4f63e2c9d2ee626b720cbce54a14" [[package]] name = "icu_provider" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" +checksum = "139c4cf31c8b5f33d7e199446eff9c1e02decfc2f0eec2c8d71f65befa45b421" dependencies = [ "displaydoc", "icu_locale_core", @@ -1592,12 +1986,6 @@ dependencies = [ "zerovec", ] -[[package]] -name = "id-arena" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" - [[package]] name = "ident_case" version = "1.0.1" @@ -1617,9 +2005,9 @@ dependencies = [ [[package]] name = "idna_adapter" -version = "1.2.1" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" +checksum = "cb68373c0d6620ef8105e855e7745e18b0d00d3bdb07fb532e434244cdb9a714" dependencies = [ "icu_normalizer", "icu_properties", @@ -1627,9 +2015,9 @@ dependencies = [ [[package]] name = "impl-more" -version = "0.1.9" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8a5a9a0ff0086c7a148acb942baaabeadf9504d10400b5a05645853729b9cd2" +checksum = "35a84fd5aa25fae5c0f4a33d9cac2ca017fc622cbd089be2229993514990f870" [[package]] name = "indexmap" @@ -1644,12 +2032,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.13.0" +version = "2.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" +checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" dependencies = [ "equivalent", - "hashbrown 0.16.1", + "hashbrown 0.17.1", "serde", "serde_core", ] @@ -1663,7 +2051,7 @@ dependencies = [ "console", "number_prefix", "portable-atomic", - "unicode-width 0.2.0", + "unicode-width 0.2.2", "web-time", ] @@ -1678,15 +2066,15 @@ dependencies = [ [[package]] name = "instability" -version = "0.3.11" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "357b7205c6cd18dd2c86ed312d1e70add149aea98e7ef72b9fdf0270e555c11d" +checksum = "5eb2d60ef19920a3a9193c3e371f726ec1dafc045dac788d0fb3704272458971" dependencies = [ - "darling 0.23.0", + "darling", "indoc", "proc-macro2", "quote", - "syn", + "syn 2.0.118", ] [[package]] @@ -1700,27 +2088,29 @@ dependencies = [ [[package]] name = "ipnet" -version = "2.11.0" +version = "2.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" +checksum = "d98f6fed1fde3f8c21bc40a1abb88dd75e67924f9cffc3ef95607bad8017f8e2" [[package]] -name = "iri-string" -version = "0.7.10" +name = "is-docker" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c91338f0783edbd6195decb37bae672fd3b165faffb89bf7b9e6942f8b1a731a" +checksum = "928bae27f42bc99b60d9ac7334e3a21d10ad8f1835a4e12ec3ec0464765ed1b3" dependencies = [ - "memchr", - "serde", + "once_cell", ] [[package]] -name = "is-docker" -version = "0.2.0" +name = "is-macro" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "928bae27f42bc99b60d9ac7334e3a21d10ad8f1835a4e12ec3ec0464765ed1b3" +checksum = "1d57a3e447e24c22647738e4607f1df1e0ec6f72e16182c4cd199f647cdfb0e4" dependencies = [ - "once_cell", + "heck", + "proc-macro2", + "quote", + "syn 2.0.118", ] [[package]] @@ -1759,30 +2149,57 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.17" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" [[package]] name = "jobserver" -version = "0.1.34" +version = "0.1.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" +checksum = "1c00acbd29eabad4a2392fa0e921c874934dbbf4194312ad20f04a0ed67a3cb3" dependencies = [ - "getrandom 0.3.4", + "getrandom 0.4.3", "libc", ] [[package]] name = "js-sys" -version = "0.3.90" +version = "0.3.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14dc6f6450b3f6d4ed5b16327f38fed626d375a886159ca555bd7822c0c3a5a6" +checksum = "53b44bfcdb3f8d5837a46dae1ca9660a837176eee74a28b229bc626816589102" dependencies = [ - "once_cell", + "cfg-if", + "futures-util", "wasm-bindgen", ] +[[package]] +name = "json-escape-simd" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a1f7d5786a4cb0f4e0f862b562a0e085b5bfa23a4f0dc05e7b823ed4e4d791f" +dependencies = [ + "anyhow", +] + +[[package]] +name = "kasuari" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bde5057d6143cc94e861d90f591b9303d6716c6b9602309150bd068853c10899" +dependencies = [ + "hashbrown 0.16.1", + "portable-atomic", + "thiserror 2.0.18", +] + +[[package]] +name = "lab" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf36173d4167ed999940f804952e6b08197cae5ad5d572eb4db150ce8ad5d58f" + [[package]] name = "language-tags" version = "0.3.2" @@ -1790,27 +2207,41 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d4345964bb142484797b161f473a503a434de77149dd8c7427788c6e13379388" [[package]] -name = "leb128fmt" -version = "0.1.0" +name = "lazy_static" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.182" +version = "0.2.186" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" + +[[package]] +name = "libm" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6800badb6cb2082ffd7b6a67e6125bb39f18782f793520caee8cb8846be06112" +checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" [[package]] name = "libredox" -version = "0.1.12" +version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d0b95e02c851351f877147b7deea7b1afb1df71b63aa5f8270716e0c5720616" +checksum = "c943259e342f1e06ff2da7a83eabdfe7f92ce10262688dbf1895ff0b3e6e4652" dependencies = [ - "bitflags", "libc", ] +[[package]] +name = "line-clipping" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f50e8f47623268b5407192d26876c4d7f89d686ca130fdc53bced4814cd29f8" +dependencies = [ + "bitflags 2.13.0", +] + [[package]] name = "lingua" version = "0.1.0" @@ -1829,7 +2260,7 @@ dependencies = [ "reqwest", "serde", "serde-wasm-bindgen", - "serde_json 1.0.149", + "serde_json 1.0.150", "serde_with", "serde_yaml", "thiserror 2.0.18", @@ -1855,9 +2286,9 @@ checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" [[package]] name = "litemap" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" +checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0" [[package]] name = "litrs" @@ -1893,17 +2324,17 @@ dependencies = [ [[package]] name = "log" -version = "0.4.29" +version = "0.4.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" +checksum = "0ceec5bc11778974d1bcb055b18002eba7f4b3518b6a0081b3af5f21666da9ad" [[package]] name = "lru" -version = "0.12.5" +version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38" +checksum = "0b6180140927ee907000b0aa540091f6ea512ead4447c92b8fc35bc72788a5a6" dependencies = [ - "hashbrown 0.15.5", + "hashbrown 0.17.1", ] [[package]] @@ -1912,11 +2343,36 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" +[[package]] +name = "mac_address" +version = "1.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0aeb26bf5e836cc1c341c8106051b573f1766dfa05aa87f0b98be5e51b02303" +dependencies = [ + "nix", + "winapi", +] + [[package]] name = "memchr" -version = "2.8.0" +version = "2.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98" + +[[package]] +name = "memmem" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a64a92489e2744ce060c349162be1c5f33c6969234104dbd99ddb5feb08b8c15" + +[[package]] +name = "memoffset" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" +checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" +dependencies = [ + "autocfg", +] [[package]] name = "mime" @@ -1934,6 +2390,12 @@ dependencies = [ "unicase", ] +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + [[package]] name = "miniz_oxide" version = "0.8.9" @@ -1946,9 +2408,9 @@ dependencies = [ [[package]] name = "mio" -version = "1.1.1" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc" +checksum = "02bd0af71c67b473010cbbc60715ee815645a4dc942899111f494b4b737d6fda" dependencies = [ "libc", "log", @@ -1963,1089 +2425,2384 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d87ecb2933e8aeadb3e3a02b828fed80a7528047e68b4f424523a0981a3a084" [[package]] -name = "normalize-line-endings" -version = "0.3.0" +name = "new_debug_unreachable" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be" +checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" [[package]] -name = "num-conv" -version = "0.2.0" +name = "nix" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf97ec579c3c42f953ef76dbf8d55ac91fb219dde70e49aa4a6b7d74e9919050" +checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" +dependencies = [ + "bitflags 2.13.0", + "cfg-if", + "cfg_aliases", + "libc", + "memoffset", +] [[package]] -name = "num-traits" -version = "0.2.19" +name = "nom" +version = "7.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" dependencies = [ - "autocfg", + "memchr", + "minimal-lexical", ] [[package]] -name = "number_prefix" -version = "0.4.0" +name = "nonmax" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" +checksum = "610a5acd306ec67f907abe5567859a3c693fb9886eb1f012ab8f2a47bef3db51" [[package]] -name = "oauth2" -version = "4.4.2" +name = "normalize-line-endings" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c38841cdd844847e3e7c8d29cef9dcfed8877f8f56f9071f77843ecf3baf937f" +checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be" + +[[package]] +name = "normpath" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a9da8c9922c35a1033d76f7272dfc2e7ee20392083d75aeea6ced23c6266578" dependencies = [ - "base64 0.13.1", - "chrono", - "getrandom 0.2.17", - "http 0.2.12", - "rand 0.8.5", - "serde", - "serde_json 1.0.149", - "serde_path_to_error", - "sha2", - "thiserror 1.0.69", - "url", + "winapi", ] [[package]] -name = "once_cell" -version = "1.21.3" +name = "num-bigint" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" +checksum = "c89e69e7e0f03bea5ef08013795c25018e101932225a656383bd384495ecc367" +dependencies = [ + "num-integer", + "num-traits", + "serde", +] [[package]] -name = "once_cell_polyfill" -version = "1.70.2" +name = "num-conv" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" +checksum = "521739c6d2bac4aa25192232afe6841231376b2b26d4d9fae5ecf8ca5772e441" [[package]] -name = "open" -version = "5.3.3" +name = "num-derive" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43bb73a7fa3799b198970490a51174027ba0d4ec504b03cd08caf513d40024bc" +checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" dependencies = [ - "is-wsl", - "libc", - "pathdiff", + "proc-macro2", + "quote", + "syn 2.0.118", ] [[package]] -name = "openssl-probe" -version = "0.2.1" +name = "num-integer" +version = "0.1.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" - -[[package]] -name = "option-ext" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] [[package]] -name = "parking_lot" -version = "0.12.5" +name = "num-traits" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ - "lock_api", - "parking_lot_core", + "autocfg", ] [[package]] -name = "parking_lot_core" -version = "0.9.12" +name = "num_cpus" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" +checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b" dependencies = [ - "cfg-if", + "hermit-abi", "libc", - "redox_syscall", - "smallvec", - "windows-link", ] [[package]] -name = "paste" -version = "1.0.15" +name = "num_threads" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" +checksum = "5c7398b9c8b70908f6371f47ed36737907c87c52af34c268fed0bf0ceb92ead9" +dependencies = [ + "libc", +] [[package]] -name = "pathdiff" -version = "0.2.3" +name = "number_prefix" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3" +checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" [[package]] -name = "pbjson" -version = "0.7.0" +name = "oauth2" +version = "4.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7e6349fa080353f4a597daffd05cb81572a9c031a6d4fff7e504947496fcc68" +checksum = "c38841cdd844847e3e7c8d29cef9dcfed8877f8f56f9071f77843ecf3baf937f" dependencies = [ - "base64 0.21.7", + "base64 0.13.1", + "chrono", + "getrandom 0.2.17", + "http 0.2.12", + "rand 0.8.6", "serde", + "serde_json 1.0.150", + "serde_path_to_error", + "sha2", + "thiserror 1.0.69", + "url", ] [[package]] -name = "pbjson-build" -version = "0.7.0" +name = "object" +version = "0.37.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6eea3058763d6e656105d1403cb04e0a41b7bbac6362d413e7c33be0c32279c9" +checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe" dependencies = [ - "heck", - "itertools 0.13.0", - "prost", - "prost-types", + "memchr", ] [[package]] -name = "pbjson-types" -version = "0.7.0" +name = "once_cell" +version = "1.21.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e54e5e7bfb1652f95bc361d76f3c780d8e526b134b85417e774166ee941f0887" -dependencies = [ - "bytes", - "chrono", - "pbjson", - "pbjson-build", - "prost", - "prost-build", - "serde", -] +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" [[package]] -name = "percent-encoding" -version = "2.3.2" +name = "once_cell_polyfill" +version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" +checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" [[package]] -name = "petgraph" -version = "0.7.1" +name = "open" +version = "5.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3672b37090dbd86368a4145bc067582552b29c27377cad4e0a306c97f9bd7772" +checksum = "cd8d3b65c44123a56e0133d2cd06ce4361bd3ca99d41198b2f25e3c3db9b8b4a" dependencies = [ - "fixedbitset", - "indexmap 2.13.0", + "is-wsl", + "libc", ] [[package]] -name = "pin-project-lite" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" - -[[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - -[[package]] -name = "pkg-config" -version = "0.3.32" +name = "openssl-probe" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" +checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" [[package]] -name = "portable-atomic" -version = "1.13.1" +name = "option-ext" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" +checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" [[package]] -name = "potential_utf" -version = "0.1.4" +name = "ordered-float" +version = "4.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" +checksum = "7bb71e1b3fa6ca1c61f383464aaf2bb0e2f8e772a1f01d486832464de363b951" dependencies = [ - "zerovec", + "num-traits", ] [[package]] -name = "powerfmt" -version = "0.2.0" +name = "outref" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" +checksum = "1a80800c0488c3a21695ea981a54918fbb37abf04f4d0720c453632255e2ff0e" [[package]] -name = "ppv-lite86" -version = "0.2.21" +name = "owo-colors" +version = "4.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" -dependencies = [ - "zerocopy", -] +checksum = "d211803b9b6b570f68772237e415a029d5a50c65d382910b879fb19d3271f94d" [[package]] -name = "predicates" -version = "3.1.4" +name = "oxc-browserslist" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ada8f2932f28a27ee7b70dd6c1c39ea0675c55a36879ab92f3a715eaa1e63cfe" +checksum = "abb7a1163a5501f935f8722d839b576491b749c695e7a066aa0b8df988b806df" dependencies = [ - "anstyle", - "difflib", - "float-cmp", - "normalize-line-endings", - "predicates-core", - "regex", + "flate2", + "postcard", + "rustc-hash", + "serde", + "serde_json 1.0.150", + "thiserror 2.0.18", ] [[package]] -name = "predicates-core" -version = "1.0.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cad38746f3166b4031b1a0d39ad9f954dd291e7854fcc0eed52ee41a0b50d144" - -[[package]] -name = "predicates-tree" -version = "1.0.13" +name = "oxc-miette" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0de1b847b39c8131db0467e9df1ff60e6d0562ab8e9a16e568ad0fdb372e2f2" +checksum = "4356a61f2ed4c9b3610245215fbf48970eb277126919f87db9d0efa93a74245c" dependencies = [ - "predicates-core", - "termtree", + "cfg-if", + "owo-colors", + "oxc-miette-derive", + "textwrap", + "thiserror 2.0.18", + "unicode-segmentation", + "unicode-width 0.2.2", ] [[package]] -name = "prettyplease" -version = "0.2.37" +name = "oxc-miette-derive" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" +checksum = "b237422b014f8f8fff75bb9379e697d13f8d57551a22c88bebb39f073c1bf696" dependencies = [ "proc-macro2", - "syn", + "quote", + "syn 2.0.118", ] [[package]] -name = "proc-macro2" -version = "1.0.106" +name = "oxc_allocator" +version = "0.81.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +checksum = "5c67f2b817263a72b6cc5b46e32467bc4077496f88315ce08c1796647fed84d4" dependencies = [ - "unicode-ident", + "allocator-api2", + "bumpalo", + "hashbrown 0.15.5", + "oxc_data_structures", + "rustc-hash", ] [[package]] -name = "prost" -version = "0.13.5" +name = "oxc_ast" +version = "0.81.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2796faa41db3ec313a31f7624d9286acf277b52de526150b7e69f3debf891ee5" +checksum = "989b81258ce151e23adee6f1393f7c0fb7e10e3a6c6c001f71bbaff4081c72a4" dependencies = [ - "bytes", - "prost-derive", + "bitflags 2.13.0", + "oxc_allocator", + "oxc_ast_macros", + "oxc_data_structures", + "oxc_estree", + "oxc_regular_expression", + "oxc_span", + "oxc_syntax", ] [[package]] -name = "prost-build" -version = "0.13.5" +name = "oxc_ast_macros" +version = "0.81.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be769465445e8c1474e9c5dac2018218498557af32d9ed057325ec9a41ae81bf" +checksum = "ff7e8e42eea621e6fa7072a480fa04ae4dfe73f9a958822c066cc7f1eba57e82" dependencies = [ - "heck", - "itertools 0.14.0", - "log", - "multimap", - "once_cell", - "petgraph", - "prettyplease", - "prost", - "prost-types", - "regex", - "syn", - "tempfile", + "phf 0.12.1", + "proc-macro2", + "quote", + "syn 2.0.118", ] [[package]] -name = "prost-derive" -version = "0.13.5" +name = "oxc_ast_visit" +version = "0.81.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a56d757972c98b346a9b766e3f02746cde6dd1cd1d1d563472929fdd74bec4d" +checksum = "b0a968790ef8968de08d813a2fe1a15739930fb1c171fddeebf3545d802ea216" dependencies = [ - "anyhow", - "itertools 0.14.0", - "proc-macro2", - "quote", - "syn", + "oxc_allocator", + "oxc_ast", + "oxc_span", + "oxc_syntax", ] [[package]] -name = "prost-types" -version = "0.13.5" +name = "oxc_cfg" +version = "0.81.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52c2c1bf36ddb1a1c396b3601a3cec27c2462e45f07c386894ec3ccf5332bd16" +checksum = "5361ef66f38635d9671596d83abf44bcdbc3e39dbff303f3517828b86ad60e8f" dependencies = [ - "prost", + "bitflags 2.13.0", + "itertools 0.14.0", + "nonmax", + "oxc_index", + "oxc_syntax", + "petgraph 0.8.3", + "rustc-hash", ] [[package]] -name = "quinn" -version = "0.11.9" +name = "oxc_codegen" +version = "0.81.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9e20a958963c291dc322d98411f541009df2ced7b5a4f2bd52337638cfccf20" +checksum = "fde8fc6f7337632fce3e9e51c150f57fb0ef234524c6947f63e8009e1ea613cf" dependencies = [ - "bytes", - "cfg_aliases", - "pin-project-lite", - "quinn-proto", - "quinn-udp", + "bitflags 2.13.0", + "cow-utils", + "dragonbox_ecma 0.0.5", + "nonmax", + "oxc_allocator", + "oxc_ast", + "oxc_data_structures", + "oxc_index", + "oxc_semantic", + "oxc_sourcemap", + "oxc_span", + "oxc_syntax", "rustc-hash", - "rustls", - "socket2 0.6.2", - "thiserror 2.0.18", - "tokio", - "tracing", - "web-time", ] [[package]] -name = "quinn-proto" -version = "0.11.13" +name = "oxc_data_structures" +version = "0.81.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1906b49b0c3bc04b5fe5d86a77925ae6524a19b816ae38ce1e426255f1d8a31" +checksum = "16c58a40be09dbb289150046a39da2fb130eb5b8ff1f013f2963e880e1af261c" dependencies = [ - "bytes", - "getrandom 0.3.4", - "lru-slab", - "rand 0.9.2", - "ring", - "rustc-hash", - "rustls", - "rustls-pki-types", - "slab", - "thiserror 2.0.18", - "tinyvec", - "tracing", - "web-time", + "ropey", + "rustversion", ] [[package]] -name = "quinn-udp" -version = "0.5.14" +name = "oxc_diagnostics" +version = "0.81.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "addec6a0dcad8a8d96a771f815f0eaf55f9d1805756410b39f5fa81332574cbd" +checksum = "702bde62d95587518aec86247457830f189242f814fba8389beb6e8c1585c444" dependencies = [ - "cfg_aliases", - "libc", - "once_cell", - "socket2 0.6.2", - "tracing", - "windows-sys 0.60.2", + "cow-utils", + "oxc-miette", + "percent-encoding", ] [[package]] -name = "quote" -version = "1.0.44" +name = "oxc_ecmascript" +version = "0.81.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4" +checksum = "cf4dab5abe97e790fe1b631a7eacb9a1cbecbe2dad5b984ef11fcb9115b376ab" dependencies = [ - "proc-macro2", + "cow-utils", + "num-bigint", + "num-traits", + "oxc_allocator", + "oxc_ast", + "oxc_span", + "oxc_syntax", ] [[package]] -name = "r-efi" -version = "5.3.0" +name = "oxc_estree" +version = "0.81.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" +checksum = "aa9a453daacd90f168554015dd49467038ab6894045805f861950c1d0a8e6a5e" [[package]] -name = "rand" -version = "0.8.5" +name = "oxc_index" +version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" -dependencies = [ - "libc", - "rand_chacha 0.3.1", - "rand_core 0.6.4", -] +checksum = "967ae797e1f284bd1385f2d8e8ab94293ad27f623c76839ecf66827521365f5b" [[package]] -name = "rand" -version = "0.9.2" +name = "oxc_parser" +version = "0.81.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" +checksum = "70253728183a5a92d1ba964d9952201e0269ebd07c4917c4553283d564225bab" dependencies = [ - "rand_chacha 0.9.0", - "rand_core 0.9.5", + "bitflags 2.13.0", + "cow-utils", + "memchr", + "num-bigint", + "num-traits", + "oxc_allocator", + "oxc_ast", + "oxc_data_structures", + "oxc_diagnostics", + "oxc_ecmascript", + "oxc_regular_expression", + "oxc_span", + "oxc_syntax", + "rustc-hash", + "seq-macro", ] [[package]] -name = "rand_chacha" -version = "0.3.1" +name = "oxc_regular_expression" +version = "0.81.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +checksum = "de5bb2ed6646bb7815126e0f36787c349e13561fed2c05f95b27a1f82dd066c4" dependencies = [ - "ppv-lite86", - "rand_core 0.6.4", + "bitflags 2.13.0", + "oxc_allocator", + "oxc_ast_macros", + "oxc_diagnostics", + "oxc_span", + "phf 0.12.1", + "rustc-hash", + "unicode-id-start", ] [[package]] -name = "rand_chacha" -version = "0.9.0" +name = "oxc_semantic" +version = "0.81.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +checksum = "06858ccc5976a5303ac903bef13d03b7f8860e837b7399e4899c05f5c729d30b" dependencies = [ - "ppv-lite86", - "rand_core 0.9.5", + "itertools 0.14.0", + "oxc_allocator", + "oxc_ast", + "oxc_ast_visit", + "oxc_cfg", + "oxc_data_structures", + "oxc_diagnostics", + "oxc_ecmascript", + "oxc_index", + "oxc_span", + "oxc_syntax", + "phf 0.12.1", + "rustc-hash", + "self_cell", ] [[package]] -name = "rand_core" -version = "0.6.4" +name = "oxc_sourcemap" +version = "4.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +checksum = "05ff280f25901ac054ad8552395ecd6a455e4b9352a94debbc34c433760586ef" dependencies = [ - "getrandom 0.2.17", + "base64-simd", + "json-escape-simd", + "rustc-hash", + "serde", + "serde_json 1.0.150", ] [[package]] -name = "rand_core" -version = "0.9.5" +name = "oxc_span" +version = "0.81.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" +checksum = "2b315080fee7613168e0e08d3280efccdc12fea1efe5c0285e3a2d6265660f02" dependencies = [ - "getrandom 0.3.4", + "compact_str 0.9.1", + "oxc-miette", + "oxc_allocator", + "oxc_ast_macros", + "oxc_estree", ] [[package]] -name = "ratatui" -version = "0.29.0" +name = "oxc_syntax" +version = "0.81.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eabd94c2f37801c20583fc49dd5cd6b0ba68c716787c2dd6ed18571e1e63117b" +checksum = "72d9d80d47d2eee5c1e6dbcdf1841b42afc4f1cd1f63701fc346162616dac52f" dependencies = [ - "bitflags", - "cassowary", - "compact_str", - "crossterm 0.28.1", - "indoc", - "instability", - "itertools 0.13.0", - "lru", - "paste", - "strum", - "unicode-segmentation", - "unicode-truncate", - "unicode-width 0.2.0", + "bitflags 2.13.0", + "cow-utils", + "dragonbox_ecma 0.0.5", + "nonmax", + "oxc_allocator", + "oxc_ast_macros", + "oxc_data_structures", + "oxc_estree", + "oxc_index", + "oxc_span", + "phf 0.12.1", + "rustc-hash", + "unicode-id-start", ] [[package]] -name = "redox_syscall" -version = "0.5.18" +name = "oxc_transformer" +version = "0.81.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" +checksum = "89f15659109f115788d7750f31f970d500085e9544c250aa3b20ad23a3901c46" dependencies = [ - "bitflags", + "base64 0.22.1", + "compact_str 0.9.1", + "cow-utils", + "indexmap 2.14.0", + "itoa", + "memchr", + "oxc-browserslist", + "oxc_allocator", + "oxc_ast", + "oxc_ast_visit", + "oxc_data_structures", + "oxc_diagnostics", + "oxc_ecmascript", + "oxc_parser", + "oxc_regular_expression", + "oxc_semantic", + "oxc_span", + "oxc_syntax", + "oxc_traverse", + "rustc-hash", + "serde", + "serde_json 1.0.150", + "sha1 0.10.6", ] [[package]] -name = "redox_users" -version = "0.4.6" +name = "oxc_traverse" +version = "0.81.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" +checksum = "adef9483d1b5132a82e05e7f6a4a0b72138bf3c6459d0a5ef40f1fe33e9f77d1" dependencies = [ - "getrandom 0.2.17", - "libredox", - "thiserror 1.0.69", + "itoa", + "oxc_allocator", + "oxc_ast", + "oxc_ast_visit", + "oxc_data_structures", + "oxc_ecmascript", + "oxc_semantic", + "oxc_span", + "oxc_syntax", + "rustc-hash", ] [[package]] -name = "ref-cast" -version = "1.0.25" +name = "palette" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f354300ae66f76f1c85c5f84693f0ce81d747e2c3f21a45fef496d89c960bf7d" +checksum = "4cbf71184cc5ecc2e4e1baccdb21026c20e5fc3dcf63028a086131b3ab00b6e6" dependencies = [ - "ref-cast-impl", + "approx", + "fast-srgb8", + "libm", + "palette_derive", ] [[package]] -name = "ref-cast-impl" -version = "1.0.25" +name = "palette_derive" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da" +checksum = "f5030daf005bface118c096f510ffb781fc28f9ab6a32ab224d8631be6851d30" dependencies = [ + "by_address", "proc-macro2", "quote", - "syn", + "syn 2.0.118", ] [[package]] -name = "regex" -version = "1.12.3" +name = "par-core" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" +checksum = "e96cbd21255b7fb29a5d51ef38a779b517a91abd59e2756c039583f43ef4c90f" dependencies = [ - "aho-corasick", - "memchr", - "regex-automata", - "regex-syntax", + "once_cell", ] [[package]] -name = "regex-automata" -version = "0.4.14" +name = "parking_lot" +version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", + "lock_api", + "parking_lot_core", ] [[package]] -name = "regex-lite" -version = "0.1.9" +name = "parking_lot_core" +version = "0.9.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cab834c73d247e67f4fae452806d17d3c7501756d98c8808d7c9c7aa7d18f973" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-link", +] [[package]] -name = "regex-syntax" -version = "0.8.10" +name = "path-clean" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" +checksum = "17359afc20d7ab31fdb42bb844c8b3bb1dabd7dcf7e68428492da7f16966fcef" [[package]] -name = "reqwest" -version = "0.12.28" +name = "pathdiff" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eddd3ca559203180a307f12d114c268abf583f59b03cb906fd0b3ff8646c1147" +checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3" + +[[package]] +name = "pbjson" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7e6349fa080353f4a597daffd05cb81572a9c031a6d4fff7e504947496fcc68" dependencies = [ - "base64 0.22.1", - "bytes", - "futures-core", - "futures-util", - "http 1.4.0", - "http-body", - "http-body-util", - "hyper", - "hyper-rustls", - "hyper-util", - "js-sys", - "log", - "mime_guess", - "percent-encoding", - "pin-project-lite", - "quinn", - "rustls", - "rustls-native-certs", - "rustls-pki-types", + "base64 0.21.7", "serde", - "serde_json 1.0.149", - "serde_urlencoded", - "sync_wrapper", - "tokio", - "tokio-rustls", - "tokio-util", - "tower", - "tower-http", - "tower-service", - "url", - "wasm-bindgen", - "wasm-bindgen-futures", - "wasm-streams", - "web-sys", - "webpki-roots", ] [[package]] -name = "ring" -version = "0.17.14" +name = "pbjson-build" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" +checksum = "6eea3058763d6e656105d1403cb04e0a41b7bbac6362d413e7c33be0c32279c9" dependencies = [ - "cc", - "cfg-if", - "getrandom 0.2.17", - "libc", - "untrusted", - "windows-sys 0.52.0", + "heck", + "itertools 0.13.0", + "prost", + "prost-types", ] [[package]] -name = "rustc-hash" -version = "2.1.1" +name = "pbjson-types" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" +checksum = "e54e5e7bfb1652f95bc361d76f3c780d8e526b134b85417e774166ee941f0887" +dependencies = [ + "bytes", + "chrono", + "pbjson", + "pbjson-build", + "prost", + "prost-build", + "serde", +] [[package]] -name = "rustc_version" -version = "0.4.1" +name = "percent-encoding" +version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" + +[[package]] +name = "pest" +version = "2.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47627dd7305c6a2d6c8c6bcd24c5a4c17dbbf425f4f9c5313e724b38fc9782e9" dependencies = [ - "semver", + "memchr", + "ucd-trie", ] [[package]] -name = "rustix" -version = "0.38.44" +name = "pest_derive" +version = "2.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" +checksum = "4b4254325ecad416ab689e27ba51da03ba01a9632bc6e108f5fe7c3c4ad29d58" dependencies = [ - "bitflags", - "errno", - "libc", - "linux-raw-sys 0.4.15", - "windows-sys 0.59.0", + "pest", + "pest_generator", ] [[package]] -name = "rustix" -version = "1.1.4" +name = "pest_generator" +version = "2.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" +checksum = "6c4c0e91ead7a8f7acecbca6f003fc2e8282b1dbe2dd9c9d2f16aba42995e0a7" dependencies = [ - "bitflags", - "errno", - "libc", - "linux-raw-sys 0.12.1", - "windows-sys 0.61.2", + "pest", + "pest_meta", + "proc-macro2", + "quote", + "syn 2.0.118", ] [[package]] -name = "rustls" -version = "0.23.37" +name = "pest_meta" +version = "2.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "758025cb5fccfd3bc2fd74708fd4682be41d99e5dff73c377c0646c6012c73a4" +checksum = "f9744bc48116fee06334924bb5f2bad41eed5e89bd26e29b0b799f9a3f82c210" dependencies = [ - "once_cell", - "ring", - "rustls-pki-types", - "rustls-webpki", - "subtle", - "zeroize", + "pest", ] [[package]] -name = "rustls-native-certs" -version = "0.8.3" +name = "petgraph" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "612460d5f7bea540c490b2b6395d8e34a953e52b491accd6c86c8164c5932a63" +checksum = "3672b37090dbd86368a4145bc067582552b29c27377cad4e0a306c97f9bd7772" dependencies = [ - "openssl-probe", - "rustls-pki-types", - "schannel", - "security-framework", + "fixedbitset 0.5.7", + "indexmap 2.14.0", ] [[package]] -name = "rustls-pki-types" -version = "1.14.0" +name = "petgraph" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be040f8b0a225e40375822a563fa9524378b9d63112f53e19ffff34df5d33fdd" +checksum = "8701b58ea97060d5e5b155d383a69952a60943f0e6dfe30b04c287beb0b27455" dependencies = [ - "web-time", - "zeroize", + "fixedbitset 0.5.7", + "hashbrown 0.15.5", + "indexmap 2.14.0", + "serde", ] [[package]] -name = "rustls-webpki" -version = "0.103.13" +name = "phf" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61c429a8649f110dddef65e2a5ad240f747e85f7758a6bccc7e5777bd33f756e" +checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078" dependencies = [ - "ring", - "rustls-pki-types", - "untrusted", + "phf_macros 0.11.3", + "phf_shared 0.11.3", ] [[package]] -name = "rustversion" -version = "1.0.22" +name = "phf" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" +checksum = "913273894cec178f401a31ec4b656318d95473527be05c0752cc41cdc32be8b7" +dependencies = [ + "phf_macros 0.12.1", + "phf_shared 0.12.1", + "serde", +] [[package]] -name = "ryu" -version = "1.0.23" +name = "phf_codegen" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" +checksum = "aef8048c789fa5e851558d709946d6d79a8ff88c0440c587967f8e94bfb1216a" +dependencies = [ + "phf_generator 0.11.3", + "phf_shared 0.11.3", +] [[package]] -name = "schannel" -version = "0.1.29" +name = "phf_generator" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91c1b7e4904c873ef0710c1f407dde2e6287de2bebc1bbbf7d430bb7cbffd939" +checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d" dependencies = [ - "windows-sys 0.61.2", + "phf_shared 0.11.3", + "rand 0.8.6", ] [[package]] -name = "schemars" -version = "0.9.0" +name = "phf_generator" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cd191f9397d57d581cddd31014772520aa448f65ef991055d7f61582c65165f" +checksum = "2cbb1126afed61dd6368748dae63b1ee7dc480191c6262a3b4ff1e29d86a6c5b" dependencies = [ - "dyn-clone", - "ref-cast", - "serde", - "serde_json 1.0.149", + "fastrand", + "phf_shared 0.12.1", ] [[package]] -name = "schemars" -version = "1.2.1" +name = "phf_macros" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2b42f36aa1cd011945615b92222f6bf73c599a102a300334cd7f8dbeec726cc" +checksum = "f84ac04429c13a7ff43785d75ad27569f2951ce0ffd30a3321230db2fc727216" dependencies = [ - "dyn-clone", - "ref-cast", - "serde", - "serde_json 1.0.149", + "phf_generator 0.11.3", + "phf_shared 0.11.3", + "proc-macro2", + "quote", + "syn 2.0.118", ] [[package]] -name = "scopeguard" -version = "1.2.0" +name = "phf_macros" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +checksum = "d713258393a82f091ead52047ca779d37e5766226d009de21696c4e667044368" +dependencies = [ + "phf_generator 0.12.1", + "phf_shared 0.12.1", + "proc-macro2", + "quote", + "syn 2.0.118", +] [[package]] -name = "security-framework" -version = "3.7.0" +name = "phf_shared" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d" +checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5" dependencies = [ - "bitflags", - "core-foundation", - "core-foundation-sys", - "libc", - "security-framework-sys", + "siphasher 1.0.3", ] [[package]] -name = "security-framework-sys" -version = "2.17.0" +name = "phf_shared" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ce2691df843ecc5d231c0b14ece2acc3efb62c0a398c7e1d875f3983ce020e3" +checksum = "06005508882fb681fd97892ecff4b7fd0fee13ef1aa569f8695dae7ab9099981" dependencies = [ - "core-foundation-sys", - "libc", + "siphasher 1.0.3", ] [[package]] -name = "semver" -version = "1.0.27" +name = "pin-project-lite" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" [[package]] -name = "serde" -version = "1.0.228" +name = "pkg-config" +version = "0.3.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" -dependencies = [ +checksum = "19f132c84eca552bf34cab8ec81f1c1dcc229b811638f9d283dceabe58c5569e" + +[[package]] +name = "portable-atomic" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" + +[[package]] +name = "postcard" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6764c3b5dd454e283a30e6dfe78e9b31096d9e32036b5d1eaac7a6119ccb9a24" +dependencies = [ + "cobs", + "embedded-io 0.4.0", + "embedded-io 0.6.1", + "serde", +] + +[[package]] +name = "potential_utf" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0103b1cef7ec0cf76490e969665504990193874ea05c85ff9bab8b911d0a0564" +dependencies = [ + "zerovec", +] + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "predicates" +version = "3.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ada8f2932f28a27ee7b70dd6c1c39ea0675c55a36879ab92f3a715eaa1e63cfe" +dependencies = [ + "anstyle", + "difflib", + "float-cmp", + "normalize-line-endings", + "predicates-core", + "regex", +] + +[[package]] +name = "predicates-core" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cad38746f3166b4031b1a0d39ad9f954dd291e7854fcc0eed52ee41a0b50d144" + +[[package]] +name = "predicates-tree" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0de1b847b39c8131db0467e9df1ff60e6d0562ab8e9a16e568ad0fdb372e2f2" +dependencies = [ + "predicates-core", + "termtree", +] + +[[package]] +name = "prettyplease" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" +dependencies = [ + "proc-macro2", + "syn 2.0.118", +] + +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "prost" +version = "0.13.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2796faa41db3ec313a31f7624d9286acf277b52de526150b7e69f3debf891ee5" +dependencies = [ + "bytes", + "prost-derive", +] + +[[package]] +name = "prost-build" +version = "0.13.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be769465445e8c1474e9c5dac2018218498557af32d9ed057325ec9a41ae81bf" +dependencies = [ + "heck", + "itertools 0.14.0", + "log", + "multimap", + "once_cell", + "petgraph 0.7.1", + "prettyplease", + "prost", + "prost-types", + "regex", + "syn 2.0.118", + "tempfile", +] + +[[package]] +name = "prost-derive" +version = "0.13.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a56d757972c98b346a9b766e3f02746cde6dd1cd1d1d563472929fdd74bec4d" +dependencies = [ + "anyhow", + "itertools 0.14.0", + "proc-macro2", + "quote", + "syn 2.0.118", +] + +[[package]] +name = "prost-types" +version = "0.13.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52c2c1bf36ddb1a1c396b3601a3cec27c2462e45f07c386894ec3ccf5332bd16" +dependencies = [ + "prost", +] + +[[package]] +name = "psm" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "645dbe486e346d9b5de3ef16ede18c26e6c70ad97418f4874b8b1889d6e761ea" +dependencies = [ + "ar_archive_writer", + "cc", +] + +[[package]] +name = "quinn" +version = "0.11.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c1a41e437b6bbd489372cd4971de128e85c855f56c57f283d20ff016cf7c0a8" +dependencies = [ + "bytes", + "cfg_aliases", + "pin-project-lite", + "quinn-proto", + "quinn-udp", + "rustc-hash", + "rustls", + "socket2 0.6.4", + "thiserror 2.0.18", + "tokio", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-proto" +version = "0.11.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f4bfc015262b9df63c8845072ce59068853ff5872180c2ce2f13038b970e560" +dependencies = [ + "bytes", + "getrandom 0.4.3", + "lru-slab", + "rand 0.10.2", + "rand_pcg", + "ring", + "rustc-hash", + "rustls", + "rustls-pki-types", + "slab", + "thiserror 2.0.18", + "tinyvec", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-udp" +version = "0.5.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35a133f956daabe89a61a685c2649f13d82d5aa4bd5d12d1277e1072a21c0694" +dependencies = [ + "cfg_aliases", + "libc", + "once_cell", + "socket2 0.6.4", + "tracing", + "windows-sys 0.61.2", +] + +[[package]] +name = "quote" +version = "1.0.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfbc457d0c7a0759a614551b11a6409e5951f6c7537be1f1b7682b9ae9230368" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "r-efi" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" + +[[package]] +name = "radix_fmt" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce082a9940a7ace2ad4a8b7d0b1eac6aa378895f18be598230c5f2284ac05426" + +[[package]] +name = "rand" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ca0ecfa931c29007047d1bc58e623ab12e5590e8c7cc53200d5202b69266d8a" +dependencies = [ + "libc", + "rand_chacha", + "rand_core 0.6.4", +] + +[[package]] +name = "rand" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7f5fa3a058cd35567ef9bfa5e75732bee0f9e4c55fa90477bef2dfcdbc4be80" +dependencies = [ + "chacha20", + "getrandom 0.4.3", + "rand_core 0.10.1", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.17", +] + +[[package]] +name = "rand_core" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69" + +[[package]] +name = "rand_pcg" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "caa0f4137e1c0a72f4c651489402276c8e8e1cf081f3b0ba156d2cbeef09e86a" +dependencies = [ + "rand_core 0.10.1", +] + +[[package]] +name = "ratatui" +version = "0.30.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3274ba0a2c5e1bcad2a2005d20f4dc59dad26b2eb0940fb094500dba4099d57d" +dependencies = [ + "instability", + "ratatui-core", + "ratatui-crossterm", + "ratatui-macros", + "ratatui-termina", + "ratatui-termwiz", + "ratatui-widgets", + "serde", +] + +[[package]] +name = "ratatui-core" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbb175c433c8e28a809d1f5773a2ae96e68c0ce40db865cbab1020bf33ae479c" +dependencies = [ + "bitflags 2.13.0", + "compact_str 0.9.1", + "critical-section", + "hashbrown 0.17.1", + "itertools 0.14.0", + "kasuari", + "lru", + "palette", + "serde", + "strum", + "thiserror 2.0.18", + "unicode-segmentation", + "unicode-truncate", + "unicode-width 0.2.2", +] + +[[package]] +name = "ratatui-crossterm" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567584a3b0e6a8203c23de40b4861497266725eb5363dbfd18a1edd603cca9f0" +dependencies = [ + "cfg-if", + "crossterm 0.29.0", + "instability", + "ratatui-core", +] + +[[package]] +name = "ratatui-macros" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed7dc68daa7498a43e4d68e0eb078427e10c38fbcfbb1e42d955f1fa2140d814" +dependencies = [ + "ratatui-core", + "ratatui-widgets", +] + +[[package]] +name = "ratatui-termina" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0bf912d9e66f057a759d92e386a280ea886b352ab757d6ac4d653c7ed2c43c2" +dependencies = [ + "instability", + "ratatui-core", + "termina", +] + +[[package]] +name = "ratatui-termwiz" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "faf03e0380b7744054d6cb74224fe3adf062a029754933f575ca1e3b4c2ce977" +dependencies = [ + "ratatui-core", + "termwiz", +] + +[[package]] +name = "ratatui-widgets" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66e3d19bcc9130ca376277d93b60767ff121ace3be06f5f95f81dd68956407d1" +dependencies = [ + "bitflags 2.13.0", + "hashbrown 0.17.1", + "indoc", + "instability", + "itertools 0.14.0", + "line-clipping", + "ratatui-core", + "serde", + "strum", + "time", + "unicode-segmentation", + "unicode-width 0.2.2", +] + +[[package]] +name = "redox_syscall" +version = "0.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" +dependencies = [ + "bitflags 2.13.0", +] + +[[package]] +name = "redox_users" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" +dependencies = [ + "getrandom 0.2.17", + "libredox", + "thiserror 1.0.69", +] + +[[package]] +name = "ref-cast" +version = "1.0.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f354300ae66f76f1c85c5f84693f0ce81d747e2c3f21a45fef496d89c960bf7d" +dependencies = [ + "ref-cast-impl", +] + +[[package]] +name = "ref-cast-impl" +version = "1.0.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.118", +] + +[[package]] +name = "regex" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a0e75113e14dc5acb068cd0786884f214f1312650a3d36d269f5c4f3cdee8a2" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f388202e4b80542a0921078cc23b6333bcf1409c1e3f86404cae4766a6131db" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-lite" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cab834c73d247e67f4fae452806d17d3c7501756d98c8808d7c9c7aa7d18f973" + +[[package]] +name = "regex-syntax" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4" + +[[package]] +name = "relative-path" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba39f3699c378cd8970968dcbff9c43159ea4cfbd88d43c00b22f2ef10a435d2" + +[[package]] +name = "reqwest" +version = "0.12.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eddd3ca559203180a307f12d114c268abf583f59b03cb906fd0b3ff8646c1147" +dependencies = [ + "base64 0.22.1", + "bytes", + "futures-core", + "futures-util", + "http 1.4.2", + "http-body", + "http-body-util", + "hyper", + "hyper-rustls", + "hyper-util", + "js-sys", + "log", + "mime_guess", + "percent-encoding", + "pin-project-lite", + "quinn", + "rustls", + "rustls-native-certs", + "rustls-pki-types", + "serde", + "serde_json 1.0.150", + "serde_urlencoded", + "sync_wrapper", + "tokio", + "tokio-rustls", + "tokio-util", + "tower", + "tower-http", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "wasm-streams", + "web-sys", + "webpki-roots", +] + +[[package]] +name = "ring" +version = "0.17.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" +dependencies = [ + "cc", + "cfg-if", + "getrandom 0.2.17", + "libc", + "untrusted", + "windows-sys 0.52.0", +] + +[[package]] +name = "ropey" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93411e420bcd1a75ddd1dc3caf18c23155eda2c090631a85af21ba19e97093b5" +dependencies = [ + "smallvec", + "str_indices", +] + +[[package]] +name = "rustc-hash" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b1e7f9a428571be2dc5bc0505c13fb6bf936822b894ec87abf8a08a4e51742d" + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + +[[package]] +name = "rustix" +version = "0.38.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" +dependencies = [ + "bitflags 2.13.0", + "errno", + "libc", + "linux-raw-sys 0.4.15", + "windows-sys 0.59.0", +] + +[[package]] +name = "rustix" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" +dependencies = [ + "bitflags 2.13.0", + "errno", + "libc", + "linux-raw-sys 0.12.1", + "windows-sys 0.61.2", +] + +[[package]] +name = "rustls" +version = "0.23.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b92b125634d9b795e7beca796cc790df15a7fb38323bf3196fda83292d06b1f" +dependencies = [ + "once_cell", + "ring", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-native-certs" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dab5152771c58876a2146916e53e35057e1a4dfa2b9df0f0305b07f611fdea4d" +dependencies = [ + "openssl-probe", + "rustls-pki-types", + "schannel", + "security-framework", +] + +[[package]] +name = "rustls-pki-types" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "764899a24af3980067ee14bc143654f297b22eaebfe3c7b6b211920a5a59b046" +dependencies = [ + "web-time", + "zeroize", +] + +[[package]] +name = "rustls-webpki" +version = "0.103.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61c429a8649f110dddef65e2a5ad240f747e85f7758a6bccc7e5777bd33f756e" +dependencies = [ + "ring", + "rustls-pki-types", + "untrusted", +] + +[[package]] +name = "rustversion" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f" + +[[package]] +name = "ryu" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" + +[[package]] +name = "schannel" +version = "0.1.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91c1b7e4904c873ef0710c1f407dde2e6287de2bebc1bbbf7d430bb7cbffd939" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "schemars" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd191f9397d57d581cddd31014772520aa448f65ef991055d7f61582c65165f" +dependencies = [ + "dyn-clone", + "ref-cast", + "serde", + "serde_json 1.0.150", +] + +[[package]] +name = "schemars" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2b42f36aa1cd011945615b92222f6bf73c599a102a300334cd7f8dbeec726cc" +dependencies = [ + "dyn-clone", + "ref-cast", + "serde", + "serde_json 1.0.150", +] + +[[package]] +name = "scoped-tls" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "security-framework" +version = "3.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d" +dependencies = [ + "bitflags 2.13.0", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2691df843ecc5d231c0b14ece2acc3efb62c0a398c7e1d875f3983ce020e3" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "self_cell" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b12e76d157a900eb52e81bc6e9f3069344290341720e9178cde2407113ac8d89" + +[[package]] +name = "semver" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" + +[[package]] +name = "seq-macro" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc711410fbe7399f390ca1c3b60ad0f53f80e95c5eb935e52268a0e2cd49acc" + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde-wasm-bindgen" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8302e169f0eddcc139c70f139d19d6467353af16f9fce27e8c30158036a1e16b" +dependencies = [ + "js-sys", + "serde", + "wasm-bindgen", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.118", +] + +[[package]] +name = "serde_json" +version = "1.0.145" +source = "git+https://github.com/ankrgyl/serde-json.git?rev=efa66e3a1d61459ab2d325f92ebe3acbd6ca18b1#efa66e3a1d61459ab2d325f92ebe3acbd6ca18b1" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", + "serde_core", +] + +[[package]] +name = "serde_json" +version = "1.0.150" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8014e44b4736ed0538adeecded0fce2a272f22dc9578a7eb6b2d9993c74cfb9" +dependencies = [ + "itoa", + "memchr", + "serde", "serde_core", - "serde_derive", + "zmij", ] [[package]] -name = "serde-wasm-bindgen" -version = "0.6.5" +name = "serde_path_to_error" +version = "0.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8302e169f0eddcc139c70f139d19d6467353af16f9fce27e8c30158036a1e16b" +checksum = "10a9ff822e371bb5403e391ecd83e182e0e77ba7f6fe0160b795797109d1b457" dependencies = [ - "js-sys", + "itoa", "serde", - "wasm-bindgen", + "serde_core", +] + +[[package]] +name = "serde_repr" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.118", +] + +[[package]] +name = "serde_spanned" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_with" +version = "3.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76a5c54c7310e7b8b9577c286d7e399ddd876c3e12b3ed917a8aabc4b96e9e8c" +dependencies = [ + "base64 0.22.1", + "bs58", + "chrono", + "hex", + "indexmap 1.9.3", + "indexmap 2.14.0", + "schemars 0.9.0", + "schemars 1.2.1", + "serde_core", + "serde_json 1.0.150", + "serde_with_macros", + "time", +] + +[[package]] +name = "serde_with_macros" +version = "3.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84d57bc0c8b9a17920c178daa6bb924850d54a9c97ab45194bb8c17ad66bb660" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 2.0.118", +] + +[[package]] +name = "serde_yaml" +version = "0.9.34+deprecated" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" +dependencies = [ + "indexmap 2.14.0", + "itoa", + "ryu", + "serde", + "unsafe-libyaml", +] + +[[package]] +name = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if", + "cpufeatures 0.2.17", + "digest 0.10.7", +] + +[[package]] +name = "sha1" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aacc4cc499359472b4abe1bf11d0b12e688af9a805fa5e3016f9a386dc2d0214" +dependencies = [ + "cfg-if", + "cpufeatures 0.3.0", + "digest 0.11.3", +] + +[[package]] +name = "sha2" +version = "0.10.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" +dependencies = [ + "cfg-if", + "cpufeatures 0.2.17", + "digest 0.10.7", +] + +[[package]] +name = "shell-words" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc6fe69c597f9c37bfeeeeeb33da3530379845f10be461a66d16d03eca2ded77" + +[[package]] +name = "shlex" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" + +[[package]] +name = "signal-hook" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d881a16cf4426aa584979d30bd82cb33429027e42122b169753d6ef1085ed6e2" +dependencies = [ + "libc", + "signal-hook-registry", +] + +[[package]] +name = "signal-hook-mio" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b75a19a7a740b25bc7944bdee6172368f988763b744e3d4dfe753f6b4ece40cc" +dependencies = [ + "libc", + "mio", + "signal-hook", +] + +[[package]] +name = "signal-hook-registry" +version = "1.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b" +dependencies = [ + "errno", + "libc", +] + +[[package]] +name = "simd-adler32" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "703d5c7ef118737c72f1af64ad2f6f8c5e1921f818cdcb97b8fe6fc69bf66214" + +[[package]] +name = "siphasher" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" + +[[package]] +name = "siphasher" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ee5873ec9cce0195efcb7a4e9507a04cd49aec9c83d0389df45b1ef7ba2e649" + +[[package]] +name = "slab" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" + +[[package]] +name = "smallvec" +version = "1.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ed6a63f02c8539c91a8685a86f4099661ba3da017932f6ebbea6de3f0fa7c90" + +[[package]] +name = "smartstring" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fb72c633efbaa2dd666986505016c32c3044395ceaf881518399d2f4127ee29" +dependencies = [ + "autocfg", + "static_assertions", + "version_check", +] + +[[package]] +name = "smawk" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8e2fb0f499abb4d162f2bedad68f5ef91a1682b5a03596ddb67efd37768d100" + +[[package]] +name = "socket2" +version = "0.5.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "socket2" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52d1cfed4120b4d927bf7c0f86d2087a4a7d6027c906d9f9d525a80573b9be51" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" + +[[package]] +name = "stacker" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "640c8cdd92b6b12f5bcb1803ca3bbf5ab96e5e6b6b96b9ab77dabe9e880b3190" +dependencies = [ + "cc", + "cfg-if", + "libc", + "psm", + "windows-sys 0.61.2", +] + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "str_indices" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d08889ec5408683408db66ad89e0e1f93dff55c73a4ccc71c427d5b277ee47e6" + +[[package]] +name = "string_enum" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae36a4951ca7bd1cfd991c241584a9824a70f6aff1e7d4f693fb3f2465e4030e" +dependencies = [ + "quote", + "swc_macros_common", + "syn 2.0.118", +] + +[[package]] +name = "strip-ansi-escapes" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a8f8038e7e7969abb3f1b7c2a811225e9296da208539e0f79c5251d6cac0025" +dependencies = [ + "vte", ] [[package]] -name = "serde_core" -version = "1.0.228" +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "strum" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +checksum = "9628de9b8791db39ceda2b119bbe13134770b56c138ec1d3af810d045c04f9bd" dependencies = [ - "serde_derive", + "strum_macros", ] [[package]] -name = "serde_derive" -version = "1.0.228" +name = "strum_macros" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +checksum = "ab85eea0270ee17587ed4156089e10b9e6880ee688791d45a905f5b1ca36f664" dependencies = [ + "heck", "proc-macro2", "quote", - "syn", + "syn 2.0.118", ] [[package]] -name = "serde_json" -version = "1.0.145" -source = "git+https://github.com/ankrgyl/serde-json.git?rev=efa66e3a1d61459ab2d325f92ebe3acbd6ca18b1#efa66e3a1d61459ab2d325f92ebe3acbd6ca18b1" -dependencies = [ - "itoa", - "memchr", - "ryu", - "serde", - "serde_core", -] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] -name = "serde_json" -version = "1.0.149" +name = "swc_allocator" +version = "4.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" +checksum = "9d7eefd2c8b228a8c73056482b2ae4b3a1071fbe07638e3b55ceca8570cc48bb" dependencies = [ - "itoa", - "memchr", - "serde", - "serde_core", - "zmij", + "allocator-api2", + "bumpalo", + "hashbrown 0.14.5", + "rustc-hash", ] [[package]] -name = "serde_path_to_error" -version = "0.1.20" +name = "swc_atoms" +version = "9.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10a9ff822e371bb5403e391ecd83e182e0e77ba7f6fe0160b795797109d1b457" +checksum = "845f31910b5236db42dba106e8277681098d183b9b65b8dfa88ca8abe464aeff" dependencies = [ - "itoa", + "hstr", + "once_cell", "serde", - "serde_core", ] [[package]] -name = "serde_repr" -version = "0.1.20" +name = "swc_bundler" +version = "49.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c" +checksum = "47950970ceed8a5b80e6f0702bbd72a2ebf5205bedb36438863209b4ad58a5a7" dependencies = [ - "proc-macro2", - "quote", - "syn", + "anyhow", + "crc", + "indexmap 2.14.0", + "is-macro", + "once_cell", + "petgraph 0.7.1", + "radix_fmt", + "relative-path", + "rustc-hash", + "swc_atoms", + "swc_common 21.0.2", + "swc_ecma_ast 23.0.1", + "swc_ecma_codegen", + "swc_ecma_loader", + "swc_ecma_parser", + "swc_ecma_transforms_base", + "swc_ecma_transforms_optimization", + "swc_ecma_utils", + "swc_ecma_visit 23.0.0", + "swc_graph_analyzer", + "tracing", ] [[package]] -name = "serde_spanned" -version = "0.6.9" +name = "swc_common" +version = "20.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" +checksum = "990735f1c65fac4d0f2748113f3bc8a799fd31501efbd254eb7cc5e877c50660" dependencies = [ + "anyhow", + "ast_node", + "better_scoped_tls", + "bytes-str", + "either", + "from_variant", + "num-bigint", + "once_cell", + "rustc-hash", "serde", + "siphasher 0.3.11", + "swc_atoms", + "swc_eq_ignore_macros", + "swc_visit", + "tracing", + "unicode-width 0.2.2", + "url", ] [[package]] -name = "serde_urlencoded" -version = "0.7.1" +name = "swc_common" +version = "21.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +checksum = "da38f2cee8e659bf0ec7f51ec5b37ec58c9127de755d3fe0b2c2353ec9474b09" dependencies = [ - "form_urlencoded", - "itoa", - "ryu", + "anyhow", + "ast_node", + "better_scoped_tls", + "bytes-str", + "either", + "from_variant", + "num-bigint", + "once_cell", + "rustc-hash", "serde", + "siphasher 0.3.11", + "swc_atoms", + "swc_eq_ignore_macros", + "swc_visit", + "tracing", + "unicode-width 0.2.2", + "url", ] [[package]] -name = "serde_with" -version = "3.17.0" +name = "swc_config" +version = "5.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "381b283ce7bc6b476d903296fb59d0d36633652b633b27f64db4fb46dcbfc3b9" +checksum = "6ee60aaa4eaea81fb9c730e64a0b88c363b5c237b774d114c97cba82f8655fdb" dependencies = [ - "base64 0.22.1", - "chrono", - "hex", - "indexmap 1.9.3", - "indexmap 2.13.0", - "schemars 0.9.0", - "schemars 1.2.1", - "serde_core", - "serde_json 1.0.149", - "serde_with_macros", - "time", + "anyhow", + "bytes-str", + "indexmap 2.14.0", + "serde", + "serde_json 1.0.150", + "swc_config_macro", ] [[package]] -name = "serde_with_macros" -version = "3.17.0" +name = "swc_config_macro" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6d4e30573c8cb306ed6ab1dca8423eec9a463ea0e155f45399455e0368b27e0" +checksum = "7b416e8ce6de17dc5ea496e10c7012b35bbc0e3fef38d2e065eed936490db0b3" dependencies = [ - "darling 0.21.3", "proc-macro2", "quote", - "syn", + "swc_macros_common", + "syn 2.0.118", ] [[package]] -name = "serde_yaml" -version = "0.9.34+deprecated" +name = "swc_ecma_ast" +version = "22.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" +checksum = "acb0eed1bac5703d661d16fa4b54958f6b8823a6f1385d163942cf4b90afb4a2" dependencies = [ - "indexmap 2.13.0", - "itoa", - "ryu", - "serde", - "unsafe-libyaml", + "bitflags 2.13.0", + "is-macro", + "num-bigint", + "once_cell", + "phf 0.11.3", + "rustc-hash", + "string_enum", + "swc_atoms", + "swc_common 20.0.0", + "swc_visit", + "unicode-id-start", ] [[package]] -name = "sha1" -version = "0.10.6" +name = "swc_ecma_ast" +version = "23.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +checksum = "550ee54eab536fe357090fec6d42d083c28cf44cc9bcfa93b1ea5e1606f3b2f7" dependencies = [ - "cfg-if", - "cpufeatures", - "digest", + "bitflags 2.13.0", + "is-macro", + "num-bigint", + "once_cell", + "phf 0.11.3", + "rustc-hash", + "string_enum", + "swc_atoms", + "swc_common 21.0.2", + "swc_visit", + "unicode-id-start", ] [[package]] -name = "sha2" -version = "0.10.9" +name = "swc_ecma_codegen" +version = "26.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" +checksum = "39230b073d1d785ac7a905354161e21970d15956e348f46a85deb0da0d4d5132" dependencies = [ - "cfg-if", - "cpufeatures", - "digest", + "ascii", + "compact_str 0.7.1", + "dragonbox_ecma 0.1.12", + "memchr", + "num-bigint", + "once_cell", + "regex", + "rustc-hash", + "serde", + "swc_allocator", + "swc_atoms", + "swc_common 21.0.2", + "swc_ecma_ast 23.0.1", + "swc_ecma_codegen_macros", + "tracing", ] [[package]] -name = "shell-words" -version = "1.1.1" +name = "swc_ecma_codegen_macros" +version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc6fe69c597f9c37bfeeeeeb33da3530379845f10be461a66d16d03eca2ded77" +checksum = "e276dc62c0a2625a560397827989c82a93fd545fcf6f7faec0935a82cc4ddbb8" +dependencies = [ + "proc-macro2", + "swc_macros_common", + "syn 2.0.118", +] [[package]] -name = "shlex" -version = "1.3.0" +name = "swc_ecma_hooks" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" +checksum = "ee7662517362f6726b0e107a3caec2b4cc7d629f9bf702958948e9350722e52f" +dependencies = [ + "swc_atoms", + "swc_common 21.0.2", + "swc_ecma_ast 23.0.1", + "swc_ecma_visit 23.0.0", +] [[package]] -name = "signal-hook" -version = "0.3.18" +name = "swc_ecma_loader" +version = "22.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d881a16cf4426aa584979d30bd82cb33429027e42122b169753d6ef1085ed6e2" +checksum = "562c983a163ca2a016626d03f037390a9c1de8f004605ecf44f4fa92a292ae42" dependencies = [ - "libc", - "signal-hook-registry", + "anyhow", + "dashmap", + "normpath", + "once_cell", + "path-clean", + "pathdiff", + "rustc-hash", + "serde", + "serde_json 1.0.150", + "swc_atoms", + "swc_common 21.0.2", + "tracing", ] [[package]] -name = "signal-hook-mio" -version = "0.2.5" +name = "swc_ecma_parser" +version = "39.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b75a19a7a740b25bc7944bdee6172368f988763b744e3d4dfe753f6b4ece40cc" +checksum = "bca883cdbd6107a96f60a23fd90623c9a90cf37741fc08a3337cee9bbd6c4c1a" dependencies = [ - "libc", - "mio", - "signal-hook", + "bitflags 2.13.0", + "either", + "num-bigint", + "phf 0.11.3", + "rustc-hash", + "seq-macro", + "serde", + "smartstring", + "stacker", + "swc_atoms", + "swc_common 21.0.2", + "swc_ecma_ast 23.0.1", + "tracing", ] [[package]] -name = "signal-hook-registry" -version = "1.4.8" +name = "swc_ecma_transforms_base" +version = "42.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b" +checksum = "1f0c8ee943a8f9099391cecef5b3eafc98aba64dfa5f6f7cd336a32989d92d1a" dependencies = [ - "errno", - "libc", + "better_scoped_tls", + "indexmap 2.14.0", + "once_cell", + "par-core", + "phf 0.11.3", + "rustc-hash", + "serde", + "swc_atoms", + "swc_common 21.0.2", + "swc_ecma_ast 23.0.1", + "swc_ecma_parser", + "swc_ecma_utils", + "swc_ecma_visit 23.0.0", + "tracing", ] [[package]] -name = "simd-adler32" -version = "0.3.8" +name = "swc_ecma_transforms_optimization" +version = "45.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e320a6c5ad31d271ad523dcf3ad13e2767ad8b1cb8f047f75a8aeaf8da139da2" +checksum = "bf10153f1eb750745cf0a28b2261dd32c0f0dba011b73cd1ea13256e90f1a784" +dependencies = [ + "bytes-str", + "dashmap", + "indexmap 2.14.0", + "once_cell", + "par-core", + "petgraph 0.7.1", + "rustc-hash", + "serde_json 1.0.150", + "swc_atoms", + "swc_common 21.0.2", + "swc_ecma_ast 23.0.1", + "swc_ecma_parser", + "swc_ecma_transforms_base", + "swc_ecma_utils", + "swc_ecma_visit 23.0.0", + "tracing", +] [[package]] -name = "slab" -version = "0.4.12" +name = "swc_ecma_transforms_react" +version = "47.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" +checksum = "8989e4d64e0d219f1c471c4ecd2190bab717a15ad48c4ce3ba603f6501fc551d" +dependencies = [ + "base64 0.22.1", + "bytes-str", + "indexmap 2.14.0", + "once_cell", + "rustc-hash", + "serde", + "sha1 0.10.6", + "string_enum", + "swc_atoms", + "swc_common 21.0.2", + "swc_config", + "swc_ecma_ast 23.0.1", + "swc_ecma_hooks", + "swc_ecma_parser", + "swc_ecma_transforms_base", + "swc_ecma_utils", + "swc_ecma_visit 23.0.0", +] [[package]] -name = "smallvec" -version = "1.15.1" +name = "swc_ecma_transforms_typescript" +version = "47.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" +checksum = "f4db96f7f292ecb4c819aff462a7965ddcba88ec7cc2705d2ee45db7eff56c77" +dependencies = [ + "bytes-str", + "rustc-hash", + "serde", + "swc_atoms", + "swc_common 21.0.2", + "swc_ecma_ast 23.0.1", + "swc_ecma_transforms_base", + "swc_ecma_transforms_react", + "swc_ecma_utils", + "swc_ecma_visit 23.0.0", +] [[package]] -name = "socket2" -version = "0.5.10" +name = "swc_ecma_utils" +version = "29.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" +checksum = "3d69b480aa02b5ff2ab951478d8e7633eeda42940aeb5fe0386eebc19dd3b1e4" dependencies = [ - "libc", - "windows-sys 0.52.0", + "dragonbox_ecma 0.1.12", + "indexmap 2.14.0", + "num_cpus", + "once_cell", + "par-core", + "rustc-hash", + "swc_atoms", + "swc_common 21.0.2", + "swc_ecma_ast 23.0.1", + "swc_ecma_visit 23.0.0", + "tracing", ] [[package]] -name = "socket2" -version = "0.6.2" +name = "swc_ecma_visit" +version = "22.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86f4aa3ad99f2088c990dfa82d367e19cb29268ed67c574d10d0a4bfe71f07e0" +checksum = "d9ead1b61949ce19ca2088ae0cac092bfa2287718c955ff31e55f7d1eba0a84b" dependencies = [ - "libc", - "windows-sys 0.60.2", + "new_debug_unreachable", + "num-bigint", + "swc_atoms", + "swc_common 20.0.0", + "swc_ecma_ast 22.0.0", + "swc_visit", + "tracing", ] [[package]] -name = "stable_deref_trait" -version = "1.2.1" +name = "swc_ecma_visit" +version = "23.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" +checksum = "ad65d392ed427dc9e94f16a3d802b02e27722c21227639c8d5f45f19757b447b" +dependencies = [ + "new_debug_unreachable", + "num-bigint", + "swc_atoms", + "swc_common 21.0.2", + "swc_ecma_ast 23.0.1", + "swc_visit", + "tracing", +] [[package]] -name = "static_assertions" -version = "1.1.0" +name = "swc_eq_ignore_macros" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" +checksum = "c16ce73424a6316e95e09065ba6a207eba7765496fed113702278b7711d4b632" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.118", +] [[package]] -name = "strip-ansi-escapes" -version = "0.2.1" +name = "swc_graph_analyzer" +version = "14.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a8f8038e7e7969abb3f1b7c2a811225e9296da208539e0f79c5251d6cac0025" +checksum = "5524b7dd51c772d1154feb46d177c0d938d32df8c6a1546cc71f89ce47895d2f" dependencies = [ - "vte", + "auto_impl", + "petgraph 0.7.1", + "rustc-hash", + "tracing", ] [[package]] -name = "strsim" -version = "0.11.1" +name = "swc_macros_common" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" +checksum = "aae1efbaa74943dc5ad2a2fb16cbd78b77d7e4d63188f3c5b4df2b4dcd2faaae" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.118", +] [[package]] -name = "strum" -version = "0.26.3" +name = "swc_visit" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" +checksum = "62fb71484b486c185e34d2172f0eabe7f4722742aad700f426a494bb2de232a2" dependencies = [ - "strum_macros", + "either", + "new_debug_unreachable", ] [[package]] -name = "strum_macros" -version = "0.26.4" +name = "syn" +version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" dependencies = [ - "heck", "proc-macro2", "quote", - "rustversion", - "syn", + "unicode-ident", ] -[[package]] -name = "subtle" -version = "2.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" - [[package]] name = "syn" -version = "2.0.117" +version = "2.0.118" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" +checksum = "1b9ae57f904213ebb649ce6895b8a66c66f0203b9319718f69a5612a065b1422" dependencies = [ "proc-macro2", "quote", @@ -3069,29 +4826,63 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.118", +] + +[[package]] +name = "tempfile" +version = "3.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" +dependencies = [ + "fastrand", + "getrandom 0.4.3", + "once_cell", + "rustix 1.1.4", + "windows-sys 0.61.2", +] + +[[package]] +name = "termcolor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "termina" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9048a889effe34a5cddee0af7f53285198b16dca3be510858d38dfdb3e62a04e" +dependencies = [ + "bitflags 2.13.0", + "parking_lot", + "rustix 1.1.4", + "signal-hook", + "windows-sys 0.61.2", ] [[package]] -name = "tempfile" -version = "3.26.0" +name = "terminfo" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82a72c767771b47409d2345987fda8628641887d5466101319899796367354a0" +checksum = "d4ea810f0692f9f51b382fff5893887bb4580f5fa246fde546e0b13e7fcee662" dependencies = [ - "fastrand", - "getrandom 0.4.1", - "once_cell", - "rustix 1.1.4", - "windows-sys 0.61.2", + "fnv", + "nom", + "phf 0.11.3", + "phf_codegen", ] [[package]] -name = "termcolor" -version = "1.4.1" +name = "termios" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" +checksum = "411c5bf740737c7918b8b1fe232dca4dc9f8e754b8ad5e20966814001ed0ac6b" dependencies = [ - "winapi-util", + "libc", ] [[package]] @@ -3100,6 +4891,59 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f50febec83f5ee1df3015341d8bd429f2d1cc62bcba7ea2076759d315084683" +[[package]] +name = "termwiz" +version = "0.23.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4676b37242ccbd1aabf56edb093a4827dc49086c0ffd764a5705899e0f35f8f7" +dependencies = [ + "anyhow", + "base64 0.22.1", + "bitflags 2.13.0", + "fancy-regex", + "filedescriptor", + "finl_unicode", + "fixedbitset 0.4.2", + "hex", + "lazy_static", + "libc", + "log", + "memmem", + "nix", + "num-derive", + "num-traits", + "ordered-float", + "pest", + "pest_derive", + "phf 0.11.3", + "sha2", + "signal-hook", + "siphasher 1.0.3", + "terminfo", + "termios", + "thiserror 1.0.69", + "ucd-trie", + "unicode-segmentation", + "vtparse", + "wezterm-bidi", + "wezterm-blob-leases", + "wezterm-color-types", + "wezterm-dynamic", + "wezterm-input-types", + "winapi", +] + +[[package]] +name = "textwrap" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c13547615a44dc9c452a8a534638acdf07120d4b6847c8178705da06306a3057" +dependencies = [ + "smawk", + "unicode-linebreak", + "unicode-width 0.2.2", +] + [[package]] name = "thiserror" version = "1.0.69" @@ -3126,7 +4970,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.118", ] [[package]] @@ -3137,7 +4981,7 @@ checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.118", ] [[package]] @@ -3151,13 +4995,14 @@ dependencies = [ [[package]] name = "time" -version = "0.3.47" +version = "0.3.53" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c" +checksum = "18dfaaeddcb932337b5e7866ee7d0ce9b76d2fd092997146f187ec09b4558a50" dependencies = [ "deranged", - "itoa", + "libc", "num-conv", + "num_threads", "powerfmt", "serde_core", "time-core", @@ -3166,15 +5011,15 @@ dependencies = [ [[package]] name = "time-core" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca" +checksum = "9e1c906769ad99c88eaa54e728060edef082f8e358ff32030cb7c7d315e81109" [[package]] name = "time-macros" -version = "0.2.27" +version = "0.2.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e70e4c5a0e0a8a4823ad65dfe1a6930e4f4d756dcd9dd7939022b5e8c501215" +checksum = "c431b87111666e491a90baa837f914fb45cd5dc3c268591b0220ff5057f2085f" dependencies = [ "num-conv", "time-core", @@ -3182,9 +5027,9 @@ dependencies = [ [[package]] name = "tinystr" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" +checksum = "c8323304221c2a851516f22236c5722a72eaa19749016521d6dff0824447d96d" dependencies = [ "displaydoc", "zerovec", @@ -3192,9 +5037,9 @@ dependencies = [ [[package]] name = "tinyvec" -version = "1.10.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa5fdc3bce6191a1dbc8c02d5c8bffcf557bafa17c124c5264a458f1b0613fa" +checksum = "3e61e67053d25a4e82c844e8424039d9745781b3fc4f32b8d55ed50f5f667ef3" dependencies = [ "tinyvec_macros", ] @@ -3207,9 +5052,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.49.0" +version = "1.52.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72a2903cd7736441aac9df9d7688bd0ce48edccaadf181c3b90be801e81d3d86" +checksum = "8fc7f01b389ac15039e4dc9531aa973a135d7a4135281b12d7c1bc79fd57fffe" dependencies = [ "bytes", "libc", @@ -3217,20 +5062,20 @@ dependencies = [ "parking_lot", "pin-project-lite", "signal-hook-registry", - "socket2 0.6.2", + "socket2 0.6.4", "tokio-macros", "windows-sys 0.61.2", ] [[package]] name = "tokio-macros" -version = "2.6.0" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" +checksum = "385a6cb71ab9ab790c5fe8d67f1645e6c450a7ce006a33de03daa956cf70a496" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.118", ] [[package]] @@ -3283,7 +5128,7 @@ version = "0.22.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" dependencies = [ - "indexmap 2.13.0", + "indexmap 2.14.0", "serde", "serde_spanned", "toml_datetime", @@ -3314,25 +5159,25 @@ dependencies = [ [[package]] name = "tower-http" -version = "0.6.8" +version = "0.6.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8" +checksum = "4cfcf7e2740e6fc6d4d688b4ef00650406bb94adf4731e43c096c3a19fe40840" dependencies = [ "async-compression", - "bitflags", + "bitflags 2.13.0", "bytes", "futures-core", "futures-util", - "http 1.4.0", + "http 1.4.2", "http-body", "http-body-util", - "iri-string", "pin-project-lite", "tokio", "tokio-util", "tower", "tower-layer", "tower-service", + "url", ] [[package]] @@ -3367,7 +5212,7 @@ checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.118", ] [[package]] @@ -3379,6 +5224,16 @@ dependencies = [ "once_cell", ] +[[package]] +name = "triomphe" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b40688ea6389c8171614b25491f71d4a27946e0c7ce2da1c6de27e25abf1a0ae" +dependencies = [ + "serde", + "stable_deref_trait", +] + [[package]] name = "try-lock" version = "0.2.5" @@ -3403,15 +5258,21 @@ checksum = "ee6ff59666c9cbaec3533964505d39154dc4e0a56151fdea30a09ed0301f62e2" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.118", "termcolor", ] [[package]] name = "typenum" -version = "1.19.0" +version = "1.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20" + +[[package]] +name = "ucd-trie" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" +checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" [[package]] name = "unicase" @@ -3419,27 +5280,39 @@ version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dbc4bc3a9f746d862c45cb89d705aa10f187bb96c76001afab07a0d35ce60142" +[[package]] +name = "unicode-id-start" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81b79ad29b5e19de4260020f8919b443b2ef0277d242ce532ec7b7a2cc8b6007" + [[package]] name = "unicode-ident" version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" +[[package]] +name = "unicode-linebreak" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f" + [[package]] name = "unicode-segmentation" -version = "1.12.0" +version = "1.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" +checksum = "c6f5d3c3b1bf09027a88a6bc961fc00497d651009560b5463668dc81b0fa87a8" [[package]] name = "unicode-truncate" -version = "1.1.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3644627a5af5fa321c95b9b235a72fd24cd29c648c2c379431e6628655627bf" +checksum = "16b380a1238663e5f8a691f9039c73e1cdae598a30e9855f541d29b08b53e9a5" dependencies = [ - "itertools 0.13.0", + "itertools 0.14.0", "unicode-segmentation", - "unicode-width 0.1.14", + "unicode-width 0.2.2", ] [[package]] @@ -3450,9 +5323,9 @@ checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" [[package]] name = "unicode-width" -version = "0.2.0" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd" +checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254" [[package]] name = "unicode-xid" @@ -3505,11 +5378,12 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.21.0" +version = "1.23.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b672338555252d43fd2240c714dc444b8c6fb0a5c5335e65a07bba7742735ddb" +checksum = "bf80a72845275afea99e7f2b434723d3bc7e38470fcd1c7ed39a599c73319a53" dependencies = [ - "getrandom 0.4.1", + "atomic", + "getrandom 0.4.3", "js-sys", "serde_core", "wasm-bindgen", @@ -3521,6 +5395,12 @@ version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" +[[package]] +name = "vsimd" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c3082ca00d5a5ef149bb8b555a72ae84c9c59f7250f013ac822ac2e49b19c64" + [[package]] name = "vte" version = "0.14.1" @@ -3530,6 +5410,15 @@ dependencies = [ "memchr", ] +[[package]] +name = "vtparse" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d9b2acfb050df409c972a37d3b8e08cdea3bddb0c09db9d53137e504cfabed0" +dependencies = [ + "utf8parse", +] + [[package]] name = "wait-timeout" version = "0.2.1" @@ -3556,27 +5445,18 @@ checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] name = "wasip2" -version = "1.0.2+wasi-0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" -dependencies = [ - "wit-bindgen", -] - -[[package]] -name = "wasip3" -version = "0.4.0+wasi-0.3.0-rc-2026-01-06" +version = "1.0.4+wasi-0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" +checksum = "b67efb37e106e55ce722a510d6b5f9c17f083e5fc79afc2badeb12cc313d9487" dependencies = [ "wit-bindgen", ] [[package]] name = "wasm-bindgen" -version = "0.2.113" +version = "0.2.126" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60722a937f594b7fde9adb894d7c092fc1bb6612897c46368d18e7a20208eff2" +checksum = "4b067c0c11094aef6b7a801c1e34a26affafdf3d051dba08456b868789aaf9a4" dependencies = [ "cfg-if", "once_cell", @@ -3587,23 +5467,19 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.63" +version = "0.4.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a89f4650b770e4521aa6573724e2aed4704372151bd0de9d16a3bbabb87441a" +checksum = "c62df1340f32221cb9c54d6a27b030e3dba64361d4a95bed55f9aacb44da291d" dependencies = [ - "cfg-if", - "futures-util", "js-sys", - "once_cell", "wasm-bindgen", - "web-sys", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.113" +version = "0.2.126" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fac8c6395094b6b91c4af293f4c79371c163f9a6f56184d2c9a85f5a95f3950" +checksum = "167ce5e579f6bcf889c4f7175a8a5a585de84e8ff93976ce393efa5f2837aab1" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -3611,48 +5487,26 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.113" +version = "0.2.126" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab3fabce6159dc20728033842636887e4877688ae94382766e00b180abac9d60" +checksum = "f3997c7839262f4ef12cf90b818d6340c18e80f263f1a94bf157d0ec4420380e" dependencies = [ "bumpalo", "proc-macro2", "quote", - "syn", + "syn 2.0.118", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.113" +version = "0.2.126" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de0e091bdb824da87dc01d967388880d017a0a9bc4f3bdc0d86ee9f9336e3bb5" +checksum = "dc1b4cb0cc549fcf58d7dfc081778139b3d283a081644e833e84682ad71cea24" dependencies = [ "unicode-ident", ] -[[package]] -name = "wasm-encoder" -version = "0.244.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319" -dependencies = [ - "leb128fmt", - "wasmparser", -] - -[[package]] -name = "wasm-metadata" -version = "0.244.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" -dependencies = [ - "anyhow", - "indexmap 2.13.0", - "wasm-encoder", - "wasmparser", -] - [[package]] name = "wasm-streams" version = "0.4.2" @@ -3666,23 +5520,11 @@ dependencies = [ "web-sys", ] -[[package]] -name = "wasmparser" -version = "0.244.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" -dependencies = [ - "bitflags", - "hashbrown 0.15.5", - "indexmap 2.13.0", - "semver", -] - [[package]] name = "web-sys" -version = "0.3.90" +version = "0.3.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "705eceb4ce901230f8625bd1d665128056ccbe4b7408faa625eec1ba80f59a97" +checksum = "8622dcb61c0bcc9fffa6938bed81210af2da9a7e4a1a834b2e37a59b6dfb6141" dependencies = [ "js-sys", "wasm-bindgen", @@ -3700,13 +5542,85 @@ dependencies = [ [[package]] name = "webpki-roots" -version = "1.0.6" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22cfaf3c063993ff62e73cb4311efde4db1efb31ab78a3e5c457939ad5cc0bed" +checksum = "bf85cb06032201fa7c6f829d7db5a7e5aa45bcc0655327713065f6f0576731bf" dependencies = [ "rustls-pki-types", ] +[[package]] +name = "wezterm-bidi" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c0a6e355560527dd2d1cf7890652f4f09bb3433b6aadade4c9b5ed76de5f3ec" +dependencies = [ + "log", + "wezterm-dynamic", +] + +[[package]] +name = "wezterm-blob-leases" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "692daff6d93d94e29e4114544ef6d5c942a7ed998b37abdc19b17136ea428eb7" +dependencies = [ + "getrandom 0.3.4", + "mac_address", + "sha2", + "thiserror 1.0.69", + "uuid", +] + +[[package]] +name = "wezterm-color-types" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7de81ef35c9010270d63772bebef2f2d6d1f2d20a983d27505ac850b8c4b4296" +dependencies = [ + "csscolorparser", + "deltae", + "lazy_static", + "wezterm-dynamic", +] + +[[package]] +name = "wezterm-dynamic" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f2ab60e120fd6eaa68d9567f3226e876684639d22a4219b313ff69ec0ccd5ac" +dependencies = [ + "log", + "ordered-float", + "strsim", + "thiserror 1.0.69", + "wezterm-dynamic-derive", +] + +[[package]] +name = "wezterm-dynamic-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46c0cf2d539c645b448eaffec9ec494b8b19bd5077d9e58cb1ae7efece8d575b" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "wezterm-input-types" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7012add459f951456ec9d6c7e6fc340b1ce15d6fc9629f8c42853412c029e57e" +dependencies = [ + "bitflags 1.3.2", + "euclid", + "lazy_static", + "serde", + "wezterm-dynamic", +] + [[package]] name = "winapi" version = "0.3.9" @@ -3759,7 +5673,7 @@ checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.118", ] [[package]] @@ -3770,7 +5684,7 @@ checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.118", ] [[package]] @@ -3824,15 +5738,6 @@ dependencies = [ "windows-targets 0.52.6", ] -[[package]] -name = "windows-sys" -version = "0.60.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" -dependencies = [ - "windows-targets 0.53.5", -] - [[package]] name = "windows-sys" version = "0.61.2" @@ -3866,30 +5771,13 @@ dependencies = [ "windows_aarch64_gnullvm 0.52.6", "windows_aarch64_msvc 0.52.6", "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm 0.52.6", + "windows_i686_gnullvm", "windows_i686_msvc 0.52.6", "windows_x86_64_gnu 0.52.6", "windows_x86_64_gnullvm 0.52.6", "windows_x86_64_msvc 0.52.6", ] -[[package]] -name = "windows-targets" -version = "0.53.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" -dependencies = [ - "windows-link", - "windows_aarch64_gnullvm 0.53.1", - "windows_aarch64_msvc 0.53.1", - "windows_i686_gnu 0.53.1", - "windows_i686_gnullvm 0.53.1", - "windows_i686_msvc 0.53.1", - "windows_x86_64_gnu 0.53.1", - "windows_x86_64_gnullvm 0.53.1", - "windows_x86_64_msvc 0.53.1", -] - [[package]] name = "windows_aarch64_gnullvm" version = "0.48.5" @@ -3902,12 +5790,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" - [[package]] name = "windows_aarch64_msvc" version = "0.48.5" @@ -3920,12 +5802,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" -[[package]] -name = "windows_aarch64_msvc" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" - [[package]] name = "windows_i686_gnu" version = "0.48.5" @@ -3938,24 +5814,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" -[[package]] -name = "windows_i686_gnu" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" - [[package]] name = "windows_i686_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" -[[package]] -name = "windows_i686_gnullvm" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" - [[package]] name = "windows_i686_msvc" version = "0.48.5" @@ -3968,12 +5832,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" -[[package]] -name = "windows_i686_msvc" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" - [[package]] name = "windows_x86_64_gnu" version = "0.48.5" @@ -3986,12 +5844,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" -[[package]] -name = "windows_x86_64_gnu" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" - [[package]] name = "windows_x86_64_gnullvm" version = "0.48.5" @@ -4004,12 +5856,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" - [[package]] name = "windows_x86_64_msvc" version = "0.48.5" @@ -4022,12 +5868,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" -[[package]] -name = "windows_x86_64_msvc" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" - [[package]] name = "winnow" version = "0.7.15" @@ -4039,103 +5879,21 @@ dependencies = [ [[package]] name = "wit-bindgen" -version = "0.51.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" -dependencies = [ - "wit-bindgen-rust-macro", -] - -[[package]] -name = "wit-bindgen-core" -version = "0.51.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" -dependencies = [ - "anyhow", - "heck", - "wit-parser", -] - -[[package]] -name = "wit-bindgen-rust" -version = "0.51.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" -dependencies = [ - "anyhow", - "heck", - "indexmap 2.13.0", - "prettyplease", - "syn", - "wasm-metadata", - "wit-bindgen-core", - "wit-component", -] - -[[package]] -name = "wit-bindgen-rust-macro" -version = "0.51.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a" -dependencies = [ - "anyhow", - "prettyplease", - "proc-macro2", - "quote", - "syn", - "wit-bindgen-core", - "wit-bindgen-rust", -] - -[[package]] -name = "wit-component" -version = "0.244.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" -dependencies = [ - "anyhow", - "bitflags", - "indexmap 2.13.0", - "log", - "serde", - "serde_derive", - "serde_json 1.0.149", - "wasm-encoder", - "wasm-metadata", - "wasmparser", - "wit-parser", -] - -[[package]] -name = "wit-parser" -version = "0.244.0" +version = "0.57.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" -dependencies = [ - "anyhow", - "id-arena", - "indexmap 2.13.0", - "log", - "semver", - "serde", - "serde_derive", - "serde_json 1.0.149", - "unicode-xid", - "wasmparser", -] +checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" [[package]] name = "writeable" -version = "0.6.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" +checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4" [[package]] name = "yoke" -version = "0.8.1" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" +checksum = "709fe23a0424b6a435d82152b1bd3fdfb0833487d5fa90d05d42762a9891fef5" dependencies = [ "stable_deref_trait", "yoke-derive", @@ -4144,68 +5902,68 @@ dependencies = [ [[package]] name = "yoke-derive" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" +checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.118", "synstructure", ] [[package]] name = "zerocopy" -version = "0.8.39" +version = "0.8.54" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db6d35d663eadb6c932438e763b262fe1a70987f9ae936e60158176d710cae4a" +checksum = "b7cbbc0a705a0fd05cc3676525980d2bf5a9bc4adac6d6475209a7887cf59d19" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.39" +version = "0.8.54" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4122cd3169e94605190e77839c9a40d40ed048d305bfdc146e7df40ab0f3e517" +checksum = "e2e817b7b52d0c7358d3246da9d69935ebb18116b2b102b4230dac079b4862f5" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.118", ] [[package]] name = "zerofrom" -version = "0.1.6" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" +checksum = "0ec05a11813ea801ff6d75110ad09cd0824ddba17dfe17128ea0d5f68e6c5272" dependencies = [ "zerofrom-derive", ] [[package]] name = "zerofrom-derive" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" +checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.118", "synstructure", ] [[package]] name = "zeroize" -version = "1.8.2" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" +checksum = "e13c156562582aa81c60cb29407084cdb54c4164760106ab78e6c5b0858cf64e" [[package]] name = "zerotrie" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" +checksum = "0f9152d31db0792fa83f70fb2f83148effb5c1f5b8c7686c3459e361d9bc20bf" dependencies = [ "displaydoc", "yoke", @@ -4214,9 +5972,9 @@ dependencies = [ [[package]] name = "zerovec" -version = "0.11.5" +version = "0.11.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" +checksum = "90f911cbc359ab6af17377d242225f4d75119aec87ea711a880987b18cd7b239" dependencies = [ "yoke", "zerofrom", @@ -4225,13 +5983,13 @@ dependencies = [ [[package]] name = "zerovec-derive" -version = "0.11.2" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" +checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.118", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index a7da254..d6992f8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,7 +23,7 @@ clap = { version = "4.5.20", features = ["derive", "env"] } crossterm = "0.28.1" futures-util = "0.3.31" indicatif = "0.17.8" -ratatui = "0.29.0" +ratatui = "0.30.2" reqwest = { version = "0.12.7", default-features = false, features = ["json", "rustls-tls-native-roots"] } serde = { version = "1.0.210", features = ["derive"] } serde_json = "1.0.128" @@ -52,6 +52,23 @@ glob = "0.3" flate2 = "1.1.2" tempfile = "3" uuid = { version = "1.21.0", features = ["v4"] } +oxc_allocator = "0.81" +oxc_codegen = "0.81" +oxc_parser = "0.81" +oxc_semantic = "0.81" +oxc_span = "0.81" +oxc_transformer = "0.81" +swc_atoms = "9.0.1" +swc_bundler = "49.0.0" +swc_common = "21.0.2" +swc_ecma_ast = "23.0.1" +swc_ecma_codegen = "26.0.1" +swc_ecma_loader = { version = "22.0.0", features = ["node"] } +swc_ecma_parser = "39.1.0" +swc_ecma_transforms_base = "42.0.1" +swc_ecma_transforms_react = "47.0.0" +swc_ecma_transforms_typescript = "47.0.0" +swc_ecma_visit = "22.0.0" [profile.dist] inherits = "release" diff --git a/build.rs b/build.rs index 06392f8..757aecd 100644 --- a/build.rs +++ b/build.rs @@ -1,6 +1,23 @@ use std::env; +use std::fs; +use std::path::PathBuf; use std::process::Command; +const PREVIEW_ASSETS: &[(&str, &str)] = &[ + ( + "node_modules/react/umd/react.development.js", + "views-preview-react.js", + ), + ( + "node_modules/react-dom/umd/react-dom.development.js", + "views-preview-react-dom.js", + ), + ( + "node_modules/@tailwindcss/browser/dist/index.global.js", + "views-preview-tailwindcss-browser.js", + ), +]; + fn non_empty_env(name: &str) -> Option { env::var(name) .ok() @@ -46,7 +63,36 @@ fn compute_default_version() -> String { } } +fn copy_preview_assets() { + let manifest_dir = + PathBuf::from(env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR is set by cargo")); + let out_dir = PathBuf::from(env::var("OUT_DIR").expect("OUT_DIR is set by cargo")); + + println!("cargo:rerun-if-changed=package.json"); + println!("cargo:rerun-if-changed=pnpm-lock.yaml"); + for (source, output) in PREVIEW_ASSETS { + let source_path = manifest_dir.join(source); + println!("cargo:rerun-if-changed={}", source_path.display()); + if !source_path.is_file() { + panic!( + "missing preview asset {}; run `pnpm install --ignore-scripts` before building bt", + source_path.display() + ); + } + let output_path = out_dir.join(output); + fs::copy(&source_path, &output_path).unwrap_or_else(|err| { + panic!( + "failed to copy preview asset {} to {}: {err}", + source_path.display(), + output_path.display() + ) + }); + } +} + fn main() { + copy_preview_assets(); + let version = non_empty_env("BT_VERSION_STRING").unwrap_or_else(compute_default_version); println!("cargo:rustc-env=BT_VERSION_STRING={version}"); diff --git a/package.json b/package.json index ab4fab1..144ceef 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,10 @@ "private": true, "packageManager": "pnpm@10.28.2", "devDependencies": { + "@tailwindcss/browser": "4.3.2", "@types/node": "22.15.0", + "react": "18.3.1", + "react-dom": "18.3.1", "typescript": "5.4.4" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5b20e35..663eef9 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1,45 +1,92 @@ -lockfileVersion: "9.0" +lockfileVersion: '9.0' settings: autoInstallPeers: true excludeLinksFromLockfile: false importers: + .: devDependencies: - "@types/node": + '@tailwindcss/browser': + specifier: 4.3.2 + version: 4.3.2 + '@types/node': specifier: 22.15.0 version: 22.15.0 + react: + specifier: 18.3.1 + version: 18.3.1 + react-dom: + specifier: 18.3.1 + version: 18.3.1(react@18.3.1) typescript: specifier: 5.4.4 version: 5.4.4 packages: - "@types/node@22.15.0": - resolution: - { - integrity: sha512-99S8dWD2DkeE6PBaEDw+In3aar7hdoBvjyJMR6vaKBTzpvR0P00ClzJMOoVrj9D2+Sy/YCwACYHnBTpMhg1UCA==, - } + + '@tailwindcss/browser@4.3.2': + resolution: {integrity: sha512-R6hewP9HHwLAY88bFkgAYFIQMRGi9bqx6sR1anI3IThTJtwhPlAm4aHIzDKrnJ8Ct4M3d5A9PCsah8Z5+EjLiQ==} + + '@types/node@22.15.0': + resolution: {integrity: sha512-99S8dWD2DkeE6PBaEDw+In3aar7hdoBvjyJMR6vaKBTzpvR0P00ClzJMOoVrj9D2+Sy/YCwACYHnBTpMhg1UCA==} + + js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + + loose-envify@1.4.0: + resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} + hasBin: true + + react-dom@18.3.1: + resolution: {integrity: sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==} + peerDependencies: + react: ^18.3.1 + + react@18.3.1: + resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==} + engines: {node: '>=0.10.0'} + + scheduler@0.23.2: + resolution: {integrity: sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==} typescript@5.4.4: - resolution: - { - integrity: sha512-dGE2Vv8cpVvw28v8HCPqyb08EzbBURxDpuhJvTrusShUfGnhHBafDsLdS1EhhxyL6BJQE+2cT3dDPAv+MQ6oLw==, - } - engines: { node: ">=14.17" } + resolution: {integrity: sha512-dGE2Vv8cpVvw28v8HCPqyb08EzbBURxDpuhJvTrusShUfGnhHBafDsLdS1EhhxyL6BJQE+2cT3dDPAv+MQ6oLw==} + engines: {node: '>=14.17'} hasBin: true undici-types@6.21.0: - resolution: - { - integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==, - } + resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} snapshots: - "@types/node@22.15.0": + + '@tailwindcss/browser@4.3.2': {} + + '@types/node@22.15.0': dependencies: undici-types: 6.21.0 + js-tokens@4.0.0: {} + + loose-envify@1.4.0: + dependencies: + js-tokens: 4.0.0 + + react-dom@18.3.1(react@18.3.1): + dependencies: + loose-envify: 1.4.0 + react: 18.3.1 + scheduler: 0.23.2 + + react@18.3.1: + dependencies: + loose-envify: 1.4.0 + + scheduler@0.23.2: + dependencies: + loose-envify: 1.4.0 + typescript@5.4.4: {} undici-types@6.21.0: {} diff --git a/scripts/views-preview.html b/scripts/views-preview.html new file mode 100644 index 0000000..c1baec2 --- /dev/null +++ b/scripts/views-preview.html @@ -0,0 +1,210 @@ + + + + + + __HTML_TITLE__ + + + + + + + +
+ + + diff --git a/scripts/views-runner.mjs b/scripts/views-runner.mjs new file mode 100644 index 0000000..855cd31 --- /dev/null +++ b/scripts/views-runner.mjs @@ -0,0 +1,189 @@ +import fs from "node:fs"; +import { pathToFileURL } from "node:url"; + +function isObject(value) { + return typeof value === "object" && value !== null && !Array.isArray(value); +} + +function installDiscoveryReactStub() { + if (globalThis.React) { + return; + } + + const createElement = (...args) => ({ + type: args[0], + props: args[1] ?? {}, + children: args.slice(2), + }); + globalThis.React = { + Children: {}, + Component: class {}, + Fragment: Symbol.for("react.fragment"), + Profiler: Symbol.for("react.profiler"), + PureComponent: class {}, + StrictMode: Symbol.for("react.strict_mode"), + Suspense: Symbol.for("react.suspense"), + cloneElement: createElement, + createContext: () => ({}), + createElement, + createRef: () => ({ current: null }), + forwardRef: (component) => component, + isValidElement: (value) => typeof value === "object" && value !== null, + lazy: (loader) => loader, + memo: (component) => component, + startTransition: (callback) => callback(), + useCallback: (callback) => callback, + useContext: () => undefined, + useDebugValue: () => undefined, + useDeferredValue: (value) => value, + useEffect: () => undefined, + useId: () => "bt-view-id", + useImperativeHandle: () => undefined, + useInsertionEffect: () => undefined, + useLayoutEffect: () => undefined, + useMemo: (factory) => factory(), + useReducer: (_reducer, initialValue) => [initialValue, () => undefined], + useRef: (current) => ({ current }), + useState: (initialValue) => [initialValue, () => undefined], + useSyncExternalStore: () => undefined, + useTransition: () => [false, () => undefined], + }; +} + +function defaultExportFromModule(loaded) { + if ( + !isObject(loaded) || + !Object.prototype.hasOwnProperty.call(loaded, "default") + ) { + return undefined; + } + const value = loaded.default; + if ( + isObject(value) && + Object.prototype.hasOwnProperty.call(value, "default") + ) { + return value.default; + } + return value; +} + +function validateCustomView(value, sourceFile) { + if (!isObject(value)) { + throw new Error( + `${sourceFile} must default-export customTraceView(...) or customDatasetView(...)`, + ); + } + if (value.kind !== "trace" && value.kind !== "dataset") { + throw new Error( + `${sourceFile} default export must be a trace or dataset custom view`, + ); + } + if (typeof value.name !== "string" || !value.name.trim()) { + throw new Error(`${sourceFile} custom view name is required`); + } + if (typeof value.slug !== "string" || !value.slug.trim()) { + throw new Error(`${sourceFile} custom view '${value.name}' slug is required`); + } + if (typeof value.component !== "function") { + throw new Error( + `${sourceFile} custom view '${value.slug}' component must be a function`, + ); + } +} + +function projectFields(project) { + if (typeof project === "string" && project.trim()) { + return { project_name: project }; + } + if (!isObject(project)) { + return {}; + } + return { + ...(typeof project.id === "string" && project.id.trim() + ? { project_id: project.id } + : {}), + ...(typeof project.name === "string" && project.name.trim() + ? { project_name: project.name } + : {}), + }; +} + +function datasetFields(view) { + if (view.kind !== "dataset" || !isObject(view.dataset)) { + return {}; + } + return { + ...(typeof view.dataset.id === "string" && view.dataset.id.trim() + ? { dataset_id: view.dataset.id } + : {}), + ...(typeof view.dataset.name === "string" && view.dataset.name.trim() + ? { dataset_name: view.dataset.name } + : {}), + }; +} + +async function buildManifest(inputPath) { + const input = JSON.parse(fs.readFileSync(inputPath, "utf8")); + if (!Array.isArray(input.files) || input.files.length === 0) { + throw new Error("views metadata runner requires at least one bundled view"); + } + + installDiscoveryReactStub(); + const manifest = { + runtime_context: { + runtime: "browser", + version: "latest", + }, + files: [], + }; + + for (const file of input.files) { + if (!isObject(file)) { + throw new Error("views metadata input file entries must be objects"); + } + const { source_file: sourceFile, bundle_file: bundleFile } = file; + if (typeof sourceFile !== "string" || typeof bundleFile !== "string") { + throw new Error("views metadata input entries require source_file and bundle_file"); + } + const loaded = await import( + `${pathToFileURL(bundleFile).href}?bt_view_nonce=${Date.now()}` + ); + const view = defaultExportFromModule(loaded); + validateCustomView(view, sourceFile); + manifest.files.push({ + source_file: sourceFile, + dependencies: [], + entries: [ + { + kind: "view", + view_type: view.kind, + name: view.name, + slug: view.slug, + code: "", + ...projectFields(view.project), + ...datasetFields(view), + }, + ], + }); + } + + return manifest; +} + +async function main() { + const inputPath = process.argv[2]; + if (!inputPath) { + throw new Error("views metadata runner requires an input path argument"); + } + const manifest = await buildManifest(inputPath); + process.stdout.write(`${JSON.stringify(manifest)}\n`); +} + +main().catch((error) => { + const message = + error instanceof Error + ? error.message + : `failed to build custom view metadata: ${String(error)}`; + process.stderr.write(`${message}\n`); + process.exitCode = 1; +}); diff --git a/scripts/views-sdk.ts b/scripts/views-sdk.ts new file mode 100644 index 0000000..5097c4d --- /dev/null +++ b/scripts/views-sdk.ts @@ -0,0 +1,16 @@ +type CustomViewDefinition = Record; +type Component = (props: unknown) => unknown; + +export function customTraceView( + definition: CustomViewDefinition, + component: Component, +) { + return { ...definition, component, kind: "trace" as const }; +} + +export function customDatasetView( + definition: CustomViewDefinition, + component: Component, +) { + return { ...definition, component, kind: "dataset" as const }; +} diff --git a/src/datasets/api.rs b/src/datasets/api.rs index f07532d..119dea4 100644 --- a/src/datasets/api.rs +++ b/src/datasets/api.rs @@ -230,6 +230,16 @@ pub async fn list_dataset_rows_limited( Ok((rows, truncated)) } +pub async fn get_dataset_row_by_id( + client: &ApiClient, + dataset_id: &str, + row_id: &str, +) -> Result> { + let query = build_dataset_row_by_id_query(dataset_id, row_id, DatasetRowsPreviewLength::Full); + let response = client.btql_structured::(&query).await?; + Ok(response.data.into_iter().next()) +} + pub async fn create_dataset( client: &ApiClient, project_id: &str, @@ -401,6 +411,38 @@ fn build_dataset_rows_query( query } +fn build_dataset_row_by_id_query( + dataset_id: &str, + row_id: &str, + preview_length: DatasetRowsPreviewLength, +) -> Value { + json!({ + "select": dataset_rows_select_fields(), + "from": { + "op": "function", + "name": {"op": "ident", "name": ["dataset"]}, + "args": [{"op": "literal", "value": dataset_id}] + }, + "filter": { + "op": "and", + "children": [ + { + "op": "ge", + "left": {"op": "ident", "name": ["created"]}, + "right": {"op": "literal", "value": DATASET_ROWS_SINCE} + }, + { + "op": "eq", + "left": {"op": "ident", "name": ["id"]}, + "right": {"op": "literal", "value": row_id} + } + ] + }, + "preview_length": preview_length.btql_value(), + "limit": 1 + }) +} + fn dataset_rows_select_fields() -> Vec { DATASET_RECORD_FIELDS .iter() diff --git a/src/main.rs b/src/main.rs index 5f12e60..daedcc1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -34,6 +34,7 @@ mod traces; mod ui; mod util_cmd; mod utils; +mod views; use crate::args::{has_explicit_profile_arg, ArgValueSource, BaseArgs, CLIArgs}; @@ -60,6 +61,7 @@ Core auth Authenticate bt with Braintrust switch Switch org and project context view View logs, traces, and spans + views Push and preview custom views Projects & resources projects Manage projects @@ -133,6 +135,8 @@ enum Commands { Auth(CLIArgs), /// View logs, traces, and spans View(CLIArgs), + /// Push and preview custom views + Views(CLIArgs), #[cfg(unix)] /// Run eval files Eval(CLIArgs), @@ -178,6 +182,7 @@ impl Commands { Commands::Sql(cmd) => &cmd.base, Commands::Auth(cmd) => &cmd.base, Commands::View(cmd) => &cmd.base, + Commands::Views(cmd) => &cmd.base, #[cfg(unix)] Commands::Eval(cmd) => &cmd.base, Commands::Projects(cmd) => &cmd.base, @@ -205,6 +210,7 @@ impl Commands { Commands::Sql(cmd) => &mut cmd.base, Commands::Auth(cmd) => &mut cmd.base, Commands::View(cmd) => &mut cmd.base, + Commands::Views(cmd) => &mut cmd.base, #[cfg(unix)] Commands::Eval(cmd) => &mut cmd.base, Commands::Projects(cmd) => &mut cmd.base, @@ -309,6 +315,7 @@ fn try_main() -> Result<()> { match cli.command { Commands::Auth(cmd) => auth::run(cmd.base, cmd.args).await?, Commands::View(cmd) => traces::run(cmd.base, cmd.args).await?, + Commands::Views(cmd) => views::run(cmd.base, cmd.args).await?, Commands::Init(cmd) => init::run(cmd.base, cmd.args).await?, Commands::Sql(cmd) => sql::run(cmd.base, cmd.args).await?, Commands::Setup(cmd) => setup::run_setup_top(cmd.base, cmd.args).await?, diff --git a/src/views.rs b/src/views.rs new file mode 100644 index 0000000..2e9c0e3 --- /dev/null +++ b/src/views.rs @@ -0,0 +1,3371 @@ +use std::collections::{BTreeMap, BTreeSet, HashMap}; +use std::fmt::Write as _; +use std::io::Write; +use std::net::TcpListener; +use std::path::{Path, PathBuf}; +use std::process::{Command, Stdio}; +use std::sync::{Arc, Mutex}; +use std::time::UNIX_EPOCH; + +use actix_web::{web, App, HttpResponse, HttpServer}; +use anyhow::{anyhow, bail, Context, Result}; +use clap::{builder::BoolishValueParser, Args, Subcommand}; +use oxc_allocator::Allocator; +use oxc_codegen::{Codegen, CodegenOptions}; +use oxc_parser::Parser; +use oxc_semantic::SemanticBuilder; +use oxc_span::SourceType; +use oxc_transformer::{TransformOptions, Transformer}; +use reqwest::Url; +use serde::{Deserialize, Serialize}; +use serde_json::{json, Map, Value}; +use swc_bundler::{ + Bundle, BundleKind, Bundler, Config as SwcBundlerConfig, Hook, Load, ModuleData, ModuleRecord, + ModuleType, +}; +use swc_common::{comments::NoopComments, sync::Lrc, FileName, Globals, Mark, SourceMap, Span}; +use swc_ecma_ast::{EsVersion, KeyValueProp, Program}; +use swc_ecma_codegen::to_code_default; +use swc_ecma_loader::{ + resolve::{Resolution, Resolve}, + resolvers::node::NodeModulesResolver, + TargetEnv as SwcTargetEnv, +}; +use swc_ecma_parser::{parse_file_as_module, EsSyntax, Syntax, TsSyntax}; +use swc_ecma_transforms_base::helpers::Helpers; +use swc_ecma_transforms_base::{fixer::fixer, resolver}; +use swc_ecma_transforms_react::{react, Options as ReactOptions, Runtime as ReactRuntime}; +use swc_ecma_transforms_typescript::strip as strip_typescript; +use urlencoding::encode; + +use crate::args::BaseArgs; +use crate::auth; +use crate::datasets::api as datasets_api; +use crate::functions::{self, api as functions_api, IfExistsMode}; +use crate::http::ApiClient; +use crate::project_context::{resolve_project_optional, resolve_required_project}; +use crate::projects::api::{get_project_by_name, list_projects, Project}; +use crate::ui::{self, with_spinner}; +use crate::utils::{app_project_url, app_project_url_with_encoded_path}; + +const VIEWS_JS_RUNNER_SOURCE: &str = include_str!("../scripts/views-runner.mjs"); +const VIEWS_JS_SDK_SOURCE: &str = include_str!("../scripts/views-sdk.ts"); +const VIEWS_PREVIEW_HTML_TEMPLATE: &str = include_str!("../scripts/views-preview.html"); +const VIEWS_PREVIEW_REACT_SOURCE: &str = + include_str!(concat!(env!("OUT_DIR"), "/views-preview-react.js")); +const VIEWS_PREVIEW_REACT_DOM_SOURCE: &str = + include_str!(concat!(env!("OUT_DIR"), "/views-preview-react-dom.js")); +const VIEWS_PREVIEW_TAILWIND_SOURCE: &str = include_str!(concat!( + env!("OUT_DIR"), + "/views-preview-tailwindcss-browser.js" +)); +const DEFAULT_TRACE_PREVIEW_LIMIT: usize = 1000; +const DEFAULT_CUSTOM_VIEWS_DIR: &str = "braintrust-custom-views"; +const CUSTOM_VIEW_TSCONFIG_FILE: &str = "tsconfig.json"; +const CUSTOM_VIEW_TYPES_FILE: &str = "custom-view-env.d.ts"; +const VIEW_FILE_PATTERN_HELP: &str = + "*.view.tsx, *.view.ts, *.view.jsx, *.view.js, *-view.tsx, *-view.ts, *-view.jsx, or *-view.js"; + +#[derive(Debug, Clone, Args)] +#[command(after_help = "\ +Examples: + bt views push ./views + bt views push ./conversation.view.tsx --if-exists replace + bt views trace bootstrap 'Trace Review' + bt views dataset bootstrap 'Dataset Review' --dataset test-dataset + bt views trace preview ./conversation.trace-view.tsx --url + bt views trace preview ./conversation.trace-view.tsx --trace-id + bt views dataset preview ./dataset.dataset-view.tsx --dataset test-dataset --row-index 0 +")] +pub struct ViewsArgs { + #[command(subcommand)] + command: ViewsCommands, +} + +#[derive(Debug, Clone, Subcommand)] +enum ViewsCommands { + /// Push local custom view definitions + Push(ViewsPushArgs), + /// Work with trace custom views + Trace(TraceViewsArgs), + /// Work with dataset custom views + Dataset(DatasetViewsArgs), +} + +#[derive(Debug, Clone, Args)] +struct ViewsPushArgs { + /// File or directory path(s) to scan for custom view definitions. + #[arg(value_name = "PATH")] + paths: Vec, + + /// File or directory path(s) to scan for custom view definitions. + #[arg( + long = "file", + env = "BT_VIEWS_PUSH_FILES", + value_name = "PATH", + value_delimiter = ',' + )] + file_flag: Vec, + + /// Behavior when a custom view with the same slug already exists. + #[arg( + long = "if-exists", + env = "BT_VIEWS_PUSH_IF_EXISTS", + value_enum, + default_value = "error" + )] + if_exists: IfExistsMode, + + /// Skip confirmation prompt. + #[arg( + long, + short = 'y', + env = "BT_VIEWS_PUSH_YES", + value_parser = BoolishValueParser::new(), + default_value_t = false + )] + yes: bool, +} + +impl ViewsPushArgs { + fn resolved_paths(&self) -> Vec { + let mut paths = self.paths.clone(); + paths.extend(self.file_flag.iter().cloned()); + if paths.is_empty() { + vec![PathBuf::from(".")] + } else { + paths + } + } +} + +#[derive(Debug, Clone, Args)] +struct TraceViewsArgs { + #[command(subcommand)] + command: TraceViewsCommands, +} + +#[derive(Debug, Clone, Subcommand)] +enum TraceViewsCommands { + /// Create a starter trace custom view file + Bootstrap(TraceViewBootstrapArgs), + /// Preview one trace custom view locally + Preview(TraceViewPreviewArgs), +} + +#[derive(Debug, Clone, Args)] +struct DatasetViewsArgs { + #[command(subcommand)] + command: DatasetViewsCommands, +} + +#[derive(Debug, Clone, Subcommand)] +enum DatasetViewsCommands { + /// Create a starter dataset custom view file + Bootstrap(DatasetViewBootstrapArgs), + /// Preview one dataset custom view locally + Preview(DatasetViewPreviewArgs), +} + +#[derive(Debug, Clone, Args)] +struct BootstrapCommonArgs { + /// Custom view name. + #[arg(value_name = "NAME")] + name: String, + + /// Output file or directory path. Defaults to braintrust-custom-views/.-view.tsx. + #[arg(long = "file", env = "BT_VIEWS_BOOTSTRAP_FILE", value_name = "PATH")] + file_flag: Option, + + /// Overwrite an existing file. + #[arg( + long, + short = 'f', + env = "BT_VIEWS_BOOTSTRAP_FORCE", + value_parser = BoolishValueParser::new(), + default_value_t = false + )] + force: bool, +} + +#[derive(Debug, Clone, Args)] +struct TraceViewBootstrapArgs { + #[command(flatten)] + common: BootstrapCommonArgs, +} + +#[derive(Debug, Clone, Args)] +struct DatasetViewBootstrapArgs { + #[command(flatten)] + common: BootstrapCommonArgs, + + /// Dataset name to reference in the starter view. + #[arg( + long, + env = "BT_VIEWS_BOOTSTRAP_DATASET", + value_name = "NAME", + conflicts_with = "dataset_id" + )] + dataset: Option, + + /// Dataset id to reference in the starter view. + #[arg( + long = "dataset-id", + env = "BT_VIEWS_BOOTSTRAP_DATASET_ID", + value_name = "ID", + conflicts_with = "dataset" + )] + dataset_id: Option, +} + +#[derive(Debug, Serialize)] +struct BootstrapResult { + path: String, + tsconfig_path: String, + tsconfig_created: bool, + types_path: String, + types_created: bool, + view_type: ViewType, +} + +#[derive(Debug, Clone, Args)] +struct PreviewCommonArgs { + /// Custom view file to preview. + #[arg(value_name = "PATH")] + path: PathBuf, + + /// View slug or name to preview. + #[arg(long, env = "BT_VIEWS_PREVIEW_VIEW")] + view: Option, + + /// Local port to bind. Defaults to an ephemeral port. + #[arg(long, env = "BT_VIEWS_PREVIEW_PORT", default_value_t = 0)] + port: u16, + + /// Do not open a browser. + #[arg( + long, + env = "BT_VIEWS_PREVIEW_NO_OPEN", + value_parser = BoolishValueParser::new(), + default_value_t = false + )] + no_open: bool, +} + +#[derive(Debug, Clone, Args)] +struct TraceViewPreviewArgs { + #[command(flatten)] + common: PreviewCommonArgs, + + #[command(flatten)] + target: TracePreviewTargetArgs, +} + +#[derive(Debug, Clone, Args)] +struct TracePreviewTargetArgs { + /// Braintrust app URL to resolve trace preview data from. + #[arg(long, env = "BT_VIEWS_PREVIEW_URL")] + url: Option, + + /// Project ID to query for trace preview data. + #[arg(long, env = "BT_VIEWS_PREVIEW_PROJECT_ID")] + project_id: Option, + + /// Root span id for trace preview data. + #[arg( + long = "trace-id", + alias = "root-span-id", + env = "BT_VIEWS_PREVIEW_TRACE_ID" + )] + trace_id: Option, + + /// Selected span id or row id for trace preview data. + #[arg(long, env = "BT_VIEWS_PREVIEW_SPAN_ID")] + span_id: Option, +} + +#[derive(Debug, Clone, Args)] +struct DatasetViewPreviewArgs { + #[command(flatten)] + common: PreviewCommonArgs, + + #[command(flatten)] + target: DatasetPreviewTargetArgs, +} + +#[derive(Debug, Clone, Args)] +struct DatasetPreviewTargetArgs { + /// Dataset name or id for dataset preview data. + #[arg(long, env = "BT_VIEWS_PREVIEW_DATASET")] + dataset: Option, + + /// Dataset row id for dataset preview data. + #[arg(long, env = "BT_VIEWS_PREVIEW_ROW_ID")] + row_id: Option, + + /// Dataset row index for dataset preview data. + #[arg(long, env = "BT_VIEWS_PREVIEW_ROW_INDEX")] + row_index: Option, +} + +#[derive(Debug, Deserialize)] +struct ViewsManifest { + runtime_context: ViewsRuntimeContext, + #[serde(default)] + files: Vec, +} + +#[derive(Debug, Serialize)] +struct ViewsDiscoveryInput { + files: Vec, +} + +#[derive(Debug, Serialize)] +struct ViewsDiscoveryInputFile { + source_file: String, + bundle_file: String, +} + +#[derive(Debug, Deserialize)] +struct ViewsRuntimeContext { + runtime: String, + version: String, +} + +#[derive(Debug, Deserialize)] +struct ViewsManifestFile { + source_file: String, + #[allow(dead_code)] + #[serde(default)] + dependencies: Vec, + #[serde(default)] + entries: Vec, +} + +#[derive(Debug, Deserialize, Clone)] +struct ViewManifestEntry { + view_type: ViewType, + name: String, + slug: String, + code: String, + #[serde(default)] + project_id: Option, + #[serde(default)] + project_name: Option, + #[serde(default)] + dataset_id: Option, + #[serde(default)] + dataset_name: Option, +} + +#[derive(Debug, Deserialize, Serialize, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +#[serde(rename_all = "snake_case")] +enum ViewType { + Trace, + Dataset, +} + +impl ViewType { + fn label(self) -> &'static str { + match self { + Self::Trace => "trace", + Self::Dataset => "dataset", + } + } +} + +#[derive(Debug, Clone)] +struct PreparedView { + source_file: String, + entry: ViewManifestEntry, + project: Project, + dataset: Option, +} + +#[derive(Debug, Serialize)] +struct PushedView { + source_file: String, + name: String, + slug: String, + view_type: ViewType, + project_id: String, + project_name: String, + dataset_id: Option, + function_id: Option, + url: Option, +} + +#[derive(Debug, Deserialize)] +struct BtqlResponse { + data: Vec>, +} + +struct PreviewServerState { + client: ApiClient, + project: Option, + target: PreviewTarget, + source: PreviewSource, + title: String, + dependency_paths: Mutex>, + trace_project_id: Mutex>, + trace_data: Mutex>, +} + +struct PreviewContext { + client: ApiClient, + project: Option, + source: PreviewSource, +} + +struct TracePreviewData { + project_id: String, + data: Value, +} + +#[derive(Clone)] +struct PreviewSource { + path: PathBuf, + root: PathBuf, + view: Option, + view_type: ViewType, +} + +#[derive(Clone)] +enum PreviewTarget { + Trace(TracePreviewTargetArgs), + Dataset(DatasetPreviewTargetArgs), +} + +#[derive(Debug, Deserialize)] +struct SpanFieldsRequest { + #[serde(rename = "spanIds")] + span_ids: Vec, + fields: Option>, +} + +#[derive(Debug, Deserialize)] +struct PreviewDataRequest { + view_type: ViewType, + name: String, + slug: String, + project_id: Option, + project_name: Option, + dataset_id: Option, + dataset_name: Option, +} + +pub async fn run(base: BaseArgs, args: ViewsArgs) -> Result<()> { + match args.command { + ViewsCommands::Push(push_args) => push(base, push_args).await, + ViewsCommands::Trace(trace_args) => match trace_args.command { + TraceViewsCommands::Bootstrap(bootstrap_args) => bootstrap_trace(base, bootstrap_args), + TraceViewsCommands::Preview(preview_args) => preview_trace(base, preview_args).await, + }, + ViewsCommands::Dataset(dataset_args) => match dataset_args.command { + DatasetViewsCommands::Bootstrap(bootstrap_args) => { + bootstrap_dataset(base, bootstrap_args) + } + DatasetViewsCommands::Preview(preview_args) => { + preview_dataset(base, preview_args).await + } + }, + } +} + +fn bootstrap_trace(base: BaseArgs, args: TraceViewBootstrapArgs) -> Result<()> { + let slug = bootstrap_slug(&args.common.name)?; + let default_file_name = format!("{slug}.trace-view.tsx"); + let content = trace_view_bootstrap_template(&args.common.name, &slug); + let result = write_bootstrap_scaffold(args.common, &default_file_name, &content)?; + print_bootstrap_result(base.json, ViewType::Trace, &result) +} + +fn bootstrap_dataset(base: BaseArgs, args: DatasetViewBootstrapArgs) -> Result<()> { + let slug = bootstrap_slug(&args.common.name)?; + let dataset_ref = match ( + args.dataset_id.as_deref().map(str::trim), + args.dataset.as_deref().map(str::trim), + ) { + (Some(dataset_id), _) if !dataset_id.is_empty() => { + format!("{{ id: {dataset_id:?} }}") + } + (_, Some(dataset)) if !dataset.is_empty() => format!("{{ name: {dataset:?} }}"), + _ => "{ name: \"test-dataset\" }".to_string(), + }; + let default_file_name = format!("{slug}.dataset-view.tsx"); + let content = dataset_view_bootstrap_template(&args.common.name, &slug, &dataset_ref); + let result = write_bootstrap_scaffold(args.common, &default_file_name, &content)?; + print_bootstrap_result(base.json, ViewType::Dataset, &result) +} + +fn bootstrap_slug(name: &str) -> Result { + let mut slug = String::new(); + let mut pending_separator = false; + + for ch in name.trim().chars() { + if ch.is_ascii_alphanumeric() { + if pending_separator && !slug.is_empty() { + slug.push('-'); + } + slug.push(ch.to_ascii_lowercase()); + pending_separator = false; + } else if !slug.is_empty() { + pending_separator = true; + } + } + + if slug.is_empty() { + bail!("custom view name must contain at least one ASCII letter or number"); + } + Ok(slug) +} + +struct BootstrapWriteResult { + view_path: PathBuf, + tsconfig_path: PathBuf, + tsconfig_status: BootstrapSupportFileStatus, + types_path: PathBuf, + types_status: BootstrapSupportFileStatus, +} + +impl BootstrapWriteResult { + fn tsconfig_created(&self) -> bool { + matches!(self.tsconfig_status, BootstrapSupportFileStatus::Created) + } + + fn types_created(&self) -> bool { + matches!(self.types_status, BootstrapSupportFileStatus::Created) + } +} + +#[derive(Debug, Clone, Copy)] +enum BootstrapSupportFileStatus { + Created, + Reused, + Updated, +} + +impl BootstrapSupportFileStatus { + fn label(self) -> &'static str { + match self { + Self::Created => "Created", + Self::Reused => "Reused", + Self::Updated => "Updated", + } + } +} + +fn write_bootstrap_scaffold( + args: BootstrapCommonArgs, + default_file_name: &str, + content: &str, +) -> Result { + let selected_path = args + .file_flag + .unwrap_or_else(|| PathBuf::from(DEFAULT_CUSTOM_VIEWS_DIR)); + let (view_path, config_dir) = if selected_path.is_dir() || selected_path.extension().is_none() { + (selected_path.join(default_file_name), Some(selected_path)) + } else { + let config_dir = selected_path + .parent() + .filter(|parent| !parent.as_os_str().is_empty()) + .map(Path::to_path_buf); + (selected_path, config_dir) + }; + let tsconfig_path = config_dir + .as_ref() + .map(|dir| dir.join(CUSTOM_VIEW_TSCONFIG_FILE)) + .unwrap_or_else(|| PathBuf::from(CUSTOM_VIEW_TSCONFIG_FILE)); + let types_path = config_dir + .as_ref() + .map(|dir| dir.join(CUSTOM_VIEW_TYPES_FILE)) + .unwrap_or_else(|| PathBuf::from(CUSTOM_VIEW_TYPES_FILE)); + + let is_tsx_view_file = view_path + .file_name() + .and_then(|name| name.to_str()) + .is_some_and(|name| name.ends_with(".view.tsx") || name.ends_with("-view.tsx")); + if !is_tsx_view_file { + bail!("custom view bootstrap path must end with .view.tsx or -view.tsx"); + } + if view_path.exists() && !args.force { + bail!( + "custom view file already exists: {}. Use --force to overwrite.", + view_path.display() + ); + } + if let Some(parent) = view_path + .parent() + .filter(|parent| !parent.as_os_str().is_empty()) + { + std::fs::create_dir_all(parent) + .with_context(|| format!("failed to create directory {}", parent.display()))?; + } + let tsconfig_exists = tsconfig_path.exists(); + if tsconfig_exists && !tsconfig_path.is_file() { + bail!( + "custom view tsconfig path already exists and is not a file: {}", + tsconfig_path.display() + ); + } + let types_exists = types_path.exists(); + if types_exists && !types_path.is_file() { + bail!( + "custom view types path already exists and is not a file: {}", + types_path.display() + ); + } + std::fs::write(&view_path, content) + .with_context(|| format!("failed to write custom view file {}", view_path.display()))?; + + let tsconfig_status = if !tsconfig_exists || args.force { + std::fs::write(&tsconfig_path, CUSTOM_VIEW_TSCONFIG_TEMPLATE).with_context(|| { + format!( + "failed to write custom view tsconfig {}", + tsconfig_path.display() + ) + })?; + if tsconfig_exists { + BootstrapSupportFileStatus::Updated + } else { + BootstrapSupportFileStatus::Created + } + } else { + BootstrapSupportFileStatus::Reused + }; + + let types_status = if !types_exists || args.force { + std::fs::write(&types_path, CUSTOM_VIEW_TYPES_TEMPLATE).with_context(|| { + format!("failed to write custom view types {}", types_path.display()) + })?; + if types_exists { + BootstrapSupportFileStatus::Updated + } else { + BootstrapSupportFileStatus::Created + } + } else { + BootstrapSupportFileStatus::Reused + }; + + Ok(BootstrapWriteResult { + view_path, + tsconfig_path, + tsconfig_status, + types_path, + types_status, + }) +} + +fn print_bootstrap_result( + json_output: bool, + view_type: ViewType, + result: &BootstrapWriteResult, +) -> Result<()> { + let tsconfig_action = result.tsconfig_status.label(); + let types_action = result.types_status.label(); + let result = BootstrapResult { + path: result.view_path.display().to_string(), + tsconfig_path: result.tsconfig_path.display().to_string(), + tsconfig_created: result.tsconfig_created(), + types_path: result.types_path.display().to_string(), + types_created: result.types_created(), + view_type, + }; + if json_output { + println!("{}", serde_json::to_string_pretty(&result)?); + } else { + println!( + "Created {} custom view starter at {}", + view_type.label(), + result.path + ); + println!( + "{tsconfig_action} TypeScript config at {}", + result.tsconfig_path + ); + println!( + "{types_action} custom view type declarations at {}", + result.types_path + ); + println!( + "Preview it with: bt views {} preview {}", + view_type.label(), + result.path + ); + } + Ok(()) +} + +const CUSTOM_VIEW_TSCONFIG_TEMPLATE: &str = r#"{ + "compilerOptions": { + "target": "ES2020", + "lib": ["DOM", "DOM.Iterable", "ES2020"], + "module": "ESNext", + "moduleResolution": "Bundler", + "jsx": "react-jsx", + "strict": true, + "noEmit": true, + "esModuleInterop": true, + "allowSyntheticDefaultImports": true, + "allowJs": true, + "skipLibCheck": true, + "types": [] + }, + "include": [ + "**/*.view.ts", + "**/*.view.tsx", + "**/*.view.js", + "**/*.view.jsx", + "**/*-view.ts", + "**/*-view.tsx", + "**/*-view.js", + "**/*-view.jsx", + "**/*.d.ts" + ] +} +"#; + +const CUSTOM_VIEW_TYPES_TEMPLATE: &str = r#"type CustomViewElementProps = { + [propName: string]: unknown; +}; + +type CustomViewSelectChangeEvent = { + target: { value: string }; + currentTarget: { value: string }; + preventDefault: () => void; + stopPropagation: () => void; +}; + +interface CustomViewSelectProps extends CustomViewElementProps { + value?: string | number | readonly string[]; + defaultValue?: string | number | readonly string[]; + onChange?: (event: CustomViewSelectChangeEvent) => void; +} + +interface CustomViewOptionProps extends CustomViewElementProps { + value?: string | number; +} + +interface CustomViewIntrinsicElements { + select: CustomViewSelectProps; + option: CustomViewOptionProps; + [elementName: string]: CustomViewElementProps; +} + +declare namespace JSX { + interface IntrinsicElements extends CustomViewIntrinsicElements {} +} + +declare module "react" { + type ReactNode = any; + type ComponentType = (props: Props) => ReactNode; + type Dispatch = (value: Value) => void; + type SetStateAction = Value | ((previous: Value) => Value); + + const React: { + createElement: (...args: any[]) => ReactNode; + Fragment: any; + }; + + export default React; + export const Children: any; + export const Component: any; + export const Fragment: any; + export const Profiler: any; + export const PureComponent: any; + export const StrictMode: any; + export const Suspense: any; + export const cloneElement: (...args: any[]) => ReactNode; + export const createContext: (...args: any[]) => any; + export const createElement: (...args: any[]) => ReactNode; + export const createRef: (...args: any[]) => any; + export const forwardRef: (component: any) => any; + export const isValidElement: (value: any) => boolean; + export const lazy: (loader: any) => any; + export const memo: (component: ComponentType) => ComponentType; + export const startTransition: (callback: () => void) => void; + export const useCallback: any>(callback: Value, deps?: any[]) => Value; + export const useContext: (context: any) => any; + export const useDebugValue: (...args: any[]) => void; + export const useDeferredValue: (value: Value) => Value; + export const useEffect: (effect: () => void | (() => void), deps?: any[]) => void; + export const useId: () => string; + export const useImperativeHandle: (...args: any[]) => void; + export const useInsertionEffect: (effect: () => void | (() => void), deps?: any[]) => void; + export const useLayoutEffect: (effect: () => void | (() => void), deps?: any[]) => void; + export const useMemo: (factory: () => Value, deps?: any[]) => Value; + export const useReducer: (...args: any[]) => any; + export const useRef: (initialValue: Value) => { current: Value }; + export const useState: (initialValue: Value | (() => Value)) => [Value, Dispatch>]; + export const useSyncExternalStore: (...args: any[]) => any; + export const useTransition: () => [boolean, (callback: () => void) => void]; +} + +declare module "react/jsx-runtime" { + export namespace JSX { + interface IntrinsicElements extends CustomViewIntrinsicElements {} + } + + export const Fragment: any; + export const jsx: (...args: any[]) => any; + export const jsxs: (...args: any[]) => any; +} + +declare module "react/jsx-dev-runtime" { + export namespace JSX { + interface IntrinsicElements extends CustomViewIntrinsicElements {} + } + + export const Fragment: any; + export const jsxDEV: (...args: any[]) => any; +} +"#; + +const TRACE_VIEW_BOOTSTRAP_TEMPLATE: &str = r##"import { customTraceView } from "braintrust/custom-views"; + +function pretty(value: unknown) { + return value === undefined ? "" : JSON.stringify(value, null, 2); +} + +export default customTraceView( + { + name: __VIEW_NAME__, + slug: __VIEW_SLUG__, + }, + ({ trace, span, selectSpan }) => { + const spanIds = trace.spanOrder.slice(0, 100); + + return ( +
+
+ Trace starter view + +
+ +
+
Selected span
+
row id: {span.id}
+
span id: {span.span_id}
+
children: {span.children.length}
+
+ +
+
+            {pretty(span.data.input)}
+          
+
+            {pretty(span.data.output)}
+          
+
+
+ ); + }, +); +"##; + +const DATASET_VIEW_BOOTSTRAP_TEMPLATE: &str = r##"import { customDatasetView } from "braintrust/custom-views"; + +function pretty(value: unknown) { + return value === undefined ? "" : JSON.stringify(value, null, 2); +} + +export default customDatasetView( + { + name: __VIEW_NAME__, + slug: __VIEW_SLUG__, + dataset: __DATASET_REF__, + }, + ({ id, input, expected, metadata, tags = [] }) => { + return ( +
+
+ Dataset starter view +
row id: {id}
+ {tags.length > 0 ? ( +
tags: {tags.join(", ")}
+ ) : null} +
+ +
+
+            {pretty(input)}
+          
+
+            {pretty(expected)}
+          
+
+            {pretty(metadata)}
+          
+
+
+ ); + }, +); +"##; + +fn js_string_literal(value: &str) -> String { + serde_json::to_string(value).expect("strings serialize to JSON") +} + +fn trace_view_bootstrap_template(name: &str, slug: &str) -> String { + TRACE_VIEW_BOOTSTRAP_TEMPLATE + .replace("__VIEW_NAME__", &js_string_literal(name)) + .replace("__VIEW_SLUG__", &js_string_literal(slug)) +} + +fn dataset_view_bootstrap_template(name: &str, slug: &str, dataset_ref: &str) -> String { + DATASET_VIEW_BOOTSTRAP_TEMPLATE + .replace("__VIEW_NAME__", &js_string_literal(name)) + .replace("__VIEW_SLUG__", &js_string_literal(slug)) + .replace("__DATASET_REF__", dataset_ref) +} + +async fn push(base: BaseArgs, args: ViewsPushArgs) -> Result<()> { + let auth_ctx = functions::resolve_auth_context(&base).await?; + let default_project = resolve_required_project(&base, &auth_ctx.client, true).await?; + let files = collect_view_files(&args.resolved_paths())?; + if files.is_empty() { + bail!("no custom view files found; expected files matching {VIEW_FILE_PATTERN_HELP}"); + } + + let manifest = run_views_runner(&files)?; + validate_manifest_runtime(&manifest)?; + let prepared = prepare_views(&auth_ctx.client, &default_project, &manifest).await?; + if prepared.is_empty() { + bail!("no custom views were registered by the selected files"); + } + + if !args.yes && ui::can_prompt() { + let prompt = format!("Push {} custom view(s)?", prepared.len()); + let confirmed = dialoguer::Confirm::new() + .with_prompt(prompt) + .default(true) + .interact()?; + if !confirmed { + bail!("custom view push cancelled"); + } + } + + let events = prepared + .iter() + .map(|view| build_insert_event(view, args.if_exists)) + .collect::>(); + + let ignored = with_spinner( + "Pushing custom views...", + functions_api::insert_functions(&auth_ctx.client, &events), + ) + .await + .map_err(|err| anyhow!(format_views_insert_error(&prepared, args.if_exists, &err)))? + .ignored_entries + .unwrap_or(0); + + let pushed = resolve_pushed_views(&auth_ctx.client, &auth_ctx.app_url, &prepared).await?; + if base.json { + println!( + "{}", + serde_json::to_string_pretty(&json!({ + "pushed": pushed, + "ignored": ignored, + }))? + ); + return Ok(()); + } + + eprintln!( + "{} Pushed {} custom view(s)", + dialoguer::console::style("Success:").green(), + pushed.len() + ); + for view in &pushed { + let mut details = format!( + "{} {} ({})", + view.view_type.label(), + view.name, + view.project_name + ); + if let Some(dataset_id) = &view.dataset_id { + write!(details, ", dataset {dataset_id}").ok(); + } + if let Some(url) = &view.url { + write!(details, ": {url}").ok(); + } + eprintln!(" {}", details); + } + if ignored > 0 { + eprintln!(" Ignored {} existing custom view(s)", ignored); + } + Ok(()) +} + +async fn preview_trace(base: BaseArgs, args: TraceViewPreviewArgs) -> Result<()> { + let context = resolve_preview_context( + &base, + &args.common, + ViewType::Trace, + args.target.url.as_deref(), + ) + .await?; + serve_preview( + base, + &args.common, + context.client, + context.project, + PreviewTarget::Trace(args.target), + context.source, + ) + .await +} + +async fn preview_dataset(base: BaseArgs, args: DatasetViewPreviewArgs) -> Result<()> { + let context = resolve_preview_context(&base, &args.common, ViewType::Dataset, None).await?; + serve_preview( + base, + &args.common, + context.client, + context.project, + PreviewTarget::Dataset(args.target), + context.source, + ) + .await +} + +async fn resolve_preview_context( + base: &BaseArgs, + args: &PreviewCommonArgs, + view_type: ViewType, + trace_url: Option<&str>, +) -> Result { + let source = prepare_preview_source(&args.path, args.view.clone(), view_type)?; + + let auth_ctx = auth::login_read_only(&base).await?; + let client = ApiClient::new(&auth_ctx)?; + let project = if trace_url_supplies_project(view_type, trace_url) { + None + } else if view_type == ViewType::Trace && trace_url.is_some() { + resolve_project_optional(&base, &client, true).await? + } else { + Some(resolve_required_project(&base, &client, true).await?) + }; + Ok(PreviewContext { + client, + project, + source, + }) +} + +async fn serve_preview( + base: BaseArgs, + args: &PreviewCommonArgs, + client: ApiClient, + project: Option, + target: PreviewTarget, + source: PreviewSource, +) -> Result<()> { + let listener = TcpListener::bind(("127.0.0.1", args.port)) + .with_context(|| format!("failed to bind preview server on port {}", args.port))?; + let addr = listener + .local_addr() + .context("failed to read preview address")?; + let url = format!("http://{addr}"); + let title = preview_title(&source); + let state = web::Data::new(PreviewServerState { + client, + project, + target, + source, + title, + dependency_paths: Mutex::new(Vec::new()), + trace_project_id: Mutex::new(None), + trace_data: Mutex::new(None), + }); + let server = HttpServer::new(move || { + App::new() + .app_data(state.clone()) + .route("/", web::get().to(preview_index)) + .route("/preview-assets/{asset}.js", web::get().to(preview_asset)) + .route("/preview-module/{tail:.*}", web::get().to(preview_module)) + .route( + "/preview-virtual/{module}.js", + web::get().to(preview_virtual_module), + ) + .route("/preview-version", web::get().to(preview_version)) + .route("/preview-data", web::post().to(preview_data)) + .route("/span-fields", web::post().to(preview_span_fields)) + }) + .workers(1) + .listen(listener)? + .run(); + let handle = server.handle(); + tokio::spawn(server); + + if base.json { + println!( + "{}", + serde_json::to_string_pretty(&json!({ + "url": url, + "view": { + "path": args.path.display().to_string(), + "selector": args.view, + }, + }))? + ); + } else { + println!("Previewing {} at {}", args.path.display(), url); + } + + if !args.no_open { + open::that(&url)?; + } + + tokio::signal::ctrl_c() + .await + .context("failed to wait for Ctrl+C")?; + handle.stop(true).await; + Ok(()) +} + +async fn preview_index(state: web::Data) -> HttpResponse { + let dependency_paths = state + .dependency_paths + .lock() + .map(|paths| paths.clone()) + .unwrap_or_default(); + let version = preview_source_version(&state.source, &dependency_paths); + let html = render_preview_html(&state.title, &state.source, &version); + HttpResponse::Ok() + .content_type("text/html; charset=utf-8") + .body(html) +} + +async fn preview_asset(asset: web::Path) -> HttpResponse { + match preview_asset_source(&asset) { + Some(code) => HttpResponse::Ok() + .content_type("application/javascript; charset=utf-8") + .body(code), + None => HttpResponse::NotFound().json(json!({ + "error": format!("unknown preview asset '{}'", asset.as_str()), + })), + } +} + +async fn preview_module( + state: web::Data, + tail: web::Path, +) -> HttpResponse { + match preview_module_result(&state, &tail.into_inner()) { + Ok(code) => HttpResponse::Ok() + .content_type("application/javascript; charset=utf-8") + .body(code), + Err(err) => HttpResponse::BadRequest().json(json!({ + "error": format!("{err:#}"), + })), + } +} + +async fn preview_virtual_module(module: web::Path) -> HttpResponse { + match preview_virtual_module_source(&module) { + Some(code) => HttpResponse::Ok() + .content_type("application/javascript; charset=utf-8") + .body(code), + None => HttpResponse::NotFound().json(json!({ + "error": format!("unknown preview virtual module '{}'", module.as_str()), + })), + } +} + +async fn preview_version(state: web::Data) -> HttpResponse { + let dependency_paths = state + .dependency_paths + .lock() + .map(|paths| paths.clone()) + .unwrap_or_default(); + HttpResponse::Ok().json(json!({ + "version": preview_source_version(&state.source, &dependency_paths), + })) +} + +async fn preview_data( + state: web::Data, + body: web::Json, +) -> HttpResponse { + match preview_data_result(&state, body.into_inner()).await { + Ok(data) => HttpResponse::Ok().json(data), + Err(err) => HttpResponse::BadRequest().json(json!({ + "error": format!("{err:#}"), + })), + } +} + +async fn preview_span_fields( + state: web::Data, + body: web::Json, +) -> HttpResponse { + let project_id = match state.trace_project_id.lock() { + Ok(project_id) => project_id.clone(), + Err(_) => None, + }; + let Some(project_id) = project_id else { + return HttpResponse::BadRequest().json(json!({ + "error": "fetchSpanFields is only available for trace previews" + })); + }; + + let mut response = Map::new(); + let trace_data = match state.trace_data.lock() { + Ok(trace_data) => trace_data.clone(), + Err(_) => None, + }; + let spans = trace_data + .as_ref() + .and_then(|data| data.get("trace")) + .and_then(|trace| trace.get("spans")) + .and_then(Value::as_object) + .cloned() + .unwrap_or_default(); + + for span_id in &body.span_ids { + let row_id = resolve_preview_row_id(&spans, span_id).unwrap_or_else(|| span_id.clone()); + match fetch_full_span_row(&state.client, &project_id, &row_id).await { + Ok(Some(row)) => { + response.insert( + span_id.clone(), + fields_from_row(row, body.fields.as_deref()), + ); + } + Ok(None) => { + response.insert(span_id.clone(), json!({})); + } + Err(err) => { + return HttpResponse::InternalServerError().json(json!({ + "error": format!("{err:#}") + })); + } + } + } + + HttpResponse::Ok().json(Value::Object(response)) +} + +fn prepare_preview_source( + path: &Path, + view: Option, + view_type: ViewType, +) -> Result { + if !path.exists() { + bail!("custom view file not found: {}", path.display()); + } + if !path.is_file() { + bail!( + "custom view preview requires a single view file; got {}", + path.display() + ); + } + if !is_view_file(path) { + bail!("custom view preview path must match {VIEW_FILE_PATTERN_HELP}"); + } + let path = std::fs::canonicalize(path) + .with_context(|| format!("failed to resolve custom view file {}", path.display()))?; + let root = path + .parent() + .ok_or_else(|| { + anyhow!( + "custom view file has no parent directory: {}", + path.display() + ) + })? + .to_path_buf(); + Ok(PreviewSource { + path, + root, + view, + view_type, + }) +} + +fn preview_title(source: &PreviewSource) -> String { + source + .path + .file_name() + .and_then(|name| name.to_str()) + .map(ToOwned::to_owned) + .unwrap_or_else(|| source.view_type.label().to_string()) +} + +async fn preview_data_result( + state: &PreviewServerState, + request: PreviewDataRequest, +) -> Result { + if request.view_type != state.source.view_type { + bail!( + "selected view is {}, but this preview expects {}", + request.view_type.label(), + state.source.view_type.label() + ); + } + if let Some(selector) = state.source.view.as_deref() { + if request.slug != selector && request.name != selector { + bail!( + "{} custom view '{selector}' not found in selected file", + state.source.view_type.label() + ); + } + } + + let entry = ViewManifestEntry { + view_type: request.view_type, + name: request.name, + slug: request.slug, + code: String::new(), + project_id: request.project_id, + project_name: request.project_name, + dataset_id: request.dataset_id, + dataset_name: request.dataset_name, + }; + + match &state.target { + PreviewTarget::Trace(args) => { + let project = match state.project.as_ref() { + Some(default_project) => { + Some(resolve_project_for_entry(&state.client, default_project, &entry).await?) + } + None => None, + }; + let trace_data = + build_trace_preview_data(&state.client, project.as_ref(), args).await?; + if let Ok(mut project_id) = state.trace_project_id.lock() { + *project_id = Some(trace_data.project_id.clone()); + } + if let Ok(mut data) = state.trace_data.lock() { + *data = Some(trace_data.data.clone()); + } + Ok(trace_data.data) + } + PreviewTarget::Dataset(args) => { + let default_project = state + .project + .as_ref() + .ok_or_else(|| anyhow!("dataset preview requires a project"))?; + let project = resolve_project_for_entry(&state.client, default_project, &entry).await?; + build_dataset_preview_data(&state.client, &project, &entry, args).await + } + } +} + +fn preview_module_result(state: &PreviewServerState, tail: &str) -> Result { + let path = preview_module_path_from_route(&state.source, tail)?; + let code = compile_preview_module(&path)?; + if let Ok(mut dependency_paths) = state.dependency_paths.lock() { + dependency_paths.push(path); + dependency_paths.sort(); + dependency_paths.dedup(); + } + Ok(code) +} + +fn preview_asset_source(asset: &str) -> Option<&'static str> { + match asset { + "react" => Some(VIEWS_PREVIEW_REACT_SOURCE), + "react-dom" => Some(VIEWS_PREVIEW_REACT_DOM_SOURCE), + "tailwindcss-browser" => Some(VIEWS_PREVIEW_TAILWIND_SOURCE), + _ => None, + } +} + +fn preview_virtual_module_source(module: &str) -> Option<&'static str> { + match module { + "custom-views" => Some( + r#"export function customTraceView(definition, component) { + return { ...definition, component, kind: "trace" }; +} +export function customDatasetView(definition, component) { + return { ...definition, component, kind: "dataset" }; +} +"#, + ), + "react" => Some( + r#"const ReactValue = globalThis.React; +export default ReactValue; +export const Children = ReactValue.Children; +export const Component = ReactValue.Component; +export const Fragment = ReactValue.Fragment; +export const Profiler = ReactValue.Profiler; +export const PureComponent = ReactValue.PureComponent; +export const StrictMode = ReactValue.StrictMode; +export const Suspense = ReactValue.Suspense; +export const cloneElement = ReactValue.cloneElement; +export const createContext = ReactValue.createContext; +export const createElement = ReactValue.createElement; +export const createRef = ReactValue.createRef; +export const forwardRef = ReactValue.forwardRef; +export const isValidElement = ReactValue.isValidElement; +export const lazy = ReactValue.lazy; +export const memo = ReactValue.memo; +export const startTransition = ReactValue.startTransition; +export const useCallback = ReactValue.useCallback; +export const useContext = ReactValue.useContext; +export const useDebugValue = ReactValue.useDebugValue; +export const useDeferredValue = ReactValue.useDeferredValue; +export const useEffect = ReactValue.useEffect; +export const useId = ReactValue.useId; +export const useImperativeHandle = ReactValue.useImperativeHandle; +export const useInsertionEffect = ReactValue.useInsertionEffect; +export const useLayoutEffect = ReactValue.useLayoutEffect; +export const useMemo = ReactValue.useMemo; +export const useReducer = ReactValue.useReducer; +export const useRef = ReactValue.useRef; +export const useState = ReactValue.useState; +export const useSyncExternalStore = ReactValue.useSyncExternalStore; +export const useTransition = ReactValue.useTransition; +"#, + ), + "react-jsx-runtime" => Some( + r#"const ReactValue = globalThis.React; +export const Fragment = ReactValue.Fragment; +export function jsx(type, props, key) { + return ReactValue.createElement(type, key === undefined ? props : { ...props, key }); +} +export const jsxs = jsx; +export const jsxDEV = jsx; +"#, + ), + _ => None, + } +} + +fn compile_preview_module(path: &Path) -> Result { + let source = std::fs::read_to_string(path) + .with_context(|| format!("failed to read preview module {}", path.display()))?; + if path + .extension() + .and_then(|extension| extension.to_str()) + .is_some_and(|extension| extension.eq_ignore_ascii_case("json")) + { + let json: Value = serde_json::from_str(&source) + .with_context(|| format!("failed to parse preview JSON module {}", path.display()))?; + return Ok(format!("export default {};\n", script_json(&json))); + } + + let allocator = Allocator::default(); + let source_type = SourceType::from_path(path).map_err(|err| { + anyhow!( + "failed to infer preview module type for {}: {err}", + path.display() + ) + })?; + let mut parsed = Parser::new(&allocator, &source, source_type).parse(); + if !parsed.errors.is_empty() { + bail!( + "failed to parse preview module {}:\n{}", + path.display(), + parsed + .errors + .iter() + .map(ToString::to_string) + .collect::>() + .join("\n") + ); + } + + let scoping = { + let semantic = SemanticBuilder::new() + .with_check_syntax_error(true) + .build(&parsed.program); + if !semantic.errors.is_empty() { + bail!( + "failed to analyze preview module {}:\n{}", + path.display(), + semantic + .errors + .iter() + .map(ToString::to_string) + .collect::>() + .join("\n") + ); + } + semantic.semantic.into_scoping() + }; + + let transform_options = TransformOptions::default(); + let transformed = Transformer::new(&allocator, path, &transform_options) + .build_with_scoping(scoping, &mut parsed.program); + if !transformed.errors.is_empty() { + bail!( + "failed to transform preview module {}:\n{}", + path.display(), + transformed + .errors + .iter() + .map(ToString::to_string) + .collect::>() + .join("\n") + ); + } + + Ok(Codegen::new() + .with_options(CodegenOptions { + comments: oxc_codegen::CommentOptions::disabled(), + ..CodegenOptions::default() + }) + .build(&parsed.program) + .code) +} + +fn preview_module_path_from_route(source: &PreviewSource, tail: &str) -> Result { + if tail.trim().is_empty() { + bail!("preview module path is empty"); + } + let decoded = urlencoding::decode(tail) + .with_context(|| format!("failed to decode preview module path '{tail}'"))?; + let raw = preview_route_tail_to_path(&decoded); + preview_source_path_from_raw(source, &raw) +} + +fn preview_route_tail_to_path(tail: &str) -> PathBuf { + #[cfg(windows)] + { + PathBuf::from(tail.replace('/', "\\")) + } + #[cfg(not(windows))] + { + Path::new("/").join(tail.trim_start_matches('/')) + } +} + +fn preview_module_url(path: &Path) -> String { + let mut url = String::from("/preview-module"); + for component in path.components() { + match component { + std::path::Component::Prefix(prefix) => { + url.push('/'); + url.push_str(&encode(&prefix.as_os_str().to_string_lossy())); + } + std::path::Component::RootDir | std::path::Component::CurDir => {} + std::path::Component::Normal(part) => { + url.push('/'); + url.push_str(&encode(&part.to_string_lossy())); + } + std::path::Component::ParentDir => {} + } + } + url +} + +#[cfg(test)] +fn preview_source_path_from_request(source: &PreviewSource, requested: &str) -> Result { + let path = PathBuf::from(requested); + preview_source_path_from_raw(source, &path) +} + +fn preview_source_path_from_raw(source: &PreviewSource, path: &Path) -> Result { + for candidate in preview_resolution_candidates(path) { + if candidate.is_file() { + let candidate = std::fs::canonicalize(&candidate).with_context(|| { + format!("failed to resolve preview source {}", candidate.display()) + })?; + ensure_preview_path_allowed(source, &candidate)?; + return Ok(candidate); + } + } + + bail!("preview source not found: {}", path.display()); +} + +fn ensure_preview_path_allowed(source: &PreviewSource, path: &Path) -> Result<()> { + if !path.starts_with(&source.root) { + bail!( + "preview source must be inside {}: {}", + source.root.display(), + path.display() + ); + } + Ok(()) +} + +#[cfg(test)] +fn resolve_preview_source_path( + source: &PreviewSource, + importer: Option<&str>, + specifier: &str, +) -> Result { + let raw = if Path::new(specifier).is_absolute() { + PathBuf::from(specifier) + } else if specifier.starts_with('.') { + let importer = importer + .map(PathBuf::from) + .unwrap_or_else(|| source.path.clone()); + let importer = preview_source_path_from_request(source, &importer.display().to_string())?; + importer + .parent() + .ok_or_else(|| anyhow!("preview importer has no parent: {}", importer.display()))? + .join(specifier) + } else { + bail!("preview only supports relative local imports; unsupported import '{specifier}'"); + }; + + preview_source_path_from_raw(source, &raw) + .with_context(|| format!("preview import '{specifier}' not found")) +} + +fn preview_resolution_candidates(raw: &Path) -> Vec { + const EXTENSIONS: &[&str] = &["tsx", "ts", "jsx", "js", "mjs", "cjs", "json"]; + let mut candidates = Vec::new(); + candidates.push(raw.to_path_buf()); + if raw.extension().is_none() { + for extension in EXTENSIONS { + candidates.push(raw.with_extension(extension)); + } + } + for extension in EXTENSIONS { + candidates.push(raw.join(format!("index.{extension}"))); + } + candidates +} + +fn preview_source_version(source: &PreviewSource, dependency_paths: &[PathBuf]) -> String { + let mut parts = Vec::new(); + push_preview_file_version(&mut parts, &source.path); + for dependency in dependency_paths { + if dependency != &source.path { + push_preview_file_version(&mut parts, dependency); + } + } + parts.join("|") +} + +fn push_preview_file_version(parts: &mut Vec, path: &Path) { + match std::fs::metadata(path) { + Ok(metadata) => { + let modified = metadata + .modified() + .ok() + .and_then(|time| time.duration_since(UNIX_EPOCH).ok()) + .map(|duration| duration.as_nanos()) + .unwrap_or(0); + parts.push(format!("{}:{modified}:{}", path.display(), metadata.len())); + } + Err(err) => { + parts.push(format!("{}:error:{err}", path.display())); + } + } +} + +fn render_preview_html(title: &str, source: &PreviewSource, version: &str) -> String { + let config_json = script_json(&json!({ + "title": title, + "version": version, + "sourcePath": source.path.display().to_string(), + "sourceModuleUrl": preview_module_url(&source.path), + "viewType": source.view_type.label(), + "viewSelector": source.view, + })); + VIEWS_PREVIEW_HTML_TEMPLATE + .replace("__HTML_TITLE__", &html_escape(title)) + .replace("__PREVIEW_CONFIG__", &config_json) +} + +fn script_json(value: &Value) -> String { + serde_json::to_string(value) + .unwrap_or_else(|_| "null".to_string()) + .replace(" String { + value + .replace('&', "&") + .replace('<', "<") + .replace('>', ">") + .replace('"', """) +} + +fn collect_view_files(paths: &[PathBuf]) -> Result> { + let mut files = Vec::new(); + for path in paths { + let path = path.as_path(); + if !path.exists() { + bail!("custom view path not found: {}", path.display()); + } + if path.is_file() { + if is_view_file(path) { + files.push(path.to_path_buf()); + } + continue; + } + collect_view_files_in_dir(path, &mut files)?; + } + files.sort(); + files.dedup(); + Ok(files) +} + +fn collect_view_files_in_dir(dir: &Path, files: &mut Vec) -> Result<()> { + for entry in std::fs::read_dir(dir) + .with_context(|| format!("failed to read directory {}", dir.display()))? + { + let entry = entry?; + let path = entry.path(); + if path.is_dir() { + if should_skip_dir(&path) { + continue; + } + collect_view_files_in_dir(&path, files)?; + } else if path.is_file() && is_view_file(&path) { + files.push(path); + } + } + Ok(()) +} + +fn should_skip_dir(path: &Path) -> bool { + path.file_name() + .and_then(|name| name.to_str()) + .is_some_and(|name| { + matches!( + name, + ".git" | ".bt" | "node_modules" | "target" | "dist" | "build" | ".venv" | "venv" + ) + }) +} + +fn is_view_file(path: &Path) -> bool { + let Some(name) = path.file_name().and_then(|name| name.to_str()) else { + return false; + }; + [ + ".view.tsx", + ".view.ts", + ".view.jsx", + ".view.js", + "-view.tsx", + "-view.ts", + "-view.jsx", + "-view.js", + ] + .iter() + .any(|suffix| name.ends_with(suffix)) +} + +fn run_views_runner(files: &[PathBuf]) -> Result { + let temp_dir = tempfile::tempdir().context("failed to create custom views temp directory")?; + let mut input_files = Vec::new(); + let mut bundled_files = BTreeMap::new(); + for file in files { + let source_file = std::fs::canonicalize(file) + .with_context(|| format!("failed to resolve custom view file {}", file.display()))?; + let source_key = source_file.display().to_string(); + let safe_name = source_file + .file_name() + .and_then(|name| name.to_str()) + .unwrap_or("view") + .replace(|character: char| !character.is_ascii_alphanumeric(), "_"); + + let discovery = + swc_bundle_custom_view(&source_file, temp_dir.path(), SwcBundleTarget::Discovery)?; + let discovery_bundle = temp_dir.path().join(format!("{safe_name}.discovery.cjs")); + std::fs::write( + &discovery_bundle, + module_exports_from_swc_iife(&discovery.code), + ) + .with_context(|| { + format!( + "failed to write custom view discovery bundle {}", + discovery_bundle.display() + ) + })?; + + let browser_entry = temp_dir + .path() + .join(format!("{safe_name}.browser-entry.ts")); + std::fs::write( + &browser_entry, + format!( + "import view from {};\nexport default view.component;\n", + serde_json::to_string(&source_key)? + ), + ) + .with_context(|| { + format!( + "failed to write custom view browser entry {}", + browser_entry.display() + ) + })?; + let browser = + swc_bundle_custom_view(&browser_entry, temp_dir.path(), SwcBundleTarget::Browser)?; + + let dependencies = discovery + .dependencies + .into_iter() + .chain(browser.dependencies) + .collect::>() + .into_iter() + .map(|path| path.display().to_string()) + .collect::>(); + bundled_files.insert( + source_key.clone(), + SwcBundledViewFile { + code: module_exports_from_swc_iife(&browser.code), + dependencies, + }, + ); + input_files.push(ViewsDiscoveryInputFile { + source_file: source_key, + bundle_file: discovery_bundle.display().to_string(), + }); + } + let input_path = temp_dir.path().join("views-discovery-input.json"); + std::fs::write( + &input_path, + serde_json::to_vec(&ViewsDiscoveryInput { files: input_files })?, + ) + .with_context(|| { + format!( + "failed to write custom views discovery input {}", + input_path.display() + ) + })?; + + let mut command = Command::new("node"); + command + .arg("--input-type=module") + .arg("-") + .arg(&input_path) + .stdin(Stdio::piped()) + .stdout(Stdio::piped()) + .stderr(Stdio::piped()); + let mut child = command.spawn().with_context(|| { + format!( + "failed to spawn custom views metadata runner: {}", + command_display(&command) + ) + })?; + child + .stdin + .take() + .ok_or_else(|| anyhow!("failed to open custom views metadata runner stdin"))? + .write_all(VIEWS_JS_RUNNER_SOURCE.as_bytes()) + .context("failed to write custom views metadata runner source")?; + let output = child + .wait_with_output() + .context("failed to wait for custom views metadata runner")?; + if !output.status.success() { + let stderr = String::from_utf8_lossy(&output.stderr); + let stdout = String::from_utf8_lossy(&output.stdout); + let details = stderr.trim(); + let details = if details.is_empty() { + stdout.trim() + } else { + details + }; + bail!( + "custom views metadata runner exited with status {}: {}", + output.status, + details + ); + } + + let stdout = String::from_utf8(output.stdout) + .context("custom views metadata runner output was not UTF-8")?; + let mut manifest: ViewsManifest = serde_json::from_str(&stdout).with_context(|| { + format!( + "failed to parse custom views metadata runner output as JSON: {}", + stdout.trim() + ) + })?; + for file in &mut manifest.files { + if let Some(bundled) = bundled_files.get(&file.source_file) { + file.dependencies.clone_from(&bundled.dependencies); + for entry in &mut file.entries { + entry.code.clone_from(&bundled.code); + } + } + } + Ok(manifest) +} + +#[derive(Debug, Clone, Copy)] +enum SwcBundleTarget { + Discovery, + Browser, +} + +#[derive(Debug)] +struct SwcBundledViewFile { + code: String, + dependencies: Vec, +} + +#[derive(Debug)] +struct SwcBundleOutput { + code: String, + dependencies: Vec, +} + +struct ViewsSwcResolver { + node: NodeModulesResolver, +} + +impl ViewsSwcResolver { + fn new(target: SwcBundleTarget) -> Self { + let target_env = match target { + SwcBundleTarget::Discovery => SwcTargetEnv::Node, + SwcBundleTarget::Browser => SwcTargetEnv::Browser, + }; + Self { + node: NodeModulesResolver::new(target_env, Default::default(), false), + } + } +} + +impl Resolve for ViewsSwcResolver { + fn resolve(&self, base: &FileName, module_specifier: &str) -> Result { + if is_views_virtual_module(module_specifier) { + return Ok(Resolution { + filename: FileName::Custom(module_specifier.to_string()), + slug: None, + }); + } + self.node.resolve(base, module_specifier) + } +} + +struct ViewsSwcLoader { + cm: Lrc, + temp_dir: PathBuf, + dependencies: Arc>>, +} + +impl Load for ViewsSwcLoader { + fn load(&self, file: &FileName) -> Result { + let (fm, syntax) = match file { + FileName::Real(path) => { + let source = std::fs::read_to_string(path).with_context(|| { + format!("failed to read custom view module {}", path.display()) + })?; + let resolved = std::fs::canonicalize(path).with_context(|| { + format!("failed to resolve custom view module {}", path.display()) + })?; + if !resolved.starts_with(&self.temp_dir) { + self.dependencies + .lock() + .expect("custom view dependency lock") + .insert(resolved); + } + ( + self.cm + .new_source_file(Lrc::new(FileName::Real(path.clone())), source), + swc_syntax_for_path(path), + ) + } + FileName::Custom(name) if name == "braintrust/custom-views" => ( + self.cm + .new_source_file(Lrc::new(file.clone()), VIEWS_JS_SDK_SOURCE.to_string()), + Syntax::Typescript(TsSyntax::default()), + ), + FileName::Custom(name) if name == "@braintrust/local/custom-views" => ( + self.cm + .new_source_file(Lrc::new(file.clone()), VIEWS_JS_SDK_SOURCE.to_string()), + Syntax::Typescript(TsSyntax::default()), + ), + FileName::Custom(name) if name == "react" => ( + self.cm + .new_source_file(Lrc::new(file.clone()), react_module_source()), + Syntax::Es(EsSyntax::default()), + ), + FileName::Custom(name) + if name == "react/jsx-runtime" || name == "react/jsx-dev-runtime" => + { + ( + self.cm + .new_source_file(Lrc::new(file.clone()), jsx_runtime_module_source()), + Syntax::Es(EsSyntax::default()), + ) + } + FileName::Custom(name) => bail!("unsupported custom view virtual module '{name}'"), + _ => bail!("unsupported custom view module {}", file), + }; + + let mut errors = Vec::new(); + let module = parse_file_as_module(&fm, syntax, EsVersion::Es2022, None, &mut errors) + .map_err(|err| anyhow!("{err:?}")) + .with_context(|| format!("failed to parse custom view module {}", file))?; + if !errors.is_empty() { + let details = errors + .iter() + .map(|err| format!("{err:?}")) + .collect::>() + .join("; "); + bail!("failed to parse custom view module {}: {details}", file); + } + + let unresolved_mark = Mark::new(); + let top_level_mark = Mark::new(); + let mut program = Program::Module(module); + program.mutate(resolver( + unresolved_mark, + top_level_mark, + syntax_is_typescript(syntax), + )); + if syntax_is_typescript(syntax) { + program.mutate(strip_typescript(unresolved_mark, top_level_mark)); + } + program.mutate(react( + self.cm.clone(), + None::, + ReactOptions { + runtime: Some(ReactRuntime::Classic), + pragma: Some("React.createElement".into()), + pragma_frag: Some("React.Fragment".into()), + development: Some(false), + ..Default::default() + }, + top_level_mark, + unresolved_mark, + )); + program.mutate(fixer(None)); + + let Program::Module(module) = program else { + bail!("custom view module {} did not parse as an ES module", file); + }; + Ok(ModuleData { + fm, + module, + helpers: Helpers::new(false), + }) + } +} + +struct ViewsSwcHook; + +impl Hook for ViewsSwcHook { + fn get_import_meta_props( + &self, + _span: Span, + _module_record: &ModuleRecord, + ) -> Result> { + Ok(Vec::new()) + } +} + +fn swc_bundle_custom_view( + entry: &Path, + temp_dir: &Path, + target: SwcBundleTarget, +) -> Result { + let entry = std::fs::canonicalize(entry) + .with_context(|| format!("failed to resolve custom view entry {}", entry.display()))?; + let temp_dir = std::fs::canonicalize(temp_dir).with_context(|| { + format!( + "failed to resolve custom view temp directory {}", + temp_dir.display() + ) + })?; + let cm = Lrc::new(SourceMap::default()); + let globals = Globals::new(); + let dependencies = Arc::new(Mutex::new(BTreeSet::new())); + let loader = ViewsSwcLoader { + cm: cm.clone(), + temp_dir, + dependencies: dependencies.clone(), + }; + let resolver = ViewsSwcResolver::new(target); + let mut bundler = Bundler::new( + &globals, + cm.clone(), + loader, + resolver, + SwcBundlerConfig { + module: ModuleType::Iife, + ..Default::default() + }, + Box::new(ViewsSwcHook), + ); + let bundles = bundler + .bundle(HashMap::from([( + "custom-view".to_string(), + FileName::Real(entry.clone()), + )])) + .with_context(|| format!("failed to bundle custom view {}", entry.display()))?; + let bundle = single_swc_bundle(bundles, &entry)?; + Ok(SwcBundleOutput { + code: to_code_default(cm, None, &bundle.module), + dependencies: Arc::try_unwrap(dependencies) + .unwrap_or_else(|dependencies| { + Mutex::new( + dependencies + .lock() + .expect("custom view dependency lock") + .clone(), + ) + }) + .into_inner() + .expect("custom view dependency lock") + .into_iter() + .collect(), + }) +} + +fn single_swc_bundle(mut bundles: Vec, entry: &Path) -> Result { + if bundles.len() != 1 { + bail!( + "expected one custom view bundle for {}, got {}", + entry.display(), + bundles.len() + ); + } + let bundle = bundles.remove(0); + if !matches!(bundle.kind, BundleKind::Named { .. }) { + bail!( + "custom view bundle for {} was not an entry bundle", + entry.display() + ); + } + Ok(bundle) +} + +fn module_exports_from_swc_iife(code: &str) -> String { + let expression = code.trim().trim_end_matches(';'); + format!( + "var __BraintrustCustomView = {expression};\nmodule.exports = __BraintrustCustomView;\n" + ) +} + +fn is_views_virtual_module(module_specifier: &str) -> bool { + matches!( + module_specifier, + "braintrust/custom-views" + | "@braintrust/local/custom-views" + | "react" + | "react/jsx-runtime" + | "react/jsx-dev-runtime" + ) +} + +fn swc_syntax_for_path(path: &Path) -> Syntax { + match path.extension().and_then(|extension| extension.to_str()) { + Some("ts") | Some("mts") | Some("cts") => Syntax::Typescript(TsSyntax::default()), + Some("tsx") => Syntax::Typescript(TsSyntax { + tsx: true, + ..Default::default() + }), + Some("jsx") => Syntax::Es(EsSyntax { + jsx: true, + ..Default::default() + }), + _ => Syntax::Es(EsSyntax::default()), + } +} + +fn syntax_is_typescript(syntax: Syntax) -> bool { + matches!(syntax, Syntax::Typescript(_)) +} + +fn react_module_source() -> String { + r#" +const ReactValue = globalThis.React || React; +export default ReactValue; +export const Children = ReactValue.Children; +export const Component = ReactValue.Component; +export const Fragment = ReactValue.Fragment; +export const Profiler = ReactValue.Profiler; +export const PureComponent = ReactValue.PureComponent; +export const StrictMode = ReactValue.StrictMode; +export const Suspense = ReactValue.Suspense; +export const cloneElement = ReactValue.cloneElement; +export const createContext = ReactValue.createContext; +export const createElement = ReactValue.createElement; +export const createRef = ReactValue.createRef; +export const forwardRef = ReactValue.forwardRef; +export const isValidElement = ReactValue.isValidElement; +export const lazy = ReactValue.lazy; +export const memo = ReactValue.memo; +export const startTransition = ReactValue.startTransition; +export const useCallback = ReactValue.useCallback; +export const useContext = ReactValue.useContext; +export const useDebugValue = ReactValue.useDebugValue; +export const useDeferredValue = ReactValue.useDeferredValue; +export const useEffect = ReactValue.useEffect; +export const useId = ReactValue.useId; +export const useImperativeHandle = ReactValue.useImperativeHandle; +export const useInsertionEffect = ReactValue.useInsertionEffect; +export const useLayoutEffect = ReactValue.useLayoutEffect; +export const useMemo = ReactValue.useMemo; +export const useReducer = ReactValue.useReducer; +export const useRef = ReactValue.useRef; +export const useState = ReactValue.useState; +export const useSyncExternalStore = ReactValue.useSyncExternalStore; +export const useTransition = ReactValue.useTransition; +"# + .to_string() +} + +fn jsx_runtime_module_source() -> String { + r#" +const ReactValue = globalThis.React || React; +export const Fragment = ReactValue.Fragment; +export const jsx = ReactValue.createElement; +export const jsxs = ReactValue.createElement; +export const jsxDEV = ReactValue.createElement; +"# + .to_string() +} + +fn command_display(command: &Command) -> String { + let mut rendered = command.get_program().to_string_lossy().to_string(); + for arg in command.get_args() { + rendered.push(' '); + rendered.push_str(&arg.to_string_lossy()); + } + rendered +} + +fn validate_manifest_runtime(manifest: &ViewsManifest) -> Result<()> { + if manifest.runtime_context.runtime != "browser" { + bail!( + "custom views runner returned unsupported runtime '{}'", + manifest.runtime_context.runtime + ); + } + if manifest.runtime_context.version.trim().is_empty() { + bail!("custom views runner returned an empty runtime version"); + } + Ok(()) +} + +async fn prepare_views( + client: &ApiClient, + default_project: &Project, + manifest: &ViewsManifest, +) -> Result> { + let mut prepared = Vec::new(); + let mut seen = BTreeSet::new(); + for file in &manifest.files { + for entry in &file.entries { + let key = ( + file.source_file.clone(), + entry.view_type, + entry.slug.clone(), + ); + if !seen.insert(key) { + bail!( + "duplicate custom view slug '{}' in {}", + entry.slug, + file.source_file + ); + } + let project = resolve_project_for_entry(client, default_project, entry).await?; + let dataset = if entry.view_type == ViewType::Dataset { + Some(resolve_dataset_for_entry(client, &project, entry).await?) + } else { + None + }; + prepared.push(PreparedView { + source_file: file.source_file.clone(), + entry: entry.clone(), + project, + dataset, + }); + } + } + Ok(prepared) +} + +async fn resolve_project_for_entry( + client: &ApiClient, + default_project: &Project, + entry: &ViewManifestEntry, +) -> Result { + if let Some(project_id) = entry + .project_id + .as_deref() + .map(str::trim) + .filter(|value| !value.is_empty()) + { + if project_id == default_project.id { + return Ok(default_project.clone()); + } + let projects = list_projects(client).await?; + return projects + .into_iter() + .find(|project| project.id == project_id) + .ok_or_else(|| anyhow!("project id '{project_id}' not found")); + } + + if let Some(project_name) = entry + .project_name + .as_deref() + .map(str::trim) + .filter(|value| !value.is_empty()) + { + if project_name == default_project.name { + return Ok(default_project.clone()); + } + return get_project_by_name(client, project_name) + .await? + .ok_or_else(|| anyhow!("project '{project_name}' not found")); + } + + Ok(default_project.clone()) +} + +async fn resolve_dataset_for_entry( + client: &ApiClient, + project: &Project, + entry: &ViewManifestEntry, +) -> Result { + if let Some(dataset_id) = entry + .dataset_id + .as_deref() + .map(str::trim) + .filter(|value| !value.is_empty()) + { + let datasets = datasets_api::list_datasets(client, &project.id).await?; + return datasets + .into_iter() + .find(|dataset| dataset.id == dataset_id) + .ok_or_else(|| { + anyhow!( + "dataset id '{dataset_id}' not found in project '{}'", + project.name + ) + }); + } + + let dataset_name = entry + .dataset_name + .as_deref() + .map(str::trim) + .filter(|value| !value.is_empty()) + .ok_or_else(|| { + anyhow!( + "dataset custom view '{}' requires dataset id or name", + entry.slug + ) + })?; + + datasets_api::get_dataset_by_name(client, &project.id, dataset_name) + .await? + .ok_or_else(|| { + anyhow!( + "dataset '{dataset_name}' not found in project '{}'", + project.name + ) + }) +} + +fn build_insert_event(view: &PreparedView, if_exists: IfExistsMode) -> Value { + let mut object = Map::new(); + object.insert( + "project_id".to_string(), + Value::String(view.project.id.clone()), + ); + object.insert("name".to_string(), Value::String(view.entry.name.clone())); + object.insert("slug".to_string(), Value::String(view.entry.slug.clone())); + object.insert( + "function_type".to_string(), + Value::String("custom_view".to_string()), + ); + object.insert( + "if_exists".to_string(), + Value::String(if_exists.as_str().to_string()), + ); + object.insert( + "function_data".to_string(), + json!({ + "type": "code", + "data": { + "type": "inline", + "runtime_context": { + "runtime": "browser", + "version": "latest", + }, + "code": view.entry.code, + } + }), + ); + + if let Some(dataset) = &view.dataset { + object.insert( + "origin".to_string(), + json!({ + "object_type": "dataset", + "object_id": dataset.id, + }), + ); + } + + Value::Object(object) +} + +fn format_views_insert_error( + views: &[PreparedView], + if_exists: IfExistsMode, + err: &anyhow::Error, +) -> String { + let view_list = views + .iter() + .map(|view| { + format!( + "{} '{}' in project '{}'", + view.entry.view_type.label(), + view.entry.slug, + view.project.name + ) + }) + .collect::>() + .join(", "); + let view_list = if view_list.is_empty() { + "selected custom views".to_string() + } else { + view_list + }; + let details = format!("{err:#}"); + let retry_hint = if if_exists == IfExistsMode::Error { + " If you are updating an existing custom view, rerun with `bt views push --if-exists replace`." + } else { + "" + }; + + format!( + "failed to push custom views ({view_list}) with --if-exists {}.{retry_hint} Server response: {details}", + if_exists.as_str() + ) +} + +async fn resolve_pushed_views( + client: &ApiClient, + app_url: &str, + views: &[PreparedView], +) -> Result> { + let mut pushed = Vec::new(); + for view in views { + let function = + functions_api::get_function_by_slug(client, &view.project.id, &view.entry.slug, None) + .await + .ok() + .flatten(); + let function_id = function.as_ref().map(|function| function.id.clone()); + let url = function_id + .as_deref() + .map(|id| custom_view_url(app_url, client.org_name(), view, id)); + pushed.push(PushedView { + source_file: view.source_file.clone(), + name: view.entry.name.clone(), + slug: view.entry.slug.clone(), + view_type: view.entry.view_type, + project_id: view.project.id.clone(), + project_name: view.project.name.clone(), + dataset_id: view.dataset.as_ref().map(|dataset| dataset.id.clone()), + function_id, + url, + }); + } + Ok(pushed) +} + +fn custom_view_url( + app_url: &str, + org_name: &str, + view: &PreparedView, + function_id: &str, +) -> String { + match (&view.entry.view_type, view.dataset.as_ref()) { + (ViewType::Dataset, Some(dataset)) => { + let mut url = app_project_url( + app_url, + org_name, + &view.project.name, + &["datasets", &dataset.name], + ); + write!(url, "?dvt=custom&dv={}", encode(function_id)).ok(); + url + } + _ => app_project_url_with_encoded_path( + app_url, + org_name, + &view.project.name, + &format!("logs?tvt=custom&tv={}", encode(function_id)), + ), + } +} + +async fn build_dataset_preview_data( + client: &ApiClient, + project: &Project, + entry: &ViewManifestEntry, + args: &DatasetPreviewTargetArgs, +) -> Result { + let dataset = match args.dataset.as_deref() { + Some(selector) => resolve_dataset_by_selector(client, project, selector).await?, + None => resolve_dataset_for_entry(client, project, entry).await?, + }; + + let row = if let Some(row_id) = args.row_id.as_deref() { + datasets_api::get_dataset_row_by_id(client, &dataset.id, row_id) + .await? + .ok_or_else(|| anyhow!("dataset row id '{row_id}' not found in '{}'", dataset.name))? + } else { + let index = args.row_index.unwrap_or(0); + let limit = index + 1; + let (rows, _) = datasets_api::list_dataset_rows_limited( + client, + &dataset.id, + Some(limit), + datasets_api::DatasetRowsPreviewLength::Full, + ) + .await?; + rows.into_iter().nth(index).ok_or_else(|| { + anyhow!( + "dataset '{}' does not have row index {}", + dataset.name, + index + ) + })? + }; + + Ok(json!({ + "props": { + "id": row.get("id").cloned().unwrap_or(Value::Null), + "input": row.get("input").cloned().unwrap_or(Value::Null), + "expected": row.get("expected").cloned().unwrap_or(Value::Null), + "metadata": row.get("metadata").cloned().unwrap_or_else(|| json!({})), + "tags": row.get("tags").cloned().unwrap_or_else(|| json!([])), + }, + "dataset": dataset, + })) +} + +async fn resolve_dataset_by_selector( + client: &ApiClient, + project: &Project, + selector: &str, +) -> Result { + let datasets = datasets_api::list_datasets(client, &project.id).await?; + datasets + .into_iter() + .find(|dataset| dataset.id == selector || dataset.name == selector) + .ok_or_else(|| { + anyhow!( + "dataset '{selector}' not found in project '{}'", + project.name + ) + }) +} + +async fn build_trace_preview_data( + client: &ApiClient, + project: Option<&Project>, + args: &TracePreviewTargetArgs, +) -> Result { + let target = resolve_trace_preview_target(client, project, args).await?; + let rows = fetch_trace_rows( + client, + &target.project_id, + &target.root_span_id, + DEFAULT_TRACE_PREVIEW_LIMIT, + ) + .await?; + if rows.is_empty() { + bail!("trace '{}' returned no spans", target.root_span_id); + } + let (trace, selected_span) = + build_trace_payload(rows, &target.root_span_id, target.span_id.as_deref())?; + Ok(TracePreviewData { + project_id: target.project_id, + data: json!({ + "trace": trace, + "span": selected_span, + }), + }) +} + +#[derive(Debug)] +struct TracePreviewTarget { + project_id: String, + root_span_id: String, + span_id: Option, +} + +async fn resolve_trace_preview_target( + client: &ApiClient, + default_project: Option<&Project>, + args: &TracePreviewTargetArgs, +) -> Result { + if let Some(url) = args.url.as_deref() { + let parsed = parse_trace_url(url)?; + let project_id = match parsed.project.as_deref() { + Some(project) + if default_project + .map(|default_project| { + project == default_project.id || project == default_project.name + }) + .unwrap_or(false) => + { + default_project.expect("checked above").id.clone() + } + Some(project) if is_uuid_like(project) => project.to_string(), + Some(project) => { + get_project_by_name(client, project) + .await? + .ok_or_else(|| anyhow!("project '{project}' from trace URL not found"))? + .id + } + None => default_project + .map(|project| project.id.clone()) + .ok_or_else(|| { + anyhow!( + "trace URL must include a project path like /app//p//... or a project must be supplied" + ) + })?, + }; + let root_span_id = parsed + .row_ref + .or(parsed.span_id.clone()) + .ok_or_else(|| anyhow!("trace URL must include query parameter r or s"))?; + return Ok(TracePreviewTarget { + project_id, + root_span_id, + span_id: args.span_id.clone().or(parsed.span_id), + }); + } + + let project_id = args + .project_id + .clone() + .or_else(|| default_project.map(|project| project.id.clone())) + .ok_or_else(|| { + anyhow!("trace preview requires --project-id or --project when --trace-id is used") + })?; + let root_span_id = args + .trace_id + .clone() + .ok_or_else(|| anyhow!("trace preview requires --trace-id or --url"))?; + Ok(TracePreviewTarget { + project_id, + root_span_id, + span_id: args.span_id.clone(), + }) +} + +#[derive(Debug)] +struct ParsedPreviewTraceUrl { + project: Option, + row_ref: Option, + span_id: Option, +} + +fn parse_trace_url(input: &str) -> Result { + let parsed_url = Url::parse(input) + .or_else(|_| Url::parse(&format!("https://{}", input.trim_start_matches('/')))) + .context("invalid trace URL")?; + let mut parsed = ParsedPreviewTraceUrl { + project: None, + row_ref: None, + span_id: None, + }; + if let Some(segments) = parsed_url.path_segments() { + let parts = segments.filter(|part| !part.is_empty()).collect::>(); + if parts.len() >= 4 && parts[0] == "app" && parts[2] == "p" { + parsed.project = Some(parts[3].to_string()); + } + } + for (key, value) in parsed_url.query_pairs() { + match key.as_ref() { + "r" if !value.is_empty() => parsed.row_ref = Some(value.to_string()), + "s" if !value.is_empty() => parsed.span_id = Some(value.to_string()), + _ => {} + } + } + Ok(parsed) +} + +fn trace_url_supplies_project(view_type: ViewType, trace_url: Option<&str>) -> bool { + view_type == ViewType::Trace + && trace_url + .and_then(|url| parse_trace_url(url).ok()) + .and_then(|parsed| parsed.project) + .is_some() +} + +fn is_uuid_like(value: &str) -> bool { + let bytes = value.as_bytes(); + if bytes.len() != 36 { + return false; + } + for (idx, b) in bytes.iter().enumerate() { + let is_hyphen = matches!(idx, 8 | 13 | 18 | 23); + if is_hyphen { + if *b != b'-' { + return false; + } + } else if !(*b as char).is_ascii_hexdigit() { + return false; + } + } + true +} + +async fn fetch_trace_rows( + client: &ApiClient, + project_id: &str, + root_span_id: &str, + limit: usize, +) -> Result>> { + let query = format!( + "select: * | from: project_logs({}) spans | filter: root_span_id = {} | preview_length: 125 | sort: _pagination_key ASC | limit: {}", + sql_quote(project_id), + sql_quote(root_span_id), + limit, + ); + execute_query(client, &query) + .await + .with_context(|| format!("BTQL query failed: {query}")) + .map(|response| response.data) +} + +async fn fetch_full_span_row( + client: &ApiClient, + project_id: &str, + row_id: &str, +) -> Result>> { + let query = format!( + "select: * | from: project_logs({}) spans | filter: id = {} | preview_length: -1 | limit: 1", + sql_quote(project_id), + sql_quote(row_id), + ); + execute_query(client, &query) + .await + .with_context(|| format!("BTQL query failed: {query}")) + .map(|response| response.data.into_iter().next()) +} + +async fn execute_query(client: &ApiClient, query: &str) -> Result { + let body = json!({ + "query": query, + "fmt": "json", + "query_source": "bt_views_preview_7e8680d0f2484e2fbef8a61f2de0b9df", + }); + let org_name = client.org_name(); + let headers = if org_name.is_empty() { + Vec::new() + } else { + vec![("x-bt-org-name", org_name)] + }; + client.post_with_headers("/btql", &body, &headers).await +} + +fn sql_quote(value: &str) -> String { + format!("'{}'", value.replace('\'', "''")) +} + +fn build_trace_payload( + rows: Vec>, + root_span_id: &str, + selected_selector: Option<&str>, +) -> Result<(Value, Value)> { + let mut spans = Map::new(); + let mut span_order = Vec::new(); + let mut parent_children: BTreeMap> = BTreeMap::new(); + let mut row_id_to_span_id = BTreeMap::new(); + + for row in &rows { + let Some(span_id) = row.get("span_id").and_then(Value::as_str) else { + continue; + }; + span_order.push(Value::String(span_id.to_string())); + if let Some(row_id) = row.get("id").and_then(Value::as_str) { + row_id_to_span_id.insert(row_id.to_string(), span_id.to_string()); + } + if let Some(parent) = parent_span_id(row) { + parent_children + .entry(parent) + .or_default() + .push(span_id.to_string()); + } + } + + for row in rows { + let Some(span_id) = row.get("span_id").and_then(Value::as_str) else { + continue; + }; + let span_id = span_id.to_string(); + let children = parent_children + .get(&span_id) + .cloned() + .unwrap_or_default() + .into_iter() + .map(Value::String) + .collect::>(); + spans.insert(span_id.clone(), row_to_custom_span(row, children)); + } + + let selected_span_id = selected_selector + .and_then(|selector| { + spans + .contains_key(selector) + .then(|| selector.to_string()) + .or_else(|| row_id_to_span_id.get(selector).cloned()) + }) + .or_else(|| { + spans + .contains_key(root_span_id) + .then(|| root_span_id.to_string()) + }) + .or_else(|| { + span_order + .first() + .and_then(Value::as_str) + .map(ToOwned::to_owned) + }) + .ok_or_else(|| anyhow!("trace has no selectable spans"))?; + let selected_span = spans + .get(&selected_span_id) + .cloned() + .ok_or_else(|| anyhow!("selected span '{selected_span_id}' not found"))?; + + Ok(( + json!({ + "rootSpanId": root_span_id, + "selectedSpanId": selected_span_id, + "spanOrder": span_order, + "spans": spans, + }), + selected_span, + )) +} + +fn row_to_custom_span(row: Map, children: Vec) -> Value { + let data_fields = [ + "input", + "output", + "expected", + "metadata", + "scores", + "metrics", + "error", + "tags", + "span_attributes", + ]; + let mut data = Map::new(); + for field in data_fields { + if let Some(value) = row.get(field) { + data.insert(field.to_string(), value.clone()); + } + } + + let mut span = Map::new(); + for field in ["id", "span_id", "root_span_id", "parent_span_id"] { + if let Some(value) = row.get(field) { + span.insert(field.to_string(), value.clone()); + } + } + if let Some(value) = row.get("span_parents") { + span.insert("span_parents".to_string(), value.clone()); + } + span.insert("data".to_string(), Value::Object(data)); + span.insert("children".to_string(), Value::Array(children)); + Value::Object(span) +} + +fn parent_span_id(row: &Map) -> Option { + row.get("parent_span_id") + .and_then(Value::as_str) + .map(ToOwned::to_owned) + .or_else(|| { + row.get("span_parents") + .and_then(Value::as_array) + .and_then(|parents| parents.last()) + .and_then(Value::as_str) + .map(ToOwned::to_owned) + }) +} + +fn resolve_preview_row_id(spans: &Map, requested: &str) -> Option { + spans + .get(requested) + .and_then(|span| span.get("id")) + .and_then(Value::as_str) + .map(ToOwned::to_owned) + .or_else(|| { + spans.values().find_map(|span| { + let row_id = span.get("id").and_then(Value::as_str)?; + (row_id == requested).then(|| row_id.to_string()) + }) + }) +} + +fn fields_from_row(row: Map, fields: Option<&[String]>) -> Value { + let requested = fields + .map(|fields| fields.iter().map(String::as_str).collect::>()) + .unwrap_or_else(|| vec!["input", "output", "expected", "metadata"]); + let mut object = Map::new(); + for field in requested { + if matches!(field, "input" | "output" | "expected" | "metadata") { + if let Some(value) = row.get(field) { + object.insert(field.to_string(), value.clone()); + } + } + } + Value::Object(object) +} + +#[cfg(test)] +mod tests { + use super::*; + + fn test_client() -> ApiClient { + let login = braintrust_sdk_rust::LoginState::new(); + login.set( + "sk-test".to_string(), + "org_test".to_string(), + "test-org".to_string(), + "http://127.0.0.1:1".to_string(), + "http://127.0.0.1:1".to_string(), + ); + ApiClient::new(&crate::auth::LoginContext { + login, + api_url: "http://127.0.0.1:1".to_string(), + app_url: "http://127.0.0.1:1".to_string(), + }) + .expect("test client") + } + + fn test_project() -> Project { + Project { + id: "proj_test".to_string(), + name: "test-project".to_string(), + org_id: "org_test".to_string(), + description: None, + } + } + + #[test] + fn detects_view_files() { + assert!(is_view_file(Path::new("conversation.view.tsx"))); + assert!(is_view_file(Path::new("dataset.view.js"))); + assert!(is_view_file(Path::new("conversation.trace-view.tsx"))); + assert!(is_view_file(Path::new("dataset.dataset-view.js"))); + assert!(!is_view_file(Path::new("regular.tsx"))); + } + + #[test] + fn push_runner_bundles_tsx_with_swc() { + let dir = tempfile::tempdir().expect("tempdir"); + let dependency = dir.path().join("label.ts"); + let path = dir.path().join("swc.trace-view.tsx"); + std::fs::write(&dependency, "export const label = 'SWC bundled';\n") + .expect("write dependency"); + std::fs::write( + &path, + r#" +import { customTraceView } from "braintrust/custom-views"; +import { label } from "./label"; + +export default customTraceView( + { name: "SWC Trace", slug: "swc-trace", project: { id: "proj_test" } }, + function SwcTraceView() { + return
{label}
; + }, +); +"#, + ) + .expect("write view"); + + let manifest = run_views_runner(&[path.clone()]).expect("views manifest"); + + assert_eq!(manifest.runtime_context.runtime, "browser"); + assert_eq!(manifest.files.len(), 1); + let file = &manifest.files[0]; + assert_eq!( + file.source_file, + path.canonicalize() + .expect("canonical view") + .display() + .to_string() + ); + assert!(file.dependencies.iter().any(|item| item + == &dependency + .canonicalize() + .expect("canonical dependency") + .display() + .to_string())); + assert_eq!(file.entries.len(), 1); + let entry = &file.entries[0]; + assert_eq!(entry.view_type, ViewType::Trace); + assert_eq!(entry.name, "SWC Trace"); + assert_eq!(entry.slug, "swc-trace"); + assert_eq!(entry.project_id.as_deref(), Some("proj_test")); + assert!(entry + .code + .contains("module.exports = __BraintrustCustomView")); + assert!(entry.code.contains("React.createElement")); + assert!(!entry.code.contains("esbuild")); + assert!(!entry.code.contains(": string")); + } + + fn test_preview_source(path: PathBuf, root: PathBuf) -> PreviewSource { + PreviewSource { + path, + root, + view: None, + view_type: ViewType::Trace, + } + } + + #[test] + fn preview_html_includes_hot_reload_polling() { + let dir = tempfile::tempdir().expect("tempdir"); + let path = dir.path().join("test.trace-view.tsx"); + std::fs::write(&path, "export default null;\n").expect("write view"); + let source = test_preview_source(path, dir.path().to_path_buf()); + let html = render_preview_html("Preview", &source, "v1"); + + assert!(html.contains("previewVersion")); + assert!(html.contains("/preview-version")); + assert!(html.contains("window.location.reload()")); + assert!(html.contains("sourceModuleUrl")); + assert!(html.contains("/preview-module/")); + assert!(html.contains("/preview-assets/tailwindcss-browser.js")); + assert!(html.contains("/preview-assets/react.js")); + assert!(html.contains("/preview-assets/react-dom.js")); + assert!(!html.contains("https://cdn.tailwindcss.com")); + assert!(!html.contains("https://unpkg.com")); + } + + #[test] + fn preview_assets_are_embedded_from_npm() { + let react = preview_asset_source("react").expect("react preview asset"); + let react_dom = preview_asset_source("react-dom").expect("react-dom preview asset"); + let tailwind = preview_asset_source("tailwindcss-browser").expect("tailwind preview asset"); + + assert!(react.contains("React")); + assert!(react_dom.contains("ReactDOM")); + assert!(tailwind.contains("tailwind")); + assert!(preview_asset_source("missing").is_none()); + } + + #[test] + fn preview_source_path_allows_files_inside_root() { + let dir = tempfile::tempdir().expect("tempdir"); + let path = dir.path().join("test.trace-view.tsx"); + let dependency = dir.path().join("component.tsx"); + std::fs::write(&path, "export { default } from './component';\n").expect("write view"); + std::fs::write(&dependency, "export default null;\n").expect("write dependency"); + let source = test_preview_source(path, dir.path().canonicalize().expect("root")); + + let resolved = preview_source_path_from_request(&source, &dependency.display().to_string()) + .expect("dependency should be allowed"); + + assert_eq!( + resolved, + dependency.canonicalize().expect("canonical dependency") + ); + } + + #[test] + fn preview_source_path_rejects_files_outside_root() { + let dir = tempfile::tempdir().expect("tempdir"); + let outside_dir = tempfile::tempdir().expect("outside tempdir"); + let path = dir.path().join("test.trace-view.tsx"); + let outside = outside_dir.path().join("component.tsx"); + std::fs::write(&path, "export default null;\n").expect("write view"); + std::fs::write(&outside, "export default null;\n").expect("write outside dependency"); + let source = test_preview_source(path, dir.path().canonicalize().expect("root")); + + let error = preview_source_path_from_request(&source, &outside.display().to_string()) + .expect_err("outside dependency should be rejected"); + + assert!(format!("{error:#}").contains("preview source must be inside")); + } + + #[test] + fn preview_relative_import_resolution_stays_inside_root() { + let dir = tempfile::tempdir().expect("tempdir"); + let path = dir.path().join("test.trace-view.tsx"); + let dependency = dir.path().join("component.tsx"); + std::fs::write(&path, "export { default } from './component';\n").expect("write view"); + std::fs::write(&dependency, "export default null;\n").expect("write dependency"); + let source = test_preview_source( + path.canonicalize().expect("canonical view"), + dir.path().canonicalize().expect("root"), + ); + + let resolved = resolve_preview_source_path( + &source, + Some(&source.path.display().to_string()), + "./component", + ) + .expect("relative import should resolve"); + + assert_eq!( + resolved, + dependency.canonicalize().expect("canonical dependency") + ); + } + + #[test] + fn preview_module_compiles_tsx_with_oxc() { + let dir = tempfile::tempdir().expect("tempdir"); + let path = dir.path().join("test.trace-view.tsx"); + std::fs::write( + &path, + r#"import { customTraceView } from "braintrust/custom-views"; + +type Props = { span: { id: string } }; + +export default customTraceView({ name: "Test View", slug: "test-view" }, ({ span }: Props) => { + return
{span.id}
; +}); +"#, + ) + .expect("write view"); + + let code = compile_preview_module(&path).expect("compile TSX preview module"); + + assert!(code.contains("react/jsx-runtime")); + assert!(code.contains("customTraceView")); + assert!(!code.contains("type Props")); + assert!(!code.contains("
")); + } + + #[test] + fn preview_source_version_changes_when_source_changes() { + let dir = tempfile::tempdir().expect("tempdir"); + let path = dir.path().join("test.trace-view.tsx"); + std::fs::write(&path, "export default null;\n").expect("write view"); + let source = test_preview_source(path.clone(), dir.path().to_path_buf()); + + let before = preview_source_version(&source, &[]); + std::fs::write(&path, "export default function View() { return null; }\n") + .expect("rewrite view"); + let after = preview_source_version(&source, &[]); + + assert_ne!(before, after); + } + + #[test] + fn preview_source_version_changes_when_dependency_changes() { + let dir = tempfile::tempdir().expect("tempdir"); + let path = dir.path().join("test.trace-view.tsx"); + let dependency = dir.path().join("component.tsx"); + std::fs::write(&path, "export { default } from './component';\n").expect("write view"); + std::fs::write( + &dependency, + "export default function View() { return null; }\n", + ) + .expect("write dependency"); + let source = test_preview_source(path, dir.path().to_path_buf()); + + let dependency_paths = vec![dependency.clone()]; + let before = preview_source_version(&source, &dependency_paths); + std::fs::write( + &dependency, + "export default function View() { return 'changed'; }\n", + ) + .expect("rewrite dependency"); + let after = preview_source_version(&source, &dependency_paths); + + assert_ne!(before, after); + } + + #[test] + fn parses_trace_preview_url_project_and_span_selectors() { + let parsed = parse_trace_url( + "https://www.braintrust.dev/app/test-org/p/test-project/logs?r=root-span&s=selected-span", + ) + .expect("parse URL"); + + assert_eq!(parsed.project.as_deref(), Some("test-project")); + assert_eq!(parsed.row_ref.as_deref(), Some("root-span")); + assert_eq!(parsed.span_id.as_deref(), Some("selected-span")); + } + + #[test] + fn trace_url_project_only_skips_project_resolution_for_trace_views() { + let url = Some("https://www.braintrust.dev/app/test-org/p/test-project/logs?r=root-span"); + + assert!(trace_url_supplies_project(ViewType::Trace, url)); + assert!(!trace_url_supplies_project(ViewType::Dataset, url)); + assert!(!trace_url_supplies_project( + ViewType::Trace, + Some("https://www.braintrust.dev/app/test-org/logs?r=root-span") + )); + assert!(!trace_url_supplies_project(ViewType::Trace, None)); + } + + #[tokio::test] + async fn trace_preview_url_project_id_does_not_require_default_project() { + let client = test_client(); + let project_id = "00000000-0000-4000-8000-000000000001"; + let target = resolve_trace_preview_target( + &client, + None, + &TracePreviewTargetArgs { + url: Some(format!( + "https://www.braintrust.dev/app/test-org/p/{project_id}/logs?r=root-span&s=selected-span" + )), + project_id: None, + trace_id: None, + span_id: None, + }, + ) + .await + .expect("resolve target"); + + assert_eq!(target.project_id, project_id); + assert_eq!(target.root_span_id, "root-span"); + assert_eq!(target.span_id.as_deref(), Some("selected-span")); + } + + #[tokio::test] + async fn trace_preview_url_without_project_uses_default_project() { + let client = test_client(); + let project = test_project(); + let target = resolve_trace_preview_target( + &client, + Some(&project), + &TracePreviewTargetArgs { + url: Some("https://www.braintrust.dev/app/test-org/logs?r=root-span".to_string()), + project_id: None, + trace_id: None, + span_id: Some("selected-span".to_string()), + }, + ) + .await + .expect("resolve target"); + + assert_eq!(target.project_id, "proj_test"); + assert_eq!(target.root_span_id, "root-span"); + assert_eq!(target.span_id.as_deref(), Some("selected-span")); + } + + #[tokio::test] + async fn trace_preview_url_without_project_errors_without_default_project() { + let client = test_client(); + let err = resolve_trace_preview_target( + &client, + None, + &TracePreviewTargetArgs { + url: Some("https://www.braintrust.dev/app/test-org/logs?r=root-span".to_string()), + project_id: None, + trace_id: None, + span_id: None, + }, + ) + .await + .expect_err("missing project should fail"); + + assert!(err + .to_string() + .contains("trace URL must include a project path")); + } + + #[test] + fn normalizes_bootstrap_name_to_slug() { + assert_eq!( + bootstrap_slug("Trace Review 2026").unwrap(), + "trace-review-2026" + ); + assert_eq!( + bootstrap_slug(" Dataset__Review!! ").unwrap(), + "dataset-review" + ); + assert!(bootstrap_slug("!!!").is_err()); + } + + #[test] + fn builds_inline_custom_view_insert_event() { + let view = PreparedView { + source_file: "test.view.tsx".to_string(), + entry: ViewManifestEntry { + view_type: ViewType::Trace, + name: "Test View".to_string(), + slug: "test-view".to_string(), + code: "module.exports = function View() {}".to_string(), + project_id: None, + project_name: None, + dataset_id: None, + dataset_name: None, + }, + project: test_project(), + dataset: None, + }; + + let event = build_insert_event(&view, IfExistsMode::Replace); + assert_eq!(event["function_type"], "custom_view"); + assert_eq!(event["if_exists"], "replace"); + assert_eq!(event["function_data"]["type"], "code"); + assert_eq!(event["function_data"]["data"]["type"], "inline"); + assert_eq!( + event["function_data"]["data"]["runtime_context"]["runtime"], + "browser" + ); + assert!(event.get("origin").is_none()); + assert!(event.get("description").is_none()); + assert!(event.get("metadata").is_none()); + assert!(event.get("tags").is_none()); + } + + #[test] + fn formats_actionable_custom_view_insert_error() { + let view = PreparedView { + source_file: "test.view.tsx".to_string(), + entry: ViewManifestEntry { + view_type: ViewType::Trace, + name: "Test View".to_string(), + slug: "test-view".to_string(), + code: "module.exports = function View() {}".to_string(), + project_id: None, + project_name: None, + dataset_id: None, + dataset_name: None, + }, + project: test_project(), + dataset: None, + }; + let err = anyhow!("request failed (400 Bad Request): slug already exists"); + + let message = format_views_insert_error(&[view], IfExistsMode::Error, &err); + + assert!(message.contains("trace 'test-view' in project 'test-project'")); + assert!(message.contains("--if-exists error")); + assert!(message.contains("bt views push --if-exists replace")); + assert!(message.contains("slug already exists")); + } + + #[test] + fn dataset_insert_event_sets_origin() { + let view = PreparedView { + source_file: "dataset.view.tsx".to_string(), + entry: ViewManifestEntry { + view_type: ViewType::Dataset, + name: "Dataset View".to_string(), + slug: "dataset-view".to_string(), + code: "module.exports = function View() {}".to_string(), + project_id: None, + project_name: None, + dataset_id: Some("dataset_test".to_string()), + dataset_name: None, + }, + project: test_project(), + dataset: Some(datasets_api::Dataset { + id: "dataset_test".to_string(), + name: "test-dataset".to_string(), + project_id: Some("proj_test".to_string()), + description: None, + created: None, + created_at: None, + metadata: None, + }), + }; + + let event = build_insert_event(&view, IfExistsMode::Error); + assert_eq!(event["origin"]["object_type"], "dataset"); + assert_eq!(event["origin"]["object_id"], "dataset_test"); + } +} diff --git a/tests/cli.rs b/tests/cli.rs index acb09bf..bbcc865 100644 --- a/tests/cli.rs +++ b/tests/cli.rs @@ -127,6 +127,321 @@ fn topics_report_help_accepts_global_org_short_conflict_free() { .stdout(predicate::str::contains("--output")); } +#[test] +fn views_help_accepts_push_trace_and_dataset_subcommands() { + bt_command() + .args(["views", "--help"]) + .assert() + .success() + .stdout(predicate::str::contains("push")) + .stdout(predicate::str::contains("trace")) + .stdout(predicate::str::contains("dataset")); +} + +#[test] +fn views_rejects_trace_and_dataset_aliases() { + for alias in ["traces", "datasets"] { + bt_command() + .args(["views", alias, "--help"]) + .assert() + .failure(); + } +} + +#[test] +fn views_trace_help_lists_bootstrap_and_preview() { + bt_command() + .args(["views", "trace", "--help"]) + .assert() + .success() + .stdout(predicate::str::contains("bootstrap")) + .stdout(predicate::str::contains("preview")); +} + +#[test] +fn views_dataset_help_lists_bootstrap_and_preview() { + bt_command() + .args(["views", "dataset", "--help"]) + .assert() + .success() + .stdout(predicate::str::contains("bootstrap")) + .stdout(predicate::str::contains("preview")); +} + +#[test] +fn views_push_help_lists_custom_view_flags() { + bt_command() + .args(["views", "push", "--help"]) + .assert() + .success() + .stdout(predicate::str::contains("--if-exists")); +} + +#[test] +fn views_trace_preview_help_lists_trace_selectors() { + bt_command() + .args(["views", "trace", "preview", "--help"]) + .assert() + .success() + .stdout(predicate::str::contains("--trace-id")) + .stdout(predicate::str::contains("--url")) + .stdout(predicate::str::contains("--dataset").not()) + .stdout(predicate::str::contains("--row-index").not()); +} + +#[test] +fn views_dataset_preview_help_lists_dataset_selectors() { + bt_command() + .args(["views", "dataset", "preview", "--help"]) + .assert() + .success() + .stdout(predicate::str::contains("--dataset")) + .stdout(predicate::str::contains("--trace-id").not()) + .stdout(predicate::str::contains("--url").not()) + .stdout(predicate::str::contains("--row-index")); +} + +#[test] +fn views_preview_hidden_aggregate_command_is_removed() { + bt_command() + .args(["views", "preview", "--help"]) + .assert() + .failure(); +} + +#[test] +fn views_trace_bootstrap_creates_starter_file() { + let dir = tempfile::tempdir().expect("tempdir"); + + bt_command() + .current_dir(dir.path()) + .args(["views", "trace", "bootstrap", "Trace Review"]) + .assert() + .success() + .stdout(predicate::str::contains( + "braintrust-custom-views/trace-review.trace-view.tsx", + )) + .stdout(predicate::str::contains( + "braintrust-custom-views/tsconfig.json", + )) + .stdout(predicate::str::contains( + "braintrust-custom-views/custom-view-env.d.ts", + )); + + let contents = fs::read_to_string( + dir.path() + .join("braintrust-custom-views/trace-review.trace-view.tsx"), + ) + .expect("read starter view"); + assert!(contents.contains("export default customTraceView")); + assert!(contents.contains(r#"name: "Trace Review""#)); + assert!(contents.contains(r#"slug: "trace-review""#)); + assert!(contents.contains("({ trace, span, selectSpan }) => {")); + assert!(contents.contains("onChange={(event) => selectSpan?.(event.target.value)}")); + assert!(!contents.contains("function StarterTraceView")); + assert!(!contents.contains("StarterTraceView,")); + assert!(!contents.contains("trace: { spanOrder: string[] }")); + assert!(!contents.contains("event:")); + assert!(!contents.contains(r#"from "react""#)); + assert!(!contents.contains("component: StarterTraceView")); + + let tsconfig = fs::read_to_string(dir.path().join("braintrust-custom-views/tsconfig.json")) + .expect("read custom view tsconfig"); + assert!(tsconfig.contains(r#""jsx": "react-jsx""#)); + assert!(tsconfig.contains(r#""moduleResolution": "Bundler""#)); + assert!(tsconfig.contains(r#""noEmit": true"#)); + assert!(tsconfig.contains(r#""allowJs": true"#)); + assert!(tsconfig.contains(r#""**/*.view.tsx""#)); + assert!(tsconfig.contains(r#""**/*.view.jsx""#)); + assert!(tsconfig.contains(r#""**/*-view.tsx""#)); + assert!(tsconfig.contains(r#""**/*-view.jsx""#)); + assert!(tsconfig.contains(r#""**/*.d.ts""#)); + + let types = fs::read_to_string( + dir.path() + .join("braintrust-custom-views/custom-view-env.d.ts"), + ) + .expect("read custom view type declarations"); + assert!(types.contains("declare namespace JSX")); + assert!(types.contains("interface CustomViewIntrinsicElements")); + assert!(types.contains("select: CustomViewSelectProps")); + assert!(types.contains("option: CustomViewOptionProps")); + assert!(types.contains("onChange?: (event: CustomViewSelectChangeEvent) => void")); + assert!(types.contains("interface IntrinsicElements extends CustomViewIntrinsicElements")); + assert!(types.contains(r#"declare module "react/jsx-runtime""#)); + assert!(types.contains(r#"declare module "react""#)); +} + +#[test] +fn views_dataset_bootstrap_creates_starter_file_with_dataset_name() { + let dir = tempfile::tempdir().expect("tempdir"); + + bt_command() + .current_dir(dir.path()) + .args([ + "views", + "dataset", + "bootstrap", + "Dataset Review", + "--dataset", + "test-dataset", + "--file", + "custom.dataset.view.tsx", + ]) + .assert() + .success() + .stdout(predicate::str::contains("custom.dataset.view.tsx")); + + let contents = + fs::read_to_string(dir.path().join("custom.dataset.view.tsx")).expect("read starter view"); + assert!(contents.contains("export default customDatasetView")); + assert!(contents.contains(r#"name: "Dataset Review""#)); + assert!(contents.contains(r#"slug: "dataset-review""#)); + assert!(contents.contains(r#"dataset: { name: "test-dataset" }"#)); + assert!(contents.contains("({ id, input, expected, metadata, tags = [] }) => {")); + assert!(!contents.contains("function StarterDatasetView")); + assert!(!contents.contains("StarterDatasetView,")); + assert!(!contents.contains("id: string;")); + assert!(!contents.contains(r#"from "react""#)); + assert!(!contents.contains("component: StarterDatasetView")); + + let tsconfig = + fs::read_to_string(dir.path().join("tsconfig.json")).expect("read custom view tsconfig"); + assert!(tsconfig.contains(r#""jsx": "react-jsx""#)); + assert!(dir.path().join("custom-view-env.d.ts").exists()); +} + +#[test] +fn views_bootstrap_json_reports_tsconfig() { + let dir = tempfile::tempdir().expect("tempdir"); + + let output = bt_command() + .current_dir(dir.path()) + .args(["views", "--json", "trace", "bootstrap", "Trace Review"]) + .assert() + .success() + .get_output() + .stdout + .clone(); + let payload: serde_json::Value = + serde_json::from_slice(&output).expect("parse bootstrap json output"); + + assert_eq!( + payload["path"], + "braintrust-custom-views/trace-review.trace-view.tsx" + ); + assert_eq!( + payload["tsconfig_path"], + "braintrust-custom-views/tsconfig.json" + ); + assert_eq!(payload["tsconfig_created"], true); + assert_eq!( + payload["types_path"], + "braintrust-custom-views/custom-view-env.d.ts" + ); + assert_eq!(payload["types_created"], true); + assert_eq!(payload["view_type"], "trace"); +} + +#[test] +fn views_bootstrap_preserves_existing_tsconfig_without_force() { + let dir = tempfile::tempdir().expect("tempdir"); + fs::create_dir_all(dir.path().join("custom")).expect("create custom view dir"); + fs::write( + dir.path().join("custom/tsconfig.json"), + "{ \"compilerOptions\": { \"jsx\": \"preserve\" } }\n", + ) + .expect("write existing tsconfig"); + fs::write( + dir.path().join("custom/custom-view-env.d.ts"), + "declare const preserved: true;\n", + ) + .expect("write existing types"); + + bt_command() + .current_dir(dir.path()) + .args([ + "views", + "trace", + "bootstrap", + "Trace Review", + "--file", + "custom", + ]) + .assert() + .success() + .stdout(predicate::str::contains("Reused TypeScript config")) + .stdout(predicate::str::contains( + "Reused custom view type declarations", + )); + + let tsconfig = + fs::read_to_string(dir.path().join("custom/tsconfig.json")).expect("read tsconfig"); + assert_eq!( + tsconfig, + "{ \"compilerOptions\": { \"jsx\": \"preserve\" } }\n" + ); + assert!(dir + .path() + .join("custom/trace-review.trace-view.tsx") + .exists()); + let types = + fs::read_to_string(dir.path().join("custom/custom-view-env.d.ts")).expect("read types"); + assert_eq!(types, "declare const preserved: true;\n"); +} + +#[test] +fn views_bootstrap_force_overwrites_view_and_tsconfig() { + let dir = tempfile::tempdir().expect("tempdir"); + fs::create_dir_all(dir.path().join("custom")).expect("create custom view dir"); + fs::write( + dir.path().join("custom/trace-review.trace-view.tsx"), + "old view\n", + ) + .expect("write view"); + fs::write( + dir.path().join("custom/tsconfig.json"), + "{ \"compilerOptions\": { \"jsx\": \"preserve\" } }\n", + ) + .expect("write existing tsconfig"); + fs::write( + dir.path().join("custom/custom-view-env.d.ts"), + "declare const preserved: true;\n", + ) + .expect("write existing types"); + + bt_command() + .current_dir(dir.path()) + .args([ + "views", + "trace", + "bootstrap", + "Trace Review", + "--file", + "custom", + "--force", + ]) + .assert() + .success() + .stdout(predicate::str::contains("Updated TypeScript config")) + .stdout(predicate::str::contains( + "Updated custom view type declarations", + )); + + let contents = fs::read_to_string(dir.path().join("custom/trace-review.trace-view.tsx")) + .expect("read starter view"); + assert!(contents.contains("export default customTraceView")); + + let tsconfig = + fs::read_to_string(dir.path().join("custom/tsconfig.json")).expect("read tsconfig"); + assert!(tsconfig.contains(r#""jsx": "react-jsx""#)); + assert!(!tsconfig.contains(r#""jsx": "preserve""#)); + let types = + fs::read_to_string(dir.path().join("custom/custom-view-env.d.ts")).expect("read types"); + assert!(types.contains(r#"declare module "react/jsx-runtime""#)); + assert!(!types.contains("declare const preserved")); +} + #[test] fn status_quiet_and_verbose_conflict() { bt_command()