diff --git a/Cargo.lock b/Cargo.lock index 9593b0ccee..8504c43732 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -57,7 +57,7 @@ dependencies = [ "strum_macros", "tempfile", "text-splitter", - "thiserror 2.0.17", + "thiserror 2.0.18", "tiktoken-rs", "tree-sitter", "tree-sitter-c", @@ -95,7 +95,7 @@ dependencies = [ "rubato", "screencapturekit", "symphonia", - "thiserror 2.0.17", + "thiserror 2.0.18", "uuid", "windows 0.61.3", "windows-core 0.61.2", @@ -112,11 +112,15 @@ dependencies = [ "chrono", "homedir", "lru", + "mermaid-rs-renderer", "objc2", "objc2-foundation", "sqlx", - "thiserror 2.0.17", + "thiserror 2.0.18", "tokio", + "typst", + "typst-as-lib", + "typst-svg", "uniffi", ] @@ -129,6 +133,7 @@ dependencies = [ "affine_nbstore", "affine_sqlite_v1", "chrono", + "mermaid-rs-renderer", "mimalloc", "napi", "napi-build", @@ -136,8 +141,11 @@ dependencies = [ "once_cell", "serde_json", "sqlx", - "thiserror 2.0.17", + "thiserror 2.0.18", "tokio", + "typst", + "typst-as-lib", + "typst-svg", "uuid", ] @@ -148,7 +156,7 @@ dependencies = [ "affine_common", "affine_schema", "anyhow", - "bincode", + "bincode 2.0.1", "chrono", "dotenvy", "memory-indexer", @@ -158,7 +166,7 @@ dependencies = [ "serde", "serde_json", "sqlx", - "thiserror 2.0.17", + "thiserror 2.0.18", "tokio", "uniffi", "uuid", @@ -306,9 +314,9 @@ checksum = "dc43e46599f3d77fcf2f2ca89e4d962910b0c19c44e7b58679cbbdfd1820a662" [[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", @@ -321,15 +329,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", ] @@ -356,9 +364,27 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.100" +version = "1.0.102" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" +checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" + +[[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.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7eb93bbb63b9c227414f6eb3a0adfddca591a8ce1e9b60661bb08969b87e340b" +dependencies = [ + "object", +] [[package]] name = "arbitrary" @@ -371,13 +397,19 @@ dependencies = [ [[package]] name = "arc-swap" -version = "1.8.0" +version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51d03449bb8ca2cc2ef70869af31463d1ae5ccc8fa3e334b307203fbf815207e" +checksum = "f9f3647c145568cec02c42054e07bdf9a5a698e15b466fb2341bfc393cd24aa5" dependencies = [ "rustversion", ] +[[package]] +name = "arrayref" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" + [[package]] name = "arrayvec" version = "0.7.6" @@ -411,7 +443,7 @@ dependencies = [ "rustc-hash 2.1.1", "serde", "serde_derive", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -423,7 +455,7 @@ dependencies = [ "memchr", "serde", "serde_derive", - "winnow", + "winnow 0.7.15", ] [[package]] @@ -469,7 +501,7 @@ checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -483,14 +515,14 @@ dependencies = [ [[package]] name = "auto_enums" -version = "0.8.7" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c170965892137a3a9aeb000b4524aa3cc022a310e709d848b6e1cdce4ab4781" +checksum = "65398a2893f41bce5c9259f6e1a4f03fbae40637c1bdc755b4f387f48c613b03" dependencies = [ "derive_utils", "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -499,6 +531,12 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" +[[package]] +name = "az" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be5eb007b7cacc6c660343e96f650fedf4b5a77512399eb952ca6642cf8d13f7" + [[package]] name = "base64" version = "0.22.1" @@ -517,9 +555,9 @@ dependencies = [ [[package]] name = "base64ct" -version = "1.8.2" +version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d809780667f4410e7c41b07f52439b94d2bdf8528eeedc287fa38d3b7f95d82" +checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" [[package]] name = "basic-toml" @@ -530,6 +568,29 @@ dependencies = [ "serde", ] +[[package]] +name = "biblatex" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d0c374feba1b9a59042a7c1cf00ce7c34b977b9134fe7c42b08e5183729f66" +dependencies = [ + "paste", + "roman-numerals-rs", + "strum", + "unic-langid", + "unicode-normalization", + "unscanny", +] + +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + [[package]] name = "bincode" version = "2.0.1" @@ -565,7 +626,18 @@ dependencies = [ "regex", "rustc-hash 2.1.1", "shlex", - "syn 2.0.114", + "syn 2.0.117", +] + +[[package]] +name = "binstall-tar" +version = "0.4.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3620d72763b5d8df3384f3b2ec47dc5885441c2abbd94dd32197167d08b014a" +dependencies = [ + "filetime", + "libc", + "xattr", ] [[package]] @@ -669,9 +741,9 @@ dependencies = [ [[package]] name = "bpaf" -version = "0.9.20" +version = "0.9.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "473976d7a8620bb1e06dcdd184407c2363fe4fec8e983ee03ed9197222634a31" +checksum = "b2435ff2f08be8436bdcd06a3de2bd7696fd10e45eb630ecfc09af7fbfa3e69a" [[package]] name = "brotli" @@ -707,9 +779,15 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.19.1" +version = "3.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510" +checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" + +[[package]] +name = "by_address" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64fa3c856b712db6612c019f14756e64e4bcea13337a6b33b696333a9eaa2d06" [[package]] name = "bytecount" @@ -719,9 +797,23 @@ checksum = "175812e0be2bccb6abe50bb8d566126198344f707e304f45c648fd8f2cc0365e" [[package]] name = "bytemuck" -version = "1.24.0" +version = "1.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fbdf580320f38b612e485521afda1ee26d10cc9884efaaa750d383e13e3c5f4" +checksum = "c8efb64bd706a16a1bdde310ae86b351e4d21550d98d056f22f8a7f7a2183fec" +dependencies = [ + "bytemuck_derive", +] + +[[package]] +name = "bytemuck_derive" +version = "1.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9abbd1bc6865053c427f7198e6af43bfdedc55ab791faed4fbd361d789575ff" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] [[package]] name = "byteorder" @@ -770,7 +862,7 @@ dependencies = [ "semver", "serde", "serde_json", - "thiserror 2.0.17", + "thiserror 2.0.18", ] [[package]] @@ -790,9 +882,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.51" +version = "1.2.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a0aeaff4ff1a90589618835a598e545176939b97874f7abc7851caa0618f203" +checksum = "7a0dd1ca384932ff3641c8718a02769f1698e7563dc6974ffd03346116310423" dependencies = [ "find-msvc-tools", "jobserver", @@ -837,9 +929,9 @@ dependencies = [ [[package]] name = "cff-parser" -version = "0.1.0" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31f5b6e9141c036f3ff4ce7b2f7e432b0f00dee416ddcd4f17741d189ddc2e9d" +checksum = "c5810ca1a2b5870df2aab1c03e11c40c361ba51d6e3e361e56310f1cb3b4e087" [[package]] name = "cfg-if" @@ -863,10 +955,28 @@ dependencies = [ ] [[package]] -name = "chrono" -version = "0.4.42" +name = "chinese-number" +version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "145052bdd345b87320e369255277e3fb5152762ad123a901ef5c262dd38fe8d2" +checksum = "3e964125508474a83c95eb935697abbeb446ff4e9d62c71ce880e3986d1c606b" +dependencies = [ + "chinese-variant", + "enum-ordinalize", + "num-bigint", + "num-traits", +] + +[[package]] +name = "chinese-variant" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58b52a9840ffff5d4d0058ae529fa066a75e794e3125546acfc61c23ad755e49" + +[[package]] +name = "chrono" +version = "0.4.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0" dependencies = [ "iana-time-zone", "js-sys", @@ -912,6 +1022,16 @@ dependencies = [ "inout", ] +[[package]] +name = "citationberg" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f6597e8bdbca37f1f56e5a80d15857b0932aead21a78d20de49e99e74933046" +dependencies = [ + "quick-xml 0.38.4", + "serde", +] + [[package]] name = "clang-sys" version = "1.8.1" @@ -925,9 +1045,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.54" +version = "4.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6e6ff9dcd79cff5cd969a17a545d79e84ab086e444102a591e288a8aa3ce394" +checksum = "b193af5b67834b676abd72466a96c1024e6a6ad978a1f484bd90b85c94041351" dependencies = [ "clap_builder", "clap_derive", @@ -935,9 +1055,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.54" +version = "4.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa42cf4d2b7a41bc8f663a7cab4031ebafa1bf3875705bfaf8466dc60ab52c00" +checksum = "714a53001bf66416adb0e2ef5ac857140e7dc3a0c48fb28b2f10762fc4b5069f" dependencies = [ "anstream", "anstyle", @@ -947,21 +1067,36 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.49" +version = "4.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a0b5487afeab2deb2ff4e03a807ad1a03ac532ff5a2cee5d86884440c7f7671" +checksum = "1110bd8a634a1ab8cb04345d8d878267d57c3cf1b38d91b71af6686408bbca6a" dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] name = "clap_lex" -version = "0.7.6" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1d728cc89cf3aee9ff92b05e62b19ee65a02b5702cff7d5a377e32c6ae29d8d" +checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9" + +[[package]] +name = "cobs" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa961b519f0b462e3a3b4a34b64d119eeaca1d59af726fe450bbba07a9fc0a1" +dependencies = [ + "thiserror 2.0.18", +] + +[[package]] +name = "codex" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9589e1effc5cacbea347899645c654158b03b2053d24bb426fd3128ced6e423c" [[package]] name = "color_quant" @@ -971,9 +1106,9 @@ checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" [[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 = "combine" @@ -985,6 +1120,30 @@ dependencies = [ "memchr", ] +[[package]] +name = "comemo" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c963350b2b08aa4b725d7802593245380ab53dacfedcaa971385fc33306c0d4" +dependencies = [ + "comemo-macros", + "parking_lot", + "rustc-hash 2.1.1", + "siphasher 1.0.2", + "slab", +] + +[[package]] +name = "comemo-macros" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3c400139ba1389ef9e20ad2d87cda68b437a66483aa0da616bdf2cea7413853" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + [[package]] name = "concurrent-queue" version = "2.5.0" @@ -1009,9 +1168,9 @@ checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" [[package]] name = "convert_case" -version = "0.10.0" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "633458d4ef8c78b72454de2d54fd6ab2e60f9e02be22f3c6104cdc8a4e0fceb9" +checksum = "affbf0190ed2caf063e3def54ff444b449371d55c58e513a95ab98eca50adb49" dependencies = [ "unicode-segmentation", ] @@ -1089,7 +1248,7 @@ dependencies = [ "core-foundation", "core-utils-rs", "core-video-rs", - "thiserror 2.0.17", + "thiserror 2.0.18", ] [[package]] @@ -1112,7 +1271,7 @@ dependencies = [ "core-graphics 0.24.0", "core-utils-rs", "io-surface", - "thiserror 2.0.17", + "thiserror 2.0.18", ] [[package]] @@ -1258,9 +1417,9 @@ dependencies = [ [[package]] name = "criterion2" -version = "3.0.2" +version = "3.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77cd1059d67baa066c334993d8d6e757ad257d21030db6a9a945dddbb559d4fe" +checksum = "861a56bb48e3ba7a2a38580a91577e17d90db946649f5c342fd74ba864180def" dependencies = [ "anes 0.2.1", "bpaf", @@ -1332,6 +1491,27 @@ dependencies = [ "typenum", ] +[[package]] +name = "csv" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52cd9d68cf7efc6ddfaaee42e7288d3a99d613d4b50f76ce9827ae0c6e14f938" +dependencies = [ + "csv-core", + "itoa", + "ryu", + "serde_core", +] + +[[package]] +name = "csv-core" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "704a3c26996a80471189265814dbc2c257598b96b8a7feae2d31ace646bb9782" +dependencies = [ + "memchr", +] + [[package]] name = "ctor" version = "0.6.3" @@ -1374,6 +1554,12 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c87e182de0887fd5361989c677c4e8f5000cd9491d6d563161a8f3a5519fc7f" +[[package]] +name = "data-url" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be1e0bca6c3637f992fc1cc7cbc52a78c1ef6db076dbf1059c4323d6a2048376" + [[package]] name = "der" version = "0.7.10" @@ -1385,6 +1571,15 @@ dependencies = [ "zeroize", ] +[[package]] +name = "deranged" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" +dependencies = [ + "powerfmt", +] + [[package]] name = "derive_arbitrary" version = "1.4.2" @@ -1393,7 +1588,7 @@ checksum = "1e567bd82dcff979e4b03460c307b3cdc9e96fde3d73bed1496d2bc75d9dd62a" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -1406,18 +1601,18 @@ dependencies = [ "proc-macro2", "quote", "rustc_version", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] name = "derive_utils" -version = "0.15.0" +version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccfae181bab5ab6c5478b2ccb69e4c68a02f8c3ec72f6616bfec9dbc599d2ee0" +checksum = "362f47930db19fe7735f527e6595e4900316b893ebf6d48ad3d31be928d57dd6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -1432,6 +1627,27 @@ dependencies = [ "subtle", ] +[[package]] +name = "dirs" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab" +dependencies = [ + "libc", + "option-ext", + "redox_users", + "windows-sys 0.61.2", +] + [[package]] name = "dispatch" version = "0.2.0" @@ -1440,9 +1656,9 @@ checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" [[package]] name = "dispatch2" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89a09f22a6c6069a18470eb92d2298acf25463f14256d24778e1230d789a2aec" +checksum = "1e0e367e4e7da84520dedcac1901e4da967309406d1e51017ae1abfb97adbd38" dependencies = [ "bitflags 2.11.0", "block2", @@ -1458,13 +1674,13 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] name = "docx-parser" version = "0.1.1" -source = "git+https://github.com/toeverything/docx-parser#278ba3eeb29bbf1ee7958b02436e4402af61859b" +source = "git+https://github.com/toeverything/docx-parser?rev=380beea#380beeaca82f4cf22496f63feb78b35b5cf539ae" dependencies = [ "base64", "clap", @@ -1475,9 +1691,9 @@ dependencies = [ [[package]] name = "docx-rust" -version = "0.1.10" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75463cd42bd579fdf76cf10ff1c4fb5988568c726f8ed4c2ed3921ddb6ef5c89" +checksum = "384002ebe1137c2602121f43e7c1329b88cb5d78074e4a13b041db360b4e57f1" dependencies = [ "derive_more", "hard-xml", @@ -1516,6 +1732,15 @@ dependencies = [ "cipher", ] +[[package]] +name = "ecow" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78e4f79b296fbaab6ce2e22d52cb4c7f010fe0ebe7a32e34fa25885fd797bd02" +dependencies = [ + "serde", +] + [[package]] name = "either" version = "1.15.0" @@ -1525,6 +1750,18 @@ dependencies = [ "serde", ] +[[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 = "encoding_rs" version = "0.8.35" @@ -1534,6 +1771,26 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "enum-ordinalize" +version = "4.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a1091a7bb1f8f2c4b28f1fe2cef4980ca2d410a3d727d67ecc3178c9b0800f0" +dependencies = [ + "enum-ordinalize-derive", +] + +[[package]] +name = "enum-ordinalize-derive" +version = "4.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ca9601fb2d62598ee17836250842873a413586e5d7ed88b356e38ddbb0ec631" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + [[package]] name = "equivalent" version = "1.0.2" @@ -1570,6 +1827,15 @@ dependencies = [ "num-traits", ] +[[package]] +name = "euclid" +version = "0.22.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df61bf483e837f88d5c2291dcf55c67be7e676b3a51acc48db3a7b163b91ed63" +dependencies = [ + "num-traits", +] + [[package]] name = "event-listener" version = "5.4.1" @@ -1618,13 +1884,30 @@ dependencies = [ "regex-syntax", ] +[[package]] +name = "fancy-regex" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "998b056554fbe42e03ae0e152895cd1a7e1002aec800fdc6635d20270260c46f" +dependencies = [ + "bit-set 0.8.0", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "fast-srgb8" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd2e7510819d6fbf51a5545c8f922716ecfb14df168a3242f7d33e0239efe6a1" + [[package]] name = "fastrand" version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" dependencies = [ - "getrandom 0.2.16", + "getrandom 0.2.17", ] [[package]] @@ -1643,21 +1926,39 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eab8aa2fba5f39f494000a22f44bf3c755b7d7f8ffad3f36c6d507893074159" [[package]] -name = "find-msvc-tools" -version = "0.1.6" +name = "filetime" +version = "0.2.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "645cbb3a84e60b7531617d5ae4e57f7e27308f6445f5abf653209ea76dec8dff" +checksum = "f98844151eee8917efc50bd9e8318cb963ae8b297431495d3f758616ea5c57db" +dependencies = [ + "cfg-if", + "libc", + "libredox", +] + +[[package]] +name = "find-msvc-tools" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" [[package]] name = "flate2" -version = "1.1.5" +version = "1.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfe33edd8e85a12a67454e37f8c75e730830d83e313556ab9ebf9ee7fbeb3bfb" +checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c" dependencies = [ "crc32fast", "miniz_oxide", + "zlib-rs", ] +[[package]] +name = "float-cmp" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98de4bbd547a563b716d8dfa9aad1cb19bfab00f4fa09a6a4ed21dbcf44ce9c4" + [[package]] name = "flume" version = "0.11.1" @@ -1687,6 +1988,38 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" +[[package]] +name = "font-types" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39a654f404bbcbd48ea58c617c2993ee91d1cb63727a37bf2323a4edeed1b8c5" +dependencies = [ + "bytemuck", +] + +[[package]] +name = "fontconfig-parser" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbc773e24e02d4ddd8395fd30dc147524273a83e54e0f312d986ea30de5f5646" +dependencies = [ + "roxmltree", +] + +[[package]] +name = "fontdb" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "457e789b3d1202543297a350643cf459f836cade38934e7a4cf6a39e7cde2905" +dependencies = [ + "fontconfig-parser", + "log", + "memmap2", + "slotmap", + "tinyvec", + "ttf-parser", +] + [[package]] name = "foreign-types" version = "0.5.0" @@ -1705,7 +2038,7 @@ checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -1750,9 +2083,9 @@ dependencies = [ [[package]] name = "futures" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" +checksum = "8b147ee9d1f6d097cef9ce628cd2ee62288d963e16fb287bd9286455b241382d" dependencies = [ "futures-channel", "futures-core", @@ -1765,9 +2098,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" +checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d" dependencies = [ "futures-core", "futures-sink", @@ -1775,15 +2108,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" +checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" [[package]] name = "futures-executor" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" +checksum = "baf29c38818342a3b26b5b923639e7b1f4a61fc5e76102d4b1981c6dc7a7579d" dependencies = [ "futures-core", "futures-task", @@ -1803,38 +2136,38 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" +checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718" [[package]] name = "futures-macro" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" +checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] name = "futures-sink" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" +checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893" [[package]] name = "futures-task" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" +checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" [[package]] name = "futures-util" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" dependencies = [ "futures-channel", "futures-core", @@ -1844,7 +2177,6 @@ dependencies = [ "futures-task", "memchr", "pin-project-lite", - "pin-utils", "slab", ] @@ -1884,9 +2216,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" dependencies = [ "cfg-if", "js-sys", @@ -1903,10 +2235,23 @@ checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" dependencies = [ "cfg-if", "libc", - "r-efi", + "r-efi 5.3.0", "wasip2", ] +[[package]] +name = "getrandom" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555" +dependencies = [ + "cfg-if", + "libc", + "r-efi 6.0.0", + "wasip2", + "wasip3", +] + [[package]] name = "gif" version = "0.14.1" @@ -1917,6 +2262,12 @@ dependencies = [ "weezl", ] +[[package]] +name = "glidesort" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2e102e6eb644d3e0b186fc161e4460417880a0a0b87d235f2e5b8fb30f2e9e0" + [[package]] name = "glob" version = "0.3.3" @@ -2016,6 +2367,97 @@ dependencies = [ "hashbrown 0.15.5", ] +[[package]] +name = "hayagriva" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cb69425736f184173b3ca6e27fcba440a61492a790c786b1c6af7e06a03e575" +dependencies = [ + "biblatex", + "ciborium", + "citationberg", + "indexmap", + "paste", + "roman-numerals-rs", + "serde", + "serde_yaml", + "thiserror 2.0.18", + "unic-langid", + "unicode-segmentation", + "unscanny", + "url", +] + +[[package]] +name = "hayro" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "048488ba88552bb0fb2a7e4001c64d5bed65d1a92167186a1bb9151571f32e60" +dependencies = [ + "bytemuck", + "hayro-interpret", + "image", + "kurbo 0.12.0", +] + +[[package]] +name = "hayro-font" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10e7e97ce840a6a70e7901e240ec65ba61106b66b37a4a1b899a2ce484248463" +dependencies = [ + "log", + "phf 0.13.1", +] + +[[package]] +name = "hayro-interpret" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56204c972d08e844f3db13b1e14be769f846e576699b46d4f4637cc4f8f70102" +dependencies = [ + "bitflags 2.11.0", + "hayro-font", + "hayro-syntax", + "kurbo 0.12.0", + "log", + "moxcms 0.7.11", + "phf 0.13.1", + "rustc-hash 2.1.1", + "siphasher 1.0.2", + "skrifa", + "smallvec", + "yoke 0.8.1", +] + +[[package]] +name = "hayro-svg" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8c673304cec6e0dfd3b4f71fccecd45646899aa70279b62d3f933842abc4ac5" +dependencies = [ + "base64", + "hayro-interpret", + "image", + "kurbo 0.12.0", + "siphasher 1.0.2", + "xmlwriter", +] + +[[package]] +name = "hayro-syntax" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9e5c7dbc0f11dc42775d1a6cc00f5f5137b90b6288dd7fe5f71d17b14d10be" +dependencies = [ + "flate2", + "kurbo 0.12.0", + "log", + "rustc-hash 2.1.1", + "smallvec", + "zune-jpeg 0.4.21", +] + [[package]] name = "heck" version = "0.5.0" @@ -2104,10 +2546,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" [[package]] -name = "iana-time-zone" -version = "0.1.64" +name = "hypher" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33e57f83510bb73707521ebaffa789ec8caf86f9657cad665b092b581d40e9fb" +checksum = "74e25026c579b170c59f8d3ddfc523d7dab0abe079f09eb8edaebd2417044f60" + +[[package]] +name = "iana-time-zone" +version = "0.1.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -2127,6 +2575,19 @@ dependencies = [ "cc", ] +[[package]] +name = "icu_collections" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" +dependencies = [ + "displaydoc", + "serde", + "yoke 0.7.5", + "zerofrom", + "zerovec 0.10.4", +] + [[package]] name = "icu_collections" version = "2.1.1" @@ -2135,9 +2596,9 @@ checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" dependencies = [ "displaydoc", "potential_utf", - "yoke", + "yoke 0.8.1", "zerofrom", - "zerovec", + "zerovec 0.11.5", ] [[package]] @@ -2146,13 +2607,13 @@ version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "532b11722e350ab6bf916ba6eb0efe3ee54b932666afec989465f9243fe6dd60" dependencies = [ - "icu_collections", + "icu_collections 2.1.1", "icu_locale_core", "icu_locale_data", - "icu_provider", + "icu_provider 2.1.1", "potential_utf", - "tinystr", - "zerovec", + "tinystr 0.8.2", + "zerovec 0.11.5", ] [[package]] @@ -2162,18 +2623,51 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" dependencies = [ "displaydoc", - "litemap", + "litemap 0.8.1", "serde", - "tinystr", - "writeable", - "zerovec", + "tinystr 0.8.2", + "writeable 0.6.2", + "zerovec 0.11.5", ] [[package]] name = "icu_locale_data" -version = "2.1.1" +version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f03e2fcaefecdf05619f3d6f91740e79ab969b4dd54f77cbf546b1d0d28e3147" +checksum = "1c5f1d16b4c3a2642d3a719f18f6b06070ab0aef246a6418130c955ae08aa831" + +[[package]] +name = "icu_locid" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" +dependencies = [ + "displaydoc", + "litemap 0.7.5", + "tinystr 0.7.6", + "writeable 0.5.5", + "zerovec 0.10.4", +] + +[[package]] +name = "icu_locid_transform" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_locid_transform_data", + "icu_provider 1.5.0", + "tinystr 0.7.6", + "zerovec 0.10.4", +] + +[[package]] +name = "icu_locid_transform_data" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7515e6d781098bf9f7205ab3fc7e9709d34554ae0b21ddbcb5febfa4bc7df11d" [[package]] name = "icu_normalizer" @@ -2181,12 +2675,12 @@ version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" dependencies = [ - "icu_collections", + "icu_collections 2.1.1", "icu_normalizer_data", - "icu_properties", - "icu_provider", + "icu_properties 2.1.2", + "icu_provider 2.1.1", "smallvec", - "zerovec", + "zerovec 0.11.5", ] [[package]] @@ -2195,26 +2689,67 @@ version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" +[[package]] +name = "icu_properties" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" +dependencies = [ + "displaydoc", + "icu_collections 1.5.0", + "icu_locid_transform", + "icu_properties_data 1.5.1", + "icu_provider 1.5.0", + "serde", + "tinystr 0.7.6", + "zerovec 0.10.4", +] + [[package]] name = "icu_properties" version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec" dependencies = [ - "icu_collections", + "icu_collections 2.1.1", "icu_locale_core", - "icu_properties_data", - "icu_provider", - "zerotrie", - "zerovec", + "icu_properties_data 2.1.2", + "icu_provider 2.1.1", + "zerotrie 0.2.3", + "zerovec 0.11.5", ] +[[package]] +name = "icu_properties_data" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85fb8799753b75aee8d2a21d7c14d9f38921b54b3dbda10f5a3c7a7b82dba5e2" + [[package]] name = "icu_properties_data" version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af" +[[package]] +name = "icu_provider" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_provider_macros", + "postcard", + "serde", + "stable_deref_trait", + "tinystr 0.7.6", + "writeable 0.5.5", + "yoke 0.7.5", + "zerofrom", + "zerovec 0.10.4", +] + [[package]] name = "icu_provider" version = "2.1.1" @@ -2225,11 +2760,66 @@ dependencies = [ "icu_locale_core", "serde", "stable_deref_trait", - "writeable", - "yoke", + "writeable 0.6.2", + "yoke 0.8.1", "zerofrom", - "zerotrie", - "zerovec", + "zerotrie 0.2.3", + "zerovec 0.11.5", +] + +[[package]] +name = "icu_provider_adapters" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6324dfd08348a8e0374a447ebd334044d766b1839bb8d5ccf2482a99a77c0bc" +dependencies = [ + "icu_locid", + "icu_locid_transform", + "icu_provider 1.5.0", + "tinystr 0.7.6", + "zerovec 0.10.4", +] + +[[package]] +name = "icu_provider_blob" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c24b98d1365f55d78186c205817631a4acf08d7a45bdf5dc9dcf9c5d54dccf51" +dependencies = [ + "icu_provider 1.5.0", + "postcard", + "serde", + "writeable 0.5.5", + "zerotrie 0.1.3", + "zerovec 0.10.4", +] + +[[package]] +name = "icu_provider_macros" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "icu_segmenter" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a717725612346ffc2d7b42c94b820db6908048f39434504cb130e8b46256b0de" +dependencies = [ + "core_maths", + "displaydoc", + "icu_collections 1.5.0", + "icu_locid", + "icu_provider 1.5.0", + "icu_segmenter_data 1.5.1", + "serde", + "utf8_iter", + "zerovec 0.10.4", ] [[package]] @@ -2239,21 +2829,33 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a807a7488f3f758629ae86d99d9d30dce24da2fb2945d74c80a4f4a62c71db73" dependencies = [ "core_maths", - "icu_collections", + "icu_collections 2.1.1", "icu_locale", - "icu_provider", - "icu_segmenter_data", + "icu_provider 2.1.1", + "icu_segmenter_data 2.1.1", "potential_utf", "utf8_iter", - "zerovec", + "zerovec 0.11.5", ] +[[package]] +name = "icu_segmenter_data" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1e52775179941363cc594e49ce99284d13d6948928d8e72c755f55e98caa1eb" + [[package]] name = "icu_segmenter_data" version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ebbb7321d9e21d25f5660366cb6c08201d0175898a3a6f7a41ee9685af21c80" +[[package]] +name = "id-arena" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" + [[package]] name = "idna" version = "1.1.0" @@ -2272,25 +2874,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" dependencies = [ "icu_normalizer", - "icu_properties", + "icu_properties 2.1.2", ] [[package]] name = "image" -version = "0.25.9" +version = "0.25.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6506c6c10786659413faa717ceebcb8f70731c0a60cbae39795fdf114519c1a" +checksum = "85ab80394333c02fe689eaf900ab500fbd0c2213da414687ebf995a65d5a6104" dependencies = [ "bytemuck", "byteorder-lite", "color_quant", "gif", "image-webp", - "moxcms", + "moxcms 0.8.1", "num-traits", - "png", - "zune-core", - "zune-jpeg", + "png 0.18.1", + "zune-core 0.5.1", + "zune-jpeg 0.5.13", ] [[package]] @@ -2303,6 +2905,12 @@ dependencies = [ "quick-error 2.0.1", ] +[[package]] +name = "imagesize" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edcd27d72f2f071c64249075f42e205ff93c9a4c5f6c6da53e79ed9f9832c285" + [[package]] name = "include-flate" version = "0.3.1" @@ -2326,7 +2934,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", "zstd", ] @@ -2342,12 +2950,14 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.12.1" +version = "2.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ad4bb2b565bca0645f4d68c5c9af97fba094e9791da685bf83cb5f3ce74acf2" +checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" dependencies = [ "equivalent", "hashbrown 0.16.1", + "serde", + "serde_core", ] [[package]] @@ -2494,14 +3104,33 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.83" +version = "0.3.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "464a3709c7f55f1f721e5389aa6ea4e3bc6aba669353300af094b29ffbdde1d8" +checksum = "b49715b7073f385ba4bc528e5747d02e66cb39c6146efb66b781f131f0fb399c" dependencies = [ "once_cell", "wasm-bindgen", ] +[[package]] +name = "json5" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "733a844dbd6fef128e98cb4487b887cb55454d92cd9994b1bafe004fabbe670c" +dependencies = [ + "serde", + "ucd-trie", +] + +[[package]] +name = "kamadak-exif" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1130d80c7374efad55a117d715a3af9368f0fa7a2c54573afc15a188cd984837" +dependencies = [ + "mutate_once", +] + [[package]] name = "keccak" version = "0.1.6" @@ -2511,6 +3140,28 @@ dependencies = [ "cpufeatures", ] +[[package]] +name = "kurbo" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c62026ae44756f8a599ba21140f350303d4f08dcdcc71b5ad9c9bb8128c13c62" +dependencies = [ + "arrayvec", + "euclid 0.22.13", + "smallvec", +] + +[[package]] +name = "kurbo" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce9729cc38c18d86123ab736fd2e7151763ba226ac2490ec092d1dd148825e32" +dependencies = [ + "arrayvec", + "euclid 0.22.13", + "smallvec", +] + [[package]] name = "lazy_static" version = "1.5.0" @@ -2535,6 +3186,12 @@ dependencies = [ "leak", ] +[[package]] +name = "leb128fmt" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" + [[package]] name = "lib0" version = "0.16.10" @@ -2548,9 +3205,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.179" +version = "0.2.183" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5a2d376baa530d1238d133232d15e239abad80d05838b4b59354e5268af431f" +checksum = "b5b646652bf6661599e1da8901b3b9522896f01e736bad5f723fe7a3a27f899d" [[package]] name = "libflate" @@ -2598,9 +3255,9 @@ dependencies = [ [[package]] name = "libm" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" +checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" [[package]] name = "libmimalloc-sys" @@ -2614,13 +3271,14 @@ dependencies = [ [[package]] name = "libredox" -version = "0.1.12" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d0b95e02c851351f877147b7deea7b1afb1df71b63aa5f8270716e0c5720616" +checksum = "1744e39d1d6a9948f4f388969627434e31128196de472883b39f148769bfe30a" dependencies = [ "bitflags 2.11.0", "libc", - "redox_syscall 0.7.0", + "plain", + "redox_syscall 0.7.3", ] [[package]] @@ -2646,10 +3304,35 @@ dependencies = [ ] [[package]] -name = "linux-raw-sys" -version = "0.11.0" +name = "linked-hash-map" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" +checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" + +[[package]] +name = "linux-raw-sys" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" + +[[package]] +name = "lipsum" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "636860251af8963cc40f6b4baadee105f02e21b28131d76eba8e40ce84ab8064" +dependencies = [ + "rand 0.8.5", + "rand_chacha 0.3.1", +] + +[[package]] +name = "litemap" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23fb14cb19457329c82206317a5663005a4d404783dc74f4252769b0d5f42856" +dependencies = [ + "serde", +] [[package]] name = "litemap" @@ -2668,7 +3351,7 @@ dependencies = [ "log", "miniz_oxide", "paste", - "quick-xml", + "quick-xml 0.37.5", ] [[package]] @@ -2680,7 +3363,7 @@ dependencies = [ "base64", "serde", "serde_json", - "thiserror 2.0.17", + "thiserror 2.0.18", "ureq", ] @@ -2716,9 +3399,9 @@ dependencies = [ [[package]] name = "lopdf" -version = "0.36.0" +version = "0.38.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59fa2559e99ba0f26a12458aabc754432c805bbb8cba516c427825a997af1fb7" +checksum = "c7184fdea2bc3cd272a1acec4030c321a8f9875e877b3f92a53f2f6033fdc289" dependencies = [ "aes", "bitflags 2.11.0", @@ -2726,6 +3409,7 @@ dependencies = [ "ecb", "encoding_rs", "flate2", + "getrandom 0.3.4", "indexmap", "itoa", "log", @@ -2736,7 +3420,8 @@ dependencies = [ "rangemap", "sha2", "stringprep", - "thiserror 2.0.17", + "thiserror 2.0.18", + "ttf-parser", "weezl", ] @@ -2830,9 +3515,18 @@ dependencies = [ [[package]] name = "memchr" -version = "2.7.6" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" + +[[package]] +name = "memmap2" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "714098028fe011992e1c3962653c96b2d578c4b4bce9036e15ff220319b1e0e3" +dependencies = [ + "libc", +] [[package]] name = "memory-indexer" @@ -2851,6 +3545,23 @@ dependencies = [ "unicode-script", ] +[[package]] +name = "mermaid-rs-renderer" +version = "0.2.1" +source = "git+https://github.com/toeverything/mermaid-rs-renderer?rev=fba9097#fba9097574e424de0497a91c9dc1beeb0e27e4e0" +dependencies = [ + "anyhow", + "fontdb", + "json5", + "once_cell", + "regex", + "serde", + "serde_json", + "serde_yaml", + "thiserror 2.0.18", + "ttf-parser", +] + [[package]] name = "mimalloc" version = "0.1.48" @@ -2897,6 +3608,16 @@ dependencies = [ "pxfm", ] +[[package]] +name = "moxcms" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb85c154ba489f01b25c0d36ae69a87e4a1c73a72631fc6c0eb6dde34a73e44b" +dependencies = [ + "num-traits", + "pxfm", +] + [[package]] name = "mp4parse" version = "0.17.0" @@ -2911,6 +3632,12 @@ dependencies = [ "static_assertions", ] +[[package]] +name = "mutate_once" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13d2233c9842d08cfe13f9eac96e207ca6a2ea10b80259ebe8ad0268be27d2af" + [[package]] name = "nanoid" version = "0.4.0" @@ -2922,9 +3649,9 @@ dependencies = [ [[package]] name = "napi" -version = "3.8.1" +version = "3.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "000f205daae6646003fdc38517be6232af2b150bad4b67bdaf4c5aadb119d738" +checksum = "e6944d0bf100571cd6e1a98a316cdca262deb6fccf8d93f5ae1502ca3fc88bd3" dependencies = [ "anyhow", "bitflags 2.11.0", @@ -2947,29 +3674,29 @@ checksum = "d376940fd5b723c6893cd1ee3f33abbfd86acb1cd1ec079f3ab04a2a3bc4d3b1" [[package]] name = "napi-derive" -version = "3.5.0" +version = "3.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97ef4e39564b008771df9a4983e4ea6c1f7fa6ad5252347b6dbf7f347a8f689a" +checksum = "2c914b5e420182bfb73504e0607592cdb8e2e21437d450883077669fb72a114d" dependencies = [ - "convert_case 0.10.0", + "convert_case 0.11.0", "ctor", "napi-derive-backend", "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] name = "napi-derive-backend" -version = "5.0.0" +version = "5.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb0d9a16e3fbfd6397f97e4eaafe9fbefb888a6120dd289dd12869fdb16af372" +checksum = "f0864cf6a82e2cfb69067374b64c9253d7e910e5b34db833ed7495dda56ccb18" dependencies = [ - "convert_case 0.10.0", + "convert_case 0.11.0", "proc-macro2", "quote", "semver", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -3073,6 +3800,16 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", +] + [[package]] name = "num-bigint-dig" version = "0.8.6" @@ -3098,6 +3835,12 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-conv" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf97ec579c3c42f953ef76dbf8d55ac91fb219dde70e49aa4a6b7d74e9919050" + [[package]] name = "num-derive" version = "0.4.2" @@ -3106,7 +3849,7 @@ checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -3141,9 +3884,9 @@ dependencies = [ [[package]] name = "num_enum" -version = "0.7.5" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1207a7e20ad57b847bbddc6776b968420d38292bbfe2089accff5e19e82454c" +checksum = "5d0bca838442ec211fa11de3a8b0e0e8f3a4522575b5c4c06ed722e005036f26" dependencies = [ "num_enum_derive", "rustversion", @@ -3151,14 +3894,14 @@ dependencies = [ [[package]] name = "num_enum_derive" -version = "0.7.5" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff32365de1b6743cb203b710788263c44a03de03802daf96092f2da4fe6ba4d7" +checksum = "680998035259dcfcafe653688bf2aa6d3e2dc05e98be6ab46afb089dc84f1df8" dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -3173,9 +3916,9 @@ dependencies = [ [[package]] name = "objc2" -version = "0.6.3" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7c2599ce0ec54857b29ce62166b0ed9b4f6f1a70ccc9a71165b6154caca8c05" +checksum = "3a12a8ed07aefc768292f076dc3ac8c48f3781c8f2d5851dd3d98950e8c5a89f" dependencies = [ "objc2-encode", ] @@ -3219,6 +3962,15 @@ dependencies = [ "cc", ] +[[package]] +name = "object" +version = "0.37.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe" +dependencies = [ + "memchr", +] + [[package]] name = "oboe" version = "0.6.1" @@ -3244,9 +3996,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.21.3" +version = "1.21.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" [[package]] name = "once_cell_polyfill" @@ -3260,6 +4012,12 @@ version = "11.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6790f58c7ff633d8771f42965289203411a5e5c68388703c06e14f24770b41e" +[[package]] +name = "option-ext" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" + [[package]] name = "ordered-float" version = "5.1.0" @@ -3277,6 +4035,30 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a80800c0488c3a21695ea981a54918fbb37abf04f4d0720c453632255e2ff0e" +[[package]] +name = "palette" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cbf71184cc5ecc2e4e1baccdb21026c20e5fc3dcf63028a086131b3ab00b6e6" +dependencies = [ + "approx", + "fast-srgb8", + "libm", + "palette_derive", +] + +[[package]] +name = "palette_derive" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5030daf005bface118c096f510ffb781fc28f9ab6a32ab224d8631be6851d30" +dependencies = [ + "by_address", + "proc-macro2", + "quote", + "syn 2.0.117", +] + [[package]] name = "parking" version = "2.2.1" @@ -3333,13 +4115,13 @@ checksum = "1e91099d4268b0e11973f036e885d652fb0b21fedcf69738c627f94db6a44f42" [[package]] name = "pdf-extract" -version = "0.8.2" -source = "git+https://github.com/toeverything/pdf-extract?branch=darksky%2Fimprove-font-decoding#040751a61aba51e7a28217b758c18db4415c3ee4" +version = "0.10.0" +source = "git+https://github.com/toeverything/pdf-extract?branch=darksky%2Fimprove-font-decoding#c9f93efbb7a933082f13396fab5473b6a8d8fe61" dependencies = [ "adobe-cmap-parser", "cff-parser", "encoding_rs", - "euclid", + "euclid 0.20.14", "log", "lopdf", "postscript", @@ -3378,7 +4160,7 @@ version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078" dependencies = [ - "phf_macros", + "phf_macros 0.11.3", "phf_shared 0.11.3", ] @@ -3388,6 +4170,7 @@ version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c1562dc717473dbaa4c1f85a36410e03c047b2e7df7f45ee938fbef64ae7fadf" dependencies = [ + "phf_macros 0.13.1", "phf_shared 0.13.1", "serde", ] @@ -3452,7 +4235,20 @@ dependencies = [ "phf_shared 0.11.3", "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", +] + +[[package]] +name = "phf_macros" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "812f032b54b1e759ccd5f8b6677695d5268c588701effba24601f6932f8269ef" +dependencies = [ + "phf_generator 0.13.1", + "phf_shared 0.13.1", + "proc-macro2", + "quote", + "syn 2.0.117", ] [[package]] @@ -3470,7 +4266,7 @@ version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5" dependencies = [ - "siphasher 1.0.1", + "siphasher 1.0.2", ] [[package]] @@ -3479,20 +4275,20 @@ version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e57fef6bc5981e38c2ce2d63bfa546861309f875b8a75f092d1d54ae2d64f266" dependencies = [ - "siphasher 1.0.1", + "siphasher 1.0.2", ] [[package]] -name = "pin-project-lite" -version = "0.2.16" +name = "pico-args" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" +checksum = "5be167a7af36ee22fe3115051bc51f6e6c7054c9348e28deb4f49bd6f705a315" [[package]] -name = "pin-utils" -version = "0.1.0" +name = "pin-project-lite" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" [[package]] name = "pinyin" @@ -3533,6 +4329,19 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" +[[package]] +name = "plist" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "740ebea15c5d1428f910cd1a5f52cebf8d25006245ed8ade92702f4943d91e07" +dependencies = [ + "base64", + "indexmap", + "quick-xml 0.38.4", + "serde", + "time", +] + [[package]] name = "plotters" version = "0.3.7" @@ -3561,6 +4370,19 @@ dependencies = [ "plotters-backend", ] +[[package]] +name = "png" +version = "0.17.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82151a2fc869e011c153adc57cf2789ccb8d9906ce52c0b39a6b5697749d7526" +dependencies = [ + "bitflags 1.3.2", + "crc32fast", + "fdeflate", + "flate2", + "miniz_oxide", +] + [[package]] name = "png" version = "0.18.1" @@ -3580,6 +4402,24 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60f6ce597ecdcc9a098e7fddacb1065093a3d66446fa16c675e7e71d1b5c28e6" +[[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 = "postscript" version = "0.19.0" @@ -3596,10 +4436,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" dependencies = [ "serde_core", - "writeable", - "zerovec", + "writeable 0.6.2", + "zerovec 0.11.5", ] +[[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" @@ -3615,6 +4461,16 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" +[[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.117", +] + [[package]] name = "primal-check" version = "0.3.4" @@ -3626,11 +4482,11 @@ dependencies = [ [[package]] name = "proc-macro-crate" -version = "3.4.0" +version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "219cb19e96be00ab2e37d6e299658a0cfa83e52429179969b0f0121b4ac46983" +checksum = "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f" dependencies = [ - "toml_edit", + "toml_edit 0.25.5+spec-1.1.0", ] [[package]] @@ -3658,19 +4514,25 @@ dependencies = [ ] [[package]] -name = "proc-macro2" -version = "1.0.105" +name = "proc-macro-hack" +version = "0.5.20+deprecated" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "535d180e0ecab6268a3e718bb9fd44db66bbbc256257165fc699dadf70d16fe7" +checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" + +[[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 = "proptest" -version = "1.9.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bee689443a2bd0a16ab0348b52ee43e3b2d1b1f931c8aa5c9f8de4c86fbe8c40" +checksum = "37566cb3fdacef14c0737f9546df7cfeadbfbc9fef10991038bf5015d0c80532" dependencies = [ "bit-set 0.8.0", "bit-vec 0.8.0", @@ -3693,14 +4555,24 @@ checksum = "4ee1c9ac207483d5e7db4940700de86a9aae46ef90c48b57f99fe7edb8345e49" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", +] + +[[package]] +name = "psm" +version = "0.1.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3852766467df634d74f0b2d7819bf8dc483a0eb2e3b0f50f756f9cfe8b0d18d8" +dependencies = [ + "ar_archive_writer", + "cc", ] [[package]] name = "pulldown-cmark" -version = "0.13.0" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e8bbe1a966bd2f362681a44f6edce3c2310ac21e4d5067a6e7ec396297a6ea0" +checksum = "83c41efbf8f90ac44de7f3a868f0867851d261b56291732d0cbf7cceaaeb55a6" dependencies = [ "bitflags 2.11.0", "getopts", @@ -3721,6 +4593,12 @@ version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5a041e753da8b807c9255f28de81879c78c876392ff2469cde94799b2896b9d" +[[package]] +name = "qcms" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edecfcd5d755a5e5d98e24cf43113e7cdaec5a070edd0f6b250c03a573da30fa" + [[package]] name = "quick-error" version = "1.2.3" @@ -3743,10 +4621,20 @@ dependencies = [ ] [[package]] -name = "quote" -version = "1.0.43" +name = "quick-xml" +version = "0.38.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc74d9a594b72ae6656596548f56f667211f8a97b3d4c3d467150794690dc40a" +checksum = "b66c2058c55a409d601666cffe35f04333cf1013010882cec174a7467cd4e21c" +dependencies = [ + "memchr", + "serde", +] + +[[package]] +name = "quote" +version = "1.0.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" dependencies = [ "proc-macro2", ] @@ -3757,6 +4645,12 @@ version = "5.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" +[[package]] +name = "r-efi" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" + [[package]] name = "rand" version = "0.8.5" @@ -3775,7 +4669,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" dependencies = [ "rand_chacha 0.9.0", - "rand_core 0.9.3", + "rand_core 0.9.5", ] [[package]] @@ -3795,7 +4689,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" dependencies = [ "ppv-lite86", - "rand_core 0.9.3", + "rand_core 0.9.5", ] [[package]] @@ -3804,14 +4698,14 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.16", + "getrandom 0.2.17", ] [[package]] name = "rand_core" -version = "0.9.3" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" +checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" dependencies = [ "getrandom 0.3.4", ] @@ -3832,7 +4726,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "513962919efc330f829edb2535844d1b912b0fbe2ca165d613e4e8788bb05a5a" dependencies = [ - "rand_core 0.9.3", + "rand_core 0.9.5", ] [[package]] @@ -3861,6 +4755,16 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "read-fonts" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6717cf23b488adf64b9d711329542ba34de147df262370221940dfabc2c91358" +dependencies = [ + "bytemuck", + "font-types", +] + [[package]] name = "readability" version = "0.3.0" @@ -3894,18 +4798,29 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.7.0" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f3fe0889e69e2ae9e41f4d6c4c0181701d00e4697b356fb1f74173a5e0ee27" +checksum = "6ce70a74e890531977d37e532c34d45e9055d2409ed08ddba14529471ed0be16" dependencies = [ "bitflags 2.11.0", ] [[package]] -name = "regex" -version = "1.12.2" +name = "redox_users" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "843bc0191f75f3e22651ae5f1e72939ab2f72a4bc30fa80a066bd66edefc24d4" +checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac" +dependencies = [ + "getrandom 0.2.17", + "libredox", + "thiserror 2.0.18", +] + +[[package]] +name = "regex" +version = "1.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" dependencies = [ "aho-corasick", "memchr", @@ -3915,9 +4830,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.13" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c" +checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" dependencies = [ "aho-corasick", "memchr", @@ -3926,9 +4841,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.8" +version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" +checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" [[package]] name = "ring" @@ -3938,7 +4853,7 @@ checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" dependencies = [ "cc", "cfg-if", - "getrandom 0.2.16", + "getrandom 0.2.17", "libc", "untrusted", "windows-sys 0.52.0", @@ -3950,6 +4865,18 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3582f63211428f83597b51b2ddb88e2a91a9d52d12831f9d08f5e624e8977422" +[[package]] +name = "roman-numerals-rs" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c85cd47a33a4510b1424fe796498e174c6a9cf94e606460ef022a19f3e4ff85e" + +[[package]] +name = "roxmltree" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c20b6793b5c2fa6553b250154b78d6d0db37e72700ae35fad9387a46f487c97" + [[package]] name = "rsa" version = "0.9.10" @@ -3984,9 +4911,9 @@ dependencies = [ [[package]] name = "rust-embed" -version = "8.9.0" +version = "8.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "947d7f3fad52b283d261c4c99a084937e2fe492248cb9a68a8435a861b8798ca" +checksum = "04113cb9355a377d83f06ef1f0a45b8ab8cd7d8b1288160717d66df5c7988d27" dependencies = [ "rust-embed-impl", "rust-embed-utils", @@ -3995,27 +4922,37 @@ dependencies = [ [[package]] name = "rust-embed-impl" -version = "8.9.0" +version = "8.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fa2c8c9e8711e10f9c4fd2d64317ef13feaab820a4c51541f1a8c8e2e851ab2" +checksum = "da0902e4c7c8e997159ab384e6d0fc91c221375f6894346ae107f47dd0f3ccaa" dependencies = [ "proc-macro2", "quote", "rust-embed-utils", - "syn 2.0.114", + "syn 2.0.117", "walkdir", ] [[package]] name = "rust-embed-utils" -version = "8.9.0" +version = "8.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60b161f275cb337fe0a44d924a5f4df0ed69c2c39519858f931ce61c779d3475" +checksum = "5bcdef0be6fe7f6fa333b1073c949729274b05f123a0ad7efcb8efd878e5c3b1" dependencies = [ "sha2", "walkdir", ] +[[package]] +name = "rust_decimal" +version = "1.40.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61f703d19852dbf87cbc513643fa81428361eb6940f1ac14fd58155d295a3eb0" +dependencies = [ + "arrayvec", + "num-traits", +] + [[package]] name = "rustc-hash" version = "1.1.0" @@ -4053,9 +4990,9 @@ dependencies = [ [[package]] name = "rustix" -version = "1.1.3" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "146c9e247ccc180c1f61615433868c99f3de3ae256a30a43b49f67c2d9171f34" +checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" dependencies = [ "bitflags 2.11.0", "errno", @@ -4066,9 +5003,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.36" +version = "0.23.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c665f33d38cea657d9614f766881e4d510e0eda4239891eea56b4cadcf01801b" +checksum = "758025cb5fccfd3bc2fd74708fd4682be41d99e5dff73c377c0646c6012c73a4" dependencies = [ "log", "once_cell", @@ -4081,18 +5018,18 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.13.2" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21e6f2ab2928ca4291b86736a8bd920a277a399bba1589409d72154ff87c1282" +checksum = "be040f8b0a225e40375822a563fa9524378b9d63112f53e19ffff34df5d33fdd" dependencies = [ "zeroize", ] [[package]] name = "rustls-webpki" -version = "0.103.8" +version = "0.103.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ffdfa2f5286e2247234e03f680868ac2815974dc39e00ea15adc445d0aafe52" +checksum = "d7df23109aa6c1567d1c575b9952556388da57401e4ace1d15f79eedad0d8f53" dependencies = [ "ring", "rustls-pki-types", @@ -4118,10 +5055,28 @@ dependencies = [ ] [[package]] -name = "ryu" -version = "1.0.22" +name = "rustybuzz" +version = "0.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a50f4cf475b65d88e057964e0e9bb1f0aa9bbb2036dc65c64596b42932536984" +checksum = "fd3c7c96f8a08ee34eff8857b11b49b07d71d1c3f4e88f8a88d4c9e9f90b1702" +dependencies = [ + "bitflags 2.11.0", + "bytemuck", + "core_maths", + "log", + "smallvec", + "ttf-parser", + "unicode-bidi-mirroring", + "unicode-ccc", + "unicode-properties", + "unicode-script", +] + +[[package]] +name = "ryu" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" [[package]] name = "same-file" @@ -4177,7 +5132,7 @@ checksum = "1783eabc414609e28a5ba76aee5ddd52199f7107a0b24c2e9746a1ecc34a683d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -4217,7 +5172,7 @@ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -4234,6 +5189,15 @@ dependencies = [ "zmij", ] +[[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" @@ -4246,6 +5210,19 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_yaml" +version = "0.9.34+deprecated" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" +dependencies = [ + "indexmap", + "itoa", + "ryu", + "serde", + "unsafe-libyaml", +] + [[package]] name = "sha1" version = "0.10.6" @@ -4319,6 +5296,15 @@ version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e320a6c5ad31d271ad523dcf3ad13e2767ad8b1cb8f047f75a8aeaf8da139da2" +[[package]] +name = "simplecss" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a9c6883ca9c3c7c90e888de77b7a5c849c779d25d74a1269b0218b14e8b136c" +dependencies = [ + "log", +] + [[package]] name = "siphasher" version = "0.3.11" @@ -4327,15 +5313,34 @@ checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" [[package]] name = "siphasher" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" +checksum = "b2aa850e253778c88a04c3d7323b043aeda9d3e30d5971937c1855769763678e" + +[[package]] +name = "skrifa" +version = "0.37.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c31071dedf532758ecf3fed987cdb4bd9509f900e026ab684b4ecb81ea49841" +dependencies = [ + "bytemuck", + "read-fonts", +] [[package]] name = "slab" -version = "0.4.11" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589" +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" + +[[package]] +name = "slotmap" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdd58c3c93c3d278ca835519292445cb4b0d4dc59ccfdf7ceadaab3f8aeb4038" +dependencies = [ + "version_check", +] [[package]] name = "smallstr" @@ -4363,9 +5368,9 @@ checksum = "b7c388c1b5e93756d0c740965c41e8822f866621d41acbdf6336a6a168f8840c" [[package]] name = "smol_str" -version = "0.3.4" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3498b0a27f93ef1402f20eefacfaa1691272ac4eca1cdc8c596cb0a245d6cbf5" +checksum = "4aaa7368fcf4852a4c2dd92df0cace6a71f2091ca0a23391ce7f3a31833f1523" dependencies = [ "borsh", "serde_core", @@ -4373,12 +5378,12 @@ dependencies = [ [[package]] name = "socket2" -version = "0.6.1" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17129e116933cf371d018bb80ae557e889637989d8638274fb25622827b03881" +checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e" dependencies = [ "libc", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -4442,7 +5447,7 @@ dependencies = [ "serde_json", "sha2", "smallvec", - "thiserror 2.0.17", + "thiserror 2.0.18", "tokio", "tokio-stream", "tracing", @@ -4460,7 +5465,7 @@ dependencies = [ "quote", "sqlx-core", "sqlx-macros-core", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -4483,7 +5488,7 @@ dependencies = [ "sqlx-mysql", "sqlx-postgres", "sqlx-sqlite", - "syn 2.0.114", + "syn 2.0.117", "tokio", "url", ] @@ -4526,7 +5531,7 @@ dependencies = [ "smallvec", "sqlx-core", "stringprep", - "thiserror 2.0.17", + "thiserror 2.0.18", "tracing", "whoami", ] @@ -4564,7 +5569,7 @@ dependencies = [ "smallvec", "sqlx-core", "stringprep", - "thiserror 2.0.17", + "thiserror 2.0.18", "tracing", "whoami", ] @@ -4589,7 +5594,7 @@ dependencies = [ "serde", "serde_urlencoded", "sqlx-core", - "thiserror 2.0.17", + "thiserror 2.0.18", "tracing", "url", ] @@ -4600,6 +5605,19 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" +[[package]] +name = "stacker" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d74a23609d509411d10e2176dc2a4346e3b4aea2e7b1869f19fdedbc71c013" +dependencies = [ + "cc", + "cfg-if", + "libc", + "psm", + "windows-sys 0.59.0", +] + [[package]] name = "static_assertions" version = "1.1.0" @@ -4618,6 +5636,15 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fe895eb47f22e2ddd4dabc02bce419d2e643c8e3b585c78158b349195bc24d82" +[[package]] +name = "strict-num" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6637bab7722d379c8b41ba849228d680cc12d0a45ba1fa2b48f2a30577a06731" +dependencies = [ + "float-cmp", +] + [[package]] name = "string_cache" version = "0.8.9" @@ -4678,7 +5705,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -4687,6 +5714,16 @@ version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" +[[package]] +name = "svgtypes" +version = "0.15.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68c7541fff44b35860c1a7a47a7cadf3e4a304c457b58f9870d9706ece028afc" +dependencies = [ + "kurbo 0.11.3", + "siphasher 1.0.2", +] + [[package]] name = "symphonia" version = "0.5.5" @@ -4896,9 +5933,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.114" +version = "2.0.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4d107df263a3013ef9b1879b0df87d706ff80f65a86ea879bd9c31f9b307c2a" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" dependencies = [ "proc-macro2", "quote", @@ -4913,17 +5950,38 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", +] + +[[package]] +name = "syntect" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "656b45c05d95a5704399aeef6bd0ddec7b2b3531b7c9e900abbf7c4d2190c925" +dependencies = [ + "bincode 1.3.3", + "fancy-regex 0.16.2", + "flate2", + "fnv", + "once_cell", + "plist", + "regex-syntax", + "serde", + "serde_derive", + "serde_json", + "thiserror 2.0.18", + "walkdir", + "yaml-rust", ] [[package]] name = "tempfile" -version = "3.24.0" +version = "3.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "655da9c7eb6305c55742045d5a8d2037996d61d8de95806335c7c86ce0f82e9c" +checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" dependencies = [ "fastrand", - "getrandom 0.3.4", + "getrandom 0.4.2", "once_cell", "rustix", "windows-sys 0.61.2", @@ -4949,13 +6007,13 @@ dependencies = [ "ahash", "auto_enums", "either", - "icu_provider", - "icu_segmenter", + "icu_provider 2.1.1", + "icu_segmenter 2.1.2", "itertools 0.14.0", "memchr", "pulldown-cmark", "strum", - "thiserror 2.0.17", + "thiserror 2.0.18", "tiktoken-rs", ] @@ -4968,6 +6026,12 @@ dependencies = [ "smawk", ] +[[package]] +name = "thin-vec" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "144f754d318415ac792f9d69fc87abbbfc043ce2ef041c60f16ad828f638717d" + [[package]] name = "thiserror" version = "1.0.69" @@ -4979,11 +6043,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.17" +version = "2.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" +checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" dependencies = [ - "thiserror-impl 2.0.17", + "thiserror-impl 2.0.18", ] [[package]] @@ -4994,18 +6058,18 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] name = "thiserror-impl" -version = "2.0.17" +version = "2.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" +checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -5026,12 +6090,65 @@ dependencies = [ "anyhow", "base64", "bstr", - "fancy-regex", + "fancy-regex 0.13.0", "lazy_static", "regex", "rustc-hash 1.1.0", ] +[[package]] +name = "time" +version = "0.3.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c" +dependencies = [ + "deranged", + "itoa", + "num-conv", + "powerfmt", + "serde_core", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca" + +[[package]] +name = "time-macros" +version = "0.2.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e70e4c5a0e0a8a4823ad65dfe1a6930e4f4d756dcd9dd7939022b5e8c501215" +dependencies = [ + "num-conv", + "time-core", +] + +[[package]] +name = "tiny-skia-path" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c9e7fc0c2e86a30b117d0462aa261b72b7a99b7ebd7deb3a14ceda95c5bdc93" +dependencies = [ + "arrayref", + "bytemuck", + "strict-num", +] + +[[package]] +name = "tinystr" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" +dependencies = [ + "displaydoc", + "serde", + "zerovec 0.10.4", +] + [[package]] name = "tinystr" version = "0.8.2" @@ -5040,7 +6157,7 @@ checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" dependencies = [ "displaydoc", "serde_core", - "zerovec", + "zerovec 0.11.5", ] [[package]] @@ -5055,9 +6172,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", ] @@ -5070,9 +6187,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.49.0" +version = "1.50.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72a2903cd7736441aac9df9d7688bd0ce48edccaadf181c3b90be801e81d3d86" +checksum = "27ad5e34374e03cfffefc301becb44e9dc3c17584f414349ebe29ed26661822d" dependencies = [ "bytes", "libc", @@ -5087,13 +6204,13 @@ dependencies = [ [[package]] name = "tokio-macros" -version = "2.6.0" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" +checksum = "5c55a2eff8b69ce66c84f85e1da1c233edc36ceb85a2058d11b0d6a3c7e7569c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -5117,35 +6234,76 @@ dependencies = [ ] [[package]] -name = "toml_datetime" -version = "0.7.5+spec-1.1.0" +name = "toml" +version = "0.8.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92e1cfed4a3038bc5a127e35a2d360f145e1f4b971b551a2ba5fd7aedf7e1347" +checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime 0.6.11", + "toml_edit 0.22.27", +] + +[[package]] +name = "toml_datetime" +version = "0.6.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_datetime" +version = "1.0.1+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b320e741db58cac564e26c607d3cc1fdc4a88fd36c879568c07856ed83ff3e9" dependencies = [ "serde_core", ] [[package]] name = "toml_edit" -version = "0.23.10+spec-1.0.0" +version = "0.22.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84c8b9f757e028cee9fa244aea147aab2a9ec09d5325a9b01e0a49730c2b5269" +checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" dependencies = [ "indexmap", - "toml_datetime", + "serde", + "serde_spanned", + "toml_datetime 0.6.11", + "toml_write", + "winnow 0.7.15", +] + +[[package]] +name = "toml_edit" +version = "0.25.5+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ca1a40644a28bce036923f6a431df0b34236949d111cc07cb6dca830c9ef2e1" +dependencies = [ + "indexmap", + "toml_datetime 1.0.1+spec-1.1.0", "toml_parser", - "winnow", + "winnow 1.0.0", ] [[package]] name = "toml_parser" -version = "1.0.9+spec-1.1.0" +version = "1.0.10+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "702d4415e08923e7e1ef96cd5727c0dfed80b4d2fa25db9647fe5eb6f7c5a4c4" +checksum = "7df25b4befd31c4816df190124375d5a20c6b6921e2cad937316de3fccd63420" dependencies = [ - "winnow", + "winnow 1.0.0", ] +[[package]] +name = "toml_write" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" + [[package]] name = "tracing" version = "0.1.44" @@ -5166,7 +6324,7 @@ checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -5192,9 +6350,9 @@ dependencies = [ [[package]] name = "tracing-subscriber" -version = "0.3.22" +version = "0.3.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f30143827ddab0d256fd843b7a66d164e9f271cfa0dde49142c5ca0ca291f1e" +checksum = "cb7f578e5945fb242538965c2d0b04418d38ec25c79d160cd279bf0731c8d319" dependencies = [ "matchers", "nu-ansi-term", @@ -5304,9 +6462,9 @@ dependencies = [ [[package]] name = "tree-sitter-language" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ae62f7eae5eb549c71b76658648b72cc6111f2d87d24a1e31fa907f4943e3ce" +checksum = "009994f150cc0cd50ff54917d5bc8bffe8cad10ca10d81c34da2ec421ae61782" [[package]] name = "tree-sitter-python" @@ -5330,9 +6488,9 @@ dependencies = [ [[package]] name = "tree-sitter-scala" -version = "0.24.0" +version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7516aeb3d1f40ede8e3045b163e86993b3434514dd06c34c0b75e782d9a0b251" +checksum = "3b4f354028b5fcf1d0c77f1c6d84cd5a579f29a1e43cb61551ec6580e9a99229" dependencies = [ "cc", "tree-sitter-language", @@ -5348,6 +6506,26 @@ dependencies = [ "tree-sitter-language", ] +[[package]] +name = "ttf-parser" +version = "0.25.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2df906b07856748fa3f6e0ad0cbaa047052d4a7dd609e231c4f72cee8c36f31" +dependencies = [ + "core_maths", +] + +[[package]] +name = "two-face" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39e51b6e60e545cfdae5a4639ff423818f52372211a8d9a3e892b4b0761f76b2" +dependencies = [ + "serde", + "serde_derive", + "syntect", +] + [[package]] name = "type1-encoding-parser" version = "0.1.0" @@ -5357,6 +6535,12 @@ dependencies = [ "pom", ] +[[package]] +name = "typed-arena" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6af6ae20167a9ece4bcb41af5b80f8a1f1df981f6391189ce00fd257af04126a" + [[package]] name = "typeface" version = "0.5.0" @@ -5369,12 +6553,366 @@ version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" +[[package]] +name = "typst" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f6511ee598476f4f322b4d13891083d96dbacb8f9c2b908604c7094ba390653" +dependencies = [ + "comemo", + "ecow", + "rustc-hash 2.1.1", + "typst-eval", + "typst-html", + "typst-layout", + "typst-library", + "typst-macros", + "typst-realize", + "typst-syntax", + "typst-timing", + "typst-utils", +] + +[[package]] +name = "typst-as-lib" +version = "0.15.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5d1310816d33fa3582dbb60bf0e5272af44d955a5fa13b148ddea62005088df" +dependencies = [ + "binstall-tar", + "chrono", + "comemo", + "dirs", + "ecow", + "flate2", + "thiserror 2.0.18", + "typst", + "typst-kit", + "ureq", +] + +[[package]] +name = "typst-assets" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5613cb719a6222fe9b74027c3625d107767ec187bff26b8fc931cf58942c834f" + +[[package]] +name = "typst-eval" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "687757487dfc0c1e941344d5024cf7a28364e70c3e304faad89ac65597f62526" +dependencies = [ + "comemo", + "ecow", + "indexmap", + "rustc-hash 2.1.1", + "stacker", + "toml 0.8.23", + "typst-library", + "typst-macros", + "typst-syntax", + "typst-timing", + "typst-utils", + "unicode-segmentation", +] + +[[package]] +name = "typst-html" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e29f8da4f964d4c90739c3c1e0288b0ba1bccc3cc50623a6d558300b86ca8aad" +dependencies = [ + "bumpalo", + "comemo", + "ecow", + "palette", + "rustc-hash 2.1.1", + "time", + "typst-assets", + "typst-library", + "typst-macros", + "typst-svg", + "typst-syntax", + "typst-timing", + "typst-utils", +] + +[[package]] +name = "typst-kit" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31476ec753e080ffdd543a0e74b6d319355449ff3eca3f216634f31cfd09a92a" +dependencies = [ + "ecow", + "fontdb", + "once_cell", + "serde", + "serde_json", + "typst-assets", + "typst-library", + "typst-syntax", + "typst-timing", + "typst-utils", +] + +[[package]] +name = "typst-layout" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cab0200105831a9158e63718a0f6141c78cb2c1722ed17d19ad28941e3b8491" +dependencies = [ + "az", + "bumpalo", + "codex", + "comemo", + "ecow", + "either", + "hypher", + "icu_properties 1.5.1", + "icu_provider 1.5.0", + "icu_provider_adapters", + "icu_provider_blob", + "icu_segmenter 1.5.0", + "kurbo 0.12.0", + "memchr", + "rustc-hash 2.1.1", + "rustybuzz", + "smallvec", + "ttf-parser", + "typst-assets", + "typst-library", + "typst-macros", + "typst-syntax", + "typst-timing", + "typst-utils", + "unicode-bidi", + "unicode-math-class", + "unicode-script", + "unicode-segmentation", +] + +[[package]] +name = "typst-library" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e276a5de53020c43efe2111ec236252e54ea4480b5ac18063e663dfbe03d9d1b" +dependencies = [ + "az", + "bitflags 2.11.0", + "bumpalo", + "chinese-number", + "ciborium", + "codex", + "comemo", + "csv", + "ecow", + "flate2", + "fontdb", + "glidesort", + "hayagriva", + "hayro-syntax", + "icu_properties 1.5.1", + "icu_provider 1.5.0", + "icu_provider_blob", + "image", + "indexmap", + "kamadak-exif", + "kurbo 0.12.0", + "lipsum", + "memchr", + "palette", + "phf 0.13.1", + "png 0.17.16", + "qcms", + "rayon", + "regex", + "regex-syntax", + "roxmltree", + "rust_decimal", + "rustc-hash 2.1.1", + "rustybuzz", + "serde", + "serde_json", + "serde_yaml", + "siphasher 1.0.2", + "smallvec", + "syntect", + "time", + "toml 0.8.23", + "ttf-parser", + "two-face", + "typed-arena", + "typst-assets", + "typst-macros", + "typst-syntax", + "typst-timing", + "typst-utils", + "unicode-math-class", + "unicode-normalization", + "unicode-segmentation", + "unscanny", + "usvg", + "utf8_iter", + "wasmi", + "xmlwriter", +] + +[[package]] +name = "typst-macros" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "141cbd1027129fbf6bda1013f52a264df7befc7388cc8f47767d65e803fd3a59" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "typst-realize" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7ffe964757fb93d2e98978aa2a74ee85b0f94c8643e8f3550737258b58f39d8" +dependencies = [ + "arrayvec", + "bumpalo", + "comemo", + "ecow", + "regex", + "typst-library", + "typst-macros", + "typst-syntax", + "typst-timing", + "typst-utils", +] + +[[package]] +name = "typst-svg" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e46b811837ade1f0243ef0d8bf3fb06d166443090eac22c28643f374c2ccdc9d" +dependencies = [ + "base64", + "comemo", + "ecow", + "flate2", + "hayro", + "hayro-svg", + "image", + "rustc-hash 2.1.1", + "ttf-parser", + "typst-assets", + "typst-library", + "typst-macros", + "typst-timing", + "typst-utils", + "xmlparser", + "xmlwriter", +] + +[[package]] +name = "typst-syntax" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a95d9192060e23b1e491b0b94dff676acddc92a4d672aeb8ca3890a5a734e879" +dependencies = [ + "ecow", + "rustc-hash 2.1.1", + "serde", + "toml 0.8.23", + "typst-timing", + "typst-utils", + "unicode-ident", + "unicode-math-class", + "unicode-script", + "unicode-segmentation", + "unscanny", +] + +[[package]] +name = "typst-timing" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7be94f8faf19841b49574ef5c7fd7a12e2deb7c3d8deba5a596f35d2222024cd" +dependencies = [ + "parking_lot", + "serde", + "serde_json", +] + +[[package]] +name = "typst-utils" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3966c92e8fa48c7ce898130d07000d985f18206d92b250f0f939287fbccdee3" +dependencies = [ + "once_cell", + "portable-atomic", + "rayon", + "rustc-hash 2.1.1", + "siphasher 1.0.2", + "thin-vec", + "unicode-math-class", +] + +[[package]] +name = "ucd-trie" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" + [[package]] name = "unarray" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" +[[package]] +name = "unic-langid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a28ba52c9b05311f4f6e62d5d9d46f094bd6e84cb8df7b3ef952748d752a7d05" +dependencies = [ + "unic-langid-impl", + "unic-langid-macros", +] + +[[package]] +name = "unic-langid-impl" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dce1bf08044d4b7a94028c93786f8566047edc11110595914de93362559bc658" +dependencies = [ + "serde", + "tinystr 0.8.2", +] + +[[package]] +name = "unic-langid-macros" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5957eb82e346d7add14182a3315a7e298f04e1ba4baac36f7f0dbfedba5fc25" +dependencies = [ + "proc-macro-hack", + "tinystr 0.8.2", + "unic-langid-impl", + "unic-langid-macros-impl", +] + +[[package]] +name = "unic-langid-macros-impl" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1249a628de3ad34b821ecb1001355bca3940bcb2f88558f1a8bd82e977f75b5" +dependencies = [ + "proc-macro-hack", + "quote", + "syn 2.0.117", + "unic-langid-impl", +] + [[package]] name = "unicase" version = "2.9.0" @@ -5388,10 +6926,28 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5" [[package]] -name = "unicode-ident" -version = "1.0.22" +name = "unicode-bidi-mirroring" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" +checksum = "5dfa6e8c60bb66d49db113e0125ee8711b7647b5579dc7f5f19c42357ed039fe" + +[[package]] +name = "unicode-ccc" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce61d488bcdc9bc8b5d1772c404828b17fc481c0a582b5581e95fb233aef503e" + +[[package]] +name = "unicode-ident" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "unicode-math-class" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d246cf599d5fae3c8d56e04b20eb519adb89a8af8d0b0fbcded369aa3647d65" [[package]] name = "unicode-normalization" @@ -5420,12 +6976,24 @@ version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" +[[package]] +name = "unicode-vo" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1d386ff53b415b7fe27b50bb44679e2cc4660272694b7b6f3326d8480823a94" + [[package]] name = "unicode-width" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254" +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + [[package]] name = "uniffi" version = "0.29.5" @@ -5462,7 +7030,7 @@ dependencies = [ "serde", "tempfile", "textwrap", - "toml", + "toml 0.5.11", "uniffi_internal_macros", "uniffi_meta", "uniffi_pipeline", @@ -5503,7 +7071,7 @@ dependencies = [ "indexmap", "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -5518,8 +7086,8 @@ dependencies = [ "proc-macro2", "quote", "serde", - "syn 2.0.114", - "toml", + "syn 2.0.117", + "toml 0.5.11", "uniffi_meta", ] @@ -5560,6 +7128,18 @@ dependencies = [ "weedle2", ] +[[package]] +name = "unsafe-libyaml" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" + +[[package]] +name = "unscanny" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9df2af067a7953e9c3831320f35c1cc0600c30d44d9f7a12b01db1cd88d6b47" + [[package]] name = "untrusted" version = "0.9.0" @@ -5586,7 +7166,7 @@ dependencies = [ "rustls-pki-types", "ureq-proto", "utf-8", - "webpki-roots 1.0.5", + "webpki-roots 1.0.6", ] [[package]] @@ -5611,6 +7191,34 @@ dependencies = [ "idna", "percent-encoding", "serde", + "serde_derive", +] + +[[package]] +name = "usvg" +version = "0.45.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80be9b06fbae3b8b303400ab20778c80bbaf338f563afe567cf3c9eea17b47ef" +dependencies = [ + "base64", + "data-url", + "flate2", + "fontdb", + "imagesize", + "kurbo 0.11.3", + "log", + "pico-args", + "roxmltree", + "rustybuzz", + "simplecss", + "siphasher 1.0.2", + "strict-num", + "svgtypes", + "tiny-skia-path", + "unicode-bidi", + "unicode-script", + "unicode-vo", + "xmlwriter", ] [[package]] @@ -5633,11 +7241,11 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.19.0" +version = "1.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2e054861b4bd027cd373e18e8d8d8e6548085000e41290d95ce0c373a654b4a" +checksum = "a68d3c8f01c0cfa54a75291d83601161799e4a89a39e0929f4b0354d88757a37" dependencies = [ - "getrandom 0.3.4", + "getrandom 0.4.2", "js-sys", "wasm-bindgen", ] @@ -5705,9 +7313,18 @@ checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] name = "wasip2" -version = "1.0.1+wasi-0.2.4" +version = "1.0.2+wasi-0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" +checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wasip3" +version = "0.4.0+wasi-0.3.0-rc-2026-01-06" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" dependencies = [ "wit-bindgen", ] @@ -5720,9 +7337,9 @@ checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" [[package]] name = "wasm-bindgen" -version = "0.2.106" +version = "0.2.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d759f433fa64a2d763d1340820e46e111a7a5ab75f993d1852d70b03dbb80fd" +checksum = "6532f9a5c1ece3798cb1c2cfdba640b9b3ba884f5db45973a6f442510a87d38e" dependencies = [ "cfg-if", "once_cell", @@ -5733,11 +7350,12 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.56" +version = "0.4.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "836d9622d604feee9e5de25ac10e3ea5f2d65b41eac0d9ce72eb5deae707ce7c" +checksum = "e9c5522b3a28661442748e09d40924dfb9ca614b21c00d3fd135720e48b67db8" dependencies = [ "cfg-if", + "futures-util", "js-sys", "once_cell", "wasm-bindgen", @@ -5746,9 +7364,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.106" +version = "0.2.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48cb0d2638f8baedbc542ed444afc0644a29166f1595371af4fecf8ce1e7eeb3" +checksum = "18a2d50fcf105fb33bb15f00e7a77b772945a2ee45dcf454961fd843e74c18e6" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -5756,31 +7374,111 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.106" +version = "0.2.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cefb59d5cd5f92d9dcf80e4683949f15ca4b511f4ac0a6e14d4e1ac60c6ecd40" +checksum = "03ce4caeaac547cdf713d280eda22a730824dd11e6b8c3ca9e42247b25c631e3" dependencies = [ "bumpalo", "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.106" +version = "0.2.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbc538057e648b67f72a982e708d485b2efa771e1ac05fec311f9f63e5800db4" +checksum = "75a326b8c223ee17883a4251907455a2431acc2791c98c26279376490c378c16" dependencies = [ "unicode-ident", ] [[package]] -name = "web-sys" -version = "0.3.83" +name = "wasm-encoder" +version = "0.244.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b32828d774c412041098d182a8b38b16ea816958e07cf40eec2bc080ae137ac" +checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319" +dependencies = [ + "leb128fmt", + "wasmparser 0.244.0", +] + +[[package]] +name = "wasm-metadata" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" +dependencies = [ + "anyhow", + "indexmap", + "wasm-encoder", + "wasmparser 0.244.0", +] + +[[package]] +name = "wasmi" +version = "0.51.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb321403ce594274827657a908e13d1d9918aa02257b8bf8391949d9764023ff" +dependencies = [ + "spin", + "wasmi_collections", + "wasmi_core", + "wasmi_ir", + "wasmparser 0.228.0", +] + +[[package]] +name = "wasmi_collections" +version = "0.51.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9b8e98e45a2a534489f8225e765cbf1cb9a3078072605e58158910cf4749172" + +[[package]] +name = "wasmi_core" +version = "0.51.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c25f375c0cdf14810eab07f532f61f14d4966f09c747a55067fdf3196e8512e6" +dependencies = [ + "libm", +] + +[[package]] +name = "wasmi_ir" +version = "0.51.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "624e2a68a4293ecb8f564260b68394b29cf3b3edba6bce35532889a2cb33c3d9" +dependencies = [ + "wasmi_core", +] + +[[package]] +name = "wasmparser" +version = "0.228.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4abf1132c1fdf747d56bbc1bb52152400c70f336870f968b85e89ea422198ae3" +dependencies = [ + "bitflags 2.11.0", +] + +[[package]] +name = "wasmparser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" +dependencies = [ + "bitflags 2.11.0", + "hashbrown 0.15.5", + "indexmap", + "semver", +] + +[[package]] +name = "web-sys" +version = "0.3.91" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "854ba17bb104abfb26ba36da9729addc7ce7f06f5c0f90f3c391f8461cca21f9" dependencies = [ "js-sys", "wasm-bindgen", @@ -5792,14 +7490,14 @@ version = "0.26.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9" dependencies = [ - "webpki-roots 1.0.5", + "webpki-roots 1.0.6", ] [[package]] name = "webpki-roots" -version = "1.0.5" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12bed680863276c63889429bfd6cab3b99943659923822de1c8a39c49e4d722c" +checksum = "22cfaf3c063993ff62e73cb4311efde4db1efb31ab78a3e5c457939ad5cc0bed" dependencies = [ "rustls-pki-types", ] @@ -5931,7 +7629,7 @@ checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -5942,7 +7640,7 @@ checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -6041,11 +7739,11 @@ dependencies = [ [[package]] name = "windows-sys" -version = "0.60.2" +version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" dependencies = [ - "windows-targets 0.53.5", + "windows-targets 0.52.6", ] [[package]] @@ -6096,30 +7794,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 0.2.1", - "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-threading" version = "0.1.0" @@ -6147,12 +7828,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.42.2" @@ -6171,12 +7846,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.42.2" @@ -6195,24 +7864,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.42.2" @@ -6231,12 +7888,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.42.2" @@ -6255,12 +7906,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.42.2" @@ -6279,12 +7924,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.42.2" @@ -6304,25 +7943,116 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] -name = "windows_x86_64_msvc" -version = "0.53.1" +name = "winnow" +version = "0.7.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" +checksum = "df79d97927682d2fd8adb29682d1140b343be4ac0f08fd68b7765d9c059d3945" +dependencies = [ + "memchr", +] [[package]] name = "winnow" -version = "0.7.14" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a5364e9d77fcdeeaa6062ced926ee3381faa2ee02d3eb83a5c27a8825540829" +checksum = "a90e88e4667264a994d34e6d1ab2d26d398dcdca8b7f52bec8668957517fc7d8" dependencies = [ "memchr", ] [[package]] name = "wit-bindgen" -version = "0.46.0" +version = "0.51.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" +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", + "prettyplease", + "syn 2.0.117", + "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 2.0.117", + "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 2.11.0", + "indexmap", + "log", + "serde", + "serde_derive", + "serde_json", + "wasm-encoder", + "wasm-metadata", + "wasmparser 0.244.0", + "wit-parser", +] + +[[package]] +name = "wit-parser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" +dependencies = [ + "anyhow", + "id-arena", + "indexmap", + "log", + "semver", + "serde", + "serde_derive", + "serde_json", + "unicode-xid", + "wasmparser 0.244.0", +] + +[[package]] +name = "writeable" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" [[package]] name = "writeable" @@ -6330,6 +8060,16 @@ version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" +[[package]] +name = "xattr" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32e45ad4206f6d2479085147f02bc2ef834ac85886624a23575ae137c8aa8156" +dependencies = [ + "libc", + "rustix", +] + [[package]] name = "xml5ever" version = "0.17.0" @@ -6347,6 +8087,12 @@ version = "0.13.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "66fee0b777b0f5ac1c69bb06d361268faafa61cd4682ae064a171c16c433e9e4" +[[package]] +name = "xmlwriter" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec7a2a501ed189703dba8b08142f057e887dfc4b2cc4db2d343ac6376ba3e0b9" + [[package]] name = "y-octo" version = "0.0.2" @@ -6372,7 +8118,7 @@ dependencies = [ "serde", "serde_json", "smol_str", - "thiserror 2.0.17", + "thiserror 2.0.18", "yrs", ] @@ -6395,6 +8141,27 @@ dependencies = [ "yrs", ] +[[package]] +name = "yaml-rust" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85" +dependencies = [ + "linked-hash-map", +] + +[[package]] +name = "yoke" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" +dependencies = [ + "serde", + "stable_deref_trait", + "yoke-derive 0.7.5", + "zerofrom", +] + [[package]] name = "yoke" version = "0.8.1" @@ -6402,10 +8169,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" dependencies = [ "stable_deref_trait", - "yoke-derive", + "yoke-derive 0.8.1", "zerofrom", ] +[[package]] +name = "yoke-derive" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", + "synstructure", +] + [[package]] name = "yoke-derive" version = "0.8.1" @@ -6414,7 +8193,7 @@ checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", "synstructure", ] @@ -6433,27 +8212,27 @@ dependencies = [ "serde_json", "smallstr", "smallvec", - "thiserror 2.0.17", + "thiserror 2.0.18", ] [[package]] name = "zerocopy" -version = "0.8.32" +version = "0.8.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fabae64378cb18147bb18bca364e63bdbe72a0ffe4adf0addfec8aa166b2c56" +checksum = "f2578b716f8a7a858b7f02d5bd870c14bf4ddbbcf3a4c05414ba6503640505e3" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.32" +version = "0.8.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9c2d862265a8bb4471d87e033e730f536e2a285cc7cb05dbce09a2a97075f90" +checksum = "7e6cc098ea4d3bd6246687de65af3f920c430e236bee1e3bf2e441463f08a02f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -6473,7 +8252,7 @@ checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", "synstructure", ] @@ -6483,6 +8262,18 @@ version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" +[[package]] +name = "zerotrie" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb594dd55d87335c5f60177cee24f19457a5ec10a065e0a3014722ad252d0a1f" +dependencies = [ + "displaydoc", + "litemap 0.7.5", + "serde", + "zerovec 0.10.4", +] + [[package]] name = "zerotrie" version = "0.2.3" @@ -6490,10 +8281,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" dependencies = [ "displaydoc", - "yoke", + "yoke 0.8.1", "zerofrom", ] +[[package]] +name = "zerovec" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" +dependencies = [ + "serde", + "yoke 0.7.5", + "zerofrom", + "zerovec-derive 0.10.3", +] + [[package]] name = "zerovec" version = "0.11.5" @@ -6501,9 +8304,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" dependencies = [ "serde", - "yoke", + "yoke 0.8.1", "zerofrom", - "zerovec-derive", + "zerovec-derive 0.11.2", +] + +[[package]] +name = "zerovec-derive" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", ] [[package]] @@ -6514,30 +8328,46 @@ checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] name = "zip" -version = "1.1.4" +version = "4.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cc23c04387f4da0374be4533ad1208cbb091d5c11d070dfef13676ad6497164" +checksum = "caa8cd6af31c3b31c6631b8f483848b91589021b28fffe50adada48d4f4d2ed1" dependencies = [ "arbitrary", "crc32fast", - "crossbeam-utils", - "displaydoc", "flate2", "indexmap", - "num_enum", - "thiserror 1.0.69", + "memchr", + "zopfli", ] [[package]] -name = "zmij" -version = "1.0.12" +name = "zlib-rs" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fc5a66a20078bf1251bde995aa2fdcc4b800c70b5d92dd2c62abc5c60f679f8" +checksum = "3be3d40e40a133f9c916ee3f9f4fa2d9d63435b5fbe1bfc6d9dae0aa0ada1513" + +[[package]] +name = "zmij" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" + +[[package]] +name = "zopfli" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f05cd8797d63865425ff89b5c4a48804f35ba0ce8d125800027ad6017d2b5249" +dependencies = [ + "bumpalo", + "crc32fast", + "log", + "simd-adler32", +] [[package]] name = "zstd" @@ -6567,6 +8397,12 @@ dependencies = [ "pkg-config", ] +[[package]] +name = "zune-core" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f423a2c17029964870cfaabb1f13dfab7d092a62a29a89264f4d36990ca414a" + [[package]] name = "zune-core" version = "0.5.1" @@ -6575,9 +8411,18 @@ checksum = "cb8a0807f7c01457d0379ba880ba6322660448ddebc890ce29bb64da71fb40f9" [[package]] name = "zune-jpeg" -version = "0.5.12" +version = "0.4.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "410e9ecef634c709e3831c2cfdb8d9c32164fae1c67496d5b68fff728eec37fe" +checksum = "29ce2c8a9384ad323cf564b67da86e21d3cfdff87908bc1223ed5c99bc792713" dependencies = [ - "zune-core", + "zune-core 0.4.12", +] + +[[package]] +name = "zune-jpeg" +version = "0.5.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec5f41c76397b7da451efd19915684f727d7e1d516384ca6bd0ec43ec94de23c" +dependencies = [ + "zune-core 0.5.1", ] diff --git a/Cargo.toml b/Cargo.toml index a547b0f89a..b3691d2834 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -36,7 +36,7 @@ resolver = "3" criterion2 = { version = "3", default-features = false } crossbeam-channel = "0.5" dispatch2 = "0.3" - docx-parser = { git = "https://github.com/toeverything/docx-parser" } + docx-parser = { git = "https://github.com/toeverything/docx-parser", rev = "380beea" } dotenvy = "0.15" file-format = { version = "0.28", features = ["reader"] } homedir = "0.3" @@ -59,6 +59,7 @@ resolver = "3" lru = "0.16" matroska = "0.30" memory-indexer = "0.3.0" + mermaid-rs-renderer = { git = "https://github.com/toeverything/mermaid-rs-renderer", rev = "fba9097", default-features = false } mimalloc = "0.1" mp4parse = "0.17" nanoid = "0.4" @@ -122,6 +123,14 @@ resolver = "3" tree-sitter-rust = { version = "0.24" } tree-sitter-scala = { version = "0.24" } tree-sitter-typescript = { version = "0.23" } + typst = "0.14.2" + typst-as-lib = { version = "0.15.4", default-features = false, features = [ + "packages", + "typst-kit-embed-fonts", + "typst-kit-fonts", + "ureq", + ] } + typst-svg = "0.14.2" uniffi = "0.29" url = { version = "2.5" } uuid = "1.8" diff --git a/blocksuite/affine/blocks/bookmark/package.json b/blocksuite/affine/blocks/bookmark/package.json index 334a0705b1..20b4d4c626 100644 --- a/blocksuite/affine/blocks/bookmark/package.json +++ b/blocksuite/affine/blocks/bookmark/package.json @@ -32,6 +32,7 @@ }, "devDependencies": { "@vitest/browser-playwright": "^4.0.18", + "playwright": "=1.58.2", "vitest": "^4.0.18" }, "exports": { diff --git a/blocksuite/affine/inlines/footnote/package.json b/blocksuite/affine/inlines/footnote/package.json index 849f2e5157..5eca7348f4 100644 --- a/blocksuite/affine/inlines/footnote/package.json +++ b/blocksuite/affine/inlines/footnote/package.json @@ -35,6 +35,7 @@ }, "devDependencies": { "@vitest/browser-playwright": "^4.0.18", + "playwright": "=1.58.2", "vitest": "^4.0.18" }, "exports": { diff --git a/blocksuite/framework/std/package.json b/blocksuite/framework/std/package.json index c324f348ce..6b0dec2662 100644 --- a/blocksuite/framework/std/package.json +++ b/blocksuite/framework/std/package.json @@ -34,6 +34,7 @@ }, "devDependencies": { "@vitest/browser-playwright": "^4.0.18", + "playwright": "=1.58.2", "vitest": "^4.0.18" }, "exports": { diff --git a/blocksuite/integration-test/package.json b/blocksuite/integration-test/package.json index 434b68bb6b..6d19a051bc 100644 --- a/blocksuite/integration-test/package.json +++ b/blocksuite/integration-test/package.json @@ -42,6 +42,7 @@ "devDependencies": { "@vanilla-extract/vite-plugin": "^5.0.0", "@vitest/browser-playwright": "^4.0.18", + "playwright": "=1.58.2", "vite": "^7.2.7", "vite-plugin-istanbul": "^7.2.1", "vite-plugin-wasm": "^3.5.0", diff --git a/deny.toml b/deny.toml new file mode 100644 index 0000000000..6dc39793ab --- /dev/null +++ b/deny.toml @@ -0,0 +1,48 @@ +[graph] +all-features = true +exclude-dev = true +targets = [ + "x86_64-unknown-linux-gnu", + "aarch64-apple-darwin", + "x86_64-apple-darwin", + "x86_64-pc-windows-msvc", + "aarch64-linux-android", + "aarch64-apple-ios", + "aarch64-apple-ios-sim", +] + +[licenses] +allow = [ + "0BSD", + "Apache-2.0", + "Apache-2.0 WITH LLVM-exception", + "BSD-2-Clause", + "BSD-3-Clause", + "BSL-1.0", + "CC0-1.0", + "CDLA-Permissive-2.0", + "ISC", + "MIT", + "MPL-2.0", + "Unicode-3.0", + "Unlicense", + "Zlib", +] +confidence-threshold = 0.93 +unused-allowed-license = "allow" +version = 2 + + [[licenses.exceptions]] + allow = ["AGPL-3.0-only"] + crate = "llm_adapter" + + [[licenses.exceptions]] + allow = ["AGPL-3.0-or-later"] + crate = "memory-indexer" + + [[licenses.exceptions]] + allow = ["AGPL-3.0-or-later"] + crate = "path-ext" + + [licenses.private] + ignore = true diff --git a/packages/backend/native/Cargo.toml b/packages/backend/native/Cargo.toml index 8309dc13a9..c0788f047a 100644 --- a/packages/backend/native/Cargo.toml +++ b/packages/backend/native/Cargo.toml @@ -2,6 +2,7 @@ edition = "2024" license-file = "LICENSE" name = "affine_server_native" +publish = false version = "1.0.0" [lib] diff --git a/packages/common/infra/src/op/__tests__/client.spec.ts b/packages/common/infra/src/op/__tests__/client.spec.ts index fa90f47aed..69990bc8e7 100644 --- a/packages/common/infra/src/op/__tests__/client.spec.ts +++ b/packages/common/infra/src/op/__tests__/client.spec.ts @@ -10,6 +10,7 @@ interface TestOps extends OpSchema { add: [{ a: number; b: number }, number]; bin: [Uint8Array, Uint8Array]; sub: [Uint8Array, number]; + init: [{ fastText?: boolean } | undefined, { ok: true }]; } declare module 'vitest' { @@ -84,6 +85,55 @@ describe('op client', () => { expect(data.byteLength).toBe(0); }); + it('should send optional payload call with abort signal', async ctx => { + const abortController = new AbortController(); + const result = ctx.producer.call( + 'init', + { fastText: true }, + abortController.signal + ); + + expect(ctx.postMessage.mock.calls[0][0]).toMatchInlineSnapshot(` + { + "id": "init:1", + "name": "init", + "payload": { + "fastText": true, + }, + "type": "call", + } + `); + + ctx.handlers.return({ + type: 'return', + id: 'init:1', + data: { ok: true }, + }); + + await expect(result).resolves.toEqual({ ok: true }); + }); + + it('should send undefined payload for optional input call', async ctx => { + const result = ctx.producer.call('init', undefined); + + expect(ctx.postMessage.mock.calls[0][0]).toMatchInlineSnapshot(` + { + "id": "init:1", + "name": "init", + "payload": undefined, + "type": "call", + } + `); + + ctx.handlers.return({ + type: 'return', + id: 'init:1', + data: { ok: true }, + }); + + await expect(result).resolves.toEqual({ ok: true }); + }); + it('should cancel call', async ctx => { const promise = ctx.producer.call('add', { a: 1, b: 2 }); diff --git a/packages/common/infra/src/op/__tests__/consumer.spec.ts b/packages/common/infra/src/op/__tests__/consumer.spec.ts index 628407bb29..2a424b97a7 100644 --- a/packages/common/infra/src/op/__tests__/consumer.spec.ts +++ b/packages/common/infra/src/op/__tests__/consumer.spec.ts @@ -40,18 +40,14 @@ describe('op consumer', () => { it('should throw if no handler registered', async ctx => { ctx.handlers.call({ type: 'call', id: 'add:1', name: 'add', payload: {} }); await vi.advanceTimersToNextTimerAsync(); - expect(ctx.postMessage.mock.lastCall).toMatchInlineSnapshot(` - [ - { - "error": { - "message": "Handler for operation [add] is not registered.", - "name": "Error", - }, - "id": "add:1", - "type": "return", - }, - ] - `); + expect(ctx.postMessage.mock.lastCall?.[0]).toMatchObject({ + type: 'return', + id: 'add:1', + error: { + message: 'Handler for operation [add] is not registered.', + name: 'Error', + }, + }); }); it('should handle call message', async ctx => { @@ -73,6 +69,38 @@ describe('op consumer', () => { `); }); + it('should serialize string errors with message', async ctx => { + ctx.consumer.register('any', () => { + throw 'worker panic'; + }); + + ctx.handlers.call({ type: 'call', id: 'any:1', name: 'any', payload: {} }); + await vi.advanceTimersToNextTimerAsync(); + + expect(ctx.postMessage.mock.calls[0][0]).toMatchObject({ + type: 'return', + id: 'any:1', + error: { + name: 'Error', + message: 'worker panic', + }, + }); + }); + + it('should serialize plain object errors with fallback message', async ctx => { + ctx.consumer.register('any', () => { + throw { reason: 'panic', code: 'E_PANIC' }; + }); + + ctx.handlers.call({ type: 'call', id: 'any:1', name: 'any', payload: {} }); + await vi.advanceTimersToNextTimerAsync(); + + const message = ctx.postMessage.mock.calls[0][0]?.error?.message; + expect(typeof message).toBe('string'); + expect(message).toContain('"reason":"panic"'); + expect(message).toContain('"code":"E_PANIC"'); + }); + it('should handle cancel message', async ctx => { ctx.consumer.register('add', ({ a, b }, { signal }) => { const { reject, resolve, promise } = Promise.withResolvers(); diff --git a/packages/common/infra/src/op/consumer.ts b/packages/common/infra/src/op/consumer.ts index 06bd38284c..61e33405aa 100644 --- a/packages/common/infra/src/op/consumer.ts +++ b/packages/common/infra/src/op/consumer.ts @@ -16,6 +16,96 @@ import { } from './message'; import type { OpInput, OpNames, OpOutput, OpSchema } from './types'; +const SERIALIZABLE_ERROR_FIELDS = [ + 'name', + 'message', + 'code', + 'type', + 'status', + 'data', + 'stacktrace', +] as const; + +type SerializableErrorShape = Partial< + Record<(typeof SERIALIZABLE_ERROR_FIELDS)[number], unknown> +> & { + name?: string; + message?: string; +}; + +function getFallbackErrorMessage(error: unknown): string { + if (typeof error === 'string') { + return error; + } + + if (error instanceof Error && error.message) { + return error.message; + } + + if ( + typeof error === 'number' || + typeof error === 'boolean' || + typeof error === 'bigint' || + typeof error === 'symbol' + ) { + return String(error); + } + + if (error === null || error === undefined) { + return 'Unknown error'; + } + + try { + const jsonMessage = JSON.stringify(error); + if (jsonMessage && jsonMessage !== '{}') { + return jsonMessage; + } + } catch { + return 'Unknown error'; + } + + return 'Unknown error'; +} + +function serializeError(error: unknown): Error { + const valueToPick = + error && typeof error === 'object' + ? error + : ({} as Record); + const serialized = pick( + valueToPick, + SERIALIZABLE_ERROR_FIELDS + ) as SerializableErrorShape; + + if (!serialized.message || typeof serialized.message !== 'string') { + serialized.message = getFallbackErrorMessage(error); + } + + if (!serialized.name || typeof serialized.name !== 'string') { + if (error instanceof Error && error.name) { + serialized.name = error.name; + } else if (error && typeof error === 'object') { + const constructorName = error.constructor?.name; + serialized.name = + typeof constructorName === 'string' && constructorName.length > 0 + ? constructorName + : 'Error'; + } else { + serialized.name = 'Error'; + } + } + + if ( + !serialized.stacktrace && + error instanceof Error && + typeof error.stack === 'string' + ) { + serialized.stacktrace = error.stack; + } + + return serialized as Error; +} + interface OpCallContext { signal: AbortSignal; } @@ -71,15 +161,7 @@ export class OpConsumer extends AutoMessageHandler { this.port.postMessage({ type: 'return', id: msg.id, - error: pick(error, [ - 'name', - 'message', - 'code', - 'type', - 'status', - 'data', - 'stacktrace', - ]), + error: serializeError(error), } satisfies ReturnMessage); }, complete: () => { @@ -109,15 +191,7 @@ export class OpConsumer extends AutoMessageHandler { this.port.postMessage({ type: 'error', id: msg.id, - error: pick(error, [ - 'name', - 'message', - 'code', - 'type', - 'status', - 'data', - 'stacktrace', - ]), + error: serializeError(error), } satisfies SubscriptionErrorMessage); }, complete: () => { diff --git a/packages/common/infra/src/op/types.ts b/packages/common/infra/src/op/types.ts index cae15e68bd..6968582149 100644 --- a/packages/common/infra/src/op/types.ts +++ b/packages/common/infra/src/op/types.ts @@ -12,7 +12,16 @@ export interface OpSchema { [key: string]: [any, any?]; } -type RequiredInput = In extends void ? [] : In extends never ? [] : [In]; +type IsAny = 0 extends 1 & T ? true : false; + +type RequiredInput = + IsAny extends true + ? [In] + : [In] extends [never] + ? [] + : [In] extends [void] + ? [] + : [In]; export type OpNames = ValuesOf>; export type OpInput< diff --git a/packages/common/native/Cargo.toml b/packages/common/native/Cargo.toml index ee9c0f6eeb..9d97c884ef 100644 --- a/packages/common/native/Cargo.toml +++ b/packages/common/native/Cargo.toml @@ -2,6 +2,7 @@ edition = "2024" license-file = "LICENSE" name = "affine_common" +publish = false version = "0.1.0" [features] diff --git a/packages/frontend/apps/android/App/app/src/main/java/app/affine/pro/MainActivity.kt b/packages/frontend/apps/android/App/app/src/main/java/app/affine/pro/MainActivity.kt index 634ca00798..2f75eb5acf 100644 --- a/packages/frontend/apps/android/App/app/src/main/java/app/affine/pro/MainActivity.kt +++ b/packages/frontend/apps/android/App/app/src/main/java/app/affine/pro/MainActivity.kt @@ -19,6 +19,7 @@ import app.affine.pro.plugin.AFFiNEThemePlugin import app.affine.pro.plugin.AuthPlugin import app.affine.pro.plugin.HashCashPlugin import app.affine.pro.plugin.NbStorePlugin +import app.affine.pro.plugin.PreviewPlugin import app.affine.pro.service.GraphQLService import app.affine.pro.service.SSEService import app.affine.pro.service.WebService @@ -52,6 +53,7 @@ class MainActivity : BridgeActivity(), AIButtonPlugin.Callback, AFFiNEThemePlugi AuthPlugin::class.java, HashCashPlugin::class.java, NbStorePlugin::class.java, + PreviewPlugin::class.java, ) ) } diff --git a/packages/frontend/apps/android/App/app/src/main/java/app/affine/pro/ai/chat/ChatUiState.kt b/packages/frontend/apps/android/App/app/src/main/java/app/affine/pro/ai/chat/ChatUiState.kt index b506880d43..aac2c788e6 100644 --- a/packages/frontend/apps/android/App/app/src/main/java/app/affine/pro/ai/chat/ChatUiState.kt +++ b/packages/frontend/apps/android/App/app/src/main/java/app/affine/pro/ai/chat/ChatUiState.kt @@ -1,8 +1,6 @@ package app.affine.pro.ai.chat -import com.affine.pro.graphql.GetCopilotHistoriesQuery import com.affine.pro.graphql.fragment.CopilotChatHistory -import com.affine.pro.graphql.fragment.CopilotChatMessage import kotlinx.datetime.Clock import kotlinx.datetime.Instant @@ -53,7 +51,7 @@ data class ChatMessage( createAt = Clock.System.now(), ) - fun from(message: CopilotChatMessage) = ChatMessage( + fun from(message: CopilotChatHistory.Message) = ChatMessage( id = message.id, role = Role.fromValue(message.role), content = message.content, diff --git a/packages/frontend/apps/android/App/app/src/main/java/app/affine/pro/plugin/PreviewPlugin.kt b/packages/frontend/apps/android/App/app/src/main/java/app/affine/pro/plugin/PreviewPlugin.kt new file mode 100644 index 0000000000..86d74275d0 --- /dev/null +++ b/packages/frontend/apps/android/App/app/src/main/java/app/affine/pro/plugin/PreviewPlugin.kt @@ -0,0 +1,106 @@ +package app.affine.pro.plugin + +import android.net.Uri +import com.getcapacitor.JSObject +import com.getcapacitor.Plugin +import com.getcapacitor.PluginCall +import com.getcapacitor.PluginMethod +import com.getcapacitor.annotation.CapacitorPlugin +import kotlinx.coroutines.Dispatchers +import timber.log.Timber +import uniffi.affine_mobile_native.renderMermaidPreviewSvg +import uniffi.affine_mobile_native.renderTypstPreviewSvg +import java.io.File + +private fun JSObject.getOptionalString(key: String): String? { + return if (has(key) && !isNull(key)) getString(key) else null +} + +private fun JSObject.getOptionalDouble(key: String): Double? { + return if (has(key) && !isNull(key)) getDouble(key) else null +} + +private fun resolveLocalFontDir(fontUrl: String): String? { + val uri = Uri.parse(fontUrl) + val path = when { + uri.scheme == null -> { + val file = File(fontUrl) + if (!file.isAbsolute) { + return null + } + file.path + } + uri.scheme == "file" -> uri.path + else -> null + } ?: return null + + val file = File(path) + val directory = if (file.isDirectory) file else file.parentFile ?: return null + return directory.absolutePath +} + +private fun JSObject.resolveTypstFontDirs(): List? { + if (!has("fontUrls") || isNull("fontUrls")) { + return null + } + + val fontUrls = optJSONArray("fontUrls") + ?: throw IllegalArgumentException("Typst preview fontUrls must be an array of strings.") + val fontDirs = buildList(fontUrls.length()) { + repeat(fontUrls.length()) { index -> + val fontUrl = fontUrls.optString(index, null) + ?: throw IllegalArgumentException("Typst preview fontUrls must be strings.") + val fontDir = resolveLocalFontDir(fontUrl) + ?: throw IllegalArgumentException("Typst preview on mobile only supports local font file URLs or absolute font directories.") + add(fontDir) + } + } + return fontDirs.distinct() +} + +@CapacitorPlugin(name = "Preview") +class PreviewPlugin : Plugin() { + + @PluginMethod + fun renderMermaidSvg(call: PluginCall) { + launch(Dispatchers.IO) { + try { + val code = call.getStringEnsure("code") + val options = call.getObject("options") + val svg = renderMermaidPreviewSvg( + code = code, + theme = options?.getOptionalString("theme"), + fontFamily = options?.getOptionalString("fontFamily"), + fontSize = options?.getOptionalDouble("fontSize"), + ) + call.resolve(JSObject().apply { + put("svg", svg) + }) + } catch (e: Exception) { + Timber.e(e, "Failed to render Mermaid preview.") + call.reject("Failed to render Mermaid preview.", null, e) + } + } + } + + @PluginMethod + fun renderTypstSvg(call: PluginCall) { + launch(Dispatchers.IO) { + try { + val code = call.getStringEnsure("code") + val options = call.getObject("options") + val svg = renderTypstPreviewSvg( + code = code, + fontDirs = options?.resolveTypstFontDirs(), + cacheDir = context.cacheDir.absolutePath, + ) + call.resolve(JSObject().apply { + put("svg", svg) + }) + } catch (e: Exception) { + Timber.e(e, "Failed to render Typst preview.") + call.reject("Failed to render Typst preview.", null, e) + } + } + } +} diff --git a/packages/frontend/apps/android/App/app/src/main/java/app/affine/pro/service/GraphQLService.kt b/packages/frontend/apps/android/App/app/src/main/java/app/affine/pro/service/GraphQLService.kt index 51f1fe314f..9c44dbacc8 100644 --- a/packages/frontend/apps/android/App/app/src/main/java/app/affine/pro/service/GraphQLService.kt +++ b/packages/frontend/apps/android/App/app/src/main/java/app/affine/pro/service/GraphQLService.kt @@ -72,7 +72,7 @@ class GraphQLService @Inject constructor() { ).mapCatching { data -> data.currentUser?.copilot?.chats?.paginatedCopilotChats?.edges?.map { item -> item.node.copilotChatHistory }?.firstOrNull { history -> history.sessionId == sessionId - }?.messages?.map { msg -> msg.copilotChatMessage } ?: emptyList() + }?.messages ?: emptyList() } suspend fun getCopilotHistoryIds( diff --git a/packages/frontend/apps/android/App/app/src/main/java/uniffi/affine_mobile_native/affine_mobile_native.kt b/packages/frontend/apps/android/App/app/src/main/java/uniffi/affine_mobile_native/affine_mobile_native.kt index 902212ceef..784bbb6dcb 100644 --- a/packages/frontend/apps/android/App/app/src/main/java/uniffi/affine_mobile_native/affine_mobile_native.kt +++ b/packages/frontend/apps/android/App/app/src/main/java/uniffi/affine_mobile_native/affine_mobile_native.kt @@ -792,6 +792,10 @@ internal interface UniffiForeignFutureCompleteVoid : com.sun.jna.Callback { + + + + @@ -816,6 +820,10 @@ internal interface IntegrityCheckingUniffiLib : Library { ): Short fun uniffi_affine_mobile_native_checksum_func_new_doc_storage_pool( ): Short +fun uniffi_affine_mobile_native_checksum_func_render_mermaid_preview_svg( +): Short +fun uniffi_affine_mobile_native_checksum_func_render_typst_preview_svg( +): Short fun uniffi_affine_mobile_native_checksum_method_docstoragepool_clear_clocks( ): Short fun uniffi_affine_mobile_native_checksum_method_docstoragepool_connect( @@ -1017,6 +1025,10 @@ fun uniffi_affine_mobile_native_fn_func_hashcash_mint(`resource`: RustBuffer.ByV ): RustBuffer.ByValue fun uniffi_affine_mobile_native_fn_func_new_doc_storage_pool(uniffi_out_err: UniffiRustCallStatus, ): Pointer +fun uniffi_affine_mobile_native_fn_func_render_mermaid_preview_svg(`code`: RustBuffer.ByValue,`theme`: RustBuffer.ByValue,`fontFamily`: RustBuffer.ByValue,`fontSize`: RustBuffer.ByValue,uniffi_out_err: UniffiRustCallStatus, +): RustBuffer.ByValue +fun uniffi_affine_mobile_native_fn_func_render_typst_preview_svg(`code`: RustBuffer.ByValue,`fontDirs`: RustBuffer.ByValue,`cacheDir`: RustBuffer.ByValue,uniffi_out_err: UniffiRustCallStatus, +): RustBuffer.ByValue fun ffi_affine_mobile_native_rustbuffer_alloc(`size`: Long,uniffi_out_err: UniffiRustCallStatus, ): RustBuffer.ByValue fun ffi_affine_mobile_native_rustbuffer_from_bytes(`bytes`: ForeignBytes.ByValue,uniffi_out_err: UniffiRustCallStatus, @@ -1149,6 +1161,12 @@ private fun uniffiCheckApiChecksums(lib: IntegrityCheckingUniffiLib) { if (lib.uniffi_affine_mobile_native_checksum_func_new_doc_storage_pool() != 32882.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } + if (lib.uniffi_affine_mobile_native_checksum_func_render_mermaid_preview_svg() != 54334.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_affine_mobile_native_checksum_func_render_typst_preview_svg() != 42796.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } if (lib.uniffi_affine_mobile_native_checksum_method_docstoragepool_clear_clocks() != 51151.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } @@ -3178,6 +3196,38 @@ public object FfiConverterOptionalLong: FfiConverterRustBuffer { +/** + * @suppress + */ +public object FfiConverterOptionalDouble: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): kotlin.Double? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterDouble.read(buf) + } + + override fun allocationSize(value: kotlin.Double?): ULong { + if (value == null) { + return 1UL + } else { + return 1UL + FfiConverterDouble.allocationSize(value) + } + } + + override fun write(value: kotlin.Double?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterDouble.write(value, buf) + } + } +} + + + + /** * @suppress */ @@ -3584,4 +3634,24 @@ public object FfiConverterSequenceTypeSearchHit: FfiConverterRustBuffer + UniffiLib.INSTANCE.uniffi_affine_mobile_native_fn_func_render_mermaid_preview_svg( + FfiConverterString.lower(`code`),FfiConverterOptionalString.lower(`theme`),FfiConverterOptionalString.lower(`fontFamily`),FfiConverterOptionalDouble.lower(`fontSize`),_status) +} + ) + } + + + @Throws(UniffiException::class) fun `renderTypstPreviewSvg`(`code`: kotlin.String, `fontDirs`: List?, `cacheDir`: kotlin.String?): kotlin.String { + return FfiConverterString.lift( + uniffiRustCallWithError(UniffiException) { _status -> + UniffiLib.INSTANCE.uniffi_affine_mobile_native_fn_func_render_typst_preview_svg( + FfiConverterString.lower(`code`),FfiConverterOptionalSequenceString.lower(`fontDirs`),FfiConverterOptionalString.lower(`cacheDir`),_status) +} + ) + } + + diff --git a/packages/frontend/apps/android/src/app.tsx b/packages/frontend/apps/android/src/app.tsx index 3c729b3ec8..b107e999a0 100644 --- a/packages/frontend/apps/android/src/app.tsx +++ b/packages/frontend/apps/android/src/app.tsx @@ -15,6 +15,7 @@ import { ServersService, ValidatorProvider, } from '@affine/core/modules/cloud'; +import { registerNativePreviewHandlers } from '@affine/core/modules/code-block-preview-renderer'; import { DocsService } from '@affine/core/modules/doc'; import { GlobalContextService } from '@affine/core/modules/global-context'; import { I18nProvider } from '@affine/core/modules/i18n'; @@ -54,6 +55,7 @@ import { AIButton } from './plugins/ai-button'; import { Auth } from './plugins/auth'; import { HashCash } from './plugins/hashcash'; import { NbStoreNativeDBApis } from './plugins/nbstore'; +import { Preview } from './plugins/preview'; import { writeEndpointToken } from './proxy'; const storeManagerClient = createStoreManagerClient(); @@ -85,6 +87,11 @@ framework.impl(NbstoreProvider, { }); const frameworkProvider = framework.provider(); +registerNativePreviewHandlers({ + renderMermaidSvg: request => Preview.renderMermaidSvg(request), + renderTypstSvg: request => Preview.renderTypstSvg(request), +}); + framework.impl(PopupWindowProvider, { open: (url: string) => { InAppBrowser.open({ diff --git a/packages/frontend/apps/android/src/plugins/preview/definitions.ts b/packages/frontend/apps/android/src/plugins/preview/definitions.ts new file mode 100644 index 0000000000..5e6cfaf26f --- /dev/null +++ b/packages/frontend/apps/android/src/plugins/preview/definitions.ts @@ -0,0 +1,16 @@ +export interface PreviewPlugin { + renderMermaidSvg(options: { + code: string; + options?: { + theme?: string; + fontFamily?: string; + fontSize?: number; + }; + }): Promise<{ svg: string }>; + renderTypstSvg(options: { + code: string; + options?: { + fontUrls?: string[]; + }; + }): Promise<{ svg: string }>; +} diff --git a/packages/frontend/apps/android/src/plugins/preview/index.ts b/packages/frontend/apps/android/src/plugins/preview/index.ts new file mode 100644 index 0000000000..4be99d9096 --- /dev/null +++ b/packages/frontend/apps/android/src/plugins/preview/index.ts @@ -0,0 +1,8 @@ +import { registerPlugin } from '@capacitor/core'; + +import type { PreviewPlugin } from './definitions'; + +const Preview = registerPlugin('Preview'); + +export * from './definitions'; +export { Preview }; diff --git a/packages/frontend/apps/electron/src/helper/exposed.ts b/packages/frontend/apps/electron/src/helper/exposed.ts index 9fa9ad05ff..60e5560375 100644 --- a/packages/frontend/apps/electron/src/helper/exposed.ts +++ b/packages/frontend/apps/electron/src/helper/exposed.ts @@ -1,5 +1,6 @@ import { dialogHandlers } from './dialog'; import { dbEventsV1, dbHandlersV1, nbstoreHandlers } from './nbstore'; +import { previewHandlers } from './preview'; import { provideExposed } from './provide'; import { workspaceEvents, workspaceHandlers } from './workspace'; @@ -8,6 +9,7 @@ export const handlers = { nbstore: nbstoreHandlers, workspace: workspaceHandlers, dialog: dialogHandlers, + preview: previewHandlers, }; export const events = { diff --git a/packages/frontend/apps/electron/src/helper/preview/index.ts b/packages/frontend/apps/electron/src/helper/preview/index.ts new file mode 100644 index 0000000000..2945fd40e0 --- /dev/null +++ b/packages/frontend/apps/electron/src/helper/preview/index.ts @@ -0,0 +1,69 @@ +import fs from 'node:fs'; +import path from 'node:path'; + +import { + type MermaidRenderRequest, + type MermaidRenderResult, + renderMermaidSvg, + renderTypstSvg, + type TypstRenderRequest, + type TypstRenderResult, +} from '@affine/native'; + +const TYPST_FONT_DIRS_ENV = 'AFFINE_TYPST_FONT_DIRS'; + +function parseTypstFontDirsFromEnv() { + const value = process.env[TYPST_FONT_DIRS_ENV]; + if (!value) { + return []; + } + + return value + .split(path.delimiter) + .map(dir => dir.trim()) + .filter(Boolean); +} + +function getTypstFontDirCandidates() { + const resourcesPath = process.resourcesPath ?? ''; + + return [ + ...parseTypstFontDirsFromEnv(), + path.join(resourcesPath, 'fonts'), + path.join(resourcesPath, 'js', 'fonts'), + path.join(resourcesPath, 'app.asar.unpacked', 'fonts'), + path.join(resourcesPath, 'app.asar.unpacked', 'js', 'fonts'), + ]; +} + +function resolveTypstFontDirs() { + return Array.from( + new Set(getTypstFontDirCandidates().map(dir => path.resolve(dir))) + ).filter(dir => fs.statSync(dir, { throwIfNoEntry: false })?.isDirectory()); +} + +function withTypstFontDirs( + request: TypstRenderRequest, + fontDirs: string[] +): TypstRenderRequest { + const nextOptions = request.options ? { ...request.options } : {}; + if (!nextOptions.fontDirs?.length) { + nextOptions.fontDirs = fontDirs; + } + return { ...request, options: nextOptions }; +} + +const typstFontDirs = resolveTypstFontDirs(); + +export const previewHandlers = { + renderMermaidSvg: async ( + request: MermaidRenderRequest + ): Promise => { + return renderMermaidSvg(request); + }, + renderTypstSvg: async ( + request: TypstRenderRequest + ): Promise => { + return renderTypstSvg(withTypstFontDirs(request, typstFontDirs)); + }, +}; diff --git a/packages/frontend/apps/electron/test/helper/preview.spec.ts b/packages/frontend/apps/electron/test/helper/preview.spec.ts new file mode 100644 index 0000000000..0ce10011f3 --- /dev/null +++ b/packages/frontend/apps/electron/test/helper/preview.spec.ts @@ -0,0 +1,85 @@ +import path from 'node:path'; + +import fs from 'fs-extra'; +import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest'; + +const { native } = vi.hoisted(() => ({ + native: { + renderMermaidSvg: vi.fn(), + renderTypstSvg: vi.fn(), + }, +})); + +vi.mock('@affine/native', () => native); + +const tmpDir = path.join(__dirname, 'tmp'); +const typstFontDirA = path.join(tmpDir, 'fonts-a'); +const typstFontDirB = path.join(tmpDir, 'fonts-b'); + +async function loadPreviewHandlers() { + vi.resetModules(); + const module = await import('../../src/helper/preview'); + return module.previewHandlers; +} + +describe('helper preview handlers', () => { + beforeEach(async () => { + await fs.ensureDir(typstFontDirA); + await fs.ensureDir(typstFontDirB); + process.env.AFFINE_TYPST_FONT_DIRS = [ + typstFontDirA, + typstFontDirB, + path.join(tmpDir, 'missing'), + ].join(path.delimiter); + native.renderMermaidSvg.mockReset(); + native.renderTypstSvg.mockReset(); + native.renderMermaidSvg.mockReturnValue({ + svg: 'mermaid', + }); + native.renderTypstSvg.mockReturnValue({ + svg: 'typst', + }); + }); + + afterEach(async () => { + delete process.env.AFFINE_TYPST_FONT_DIRS; + await fs.remove(tmpDir); + }); + + test('passes mermaid request to native renderer', async () => { + const previewHandlers = await loadPreviewHandlers(); + const request = { code: 'flowchart TD; A-->B' }; + + await previewHandlers.renderMermaidSvg(request); + + expect(native.renderMermaidSvg).toHaveBeenCalledWith(request); + }); + + test('injects resolved fontDirs into typst requests', async () => { + const previewHandlers = await loadPreviewHandlers(); + + await previewHandlers.renderTypstSvg({ code: '= hello' }); + + const [request] = native.renderTypstSvg.mock.calls[0]; + expect(request.options?.fontDirs).toEqual( + expect.arrayContaining([ + path.resolve(typstFontDirA), + path.resolve(typstFontDirB), + ]) + ); + }); + + test('keeps explicit typst fontDirs', async () => { + const previewHandlers = await loadPreviewHandlers(); + const request = { + code: '= hello', + options: { + fontDirs: ['/tmp/custom-fonts'], + }, + }; + + await previewHandlers.renderTypstSvg(request); + + expect(native.renderTypstSvg).toHaveBeenCalledWith(request); + }); +}); diff --git a/packages/frontend/apps/ios/App/App.xcworkspace/xcshareddata/swiftpm/Package.resolved b/packages/frontend/apps/ios/App/App.xcworkspace/xcshareddata/swiftpm/Package.resolved index 3d52e4291b..ad3a119025 100644 --- a/packages/frontend/apps/ios/App/App.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/packages/frontend/apps/ios/App/App.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -14,8 +14,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/Recouse/EventSource", "state" : { - "revision" : "7b2f4f585d3927876bd76eaede9fdff779eff102", - "version" : "0.1.5" + "revision" : "713f8c0a0270a80a968c007ddc0d6067e80a5393", + "version" : "0.1.7" } }, { @@ -41,8 +41,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/Lakr233/Litext", "state" : { - "revision" : "c7e83f2f580ce34a102ca9ba9d2bb24e507dccd9", - "version" : "0.5.6" + "revision" : "a2ed9b63ae623a20591effc72f9db7d04e41a64c", + "version" : "1.2.1" } }, { @@ -77,8 +77,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/RevenueCat/purchases-ios-spm.git", "state" : { - "revision" : "8f5df97653eb361a2097119479332afccf0aa816", - "version" : "5.58.0" + "revision" : "2913a336eb37dc06795cdbaa5b5de330b6707669", + "version" : "5.65.0" } }, { diff --git a/packages/frontend/apps/ios/App/App/AffineViewController.swift b/packages/frontend/apps/ios/App/App/AffineViewController.swift index c5a430c925..3ec69a5cc5 100644 --- a/packages/frontend/apps/ios/App/App/AffineViewController.swift +++ b/packages/frontend/apps/ios/App/App/AffineViewController.swift @@ -34,6 +34,7 @@ class AFFiNEViewController: CAPBridgeViewController { NavigationGesturePlugin(), NbStorePlugin(), PayWallPlugin(associatedController: self), + PreviewPlugin(), ] plugins.forEach { bridge?.registerPluginInstance($0) } } diff --git a/packages/frontend/apps/ios/App/App/Plugins/Preview/PreviewPlugin.swift b/packages/frontend/apps/ios/App/App/Plugins/Preview/PreviewPlugin.swift new file mode 100644 index 0000000000..c01f22a626 --- /dev/null +++ b/packages/frontend/apps/ios/App/App/Plugins/Preview/PreviewPlugin.swift @@ -0,0 +1,119 @@ +import Foundation +import Capacitor + +private func resolveLocalFontDir(from fontURL: String) -> String? { + let path: String + if fontURL.hasPrefix("file://") { + guard let url = URL(string: fontURL), url.isFileURL else { + return nil + } + path = url.path + } else { + let candidate = (fontURL as NSString).standardizingPath + guard candidate.hasPrefix("/") else { + return nil + } + path = candidate + } + + var isDirectory: ObjCBool = false + if FileManager.default.fileExists(atPath: path, isDirectory: &isDirectory), + isDirectory.boolValue + { + return path + } + + let directory = (path as NSString).deletingLastPathComponent + return directory.isEmpty ? nil : directory +} + +private func resolveTypstFontDirs(from options: [AnyHashable: Any]?) throws -> [String]? { + guard let rawFontUrls = options?["fontUrls"] else { + return nil + } + + guard let fontUrls = rawFontUrls as? [Any] else { + throw NSError( + domain: "PreviewPlugin", + code: 1, + userInfo: [ + NSLocalizedDescriptionKey: "Typst preview fontUrls must be an array of strings." + ] + ) + } + + var seenFontDirs = Set() + var orderedFontDirs = [String]() + orderedFontDirs.reserveCapacity(fontUrls.count) + + for fontUrl in fontUrls { + guard let fontURL = fontUrl as? String else { + throw NSError( + domain: "PreviewPlugin", + code: 1, + userInfo: [ + NSLocalizedDescriptionKey: "Typst preview fontUrls must be strings." + ] + ) + } + + guard let fontDir = resolveLocalFontDir(from: fontURL) else { + throw NSError( + domain: "PreviewPlugin", + code: 1, + userInfo: [ + NSLocalizedDescriptionKey: "Typst preview on mobile only supports local font file URLs or absolute font directories." + ] + ) + } + + if seenFontDirs.insert(fontDir).inserted { + orderedFontDirs.append(fontDir) + } + } + + return orderedFontDirs +} + +@objc(PreviewPlugin) +public class PreviewPlugin: CAPPlugin, CAPBridgedPlugin { + public let identifier = "PreviewPlugin" + public let jsName = "Preview" + public let pluginMethods: [CAPPluginMethod] = [ + CAPPluginMethod(name: "renderMermaidSvg", returnType: CAPPluginReturnPromise), + CAPPluginMethod(name: "renderTypstSvg", returnType: CAPPluginReturnPromise), + ] + + @objc func renderMermaidSvg(_ call: CAPPluginCall) { + DispatchQueue.global(qos: .userInitiated).async { + do { + let code = try call.getStringEnsure("code") + let options = call.getObject("options") + let svg = try renderMermaidPreviewSvg( + code: code, + theme: options?["theme"] as? String, + fontFamily: options?["fontFamily"] as? String, + fontSize: (options?["fontSize"] as? NSNumber)?.doubleValue + ) + call.resolve(["svg": svg]) + } catch { + call.reject("Failed to render Mermaid preview, \(error)", nil, error) + } + } + } + + @objc func renderTypstSvg(_ call: CAPPluginCall) { + DispatchQueue.global(qos: .userInitiated).async { + do { + let code = try call.getStringEnsure("code") + let options = call.getObject("options") + let cacheDir = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask).first?.path + let fontDirs = try resolveTypstFontDirs(from: options) + let svg = try renderTypstPreviewSvg(code: code, fontDirs: fontDirs, cacheDir: cacheDir) + call.resolve(["svg": svg]) + } catch { + call.reject("Failed to render Typst preview, \(error)", nil, error) + } + } + } +} diff --git a/packages/frontend/apps/ios/App/App/uniffi/affine_mobile_native.swift b/packages/frontend/apps/ios/App/App/uniffi/affine_mobile_native.swift index 590b1be0f6..1cacb1d360 100644 --- a/packages/frontend/apps/ios/App/App/uniffi/affine_mobile_native.swift +++ b/packages/frontend/apps/ios/App/App/uniffi/affine_mobile_native.swift @@ -2265,6 +2265,30 @@ fileprivate struct FfiConverterOptionInt64: FfiConverterRustBuffer { } } +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +fileprivate struct FfiConverterOptionDouble: FfiConverterRustBuffer { + typealias SwiftType = Double? + + public static func write(_ value: SwiftType, into buf: inout [UInt8]) { + guard let value = value else { + writeInt(&buf, Int8(0)) + return + } + writeInt(&buf, Int8(1)) + FfiConverterDouble.write(value, into: &buf) + } + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { + switch try readInt(&buf) as Int8 { + case 0: return nil + case 1: return try FfiConverterDouble.read(from: &buf) + default: throw UniffiInternalError.unexpectedOptionalTag + } + } +} + #if swift(>=5.8) @_documentation(visibility: private) #endif @@ -2644,6 +2668,25 @@ public func newDocStoragePool() -> DocStoragePool { ) }) } +public func renderMermaidPreviewSvg(code: String, theme: String?, fontFamily: String?, fontSize: Double?)throws -> String { + return try FfiConverterString.lift(try rustCallWithError(FfiConverterTypeUniffiError_lift) { + uniffi_affine_mobile_native_fn_func_render_mermaid_preview_svg( + FfiConverterString.lower(code), + FfiConverterOptionString.lower(theme), + FfiConverterOptionString.lower(fontFamily), + FfiConverterOptionDouble.lower(fontSize),$0 + ) +}) +} +public func renderTypstPreviewSvg(code: String, fontDirs: [String]?, cacheDir: String?)throws -> String { + return try FfiConverterString.lift(try rustCallWithError(FfiConverterTypeUniffiError_lift) { + uniffi_affine_mobile_native_fn_func_render_typst_preview_svg( + FfiConverterString.lower(code), + FfiConverterOptionSequenceString.lower(fontDirs), + FfiConverterOptionString.lower(cacheDir),$0 + ) +}) +} private enum InitializationResult { case ok @@ -2666,6 +2709,12 @@ private let initializationResult: InitializationResult = { if (uniffi_affine_mobile_native_checksum_func_new_doc_storage_pool() != 32882) { return InitializationResult.apiChecksumMismatch } + if (uniffi_affine_mobile_native_checksum_func_render_mermaid_preview_svg() != 54334) { + return InitializationResult.apiChecksumMismatch + } + if (uniffi_affine_mobile_native_checksum_func_render_typst_preview_svg() != 42796) { + return InitializationResult.apiChecksumMismatch + } if (uniffi_affine_mobile_native_checksum_method_docstoragepool_clear_clocks() != 51151) { return InitializationResult.apiChecksumMismatch } diff --git a/packages/frontend/apps/ios/App/App/uniffi/affine_mobile_nativeFFI.h b/packages/frontend/apps/ios/App/App/uniffi/affine_mobile_nativeFFI.h index 04f5dc26d2..10535af306 100644 --- a/packages/frontend/apps/ios/App/App/uniffi/affine_mobile_nativeFFI.h +++ b/packages/frontend/apps/ios/App/App/uniffi/affine_mobile_nativeFFI.h @@ -450,6 +450,16 @@ RustBuffer uniffi_affine_mobile_native_fn_func_hashcash_mint(RustBuffer resource #define UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_FN_FUNC_NEW_DOC_STORAGE_POOL void*_Nonnull uniffi_affine_mobile_native_fn_func_new_doc_storage_pool(RustCallStatus *_Nonnull out_status +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_FN_FUNC_RENDER_MERMAID_PREVIEW_SVG +#define UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_FN_FUNC_RENDER_MERMAID_PREVIEW_SVG +RustBuffer uniffi_affine_mobile_native_fn_func_render_mermaid_preview_svg(RustBuffer code, RustBuffer theme, RustBuffer font_family, RustBuffer font_size, RustCallStatus *_Nonnull out_status +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_FN_FUNC_RENDER_TYPST_PREVIEW_SVG +#define UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_FN_FUNC_RENDER_TYPST_PREVIEW_SVG +RustBuffer uniffi_affine_mobile_native_fn_func_render_typst_preview_svg(RustBuffer code, RustBuffer font_dirs, RustBuffer cache_dir, RustCallStatus *_Nonnull out_status ); #endif #ifndef UNIFFI_FFIDEF_FFI_AFFINE_MOBILE_NATIVE_RUSTBUFFER_ALLOC @@ -742,6 +752,18 @@ uint16_t uniffi_affine_mobile_native_checksum_func_hashcash_mint(void #define UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_CHECKSUM_FUNC_NEW_DOC_STORAGE_POOL uint16_t uniffi_affine_mobile_native_checksum_func_new_doc_storage_pool(void +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_CHECKSUM_FUNC_RENDER_MERMAID_PREVIEW_SVG +#define UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_CHECKSUM_FUNC_RENDER_MERMAID_PREVIEW_SVG +uint16_t uniffi_affine_mobile_native_checksum_func_render_mermaid_preview_svg(void + +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_CHECKSUM_FUNC_RENDER_TYPST_PREVIEW_SVG +#define UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_CHECKSUM_FUNC_RENDER_TYPST_PREVIEW_SVG +uint16_t uniffi_affine_mobile_native_checksum_func_render_typst_preview_svg(void + ); #endif #ifndef UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_CHECKSUM_METHOD_DOCSTORAGEPOOL_CLEAR_CLOCKS diff --git a/packages/frontend/apps/ios/App/Packages/AffineGraphQL/Sources/Schema/CustomScalars/JSON.swift b/packages/frontend/apps/ios/App/Packages/AffineGraphQL/Sources/Schema/CustomScalars/JSON.swift index d987fea99f..e17e2f6a13 100644 --- a/packages/frontend/apps/ios/App/Packages/AffineGraphQL/Sources/Schema/CustomScalars/JSON.swift +++ b/packages/frontend/apps/ios/App/Packages/AffineGraphQL/Sources/Schema/CustomScalars/JSON.swift @@ -8,4 +8,18 @@ import ApolloAPI /// The `JSON` scalar type represents JSON values as specified by [ECMA-404](http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf). -public typealias JSON = String +public struct JSON: CustomScalarType, Hashable, ExpressibleByDictionaryLiteral { + public let value: JSONValue + + public init(_jsonValue value: JSONValue) throws { + self.value = value + } + + public init(dictionaryLiteral elements: (String, JSONValue)...) { + value = ApolloAPI.JSONObject(uniqueKeysWithValues: elements) as JSONValue + } + + public var _jsonValue: JSONValue { + value + } +} diff --git a/packages/frontend/apps/ios/App/Packages/AffineGraphQL/Sources/Schema/CustomScalars/JSONObject.swift b/packages/frontend/apps/ios/App/Packages/AffineGraphQL/Sources/Schema/CustomScalars/JSONObject.swift index b89e7a619a..c1f2c501f4 100644 --- a/packages/frontend/apps/ios/App/Packages/AffineGraphQL/Sources/Schema/CustomScalars/JSONObject.swift +++ b/packages/frontend/apps/ios/App/Packages/AffineGraphQL/Sources/Schema/CustomScalars/JSONObject.swift @@ -8,4 +8,22 @@ import ApolloAPI /// The `JSONObject` scalar type represents JSON objects as specified by [ECMA-404](http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf). -public typealias JSONObject = String +public struct JSONObject: CustomScalarType, Hashable, ExpressibleByDictionaryLiteral { + public let object: ApolloAPI.JSONObject + + public init(_jsonValue value: JSONValue) throws { + object = try ApolloAPI.JSONObject(_jsonValue: value) + } + + public init(_ object: ApolloAPI.JSONObject) { + self.object = object + } + + public init(dictionaryLiteral elements: (String, JSONValue)...) { + object = ApolloAPI.JSONObject(uniqueKeysWithValues: elements) + } + + public var _jsonValue: JSONValue { + object + } +} diff --git a/packages/frontend/apps/ios/App/Packages/Intelligents/Sources/Intelligents/ChatManager/ChatManager+Stream.swift b/packages/frontend/apps/ios/App/Packages/Intelligents/Sources/Intelligents/ChatManager/ChatManager+Stream.swift index 86b3d44063..3730d5e989 100644 --- a/packages/frontend/apps/ios/App/Packages/Intelligents/Sources/Intelligents/ChatManager/ChatManager+Stream.swift +++ b/packages/frontend/apps/ios/App/Packages/Intelligents/Sources/Intelligents/ChatManager/ChatManager+Stream.swift @@ -26,6 +26,7 @@ private extension InputBoxData { } public extension ChatManager { + @MainActor func startUserRequest(editorData: InputBoxData, sessionId: String) { append(sessionId: sessionId, UserMessageCellViewModel( id: .init(), @@ -163,7 +164,7 @@ private extension ChatManager { assert(!Thread.isMainThread) print("[+] starting copilot response for session: \(sessionId)") - let messageParameters: [String: AnyHashable] = [ + let messageParameters: AffineGraphQL.JSON = [ // packages/frontend/core/src/blocksuite/ai/provider/setup-provider.tsx "docs": editorData.documentAttachments.map(\.documentID), // affine doc "files": [String](), // attachment in context, keep nil for now @@ -193,18 +194,14 @@ private extension ChatManager { }, ].flatMap(\.self) assert(uploadableAttachments.allSatisfy { !($0.data?.isEmpty ?? true) }) - guard let input = try? CreateChatMessageInput( + let input = CreateChatMessageInput( attachments: [], blob: attachmentCount == 1 ? "" : .none, blobs: attachmentCount > 1 && attachmentCount != 0 ? .some([]) : .none, content: .some(contextSnippet.isEmpty ? editorData.text : "\(contextSnippet)\n\(editorData.text)"), - params: .some(AffineGraphQL.JSON(_jsonValue: messageParameters)), + params: .some(messageParameters), sessionId: sessionId - ) else { - report(sessionId, ChatError.unknownError) - assertionFailure() // very unlikely to happen - return - } + ) let mutation = CreateCopilotMessageMutation(options: input) QLService.shared.client.upload(operation: mutation, files: uploadableAttachments) { result in print("[*] createCopilotMessage result: \(result)") @@ -277,7 +274,7 @@ private extension ChatManager { let eventSource = EventSource() let dataTask = eventSource.dataTask(for: request) var document = "" - self.writeMarkdownContent(document + loadingIndicator, sessionId: sessionId, vmId: vmId) + await self.writeMarkdownContent(document + loadingIndicator, sessionId: sessionId, vmId: vmId) for await event in dataTask.events() { switch event { case .open: @@ -287,7 +284,7 @@ private extension ChatManager { case let .event(event): guard let data = event.data else { continue } document += data - self.writeMarkdownContent( + await self.writeMarkdownContent( document + loadingIndicator, sessionId: sessionId, vmId: vmId @@ -297,13 +294,13 @@ private extension ChatManager { print("[*] connection closed") } } - self.writeMarkdownContent(document, sessionId: sessionId, vmId: vmId) + await self.writeMarkdownContent(document, sessionId: sessionId, vmId: vmId) self.closeAll() })) self.closable.append(closable) } - private func writeMarkdownContent( + @MainActor private func writeMarkdownContent( _ document: String, sessionId: SessionID, vmId: UUID diff --git a/packages/frontend/apps/ios/App/Packages/Intelligents/Sources/Intelligents/IntelligentContext/IntelligentContext+Markdown.swift b/packages/frontend/apps/ios/App/Packages/Intelligents/Sources/Intelligents/IntelligentContext/IntelligentContext+Markdown.swift index 6246f778bf..c1759a9dec 100644 --- a/packages/frontend/apps/ios/App/Packages/Intelligents/Sources/Intelligents/IntelligentContext/IntelligentContext+Markdown.swift +++ b/packages/frontend/apps/ios/App/Packages/Intelligents/Sources/Intelligents/IntelligentContext/IntelligentContext+Markdown.swift @@ -9,7 +9,7 @@ import Foundation import MarkdownView extension IntelligentContext { - func prepareMarkdownViewThemes() { + @MainActor func prepareMarkdownViewThemes() { MarkdownTheme.default.colors.body = .affineTextPrimary MarkdownTheme.default.colors.highlight = .affineTextLink } diff --git a/packages/frontend/apps/ios/App/Packages/Intelligents/Sources/Intelligents/Interface/View/ChatCell/ViewModel/CCVM+Assistant.swift b/packages/frontend/apps/ios/App/Packages/Intelligents/Sources/Intelligents/Interface/View/ChatCell/ViewModel/CCVM+Assistant.swift index 037a7344de..cbfe5cd937 100644 --- a/packages/frontend/apps/ios/App/Packages/Intelligents/Sources/Intelligents/Interface/View/ChatCell/ViewModel/CCVM+Assistant.swift +++ b/packages/frontend/apps/ios/App/Packages/Intelligents/Sources/Intelligents/Interface/View/ChatCell/ViewModel/CCVM+Assistant.swift @@ -40,7 +40,7 @@ struct AssistantMessageCellViewModel: ChatCellViewModel { var preprocessedContent: MarkdownTextView.PreprocessedContent - init( + @MainActor init( id: UUID, content: String, timestamp: Date, diff --git a/packages/frontend/apps/ios/App/Podfile.lock b/packages/frontend/apps/ios/App/Podfile.lock index e7f8112cbb..861cf00bf9 100644 --- a/packages/frontend/apps/ios/App/Podfile.lock +++ b/packages/frontend/apps/ios/App/Podfile.lock @@ -45,13 +45,13 @@ EXTERNAL SOURCES: :path: "../../../../../node_modules/capacitor-plugin-app-tracking-transparency" SPEC CHECKSUMS: - Capacitor: 12914e6f1b7835e161a74ebd19cb361efa37a7dd - CapacitorApp: 63b237168fc869e758481dba283315a85743ee78 - CapacitorBrowser: b98aa3db018a2ce4c68242d27e596c344f3b81b3 + Capacitor: a5bf59e09f9dd82694fdcca4d107b4d215ac470f + CapacitorApp: 3ddbd30ac18c321531c3da5e707b60873d89dd60 + CapacitorBrowser: 66aa8ff09cdca2a327ce464b113b470e6f667753 CapacitorCordova: 31bbe4466000c6b86d9b7f1181ee286cff0205aa - CapacitorHaptics: ce15be8f287fa2c61c7d2d9e958885b90cf0bebc - CapacitorKeyboard: 5660c760113bfa48962817a785879373cf5339c3 - CapacitorPluginAppTrackingTransparency: 92ae9c1cfb5cf477753db9269689332a686f675a + CapacitorHaptics: d17da7dd984cae34111b3f097ccd3e21f9feec62 + CapacitorKeyboard: 45cae3956a6f4fb1753f9a4df3e884aeaed8fe82 + CapacitorPluginAppTrackingTransparency: 2a2792623a5a72795f2e8f9ab3f1147573732fd8 CryptoSwift: 967f37cea5a3294d9cce358f78861652155be483 PODFILE CHECKSUM: 2c1e4be82121f2d9724ecf7e31dd14e165aeb082 diff --git a/packages/frontend/apps/ios/src/app.tsx b/packages/frontend/apps/ios/src/app.tsx index 8072a85bbb..5a6e4068b5 100644 --- a/packages/frontend/apps/ios/src/app.tsx +++ b/packages/frontend/apps/ios/src/app.tsx @@ -17,6 +17,7 @@ import { SubscriptionService, ValidatorProvider, } from '@affine/core/modules/cloud'; +import { registerNativePreviewHandlers } from '@affine/core/modules/code-block-preview-renderer'; import { DocsService } from '@affine/core/modules/doc'; import { FeatureFlagService } from '@affine/core/modules/feature-flag'; import { GlobalContextService } from '@affine/core/modules/global-context'; @@ -71,6 +72,7 @@ import { Auth } from './plugins/auth'; import { Hashcash } from './plugins/hashcash'; import { NbStoreNativeDBApis } from './plugins/nbstore'; import { PayWall } from './plugins/paywall'; +import { Preview } from './plugins/preview'; import { writeEndpointToken } from './proxy'; import { enableNavigationGesture$ } from './web-navigation-control'; @@ -215,6 +217,11 @@ framework.impl(NativePaywallProvider, { const frameworkProvider = framework.provider(); +registerNativePreviewHandlers({ + renderMermaidSvg: request => Preview.renderMermaidSvg(request), + renderTypstSvg: request => Preview.renderTypstSvg(request), +}); + // ------ some apis for native ------ (window as any).getCurrentServerBaseUrl = () => { const globalContextService = frameworkProvider.get(GlobalContextService); diff --git a/packages/frontend/apps/ios/src/plugins/preview/definitions.ts b/packages/frontend/apps/ios/src/plugins/preview/definitions.ts new file mode 100644 index 0000000000..5e6cfaf26f --- /dev/null +++ b/packages/frontend/apps/ios/src/plugins/preview/definitions.ts @@ -0,0 +1,16 @@ +export interface PreviewPlugin { + renderMermaidSvg(options: { + code: string; + options?: { + theme?: string; + fontFamily?: string; + fontSize?: number; + }; + }): Promise<{ svg: string }>; + renderTypstSvg(options: { + code: string; + options?: { + fontUrls?: string[]; + }; + }): Promise<{ svg: string }>; +} diff --git a/packages/frontend/apps/ios/src/plugins/preview/index.ts b/packages/frontend/apps/ios/src/plugins/preview/index.ts new file mode 100644 index 0000000000..4be99d9096 --- /dev/null +++ b/packages/frontend/apps/ios/src/plugins/preview/index.ts @@ -0,0 +1,8 @@ +import { registerPlugin } from '@capacitor/core'; + +import type { PreviewPlugin } from './definitions'; + +const Preview = registerPlugin('Preview'); + +export * from './definitions'; +export { Preview }; diff --git a/packages/frontend/core/package.json b/packages/frontend/core/package.json index 51c1c01cd1..d4f103dcf9 100644 --- a/packages/frontend/core/package.json +++ b/packages/frontend/core/package.json @@ -47,6 +47,7 @@ "@radix-ui/react-toolbar": "^1.1.1", "@sentry/react": "^10.40.0", "@toeverything/infra": "workspace:*", + "@toeverything/mermaid-wasm": "^0.1.0", "@toeverything/pdf-viewer": "^0.1.1", "@toeverything/theme": "^1.1.23", "@vanilla-extract/dynamic": "^2.1.2", @@ -57,6 +58,7 @@ "cmdk": "^1.0.4", "core-js": "^3.39.0", "dayjs": "^1.11.13", + "dompurify": "^3.3.0", "eventemitter2": "^6.4.9", "file-type": "^21.0.0", "filesize": "^10.1.6", @@ -76,7 +78,7 @@ "lit": "^3.2.1", "lodash-es": "^4.17.23", "lottie-react": "^2.4.0", - "mermaid": "^11.12.2", + "mermaid": "^11.13.0", "mp4-muxer": "^5.2.2", "nanoid": "^5.1.6", "next-themes": "^0.4.4", diff --git a/packages/frontend/core/src/blocksuite/view-extensions/code-block-preview/mermaid-preview.ts b/packages/frontend/core/src/blocksuite/view-extensions/code-block-preview/mermaid-preview.ts index 2c4edf7ae2..366c5641c1 100644 --- a/packages/frontend/core/src/blocksuite/view-extensions/code-block-preview/mermaid-preview.ts +++ b/packages/frontend/core/src/blocksuite/view-extensions/code-block-preview/mermaid-preview.ts @@ -1,3 +1,4 @@ +import { renderMermaidSvg } from '@affine/core/modules/code-block-preview-renderer/bridge'; import { CodeBlockPreviewExtension } from '@blocksuite/affine/blocks/code'; import { SignalWatcher, WithDisposable } from '@blocksuite/affine/global/lit'; import type { CodeBlockModel } from '@blocksuite/affine/model'; @@ -7,7 +8,6 @@ import { css, html, nothing, type PropertyValues } from 'lit'; import { property, query, state } from 'lit/decorators.js'; import { choose } from 'lit/directives/choose.js'; import { styleMap } from 'lit/directives/style-map.js'; -import type { Mermaid } from 'mermaid'; export const CodeBlockMermaidPreview = CodeBlockPreviewExtension( 'mermaid', @@ -154,7 +154,6 @@ export class MermaidPreview extends SignalWatcher( @query('.mermaid-preview-container') accessor container!: HTMLDivElement; - private mermaid: Mermaid | null = null; private retryCount = 0; private readonly maxRetries = 3; private renderTimeout: ReturnType | null = null; @@ -169,9 +168,6 @@ export class MermaidPreview extends SignalWatcher( private lastMouseY = 0; override firstUpdated(_changedProperties: PropertyValues): void { - this._loadMermaid().catch(error => { - console.error('Failed to load mermaid in firstUpdated:', error); - }); this._scheduleRender(); this._setupEventListeners(); @@ -271,7 +267,8 @@ export class MermaidPreview extends SignalWatcher( event.preventDefault(); const delta = event.deltaY > 0 ? 0.9 : 1.1; - const newScale = Math.max(0.1, Math.min(5, this.scale * delta)); + const previousScale = this.scale; + const newScale = Math.max(0.1, Math.min(5, previousScale * delta)); // calculate mouse position relative to container const rect = this.container.getBoundingClientRect(); @@ -284,8 +281,8 @@ export class MermaidPreview extends SignalWatcher( // update transform this.scale = newScale; - this.translateX = mouseX - scaleCenterX * (newScale / this.scale); - this.translateY = mouseY - scaleCenterY * (newScale / this.scale); + this.translateX = mouseX - scaleCenterX * (newScale / previousScale); + this.translateY = mouseY - scaleCenterY * (newScale / previousScale); this._updateTransform(); }; @@ -309,44 +306,6 @@ export class MermaidPreview extends SignalWatcher( ); } - private async _loadMermaid() { - try { - // dynamic load mermaid - const mermaidModule = await import('mermaid'); - this.mermaid = mermaidModule.default; - - // initialize mermaid - this.mermaid.initialize({ - startOnLoad: false, - theme: 'default', - securityLevel: 'strict', - fontFamily: 'IBM Plex Mono', - flowchart: { - useMaxWidth: true, - htmlLabels: true, - }, - sequence: { - useMaxWidth: true, - }, - gantt: { - useMaxWidth: true, - }, - pie: { - useMaxWidth: true, - }, - journey: { - useMaxWidth: true, - }, - gitGraph: { - useMaxWidth: true, - }, - }); - } catch (error) { - console.error('Failed to load mermaid:', error); - this.state = 'error'; - } - } - private async _render() { // prevent duplicate rendering if (this.isRendering) { @@ -356,28 +315,25 @@ export class MermaidPreview extends SignalWatcher( this.isRendering = true; this.state = 'loading'; - if (!this.normalizedMermaidCode) { + const code = this.normalizedMermaidCode?.trim(); + + if (!code) { + this.svgContent = ''; this.state = 'fallback'; this.isRendering = false; return; } - if (!this.mermaid) { - await this._loadMermaid(); - } - if (!this.mermaid) { - return; - } - try { - // generate unique ID - const diagramId = `mermaid-diagram-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`; - - // generate SVG - const { svg } = await this.mermaid.render( - diagramId, - this.normalizedMermaidCode - ); + const { svg } = await renderMermaidSvg({ + code, + options: { + fastText: true, + svgOnly: true, + theme: 'default', + fontFamily: 'IBM Plex Mono', + }, + }); // update SVG content this.svgContent = svg; diff --git a/packages/frontend/core/src/blocksuite/view-extensions/code-block-preview/typst-preview.ts b/packages/frontend/core/src/blocksuite/view-extensions/code-block-preview/typst-preview.ts index 7da66135cd..38d430bb6d 100644 --- a/packages/frontend/core/src/blocksuite/view-extensions/code-block-preview/typst-preview.ts +++ b/packages/frontend/core/src/blocksuite/view-extensions/code-block-preview/typst-preview.ts @@ -1,3 +1,4 @@ +import { renderTypstSvg } from '@affine/core/modules/code-block-preview-renderer/bridge'; import { CodeBlockPreviewExtension } from '@blocksuite/affine/blocks/code'; import { SignalWatcher, WithDisposable } from '@blocksuite/affine/global/lit'; import type { CodeBlockModel } from '@blocksuite/affine/model'; @@ -8,8 +9,6 @@ import { property, query, state } from 'lit/decorators.js'; import { choose } from 'lit/directives/choose.js'; import { styleMap } from 'lit/directives/style-map.js'; -import { ensureTypstReady, getTypst } from './typst'; - const RENDER_DEBOUNCE_MS = 200; export const CodeBlockTypstPreview = CodeBlockPreviewExtension( @@ -378,9 +377,7 @@ ${this.errorMessage} [ - loadFonts([...FONT_CDN_URLS]), -]; - -const compilerWasmUrl = new URL( - '@myriaddreamin/typst-ts-web-compiler/pkg/typst_ts_web_compiler_bg.wasm', - import.meta.url -).toString(); - -const rendererWasmUrl = new URL( - '@myriaddreamin/typst-ts-renderer/pkg/typst_ts_renderer_bg.wasm', - import.meta.url -).toString(); - -let typstInitPromise: Promise | null = null; - -export async function ensureTypstReady() { - if (typstInitPromise) { - return typstInitPromise; - } - - typstInitPromise = Promise.resolve() - .then(() => { - $typst.setCompilerInitOptions({ - beforeBuild: getBeforeBuildHooks(), - getModule: () => compilerWasmUrl, - }); - - $typst.setRendererInitOptions({ - beforeBuild: getBeforeBuildHooks(), - getModule: () => rendererWasmUrl, - }); - }) - .catch(error => { - typstInitPromise = null; - throw error; - }); - - return typstInitPromise; -} - -export async function getTypst() { - await ensureTypstReady(); - return $typst; -} - -export const TYPST_FONT_URLS = FONT_CDN_URLS; diff --git a/packages/frontend/core/src/modules/code-block-preview-renderer/bridge.spec.ts b/packages/frontend/core/src/modules/code-block-preview-renderer/bridge.spec.ts new file mode 100644 index 0000000000..d9dad6232c --- /dev/null +++ b/packages/frontend/core/src/modules/code-block-preview-renderer/bridge.spec.ts @@ -0,0 +1,74 @@ +import { beforeEach, describe, expect, test, vi } from 'vitest'; + +const { mermaidRender, typstRender } = vi.hoisted(() => ({ + mermaidRender: vi.fn(), + typstRender: vi.fn(), +})); + +const { domPurifySanitize } = vi.hoisted(() => ({ + domPurifySanitize: vi.fn((value: unknown) => { + if (typeof value !== 'string') { + return ''; + } + return value.replace(//gi, ''); + }), +})); + +vi.mock( + '@affine/core/modules/code-block-preview-renderer/platform-backend', + () => ({ + renderMermaidSvgBackend: mermaidRender, + renderTypstSvgBackend: typstRender, + }) +); + +vi.mock('dompurify', () => ({ + default: { + sanitize: domPurifySanitize, + }, +})); + +import { renderMermaidSvg, renderTypstSvg } from './bridge'; + +describe('preview render bridge', () => { + beforeEach(() => { + vi.clearAllMocks(); + domPurifySanitize.mockImplementation((value: unknown) => { + if (typeof value !== 'string') { + return ''; + } + return value.replace(//gi, ''); + }); + }); + + test('uses worker renderers and only sanitizes mermaid output', async () => { + mermaidRender.mockResolvedValue({ + svg: 'mermaid', + }); + typstRender.mockResolvedValue({ + svg: '
typst
', + }); + + const mermaid = await renderMermaidSvg({ code: 'flowchart TD;A-->B' }); + const typst = await renderTypstSvg({ code: '= Title' }); + + expect(mermaidRender).toHaveBeenCalledTimes(1); + expect(typstRender).toHaveBeenCalledTimes(1); + expect(mermaid.svg).toContain('typst' + ); + }); + + test('throws when sanitized svg is empty', async () => { + mermaidRender.mockResolvedValue({ + svg: '
invalid
', + }); + + await expect( + renderMermaidSvg({ code: 'flowchart TD;A-->B' }) + ).rejects.toThrow('Preview renderer returned invalid SVG.'); + }); +}); diff --git a/packages/frontend/core/src/modules/code-block-preview-renderer/bridge.ts b/packages/frontend/core/src/modules/code-block-preview-renderer/bridge.ts new file mode 100644 index 0000000000..a6b531bed4 --- /dev/null +++ b/packages/frontend/core/src/modules/code-block-preview-renderer/bridge.ts @@ -0,0 +1,68 @@ +import { + renderMermaidSvgBackend, + renderTypstSvgBackend, +} from '@affine/core/modules/code-block-preview-renderer/platform-backend'; +import type { + MermaidRenderRequest, + MermaidRenderResult, +} from '@affine/core/modules/mermaid/renderer'; +import type { + TypstRenderRequest, + TypstRenderResult, +} from '@affine/core/modules/typst/renderer'; +import DOMPurify from 'dompurify'; + +function removeForeignObject(root: ParentNode) { + root + .querySelectorAll('foreignObject, foreignobject') + .forEach(element => element.remove()); +} + +export function sanitizeSvg(svg: string): string { + if ( + typeof DOMParser === 'undefined' || + typeof XMLSerializer === 'undefined' + ) { + const sanitized = DOMPurify.sanitize(svg, { USE_PROFILES: { svg: true } }); + if (typeof sanitized !== 'string' || !/^\s*]/i.test(sanitized)) { + return ''; + } + return sanitized.trim(); + } + + const parser = new DOMParser(); + const parsed = parser.parseFromString(svg, 'image/svg+xml'); + const root = parsed.documentElement; + if (!root || root.tagName.toLowerCase() !== 'svg') return ''; + + const sanitized = DOMPurify.sanitize(root, { USE_PROFILES: { svg: true } }); + if (typeof sanitized !== 'string') return ''; + + const sanitizedDoc = parser.parseFromString(sanitized, 'image/svg+xml'); + const sanitizedRoot = sanitizedDoc.documentElement; + if (!sanitizedRoot || sanitizedRoot.tagName.toLowerCase() !== 'svg') + return ''; + + removeForeignObject(sanitizedRoot); + return new XMLSerializer().serializeToString(sanitizedRoot).trim(); +} + +export async function renderMermaidSvg( + request: MermaidRenderRequest +): Promise { + const rendered = await renderMermaidSvgBackend(request); + + const sanitizedSvg = sanitizeSvg(rendered.svg); + if (!sanitizedSvg) { + throw new Error('Preview renderer returned invalid SVG.'); + } + return { svg: sanitizedSvg }; +} + +export async function renderTypstSvg( + request: TypstRenderRequest +): Promise { + const rendered = await renderTypstSvgBackend(request); + + return { svg: rendered.svg }; +} diff --git a/packages/frontend/core/src/modules/code-block-preview-renderer/classic-mermaid.spec.ts b/packages/frontend/core/src/modules/code-block-preview-renderer/classic-mermaid.spec.ts new file mode 100644 index 0000000000..5d7711ac84 --- /dev/null +++ b/packages/frontend/core/src/modules/code-block-preview-renderer/classic-mermaid.spec.ts @@ -0,0 +1,68 @@ +import { beforeEach, describe, expect, test, vi } from 'vitest'; + +const { initialize, render } = vi.hoisted(() => ({ + initialize: vi.fn(), + render: vi.fn(), +})); + +vi.mock('mermaid', () => ({ + default: { + initialize, + render, + }, +})); + +import { renderClassicMermaidSvg } from './classic-mermaid'; + +describe('renderClassicMermaidSvg', () => { + beforeEach(() => { + vi.clearAllMocks(); + }); + + test('serializes initialize and render across concurrent calls', async () => { + const events: string[] = []; + let releaseFirstRender!: () => void; + + initialize.mockImplementation(config => { + events.push(`init:${config.theme}`); + }); + render + .mockImplementationOnce(async () => { + events.push('render:first:start'); + await new Promise(resolve => { + releaseFirstRender = resolve; + }); + events.push('render:first:end'); + return { svg: 'first' }; + }) + .mockImplementationOnce(async () => { + events.push('render:second:start'); + return { svg: 'second' }; + }); + + const first = renderClassicMermaidSvg({ + code: 'flowchart TD;A-->B', + options: { theme: 'default' }, + }); + const second = renderClassicMermaidSvg({ + code: 'flowchart TD;B-->C', + options: { theme: 'modern' }, + }); + + await vi.waitFor(() => { + expect(events).toEqual(['init:default', 'render:first:start']); + }); + + releaseFirstRender(); + + await expect(first).resolves.toEqual({ svg: 'first' }); + await expect(second).resolves.toEqual({ svg: 'second' }); + expect(events).toEqual([ + 'init:default', + 'render:first:start', + 'render:first:end', + 'init:base', + 'render:second:start', + ]); + }); +}); diff --git a/packages/frontend/core/src/modules/code-block-preview-renderer/classic-mermaid.ts b/packages/frontend/core/src/modules/code-block-preview-renderer/classic-mermaid.ts new file mode 100644 index 0000000000..5f21964741 --- /dev/null +++ b/packages/frontend/core/src/modules/code-block-preview-renderer/classic-mermaid.ts @@ -0,0 +1,62 @@ +import type { Mermaid } from 'mermaid'; + +import type { + MermaidRenderOptions, + MermaidRenderRequest, + MermaidRenderResult, + MermaidRenderTheme, +} from '../mermaid/renderer'; + +let mermaidPromise: Promise | null = null; +let mermaidRenderQueue: Promise = Promise.resolve(); + +function toTheme(theme: MermaidRenderTheme | undefined) { + return theme === 'modern' ? ('base' as const) : ('default' as const); +} + +function createClassicMermaidConfig(options?: MermaidRenderOptions) { + return { + startOnLoad: false, + theme: toTheme(options?.theme), + securityLevel: 'strict' as const, + fontFamily: options?.fontFamily ?? 'IBM Plex Mono', + flowchart: { useMaxWidth: true, htmlLabels: true }, + sequence: { useMaxWidth: true }, + gantt: { useMaxWidth: true }, + pie: { useMaxWidth: true }, + journey: { useMaxWidth: true }, + gitGraph: { useMaxWidth: true }, + }; +} + +async function loadMermaid() { + if (!mermaidPromise) { + mermaidPromise = import('mermaid').then(module => module.default); + } + return mermaidPromise; +} + +function createDiagramId() { + return `mermaid-diagram-${Date.now()}-${Math.random().toString(36).slice(2)}`; +} + +function enqueueClassicMermaidRender(task: () => Promise): Promise { + const run = mermaidRenderQueue.then(task, task); + mermaidRenderQueue = run.then( + () => undefined, + () => undefined + ); + return run; +} + +export async function renderClassicMermaidSvg( + request: MermaidRenderRequest +): Promise { + return enqueueClassicMermaidRender(async () => { + const mermaid = await loadMermaid(); + mermaid.initialize(createClassicMermaidConfig(request.options)); + + const { svg } = await mermaid.render(createDiagramId(), request.code); + return { svg }; + }); +} diff --git a/packages/frontend/core/src/modules/code-block-preview-renderer/index.ts b/packages/frontend/core/src/modules/code-block-preview-renderer/index.ts new file mode 100644 index 0000000000..71cd93bcf7 --- /dev/null +++ b/packages/frontend/core/src/modules/code-block-preview-renderer/index.ts @@ -0,0 +1,14 @@ +import type { Framework } from '@toeverything/infra'; + +import { FeatureFlagService } from '../feature-flag'; +import { PreviewRendererFeatureSyncService } from './services/preview-renderer-feature-sync'; + +export { renderMermaidSvg, renderTypstSvg, sanitizeSvg } from './bridge'; +export { + registerNativePreviewHandlers, + setMermaidWasmNativeRendererEnabled, +} from './runtime-config'; + +export function configureCodeBlockPreviewRendererModule(framework: Framework) { + framework.service(PreviewRendererFeatureSyncService, [FeatureFlagService]); +} diff --git a/packages/frontend/core/src/modules/code-block-preview-renderer/platform-backend.desktop.ts b/packages/frontend/core/src/modules/code-block-preview-renderer/platform-backend.desktop.ts new file mode 100644 index 0000000000..410c111b7b --- /dev/null +++ b/packages/frontend/core/src/modules/code-block-preview-renderer/platform-backend.desktop.ts @@ -0,0 +1,52 @@ +import { apis } from '@affine/electron-api'; + +import { renderClassicMermaidSvg } from './classic-mermaid'; +import { isMermaidWasmNativeRendererEnabled } from './runtime-config'; +import type { PreviewRenderRequestMap, PreviewRenderResultMap } from './types'; + +type DesktopPreviewHandlers = { + renderMermaidSvg?: ( + request: PreviewRenderRequestMap['mermaid'] + ) => Promise; + renderTypstSvg?: ( + request: PreviewRenderRequestMap['typst'] + ) => Promise; +}; + +type DesktopPreviewApis = { + preview?: DesktopPreviewHandlers; +}; + +function getDesktopPreviewHandlers() { + const previewApis = apis as unknown as DesktopPreviewApis; + return previewApis.preview ?? null; +} + +function getRequiredDesktopHandler( + name: Name +): NonNullable { + const handlers = getDesktopPreviewHandlers(); + const handler = handlers?.[name]; + if (!handler) { + throw new Error( + `Electron preview handler "${String(name)}" is unavailable.` + ); + } + return handler as NonNullable; +} + +export async function renderMermaidSvgBackend( + request: PreviewRenderRequestMap['mermaid'] +): Promise { + if (!isMermaidWasmNativeRendererEnabled()) { + return renderClassicMermaidSvg(request); + } + + return getRequiredDesktopHandler('renderMermaidSvg')(request); +} + +export async function renderTypstSvgBackend( + request: PreviewRenderRequestMap['typst'] +): Promise { + return getRequiredDesktopHandler('renderTypstSvg')(request); +} diff --git a/packages/frontend/core/src/modules/code-block-preview-renderer/platform-backend.mobile.ts b/packages/frontend/core/src/modules/code-block-preview-renderer/platform-backend.mobile.ts new file mode 100644 index 0000000000..c8b2e4073e --- /dev/null +++ b/packages/frontend/core/src/modules/code-block-preview-renderer/platform-backend.mobile.ts @@ -0,0 +1,24 @@ +import { getNativePreviewHandlers } from './runtime-config'; +import type { PreviewRenderRequestMap, PreviewRenderResultMap } from './types'; + +function getRequiredNativeHandler< + Name extends keyof NonNullable>, +>(name: Name) { + const handler = getNativePreviewHandlers()?.[name]; + if (!handler) { + throw new Error(`Mobile preview handler "${String(name)}" is unavailable.`); + } + return handler; +} + +export async function renderMermaidSvgBackend( + request: PreviewRenderRequestMap['mermaid'] +): Promise { + return getRequiredNativeHandler('renderMermaidSvg')(request); +} + +export async function renderTypstSvgBackend( + request: PreviewRenderRequestMap['typst'] +): Promise { + return getRequiredNativeHandler('renderTypstSvg')(request); +} diff --git a/packages/frontend/core/src/modules/code-block-preview-renderer/platform-backend.ts b/packages/frontend/core/src/modules/code-block-preview-renderer/platform-backend.ts new file mode 100644 index 0000000000..a64df9827e --- /dev/null +++ b/packages/frontend/core/src/modules/code-block-preview-renderer/platform-backend.ts @@ -0,0 +1,22 @@ +import { getMermaidRenderer } from '@affine/core/modules/mermaid/renderer'; +import { getTypstRenderer } from '@affine/core/modules/typst/renderer'; + +import { renderClassicMermaidSvg } from './classic-mermaid'; +import { isMermaidWasmNativeRendererEnabled } from './runtime-config'; +import type { PreviewRenderRequestMap, PreviewRenderResultMap } from './types'; + +export async function renderMermaidSvgBackend( + request: PreviewRenderRequestMap['mermaid'] +): Promise { + if (!isMermaidWasmNativeRendererEnabled()) { + return renderClassicMermaidSvg(request); + } + + return getMermaidRenderer().render(request); +} + +export async function renderTypstSvgBackend( + request: PreviewRenderRequestMap['typst'] +): Promise { + return getTypstRenderer().render(request); +} diff --git a/packages/frontend/core/src/modules/code-block-preview-renderer/runtime-config.ts b/packages/frontend/core/src/modules/code-block-preview-renderer/runtime-config.ts new file mode 100644 index 0000000000..eb27570f39 --- /dev/null +++ b/packages/frontend/core/src/modules/code-block-preview-renderer/runtime-config.ts @@ -0,0 +1,39 @@ +import type { + MermaidRenderRequest, + MermaidRenderResult, +} from '@affine/core/modules/mermaid/renderer'; +import type { + TypstRenderRequest, + TypstRenderResult, +} from '@affine/core/modules/typst/renderer'; + +type NativePreviewHandlers = { + renderMermaidSvg?: ( + request: MermaidRenderRequest + ) => Promise; + renderTypstSvg?: (request: TypstRenderRequest) => Promise; +}; + +let enableMermaidWasmNativeRenderer = + BUILD_CONFIG.isIOS || BUILD_CONFIG.isAndroid; +let nativePreviewHandlers: NativePreviewHandlers | null = null; + +export function setMermaidWasmNativeRendererEnabled(enabled: boolean) { + enableMermaidWasmNativeRenderer = enabled; +} + +export function isMermaidWasmNativeRendererEnabled() { + return enableMermaidWasmNativeRenderer; +} + +export function registerNativePreviewHandlers( + handlers: NativePreviewHandlers | null +) { + nativePreviewHandlers = handlers; +} + +export function getNativePreviewHandlers() { + return nativePreviewHandlers; +} + +export type { NativePreviewHandlers }; diff --git a/packages/frontend/core/src/modules/code-block-preview-renderer/services/preview-renderer-feature-sync.ts b/packages/frontend/core/src/modules/code-block-preview-renderer/services/preview-renderer-feature-sync.ts new file mode 100644 index 0000000000..9c5e223cf3 --- /dev/null +++ b/packages/frontend/core/src/modules/code-block-preview-renderer/services/preview-renderer-feature-sync.ts @@ -0,0 +1,26 @@ +import { OnEvent, Service } from '@toeverything/infra'; +import { distinctUntilChanged } from 'rxjs'; + +import type { FeatureFlagService } from '../../feature-flag'; +import { ApplicationStarted } from '../../lifecycle'; +import { setMermaidWasmNativeRendererEnabled } from '../runtime-config'; + +@OnEvent(ApplicationStarted, e => e.syncFlag) +export class PreviewRendererFeatureSyncService extends Service { + constructor(private readonly featureFlagService: FeatureFlagService) { + super(); + } + + syncFlag() { + const mermaidFlag = + this.featureFlagService.flags.enable_mermaid_wasm_native_renderer; + + setMermaidWasmNativeRendererEnabled(!!mermaidFlag.value); + const subscription = mermaidFlag.$.pipe(distinctUntilChanged()).subscribe( + enabled => { + setMermaidWasmNativeRendererEnabled(!!enabled); + } + ); + this.disposables.push(() => subscription.unsubscribe()); + } +} diff --git a/packages/frontend/core/src/modules/code-block-preview-renderer/types.ts b/packages/frontend/core/src/modules/code-block-preview-renderer/types.ts new file mode 100644 index 0000000000..24cc4bd04e --- /dev/null +++ b/packages/frontend/core/src/modules/code-block-preview-renderer/types.ts @@ -0,0 +1,18 @@ +import type { + MermaidRenderRequest, + MermaidRenderResult, +} from '@affine/core/modules/mermaid/renderer'; +import type { + TypstRenderRequest, + TypstRenderResult, +} from '@affine/core/modules/typst/renderer'; + +export type PreviewRenderRequestMap = { + mermaid: MermaidRenderRequest; + typst: TypstRenderRequest; +}; + +export type PreviewRenderResultMap = { + mermaid: MermaidRenderResult; + typst: TypstRenderResult; +}; diff --git a/packages/frontend/core/src/modules/feature-flag/constant.ts b/packages/frontend/core/src/modules/feature-flag/constant.ts index 394fde4af1..d239648974 100644 --- a/packages/frontend/core/src/modules/feature-flag/constant.ts +++ b/packages/frontend/core/src/modules/feature-flag/constant.ts @@ -4,6 +4,7 @@ import type { FlagInfo } from './types'; const isCanaryBuild = BUILD_CONFIG.appBuildType === 'canary'; const isMobile = BUILD_CONFIG.isMobileEdition; const isIOS = BUILD_CONFIG.isIOS; +const isAndroid = BUILD_CONFIG.isAndroid; export const AFFINE_FLAGS = { enable_ai: { @@ -203,6 +204,14 @@ export const AFFINE_FLAGS = { configurable: isMobile && isIOS, defaultState: isMobile && isIOS, }, + enable_mermaid_wasm_native_renderer: { + category: 'affine', + displayName: 'Enable Native Mermaid Renderer', + description: + 'Use the new Mermaid renderer backend. Web uses WASM, desktop uses native, and mobile always uses native. The native renderer is more than 10x faster, but its styling/aesthetic quality and the types of graphics it supports are not as good as the JS version.', + configurable: !isIOS && !isAndroid, + defaultState: isIOS || isAndroid, + }, enable_turbo_renderer: { category: 'blocksuite', bsFlag: 'enable_turbo_renderer', diff --git a/packages/frontend/core/src/modules/index.ts b/packages/frontend/core/src/modules/index.ts index 5104cbc98e..f56190df24 100644 --- a/packages/frontend/core/src/modules/index.ts +++ b/packages/frontend/core/src/modules/index.ts @@ -13,6 +13,7 @@ import { configureAppSidebarModule } from './app-sidebar'; import { configAtMenuConfigModule } from './at-menu-config'; import { configureBlobManagementModule } from './blob-management'; import { configureCloudModule } from './cloud'; +import { configureCodeBlockPreviewRendererModule } from './code-block-preview-renderer'; import { configureCollectionModule } from './collection'; import { configureCollectionRulesModule } from './collection-rules'; import { configureCommentModule } from './comment'; @@ -77,6 +78,7 @@ export function configureCommonModules(framework: Framework) { configureGlobalContextModule(framework); configureLifecycleModule(framework); configureFeatureFlagModule(framework); + configureCodeBlockPreviewRendererModule(framework); configureCollectionModule(framework); configureNavigationModule(framework); configureTagModule(framework); diff --git a/packages/frontend/core/src/modules/mermaid/renderer/index.ts b/packages/frontend/core/src/modules/mermaid/renderer/index.ts new file mode 100644 index 0000000000..a8d8e6bbeb --- /dev/null +++ b/packages/frontend/core/src/modules/mermaid/renderer/index.ts @@ -0,0 +1,39 @@ +import { WorkerOpRenderer } from '../../shared/worker-op-renderer'; +import type { + MermaidOps, + MermaidRenderOptions, + MermaidRenderRequest, +} from './types'; + +class MermaidRenderer extends WorkerOpRenderer { + constructor() { + super('mermaid'); + } + + init(options?: MermaidRenderOptions) { + return this.ensureInitialized(() => this.call('init', options)); + } + + async render(request: MermaidRenderRequest) { + await this.init(); + return this.call('render', request); + } +} + +let sharedMermaidRenderer: MermaidRenderer | null = null; + +export function getMermaidRenderer() { + if (!sharedMermaidRenderer) { + sharedMermaidRenderer = new MermaidRenderer(); + } + return sharedMermaidRenderer; +} + +export type { + MermaidOps, + MermaidRenderOptions, + MermaidRenderRequest, + MermaidRenderResult, + MermaidRenderTheme, + MermaidTextMetrics, +} from './types'; diff --git a/packages/frontend/core/src/modules/mermaid/renderer/mermaid.worker.ts b/packages/frontend/core/src/modules/mermaid/renderer/mermaid.worker.ts new file mode 100644 index 0000000000..387b29dc88 --- /dev/null +++ b/packages/frontend/core/src/modules/mermaid/renderer/mermaid.worker.ts @@ -0,0 +1,63 @@ +import type { MessageCommunicapable } from '@toeverything/infra/op'; +import { OpConsumer } from '@toeverything/infra/op'; +import initMmdr, { render_mermaid_svg } from '@toeverything/mermaid-wasm'; + +import type { + MermaidOps, + MermaidRenderOptions, + MermaidRenderRequest, +} from './types'; + +const DEFAULT_RENDER_OPTIONS: MermaidRenderOptions = { + fastText: true, + svgOnly: true, + theme: 'modern', + fontFamily: 'IBM Plex Mono', +}; + +function mergeOptions( + base: MermaidRenderOptions, + override: MermaidRenderOptions | undefined +): MermaidRenderOptions { + if (!override) { + return base; + } + return { + ...base, + ...override, + textMetrics: override.textMetrics ?? base.textMetrics, + }; +} + +class MermaidRendererBackend extends OpConsumer { + private initPromise: Promise | null = null; + private options: MermaidRenderOptions = DEFAULT_RENDER_OPTIONS; + + constructor(port: MessageCommunicapable) { + super(port); + this.register('init', this.init.bind(this)); + this.register('render', this.render.bind(this)); + } + + private ensureReady() { + if (!this.initPromise) { + this.initPromise = initMmdr().then(() => undefined); + } + return this.initPromise; + } + + async init(options?: MermaidRenderOptions) { + this.options = mergeOptions(DEFAULT_RENDER_OPTIONS, options); + await this.ensureReady(); + return { ok: true } as const; + } + + async render({ code, options }: MermaidRenderRequest) { + await this.ensureReady(); + const mergedOptions = mergeOptions(this.options, options); + const svg = render_mermaid_svg(code, JSON.stringify(mergedOptions)); + return { svg }; + } +} + +new MermaidRendererBackend(self as MessageCommunicapable); diff --git a/packages/frontend/core/src/modules/mermaid/renderer/types.ts b/packages/frontend/core/src/modules/mermaid/renderer/types.ts new file mode 100644 index 0000000000..6622bf9f55 --- /dev/null +++ b/packages/frontend/core/src/modules/mermaid/renderer/types.ts @@ -0,0 +1,32 @@ +import type { OpSchema } from '@toeverything/infra/op'; + +export type MermaidTextMetrics = { + ascii: number; + cjk: number; + space: number; +}; + +export type MermaidRenderTheme = 'modern' | 'default'; + +export type MermaidRenderOptions = { + fastText?: boolean; + svgOnly?: boolean; + textMetrics?: MermaidTextMetrics; + theme?: MermaidRenderTheme; + fontFamily?: string; + fontSize?: number; +}; + +export type MermaidRenderRequest = { + code: string; + options?: MermaidRenderOptions; +}; + +export type MermaidRenderResult = { + svg: string; +}; + +export interface MermaidOps extends OpSchema { + init: [MermaidRenderOptions | undefined, { ok: true }]; + render: [MermaidRenderRequest, MermaidRenderResult]; +} diff --git a/packages/frontend/core/src/modules/pdf/renderer/index.ts b/packages/frontend/core/src/modules/pdf/renderer/index.ts index 00c4e992f4..fd9aa8aa38 100644 --- a/packages/frontend/core/src/modules/pdf/renderer/index.ts +++ b/packages/frontend/core/src/modules/pdf/renderer/index.ts @@ -1,2 +1,10 @@ -export { PDFRenderer } from './renderer'; -export type { PDFMeta, RenderedPage, RenderPageOpts } from './types'; +import { WorkerOpRenderer } from '../../shared/worker-op-renderer'; +import type { PDFOps } from './types'; + +export class PDFRenderer extends WorkerOpRenderer { + constructor() { + super('pdf'); + } +} + +export type { PDFMeta, PDFOps, RenderedPage, RenderPageOpts } from './types'; diff --git a/packages/frontend/core/src/modules/pdf/renderer/ops.ts b/packages/frontend/core/src/modules/pdf/renderer/ops.ts deleted file mode 100644 index 946fa6b245..0000000000 --- a/packages/frontend/core/src/modules/pdf/renderer/ops.ts +++ /dev/null @@ -1,8 +0,0 @@ -import type { OpSchema } from '@toeverything/infra/op'; - -import type { PDFMeta, RenderedPage, RenderPageOpts } from './types'; - -export interface ClientOps extends OpSchema { - open: [{ data: ArrayBuffer }, PDFMeta]; - render: [RenderPageOpts, RenderedPage]; -} diff --git a/packages/frontend/core/src/modules/pdf/renderer/pdf.worker.ts b/packages/frontend/core/src/modules/pdf/renderer/pdf.worker.ts index ec01ae04ce..e185cf350a 100644 --- a/packages/frontend/core/src/modules/pdf/renderer/pdf.worker.ts +++ b/packages/frontend/core/src/modules/pdf/renderer/pdf.worker.ts @@ -23,10 +23,9 @@ import { switchMap, } from 'rxjs'; -import type { ClientOps } from './ops'; -import type { PDFMeta, RenderPageOpts } from './types'; +import type { PDFMeta, PDFOps, RenderPageOpts } from './types'; -class PDFRendererBackend extends OpConsumer { +class PDFRendererBackend extends OpConsumer { constructor(port: MessageCommunicapable) { super(port); this.register('open', this.open.bind(this)); diff --git a/packages/frontend/core/src/modules/pdf/renderer/renderer.ts b/packages/frontend/core/src/modules/pdf/renderer/renderer.ts deleted file mode 100644 index 8029980f47..0000000000 --- a/packages/frontend/core/src/modules/pdf/renderer/renderer.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { getWorkerUrl } from '@affine/env/worker'; -import { OpClient } from '@toeverything/infra/op'; - -import type { ClientOps } from './ops'; - -export class PDFRenderer extends OpClient { - private readonly worker: Worker; - - constructor() { - const worker = new Worker(getWorkerUrl('pdf')); - super(worker); - - this.worker = worker; - } - - override destroy() { - super.destroy(); - this.worker.terminate(); - } - - [Symbol.dispose]() { - this.destroy(); - } -} diff --git a/packages/frontend/core/src/modules/pdf/renderer/types.ts b/packages/frontend/core/src/modules/pdf/renderer/types.ts index 6ade529ce6..75365fdddc 100644 --- a/packages/frontend/core/src/modules/pdf/renderer/types.ts +++ b/packages/frontend/core/src/modules/pdf/renderer/types.ts @@ -1,3 +1,5 @@ +import type { OpSchema } from '@toeverything/infra/op'; + export type PageSize = { width: number; height: number; @@ -21,3 +23,8 @@ export type RenderPageOpts = { export type RenderedPage = { bitmap: ImageBitmap; }; + +export interface PDFOps extends OpSchema { + open: [{ data: ArrayBuffer }, PDFMeta]; + render: [RenderPageOpts, RenderedPage]; +} diff --git a/packages/frontend/core/src/modules/shared/worker-op-renderer.spec.ts b/packages/frontend/core/src/modules/shared/worker-op-renderer.spec.ts new file mode 100644 index 0000000000..27898acace --- /dev/null +++ b/packages/frontend/core/src/modules/shared/worker-op-renderer.spec.ts @@ -0,0 +1,42 @@ +import { beforeEach, describe, expect, test, vi } from 'vitest'; + +import { WorkerOpRenderer } from './worker-op-renderer'; + +vi.mock('@affine/env/worker', () => ({ + getWorkerUrl: vi.fn(() => '/worker.js'), +})); + +class MockWorker { + addEventListener = vi.fn(); + postMessage = vi.fn(); + removeEventListener = vi.fn(); + terminate = vi.fn(); +} + +class TestRenderer extends WorkerOpRenderer<{ + init: [undefined, { ok: true }]; +}> { + constructor() { + super('test'); + } + + init() { + return this.ensureInitialized(async () => { + return { ok: true } as const; + }); + } +} + +describe('WorkerOpRenderer', () => { + beforeEach(() => { + vi.stubGlobal('Worker', MockWorker); + }); + + test('rejects initialization after destroy', async () => { + const renderer = new TestRenderer(); + + renderer.destroy(); + + await expect(renderer.init()).rejects.toThrow('renderer destroyed'); + }); +}); diff --git a/packages/frontend/core/src/modules/shared/worker-op-renderer.ts b/packages/frontend/core/src/modules/shared/worker-op-renderer.ts new file mode 100644 index 0000000000..b937092986 --- /dev/null +++ b/packages/frontend/core/src/modules/shared/worker-op-renderer.ts @@ -0,0 +1,47 @@ +import { getWorkerUrl } from '@affine/env/worker'; +import { OpClient, type OpSchema } from '@toeverything/infra/op'; + +type InitTask = () => Promise; + +export abstract class WorkerOpRenderer< + Ops extends OpSchema, +> extends OpClient { + private readonly worker: Worker; + private destroyed = false; + private initPromise: Promise | null = null; + + protected constructor(workerName: string) { + const worker = new Worker(getWorkerUrl(workerName)); + super(worker); + this.worker = worker; + } + + protected ensureInitialized(task: InitTask) { + if (this.destroyed) return Promise.reject(new Error('renderer destroyed')); + if (!this.initPromise) { + this.initPromise = task() + .then(() => undefined) + .catch(error => { + this.initPromise = null; + throw error; + }); + } + return this.initPromise; + } + + protected resetInitialization() { + this.initPromise = null; + } + + override destroy() { + if (this.destroyed) return; + this.destroyed = true; + super.destroy(); + this.worker.terminate(); + this.resetInitialization(); + } + + [Symbol.dispose]() { + this.destroy(); + } +} diff --git a/packages/frontend/core/src/modules/typst/renderer/index.ts b/packages/frontend/core/src/modules/typst/renderer/index.ts new file mode 100644 index 0000000000..27d02bcb73 --- /dev/null +++ b/packages/frontend/core/src/modules/typst/renderer/index.ts @@ -0,0 +1,33 @@ +import { WorkerOpRenderer } from '../../shared/worker-op-renderer'; +import type { TypstOps, TypstRenderOptions, TypstRenderRequest } from './types'; + +class TypstRenderer extends WorkerOpRenderer { + constructor() { + super('typst'); + } + + init(options?: TypstRenderOptions) { + return this.ensureInitialized(() => this.call('init', options)); + } + + async render(request: TypstRenderRequest) { + await this.init(); + return this.call('render', request); + } +} + +let sharedTypstRenderer: TypstRenderer | null = null; + +export function getTypstRenderer() { + if (!sharedTypstRenderer) { + sharedTypstRenderer = new TypstRenderer(); + } + return sharedTypstRenderer; +} + +export type { + TypstOps, + TypstRenderOptions, + TypstRenderRequest, + TypstRenderResult, +} from './types'; diff --git a/packages/frontend/core/src/modules/typst/renderer/runtime.spec.ts b/packages/frontend/core/src/modules/typst/renderer/runtime.spec.ts new file mode 100644 index 0000000000..0443c2c390 --- /dev/null +++ b/packages/frontend/core/src/modules/typst/renderer/runtime.spec.ts @@ -0,0 +1,84 @@ +import { beforeEach, describe, expect, test, vi } from 'vitest'; + +const { loadFonts, setCompilerInitOptions, setRendererInitOptions, svg } = + vi.hoisted(() => ({ + loadFonts: vi.fn((fontUrls: string[]) => ({ fontUrls })), + setCompilerInitOptions: vi.fn(), + setRendererInitOptions: vi.fn(), + svg: vi.fn(), + })); + +vi.mock('@myriaddreamin/typst.ts', () => ({ + $typst: { + setCompilerInitOptions, + setRendererInitOptions, + svg, + }, + loadFonts, +})); + +import { ensureTypstReady, renderTypstSvgWithOptions } from './runtime'; + +describe('typst runtime', () => { + beforeEach(() => { + vi.clearAllMocks(); + svg.mockResolvedValue(''); + }); + + test('reconfigures typst when fontUrls change', async () => { + await ensureTypstReady(['font-a']); + await ensureTypstReady(['font-b']); + + expect(loadFonts).toHaveBeenNthCalledWith( + 1, + ['font-a'], + expect.any(Object) + ); + expect(loadFonts).toHaveBeenNthCalledWith( + 2, + ['font-b'], + expect.any(Object) + ); + expect(setCompilerInitOptions).toHaveBeenCalledTimes(2); + expect(setRendererInitOptions).toHaveBeenCalledTimes(2); + }); + + test('serializes typst renders that need different configuration', async () => { + const events: string[] = []; + let releaseFirstRender!: () => void; + + svg.mockImplementationOnce(async () => { + events.push('svg:first:start'); + await new Promise(resolve => { + releaseFirstRender = resolve; + }); + events.push('svg:first:end'); + return 'first'; + }); + svg.mockImplementationOnce(async () => { + events.push('svg:second:start'); + return 'second'; + }); + + const first = renderTypstSvgWithOptions('= First', { + fontUrls: ['font-a'], + }); + const second = renderTypstSvgWithOptions('= Second', { + fontUrls: ['font-b'], + }); + + await vi.waitFor(() => { + expect(events).toEqual(['svg:first:start']); + }); + + releaseFirstRender(); + + await expect(first).resolves.toEqual({ svg: 'first' }); + await expect(second).resolves.toEqual({ svg: 'second' }); + expect(events).toEqual([ + 'svg:first:start', + 'svg:first:end', + 'svg:second:start', + ]); + }); +}); diff --git a/packages/frontend/core/src/modules/typst/renderer/runtime.ts b/packages/frontend/core/src/modules/typst/renderer/runtime.ts new file mode 100644 index 0000000000..1b9ebba9fa --- /dev/null +++ b/packages/frontend/core/src/modules/typst/renderer/runtime.ts @@ -0,0 +1,209 @@ +import { $typst, type BeforeBuildFn, loadFonts } from '@myriaddreamin/typst.ts'; + +import type { TypstRenderOptions } from './types'; + +export const DEFAULT_TYPST_FONT_URLS = [ + 'https://cdn.affine.pro/fonts/Inter-Regular.woff', + 'https://cdn.affine.pro/fonts/Inter-SemiBold.woff', + 'https://cdn.affine.pro/fonts/Inter-Italic.woff', + 'https://cdn.affine.pro/fonts/Inter-SemiBoldItalic.woff', + 'https://cdn.affine.pro/fonts/SarasaGothicCL-Regular.ttf', +] as const; + +export const DEFAULT_TYPST_RENDER_OPTIONS: TypstRenderOptions = { + fontUrls: [...DEFAULT_TYPST_FONT_URLS], +}; + +const DEFAULT_FONT_FALLBACKS: Record = { + 'Inter-Regular.woff': 'Inter-Regular.woff2', + 'Inter-SemiBold.woff': 'Inter-SemiBold.woff2', + 'Inter-Italic.woff': 'Inter-Italic.woff2', + 'Inter-SemiBoldItalic.woff': 'Inter-SemiBoldItalic.woff2', + 'SarasaGothicCL-Regular.ttf': 'Inter-Regular.woff2', + 'Inter-Regular.woff2': 'Inter-Regular.woff2', + 'Inter-SemiBold.woff2': 'Inter-SemiBold.woff2', + 'Inter-Italic.woff2': 'Inter-Italic.woff2', + 'Inter-SemiBoldItalic.woff2': 'Inter-SemiBoldItalic.woff2', +}; + +const compilerWasmUrl = new URL( + '@myriaddreamin/typst-ts-web-compiler/pkg/typst_ts_web_compiler_bg.wasm', + import.meta.url +).toString(); + +const rendererWasmUrl = new URL( + '@myriaddreamin/typst-ts-renderer/pkg/typst_ts_renderer_bg.wasm', + import.meta.url +).toString(); + +type TypstWasmModuleUrls = { + compilerWasmUrl?: string; + rendererWasmUrl?: string; +}; + +type TypstInitState = { + key: string; + promise: Promise; +}; + +let typstInitState: TypstInitState | null = null; +let typstRenderQueue: Promise = Promise.resolve(); + +function extractInputUrl(input: RequestInfo | URL): string | null { + if (input instanceof URL) { + return input.toString(); + } + if (typeof input === 'string') { + return input; + } + if (typeof Request !== 'undefined' && input instanceof Request) { + return input.url; + } + return null; +} + +function resolveLocalFallbackFontUrl(sourceUrl: string): string | null { + if (typeof location === 'undefined') { + return null; + } + + const source = new URL(sourceUrl, location.href); + const fileName = source.pathname.split('/').at(-1); + if (!fileName) { + return null; + } + + const fallbackFileName = DEFAULT_FONT_FALLBACKS[fileName]; + if (!fallbackFileName) { + return null; + } + + const workerUrl = new URL(location.href); + const jsPathMarker = '/js/'; + const markerIndex = workerUrl.pathname.lastIndexOf(jsPathMarker); + const basePath = + markerIndex >= 0 ? workerUrl.pathname.slice(0, markerIndex + 1) : '/'; + + return new URL( + `${basePath}fonts/${fallbackFileName}`, + workerUrl.origin + ).toString(); +} + +export function createTypstFontFetcher(baseFetcher: typeof fetch = fetch) { + return async (input: RequestInfo | URL, init?: RequestInit) => { + const sourceUrl = extractInputUrl(input); + const fallbackUrl = sourceUrl + ? resolveLocalFallbackFontUrl(sourceUrl) + : null; + + try { + const response = await baseFetcher(input, init); + if (!fallbackUrl || response.ok || fallbackUrl === sourceUrl) { + return response; + } + + const fallbackResponse = await baseFetcher(fallbackUrl, init); + return fallbackResponse.ok ? fallbackResponse : response; + } catch (error) { + if (!fallbackUrl || fallbackUrl === sourceUrl) { + throw error; + } + + return baseFetcher(fallbackUrl, init); + } + }; +} + +export function mergeTypstRenderOptions( + base: TypstRenderOptions, + override: TypstRenderOptions | undefined +): TypstRenderOptions { + return { + ...base, + ...override, + fontUrls: override?.fontUrls ?? base.fontUrls, + }; +} + +function getBeforeBuildHooks(fontUrls: string[]): BeforeBuildFn[] { + return [ + loadFonts([...fontUrls], { + assets: ['text'], + fetcher: createTypstFontFetcher(), + }), + ]; +} + +function createTypstInitKey( + fontUrls: string[], + wasmModuleUrls: TypstWasmModuleUrls +) { + return JSON.stringify({ + fontUrls, + compilerWasmUrl: wasmModuleUrls.compilerWasmUrl ?? compilerWasmUrl, + rendererWasmUrl: wasmModuleUrls.rendererWasmUrl ?? rendererWasmUrl, + }); +} + +function enqueueTypstRender(task: () => Promise): Promise { + const run = typstRenderQueue.then(task, task); + typstRenderQueue = run.then( + () => undefined, + () => undefined + ); + return run; +} + +export async function ensureTypstReady( + fontUrls: string[], + wasmModuleUrls: TypstWasmModuleUrls = {} +) { + const key = createTypstInitKey(fontUrls, wasmModuleUrls); + if (typstInitState?.key === key) { + return typstInitState.promise; + } + + const promise = Promise.resolve() + .then(() => { + const compilerBeforeBuild = getBeforeBuildHooks(fontUrls); + + $typst.setCompilerInitOptions({ + beforeBuild: compilerBeforeBuild, + getModule: () => wasmModuleUrls.compilerWasmUrl ?? compilerWasmUrl, + }); + $typst.setRendererInitOptions({ + getModule: () => wasmModuleUrls.rendererWasmUrl ?? rendererWasmUrl, + }); + }) + .catch(error => { + if (typstInitState?.key === key) { + typstInitState = null; + } + throw error; + }); + + typstInitState = { key, promise }; + return promise; +} + +export async function renderTypstSvgWithOptions( + code: string, + options: TypstRenderOptions | undefined, + wasmModuleUrls?: TypstWasmModuleUrls +) { + const resolvedOptions = mergeTypstRenderOptions( + DEFAULT_TYPST_RENDER_OPTIONS, + options + ); + return enqueueTypstRender(async () => { + await ensureTypstReady( + resolvedOptions.fontUrls ?? [...DEFAULT_TYPST_FONT_URLS], + wasmModuleUrls + ); + const svg = await $typst.svg({ + mainContent: code, + }); + return { svg }; + }); +} diff --git a/packages/frontend/core/src/modules/typst/renderer/types.ts b/packages/frontend/core/src/modules/typst/renderer/types.ts new file mode 100644 index 0000000000..b9804ade4d --- /dev/null +++ b/packages/frontend/core/src/modules/typst/renderer/types.ts @@ -0,0 +1,19 @@ +import type { OpSchema } from '@toeverything/infra/op'; + +export type TypstRenderOptions = { + fontUrls?: string[]; +}; + +export type TypstRenderRequest = { + code: string; + options?: TypstRenderOptions; +}; + +export type TypstRenderResult = { + svg: string; +}; + +export interface TypstOps extends OpSchema { + init: [TypstRenderOptions | undefined, { ok: true }]; + render: [TypstRenderRequest, TypstRenderResult]; +} diff --git a/packages/frontend/core/src/modules/typst/renderer/typst.worker.ts b/packages/frontend/core/src/modules/typst/renderer/typst.worker.ts new file mode 100644 index 0000000000..ae758b07fd --- /dev/null +++ b/packages/frontend/core/src/modules/typst/renderer/typst.worker.ts @@ -0,0 +1,40 @@ +import type { MessageCommunicapable } from '@toeverything/infra/op'; +import { OpConsumer } from '@toeverything/infra/op'; + +import { + DEFAULT_TYPST_RENDER_OPTIONS, + ensureTypstReady, + mergeTypstRenderOptions, + renderTypstSvgWithOptions, +} from './runtime'; +import type { TypstOps, TypstRenderOptions, TypstRenderRequest } from './types'; + +class TypstRendererBackend extends OpConsumer { + private options: TypstRenderOptions = DEFAULT_TYPST_RENDER_OPTIONS; + + constructor(port: MessageCommunicapable) { + super(port); + this.register('init', this.init.bind(this)); + this.register('render', this.render.bind(this)); + } + + async init(options?: TypstRenderOptions) { + this.options = mergeTypstRenderOptions( + DEFAULT_TYPST_RENDER_OPTIONS, + options + ); + await ensureTypstReady( + this.options.fontUrls ?? [ + ...(DEFAULT_TYPST_RENDER_OPTIONS.fontUrls ?? []), + ] + ); + return { ok: true } as const; + } + + async render({ code, options }: TypstRenderRequest) { + const mergedOptions = mergeTypstRenderOptions(this.options, options); + return renderTypstSvgWithOptions(code, mergedOptions); + } +} + +new TypstRendererBackend(self as MessageCommunicapable); diff --git a/packages/frontend/mobile-native/Cargo.toml b/packages/frontend/mobile-native/Cargo.toml index a69b0cc4dd..ec13221304 100644 --- a/packages/frontend/mobile-native/Cargo.toml +++ b/packages/frontend/mobile-native/Cargo.toml @@ -1,6 +1,7 @@ [package] edition = "2024" name = "affine_mobile_native" +publish = false version = "0.0.0" [lib] @@ -40,7 +41,11 @@ objc2-foundation = { workspace = true, features = [ homedir = { workspace = true } [target.'cfg(any(target_os = "android", target_os = "ios"))'.dependencies] -lru = { workspace = true } +lru = { workspace = true } +mermaid-rs-renderer = { workspace = true } +typst = { workspace = true } +typst-as-lib = { workspace = true } +typst-svg = { workspace = true } [build-dependencies] uniffi = { workspace = true, features = ["build"] } diff --git a/packages/frontend/mobile-native/src/lib.rs b/packages/frontend/mobile-native/src/lib.rs index 981abff00f..3cff3807f9 100644 --- a/packages/frontend/mobile-native/src/lib.rs +++ b/packages/frontend/mobile-native/src/lib.rs @@ -1,6 +1,8 @@ mod error; mod ffi_types; mod payload_codec; +#[cfg(any(target_os = "android", target_os = "ios"))] +mod preview; mod storage; #[cfg(test)] mod tests; @@ -14,6 +16,8 @@ pub use error::UniffiError; pub use ffi_types::{ Blob, BlockInfo, CrawlResult, DocClock, DocRecord, DocUpdate, ListedBlob, MatchRange, SearchHit, SetBlob, }; +#[cfg(any(target_os = "android", target_os = "ios"))] +pub use preview::{render_mermaid_preview_svg, render_typst_preview_svg}; pub use storage::{DocStoragePool, new_doc_storage_pool}; uniffi::setup_scaffolding!("affine_mobile_native"); diff --git a/packages/frontend/mobile-native/src/preview.rs b/packages/frontend/mobile-native/src/preview.rs new file mode 100644 index 0000000000..0b2de51d6a --- /dev/null +++ b/packages/frontend/mobile-native/src/preview.rs @@ -0,0 +1,155 @@ +use std::{borrow::Cow, path::PathBuf}; + +use mermaid_rs_renderer::RenderOptions; +use typst::{ + diag::FileResult, + foundations::Bytes, + layout::{Abs, PagedDocument}, + syntax::{FileId, Source}, +}; +use typst_as_lib::{ + TypstEngine, + cached_file_resolver::{CachedFileResolver, IntoCachedFileResolver}, + file_resolver::FileResolver, + package_resolver::{FileSystemCache, PackageResolver}, + typst_kit_options::TypstKitFontOptions, +}; + +use crate::{Result, UniffiError}; + +const TYPST_PACKAGE_CACHE_DIR: &str = "typst-package-cache"; + +enum MobileTypstPackageResolver { + FileSystem(CachedFileResolver>), + InMemory(CachedFileResolver>), +} + +impl FileResolver for MobileTypstPackageResolver { + fn resolve_binary(&self, id: FileId) -> FileResult> { + match self { + Self::FileSystem(resolver) => resolver.resolve_binary(id), + Self::InMemory(resolver) => resolver.resolve_binary(id), + } + } + + fn resolve_source(&self, id: FileId) -> FileResult> { + match self { + Self::FileSystem(resolver) => resolver.resolve_source(id), + Self::InMemory(resolver) => resolver.resolve_source(id), + } + } +} + +fn resolve_mermaid_render_options( + theme: Option, + font_family: Option, + font_size: Option, +) -> RenderOptions { + let mut render_options = match theme.as_deref() { + Some("default") => RenderOptions::mermaid_default(), + _ => RenderOptions::modern(), + }; + + if let Some(font_family) = font_family { + render_options.theme.font_family = font_family; + } + + if let Some(font_size) = font_size { + render_options.theme.font_size = font_size as f32; + } + + render_options +} + +#[uniffi::export] +pub fn render_mermaid_preview_svg( + code: String, + theme: Option, + font_family: Option, + font_size: Option, +) -> Result { + let render_options = resolve_mermaid_render_options(theme, font_family, font_size); + + mermaid_rs_renderer::render_with_options(&code, render_options).map_err(|error| UniffiError::Err(error.to_string())) +} + +fn normalize_typst_svg(svg: String) -> String { + let mut svg = svg; + let page_background_marker = r##"") else { + break; + }; + + let end = idx + relative_end + 2; + let path_fragment = &svg[idx..end]; + let is_page_background_path = + path_fragment.contains(r#"d="M 0 0v "#) && path_fragment.contains(r#" h "#) && path_fragment.contains(r#" v -"#); + + if is_page_background_path { + svg.replace_range(idx..end, ""); + cursor = idx; + continue; + } + + cursor = end; + } + + svg +} + +fn resolve_typst_font_dirs(font_dirs: Option>) -> Vec { + font_dirs + .map(|dirs| dirs.into_iter().map(PathBuf::from).collect()) + .unwrap_or_default() +} + +fn resolve_typst_package_resolver(cache_dir: Option) -> Result { + let resolver = match cache_dir { + Some(cache_dir) => { + let cache_dir = PathBuf::from(cache_dir).join(TYPST_PACKAGE_CACHE_DIR); + std::fs::create_dir_all(&cache_dir).map_err(|error| UniffiError::Err(error.to_string()))?; + MobileTypstPackageResolver::FileSystem( + PackageResolver::builder() + .cache(FileSystemCache(cache_dir)) + .build() + .into_cached(), + ) + } + None => { + MobileTypstPackageResolver::InMemory(PackageResolver::builder().with_in_memory_cache().build().into_cached()) + } + }; + + Ok(resolver) +} + +#[uniffi::export] +pub fn render_typst_preview_svg( + code: String, + font_dirs: Option>, + cache_dir: Option, +) -> Result { + let search_options = TypstKitFontOptions::new() + .include_system_fonts(false) + .include_embedded_fonts(true) + .include_dirs(resolve_typst_font_dirs(font_dirs)); + let package_resolver = resolve_typst_package_resolver(cache_dir)?; + + let engine = TypstEngine::builder() + .main_file(code) + .search_fonts_with(search_options) + .add_file_resolver(package_resolver) + .build(); + + let document = engine + .compile::() + .output + .map_err(|error| UniffiError::Err(error.to_string()))?; + + Ok(normalize_typst_svg(typst_svg::svg_merged(&document, Abs::pt(0.0)))) +} diff --git a/packages/frontend/native/Cargo.toml b/packages/frontend/native/Cargo.toml index 6656a06ec2..aca6463ae0 100644 --- a/packages/frontend/native/Cargo.toml +++ b/packages/frontend/native/Cargo.toml @@ -1,6 +1,7 @@ [package] edition = "2024" name = "affine_native" +publish = false version = "0.0.0" [lib] @@ -25,6 +26,12 @@ sqlx = { workspace = true, default-features = false, features = [ thiserror = { workspace = true } tokio = { workspace = true, features = ["full"] } +[target.'cfg(not(any(target_os = "android", target_os = "ios")))'.dependencies] +mermaid-rs-renderer = { workspace = true } +typst = { workspace = true } +typst-as-lib = { workspace = true } +typst-svg = { workspace = true } + [target.'cfg(not(target_os = "linux"))'.dependencies] mimalloc = { workspace = true } diff --git a/packages/frontend/native/index.d.ts b/packages/frontend/native/index.d.ts index f27f9c6518..0f5e7a975b 100644 --- a/packages/frontend/native/index.d.ts +++ b/packages/frontend/native/index.d.ts @@ -40,8 +40,41 @@ export declare function decodeAudio(buf: Uint8Array, destSampleRate?: number | u /** Decode audio file into a Float32Array */ export declare function decodeAudioSync(buf: Uint8Array, destSampleRate?: number | undefined | null, filename?: string | undefined | null): Float32Array +export interface MermaidRenderOptions { + theme?: string + fontFamily?: string + fontSize?: number +} + +export interface MermaidRenderRequest { + code: string + options?: MermaidRenderOptions +} + +export interface MermaidRenderResult { + svg: string +} + export declare function mintChallengeResponse(resource: string, bits?: number | undefined | null): Promise +export declare function renderMermaidSvg(request: MermaidRenderRequest): MermaidRenderResult + +export declare function renderTypstSvg(request: TypstRenderRequest): TypstRenderResult + +export interface TypstRenderOptions { + fontUrls?: Array + fontDirs?: Array +} + +export interface TypstRenderRequest { + code: string + options?: TypstRenderOptions +} + +export interface TypstRenderResult { + svg: string +} + export declare function verifyChallengeResponse(response: string, bits: number, resource: string): Promise export declare class DocStorage { constructor(path: string) diff --git a/packages/frontend/native/index.js b/packages/frontend/native/index.js index 8100c5c02b..e97ca2966f 100644 --- a/packages/frontend/native/index.js +++ b/packages/frontend/native/index.js @@ -580,6 +580,8 @@ module.exports.ShareableContent = nativeBinding.ShareableContent module.exports.decodeAudio = nativeBinding.decodeAudio module.exports.decodeAudioSync = nativeBinding.decodeAudioSync module.exports.mintChallengeResponse = nativeBinding.mintChallengeResponse +module.exports.renderMermaidSvg = nativeBinding.renderMermaidSvg +module.exports.renderTypstSvg = nativeBinding.renderTypstSvg module.exports.verifyChallengeResponse = nativeBinding.verifyChallengeResponse module.exports.DocStorage = nativeBinding.DocStorage module.exports.DocStoragePool = nativeBinding.DocStoragePool diff --git a/packages/frontend/native/media_capture/Cargo.toml b/packages/frontend/native/media_capture/Cargo.toml index e9e003be83..731d23f978 100644 --- a/packages/frontend/native/media_capture/Cargo.toml +++ b/packages/frontend/native/media_capture/Cargo.toml @@ -1,6 +1,7 @@ [package] edition = "2024" name = "affine_media_capture" +publish = false version = "0.0.0" [lib] diff --git a/packages/frontend/native/nbstore/Cargo.toml b/packages/frontend/native/nbstore/Cargo.toml index f5ac3550c7..0d1ec79db5 100644 --- a/packages/frontend/native/nbstore/Cargo.toml +++ b/packages/frontend/native/nbstore/Cargo.toml @@ -1,6 +1,7 @@ [package] edition = "2024" name = "affine_nbstore" +publish = false version = "0.0.0" [lib] diff --git a/packages/frontend/native/schema/Cargo.toml b/packages/frontend/native/schema/Cargo.toml index c75fa92d4f..e162085de3 100644 --- a/packages/frontend/native/schema/Cargo.toml +++ b/packages/frontend/native/schema/Cargo.toml @@ -1,6 +1,7 @@ [package] edition = "2024" name = "affine_schema" +publish = false version = "0.0.0" [dependencies] diff --git a/packages/frontend/native/sqlite_v1/Cargo.toml b/packages/frontend/native/sqlite_v1/Cargo.toml index 03b34f5908..b9701cb308 100644 --- a/packages/frontend/native/sqlite_v1/Cargo.toml +++ b/packages/frontend/native/sqlite_v1/Cargo.toml @@ -1,6 +1,7 @@ [package] edition = "2024" name = "affine_sqlite_v1" +publish = false version = "0.0.0" [lib] diff --git a/packages/frontend/native/src/lib.rs b/packages/frontend/native/src/lib.rs index 63582db8fb..f5b2a56d94 100644 --- a/packages/frontend/native/src/lib.rs +++ b/packages/frontend/native/src/lib.rs @@ -1,4 +1,6 @@ pub mod hashcash; +#[cfg(not(any(target_os = "android", target_os = "ios")))] +pub mod preview; #[cfg(not(target_arch = "arm"))] #[global_allocator] diff --git a/packages/frontend/native/src/preview.rs b/packages/frontend/native/src/preview.rs new file mode 100644 index 0000000000..53042351a8 --- /dev/null +++ b/packages/frontend/native/src/preview.rs @@ -0,0 +1,191 @@ +use std::path::PathBuf; + +use mermaid_rs_renderer::RenderOptions; +use napi::{Error, Result}; +use napi_derive::napi; +use typst::layout::{Abs, PagedDocument}; +use typst_as_lib::{TypstEngine, typst_kit_options::TypstKitFontOptions}; + +#[napi(object)] +pub struct MermaidRenderOptions { + pub theme: Option, + pub font_family: Option, + pub font_size: Option, +} + +#[napi(object)] +pub struct MermaidRenderRequest { + pub code: String, + pub options: Option, +} + +#[napi(object)] +pub struct MermaidRenderResult { + pub svg: String, +} + +fn resolve_mermaid_render_options(options: Option) -> RenderOptions { + let mut render_options = match options.as_ref().and_then(|options| options.theme.as_deref()) { + Some("default") => RenderOptions::mermaid_default(), + _ => RenderOptions::modern(), + }; + + if let Some(options) = options { + if let Some(font_family) = options.font_family { + render_options.theme.font_family = font_family; + } + + if let Some(font_size) = options.font_size { + render_options.theme.font_size = font_size as f32; + } + } + + render_options +} + +#[napi] +pub fn render_mermaid_svg(request: MermaidRenderRequest) -> Result { + let render_options = resolve_mermaid_render_options(request.options); + let svg = mermaid_rs_renderer::render_with_options(&request.code, render_options) + .map_err(|error| Error::from_reason(error.to_string()))?; + + Ok(MermaidRenderResult { svg }) +} + +#[napi(object)] +pub struct TypstRenderOptions { + pub font_urls: Option>, + pub font_dirs: Option>, +} + +#[napi(object)] +pub struct TypstRenderRequest { + pub code: String, + pub options: Option, +} + +#[napi(object)] +pub struct TypstRenderResult { + pub svg: String, +} + +fn resolve_local_font_dir(value: &str) -> Option { + let path = if let Some(stripped) = value.strip_prefix("file://") { + PathBuf::from(stripped) + } else { + let path = PathBuf::from(value); + if !path.is_absolute() { + return None; + } + path + }; + + if path.is_dir() { + return Some(path); + } + + path.parent().map(|parent| parent.to_path_buf()) +} + +fn resolve_typst_font_dirs(options: &Option) -> Vec { + let Some(options) = options.as_ref() else { + return Vec::new(); + }; + + let mut font_dirs = options + .font_dirs + .as_ref() + .map(|dirs| dirs.iter().map(PathBuf::from).collect::>()) + .unwrap_or_default(); + + if let Some(font_urls) = options.font_urls.as_ref() { + font_dirs.extend(font_urls.iter().filter_map(|url| resolve_local_font_dir(url))); + } + + font_dirs +} + +fn normalize_typst_svg(svg: String) -> String { + let mut svg = svg; + let page_background_marker = r##"") else { + break; + }; + + let end = idx + relative_end + 2; + let path_fragment = &svg[idx..end]; + let is_page_background_path = + path_fragment.contains(r#"d="M 0 0v "#) && path_fragment.contains(r#" h "#) && path_fragment.contains(r#" v -"#); + + if is_page_background_path { + svg.replace_range(idx..end, ""); + cursor = idx; + continue; + } + + cursor = end; + } + + svg +} + +#[napi] +pub fn render_typst_svg(request: TypstRenderRequest) -> Result { + let font_dirs = resolve_typst_font_dirs(&request.options); + let search_options = TypstKitFontOptions::new() + .include_system_fonts(false) + .include_embedded_fonts(true) + .include_dirs(font_dirs); + + let engine = TypstEngine::builder() + .main_file(request.code) + .search_fonts_with(search_options) + .with_package_file_resolver() + .build(); + + let document = engine + .compile::() + .output + .map_err(|error| Error::from_reason(error.to_string()))?; + + let svg = normalize_typst_svg(typst_svg::svg_merged(&document, Abs::pt(0.0))); + Ok(TypstRenderResult { svg }) +} + +#[cfg(test)] +mod tests { + use super::normalize_typst_svg; + + #[test] + fn normalize_typst_svg_removes_all_backgrounds() { + let input = r##" + + + + + "## + .to_string(); + + let normalized = normalize_typst_svg(input); + let retained = normalized + .matches(r##" + + "## + .to_string(); + + let normalized = normalize_typst_svg(input); + assert!(normalized.contains(r##"d="M 1 2 L 3 4 Z ""##)); + } +} diff --git a/tools/cli/src/bundle.ts b/tools/cli/src/bundle.ts index e1d7e56916..805509623e 100644 --- a/tools/cli/src/bundle.ts +++ b/tools/cli/src/bundle.ts @@ -27,6 +27,9 @@ import { type WorkerConfig = { name: string }; type CreateWorkerTargetConfig = (pkg: Package, entry: string) => WorkerConfig; +type BaseWorkerOptions = { + includeMermaidAndTypst?: boolean; +}; function assertRspackSupportedPackage(pkg: Package) { assertRspackSupportedPackageName(pkg.name); @@ -49,11 +52,13 @@ async function uploadAssetsForPackage(pkg: Package, logger: Logger) { function getBaseWorkerConfigs( pkg: Package, - createWorkerTargetConfig: CreateWorkerTargetConfig + createWorkerTargetConfig: CreateWorkerTargetConfig, + options: BaseWorkerOptions = {} ) { const core = new Package('@affine/core'); + const includeMermaidAndTypst = options.includeMermaidAndTypst ?? true; - return [ + const workerConfigs = [ createWorkerTargetConfig( pkg, core.srcPath.join( @@ -71,6 +76,21 @@ function getBaseWorkerConfigs( ).value ), ]; + + if (includeMermaidAndTypst) { + workerConfigs.push( + createWorkerTargetConfig( + pkg, + core.srcPath.join('modules/mermaid/renderer/mermaid.worker.ts').value + ), + createWorkerTargetConfig( + pkg, + core.srcPath.join('modules/typst/renderer/typst.worker.ts').value + ) + ); + } + + return workerConfigs; } function getRspackBundleConfigs(pkg: Package): MultiRspackOptions { @@ -85,9 +105,7 @@ function getRspackBundleConfigs(pkg: Package): MultiRspackOptions { ] as MultiRspackOptions; } case '@affine/web': - case '@affine/mobile': - case '@affine/ios': - case '@affine/android': { + case '@affine/mobile': { const workerConfigs = getBaseWorkerConfigs( pkg, createRspackWorkerTargetConfig @@ -109,10 +127,35 @@ function getRspackBundleConfigs(pkg: Package): MultiRspackOptions { ...workerConfigs, ] as MultiRspackOptions; } + case '@affine/ios': + case '@affine/android': { + const workerConfigs = getBaseWorkerConfigs( + pkg, + createRspackWorkerTargetConfig, + { includeMermaidAndTypst: false } + ); + workerConfigs.push( + createRspackWorkerTargetConfig( + pkg, + pkg.srcPath.join('nbstore.worker.ts').value + ) + ); + + return [ + createRspackHTMLTargetConfig( + pkg, + pkg.srcPath.join('index.tsx').value, + {}, + workerConfigs.map(config => config.name) + ), + ...workerConfigs, + ] as MultiRspackOptions; + } case '@affine/electron-renderer': { const workerConfigs = getBaseWorkerConfigs( pkg, - createRspackWorkerTargetConfig + createRspackWorkerTargetConfig, + { includeMermaidAndTypst: false } ); return [ diff --git a/tools/cli/src/rspack/index.ts b/tools/cli/src/rspack/index.ts index 1026994164..e3ea8458f0 100644 --- a/tools/cli/src/rspack/index.ts +++ b/tools/cli/src/rspack/index.ts @@ -90,6 +90,22 @@ export function createHTMLTargetConfig( ); const buildConfig = getBuildConfigFromEnv(pkg); + const codeBlockPreviewBackendFile = + buildConfig.distribution === 'desktop' + ? 'platform-backend.desktop.ts' + : buildConfig.distribution === 'ios' || + buildConfig.distribution === 'android' + ? 'platform-backend.mobile.ts' + : 'platform-backend.ts'; + const codeBlockPreviewBackendAlias = ProjectRoot.join( + 'packages', + 'frontend', + 'core', + 'src', + 'modules', + 'code-block-preview-renderer', + codeBlockPreviewBackendFile + ).value; console.log( `Building [${pkg.name}] for [${buildConfig.appBuildType}] channel in [${buildConfig.debug ? 'development' : 'production'}] mode.` @@ -145,6 +161,8 @@ export function createHTMLTargetConfig( '@preact', 'signals-core' ).value, + '@affine/core/modules/code-block-preview-renderer/platform-backend': + codeBlockPreviewBackendAlias, }, }, //#endregion diff --git a/yarn.lock b/yarn.lock index 28e1ca9c8f..9bc1e48ec2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -431,6 +431,7 @@ __metadata: "@testing-library/dom": "npm:^10.4.0" "@testing-library/react": "npm:^16.1.0" "@toeverything/infra": "workspace:*" + "@toeverything/mermaid-wasm": "npm:^0.1.0" "@toeverything/pdf-viewer": "npm:^0.1.1" "@toeverything/theme": "npm:^1.1.23" "@types/animejs": "npm:^3.1.12" @@ -447,6 +448,7 @@ __metadata: cmdk: "npm:^1.0.4" core-js: "npm:^3.39.0" dayjs: "npm:^1.11.13" + dompurify: "npm:^3.3.0" eventemitter2: "npm:^6.4.9" fake-indexeddb: "npm:^6.0.0" file-type: "npm:^21.0.0" @@ -468,7 +470,7 @@ __metadata: lit: "npm:^3.2.1" lodash-es: "npm:^4.17.23" lottie-react: "npm:^2.4.0" - mermaid: "npm:^11.12.2" + mermaid: "npm:^11.13.0" mp4-muxer: "npm:^5.2.2" nanoid: "npm:^5.1.6" next-themes: "npm:^0.4.4" @@ -1136,13 +1138,6 @@ __metadata: languageName: node linkType: hard -"@antfu/utils@npm:^9.2.0": - version: 9.2.1 - resolution: "@antfu/utils@npm:9.2.1" - checksum: 10/c629769f5301d16851de18e241cc0c7547928b080929bcfd945735eb799d13029336236bfe869935e832f3e48f8b622caf5946738158b4dd4133701f19a9b75a - languageName: node - linkType: hard - "@apollo/cache-control-types@npm:^1.0.3": version: 1.0.3 resolution: "@apollo/cache-control-types@npm:1.0.3" @@ -1736,6 +1731,7 @@ __metadata: "@toeverything/theme": "npm:^1.1.23" "@vitest/browser-playwright": "npm:^4.0.18" lit: "npm:^3.2.0" + playwright: "npm:=1.58.2" rxjs: "npm:^7.8.2" vitest: "npm:^4.0.18" yjs: "npm:^13.6.27" @@ -2800,6 +2796,7 @@ __metadata: lit: "npm:^3.2.0" lit-html: "npm:^3.2.1" lodash-es: "npm:^4.17.23" + playwright: "npm:=1.58.2" rxjs: "npm:^7.8.2" vitest: "npm:^4.0.18" yjs: "npm:^13.6.27" @@ -3610,6 +3607,7 @@ __metadata: "@vanilla-extract/vite-plugin": "npm:^5.0.0" "@vitest/browser-playwright": "npm:^4.0.18" lit: "npm:^3.2.0" + playwright: "npm:=1.58.2" rxjs: "npm:^7.8.2" vite: "npm:^7.2.7" vite-plugin-istanbul: "npm:^7.2.1" @@ -3680,6 +3678,7 @@ __metadata: lit: "npm:^3.2.0" lodash-es: "npm:^4.17.23" lz-string: "npm:^1.5.0" + playwright: "npm:=1.58.2" rehype-parse: "npm:^9.0.0" rxjs: "npm:^7.8.2" unified: "npm:^11.0.5" @@ -3740,9 +3739,9 @@ __metadata: linkType: hard "@braintree/sanitize-url@npm:^7.1.1": - version: 7.1.1 - resolution: "@braintree/sanitize-url@npm:7.1.1" - checksum: 10/a8a5535c5a0a459ba593a018c554b35493dff004fd09d7147db67243df83bce3d410b89ee7dc2d95cce195b85b877c72f8ca149e1040110a945d193c67293af0 + version: 7.1.2 + resolution: "@braintree/sanitize-url@npm:7.1.2" + checksum: 10/d9626ff8f8eb5e192cd055e6e743449c21102c76bb59e405b7028fe56230fa080bfcc80dfb1e21850a6876e75adda9f7b3c888cf0685942bb74da4d2866d6ec3 languageName: node linkType: hard @@ -3855,45 +3854,45 @@ __metadata: languageName: node linkType: hard -"@chevrotain/cst-dts-gen@npm:11.0.3": - version: 11.0.3 - resolution: "@chevrotain/cst-dts-gen@npm:11.0.3" +"@chevrotain/cst-dts-gen@npm:11.1.2": + version: 11.1.2 + resolution: "@chevrotain/cst-dts-gen@npm:11.1.2" dependencies: - "@chevrotain/gast": "npm:11.0.3" - "@chevrotain/types": "npm:11.0.3" - lodash-es: "npm:4.17.21" - checksum: 10/601d23fa3312bd0e32816bd3f9ca2dcba775a52192a082fd6c5e4a2e8ee068523401191babbe2c346d6d2551900a67b549f2f74d7ebb7d5b2ee1b6fa3c8857a0 + "@chevrotain/gast": "npm:11.1.2" + "@chevrotain/types": "npm:11.1.2" + lodash-es: "npm:4.17.23" + checksum: 10/04a84285fd4d26129f44f8e20b99fd6ab51cb1ee4c7eb104baa4842413b9e18bb171046a665583b94ff29e2c06a2e1a65205940a75cda848aa2a5e847b99bbb6 languageName: node linkType: hard -"@chevrotain/gast@npm:11.0.3": - version: 11.0.3 - resolution: "@chevrotain/gast@npm:11.0.3" +"@chevrotain/gast@npm:11.1.2": + version: 11.1.2 + resolution: "@chevrotain/gast@npm:11.1.2" dependencies: - "@chevrotain/types": "npm:11.0.3" - lodash-es: "npm:4.17.21" - checksum: 10/7169453a8fbfa994e91995523dea09eab87ab23062ad93f6e51f4a3b03f5e2958e0a8b99d5ca6fa067fccfbbbb8bcf1a4573ace2e1b5a455f6956af9eaccb35a + "@chevrotain/types": "npm:11.1.2" + lodash-es: "npm:4.17.23" + checksum: 10/8733cbadfcb982f5afe0e1825446ad8e82de3044c9ae22a69771ec20292facce25e459da23c16061c894ef49ca381ad53c0796171fa0dfce08fc25305850eeca languageName: node linkType: hard -"@chevrotain/regexp-to-ast@npm:11.0.3": - version: 11.0.3 - resolution: "@chevrotain/regexp-to-ast@npm:11.0.3" - checksum: 10/7387a1c61c5a052de41e1172b33eaaedea166fcdb1ffe4c381b86d00051a8014855a031d28fb658768a62c833ef5f5b0689d0c40de3d7bed556f8fea24396e69 +"@chevrotain/regexp-to-ast@npm:11.1.2": + version: 11.1.2 + resolution: "@chevrotain/regexp-to-ast@npm:11.1.2" + checksum: 10/9ba399b2c23ae1a86f1bcb1db4b07fd3191d0f491b63303b824850ef5f8b455f8f8a39c4d7876271c23ca06f7e03b7273b07014cd9c8ccb2328bff5dc6c9df00 languageName: node linkType: hard -"@chevrotain/types@npm:11.0.3": - version: 11.0.3 - resolution: "@chevrotain/types@npm:11.0.3" - checksum: 10/49a82b71d2de8ceb2383ff2709fa61d245f2ab2e42790b70c57102c80846edaa318d0b3645aedc904d23ea7bd9be8a58f2397b1341760a15eb5aa95a1336e2a9 +"@chevrotain/types@npm:11.1.2": + version: 11.1.2 + resolution: "@chevrotain/types@npm:11.1.2" + checksum: 10/ad39d7651a20b05ead9b4374f98afc39915118dda29678c2b623571aa3da3018a0f3fb799d1809605cafcae59cba637d640855ea0f97b9b01d0900d77d6781fe languageName: node linkType: hard -"@chevrotain/utils@npm:11.0.3": - version: 11.0.3 - resolution: "@chevrotain/utils@npm:11.0.3" - checksum: 10/29b5d84373a7761ad055c53e2f540a67b5b56550d5be1c473149f6b8923eef87ff391ce021c06ac7653843b0149f6ff0cf30b5e48c3f825d295eb06a6c517bd3 +"@chevrotain/utils@npm:11.1.2": + version: 11.1.2 + resolution: "@chevrotain/utils@npm:11.1.2" + checksum: 10/a5ba5886547665726e6680bdc6e1c939e643c8c606d8eb3806ed178ebb2c3a8a1a581db558412374f230babfe9d8c1c37f2c3edf260c63729dbe6ff9ca4f0223 languageName: node linkType: hard @@ -6391,19 +6390,14 @@ __metadata: languageName: node linkType: hard -"@iconify/utils@npm:^3.0.1": - version: 3.0.2 - resolution: "@iconify/utils@npm:3.0.2" +"@iconify/utils@npm:^3.0.2": + version: 3.1.0 + resolution: "@iconify/utils@npm:3.1.0" dependencies: "@antfu/install-pkg": "npm:^1.1.0" - "@antfu/utils": "npm:^9.2.0" "@iconify/types": "npm:^2.0.0" - debug: "npm:^4.4.1" - globals: "npm:^15.15.0" - kolorist: "npm:^1.8.0" - local-pkg: "npm:^1.1.1" - mlly: "npm:^1.7.4" - checksum: 10/b2db57b6a6b06d618b2625bf7bd056219a6c65e71a86c79c664d5e5fe03e531bc74fdd9cfa4d74e2ea469b6cd92b63012e2d588b32cade5aa7e3c31bc5124789 + mlly: "npm:^1.8.0" + checksum: 10/28e83311ec7eca3f94a9c128c6d6f0f6aa68b7a63bcac44d08a1ea6f94d3752a7447a4354f3d02fdcdbf782ba033784ef7a65212b3afe52d9b41ef8138e96b14 languageName: node linkType: hard @@ -7531,12 +7525,12 @@ __metadata: languageName: node linkType: hard -"@mermaid-js/parser@npm:^0.6.3": - version: 0.6.3 - resolution: "@mermaid-js/parser@npm:0.6.3" +"@mermaid-js/parser@npm:^1.0.1": + version: 1.0.1 + resolution: "@mermaid-js/parser@npm:1.0.1" dependencies: - langium: "npm:3.3.1" - checksum: 10/ab8bbdeaf2ef556871f3267541c0b3621d70c4d108ddac36383adc7eb1c7e6bed28d068b4ad196b54314877f263f939f90f0a1a3cfe8576fab30f4514732aa2f + langium: "npm:^4.0.0" + checksum: 10/648c96da8464113c3694587f3f950421b1914d34fddc194b6dff7a8c28da5e37273ddc4d56a4efaeda82e93c7a168389f035dbac6c8d5b65930ee60b5063ece4 languageName: node linkType: hard @@ -15772,6 +15766,13 @@ __metadata: languageName: unknown linkType: soft +"@toeverything/mermaid-wasm@npm:^0.1.0": + version: 0.1.1 + resolution: "@toeverything/mermaid-wasm@npm:0.1.1" + checksum: 10/4b701f19aad5fbe42ddec9d63c6e3cf7641ff1ab9277142db7adcde3e9b81315e2d35cfab82acead79bb81d560eef10d1d7522ab17cca300e6dae45db0380eab + languageName: node + linkType: hard + "@toeverything/pdf-viewer-types@npm:0.1.1": version: 0.1.1 resolution: "@toeverything/pdf-viewer-types@npm:0.1.1" @@ -17488,6 +17489,21 @@ __metadata: languageName: node linkType: hard +"@upsetjs/venn.js@npm:^2.0.0": + version: 2.0.0 + resolution: "@upsetjs/venn.js@npm:2.0.0" + dependencies: + d3-selection: "npm:^3.0.0" + d3-transition: "npm:^3.0.1" + dependenciesMeta: + d3-selection: + optional: true + d3-transition: + optional: true + checksum: 10/84505be440490666566a6f59e765e1f24b154e4ca45cfed9102f02261be45912149f706e21b3cc7a6247816a8703e1f1b667561295b587c6dcc3162a9a48a5f2 + languageName: node + linkType: hard + "@vanilla-extract/babel-plugin-debug-ids@npm:^1.2.2": version: 1.2.2 resolution: "@vanilla-extract/babel-plugin-debug-ids@npm:1.2.2" @@ -18149,7 +18165,7 @@ __metadata: languageName: node linkType: hard -"acorn@npm:^8.11.0, acorn@npm:^8.14.0, acorn@npm:^8.15.0, acorn@npm:^8.16.0, acorn@npm:^8.6.0, acorn@npm:^8.8.2": +"acorn@npm:^8.11.0, acorn@npm:^8.15.0, acorn@npm:^8.16.0, acorn@npm:^8.6.0, acorn@npm:^8.8.2": version: 8.16.0 resolution: "acorn@npm:8.16.0" bin: @@ -19740,7 +19756,7 @@ __metadata: languageName: node linkType: hard -"chevrotain-allstar@npm:~0.3.0": +"chevrotain-allstar@npm:~0.3.1": version: 0.3.1 resolution: "chevrotain-allstar@npm:0.3.1" dependencies: @@ -19751,17 +19767,17 @@ __metadata: languageName: node linkType: hard -"chevrotain@npm:~11.0.3": - version: 11.0.3 - resolution: "chevrotain@npm:11.0.3" +"chevrotain@npm:~11.1.1": + version: 11.1.2 + resolution: "chevrotain@npm:11.1.2" dependencies: - "@chevrotain/cst-dts-gen": "npm:11.0.3" - "@chevrotain/gast": "npm:11.0.3" - "@chevrotain/regexp-to-ast": "npm:11.0.3" - "@chevrotain/types": "npm:11.0.3" - "@chevrotain/utils": "npm:11.0.3" - lodash-es: "npm:4.17.21" - checksum: 10/8fa6253e51320dd4c3d386315b925734943e509d7954a2cd917746c0604461191bea57b0fb8fbab1903e0508fd94bfd35ebd0f8eace77cd0f3f42a9ee4f8f676 + "@chevrotain/cst-dts-gen": "npm:11.1.2" + "@chevrotain/gast": "npm:11.1.2" + "@chevrotain/regexp-to-ast": "npm:11.1.2" + "@chevrotain/types": "npm:11.1.2" + "@chevrotain/utils": "npm:11.1.2" + lodash-es: "npm:4.17.23" + checksum: 10/67caa47a3d38eeb4a584960bbf5fdc83894a1419a6428f7dcf8a07f5937c1bda4c8e1acf628fe80d3be8f4c1a84426942c0a8f6bcf44a5958f1df0cf4225bc4d languageName: node linkType: hard @@ -21051,7 +21067,7 @@ __metadata: languageName: node linkType: hard -"cytoscape@npm:^3.29.3": +"cytoscape@npm:^3.33.1": version: 3.33.1 resolution: "cytoscape@npm:3.33.1" checksum: 10/0e8d3ea87eb624899341d6a765cfb732199af8a871beedeb94971061632ce814c2c39e8257d6628c5611ca9dadc1a723a00377d04f149e0d24f6c133a6ab8647 @@ -21196,9 +21212,9 @@ __metadata: linkType: hard "d3-format@npm:1 - 3, d3-format@npm:3": - version: 3.1.0 - resolution: "d3-format@npm:3.1.0" - checksum: 10/a0fe23d2575f738027a3db0ce57160e5a473ccf24808c1ed46d45ef4f3211076b34a18b585547d34e365e78dcc26dd4ab15c069731fc4b1c07a26bfced09ea31 + version: 3.1.2 + resolution: "d3-format@npm:3.1.2" + checksum: 10/811d913c2c7624cb0d2a8f0ccd7964c50945b3de3c7f7aa14c309fba7266a3ec53cbee8c05f6ad61b2b65b93e157c55a0e07db59bc3180c39dac52be8e841ab1 languageName: node linkType: hard @@ -21295,7 +21311,7 @@ __metadata: languageName: node linkType: hard -"d3-selection@npm:2 - 3, d3-selection@npm:3": +"d3-selection@npm:2 - 3, d3-selection@npm:3, d3-selection@npm:^3.0.0": version: 3.0.0 resolution: "d3-selection@npm:3.0.0" checksum: 10/0e5acfd305b31628b7be5009ba7303d84bb34817a88ed4dde9c8bd9c23528573fc5272f89fc04e5be03d2cbf5441a248d7274aaf55a8ef3dad46e16333d72298 @@ -21345,7 +21361,7 @@ __metadata: languageName: node linkType: hard -"d3-transition@npm:2 - 3, d3-transition@npm:3": +"d3-transition@npm:2 - 3, d3-transition@npm:3, d3-transition@npm:^3.0.1": version: 3.0.1 resolution: "d3-transition@npm:3.0.1" dependencies: @@ -21411,13 +21427,13 @@ __metadata: languageName: node linkType: hard -"dagre-d3-es@npm:7.0.13": - version: 7.0.13 - resolution: "dagre-d3-es@npm:7.0.13" +"dagre-d3-es@npm:7.0.14": + version: 7.0.14 + resolution: "dagre-d3-es@npm:7.0.14" dependencies: d3: "npm:^7.9.0" lodash-es: "npm:^4.17.21" - checksum: 10/f6dbd373b85cc9fbcb23fba996656a0336ba48bc46f1e6d31c582418a5086caf230a4e8178b90acd7b1d14b090cbba2db50dc64484d67cf9c8856a4a2fe30cf0 + checksum: 10/f2787049ae2684de27950dfc61eb23437cbb5c3ca7ec7f58620e19f16059465b6d23324ca861961353a60bb4cdaa5c66edfa9bbe44ac2304b72dd00ab4199714 languageName: node linkType: hard @@ -21474,10 +21490,10 @@ __metadata: languageName: node linkType: hard -"dayjs@npm:^1.11.13, dayjs@npm:^1.11.18": - version: 1.11.18 - resolution: "dayjs@npm:1.11.18" - checksum: 10/7d29a90834cf4da2feb437c2f34b8235c3f94493a06d2f1bf9f506f1fa49eadf796f26e1d685b9fe8cb5e75ce6ee067825115e196f1af3d07b3552ff857bfc39 +"dayjs@npm:^1.11.13, dayjs@npm:^1.11.19": + version: 1.11.20 + resolution: "dayjs@npm:1.11.20" + checksum: 10/5347533f21a55b8bb1b1ef559be9b805514c3a8fb7e68b75fb7e73808131c59e70909c073aa44ce8a0d159195cd110cdd4081cf87ab96cb06fee3edacae791c6 languageName: node linkType: hard @@ -21945,15 +21961,15 @@ __metadata: languageName: node linkType: hard -"dompurify@npm:^3.2.5, dompurify@npm:^3.3.0": - version: 3.3.2 - resolution: "dompurify@npm:3.3.2" +"dompurify@npm:^3.3.0, dompurify@npm:^3.3.1": + version: 3.3.3 + resolution: "dompurify@npm:3.3.3" dependencies: "@types/trusted-types": "npm:^2.0.7" dependenciesMeta: "@types/trusted-types": optional: true - checksum: 10/3ca02559677ce6d9583a500f21ffbb6b9e88f1af99f69fa0d0d9442cddbac98810588c869f8b435addb5115492d6e49870024bca322169b941bafedb99c7f281 + checksum: 10/4cc9c539ed7136d46c6577613b8e20871c2b6165db01dfbd2a3c11c75f9e339c496ac6519a1c3190115def8cadae3720bef0417fc43fa28802c7407bab174da9 languageName: node linkType: hard @@ -24462,13 +24478,6 @@ __metadata: languageName: node linkType: hard -"globals@npm:^15.15.0": - version: 15.15.0 - resolution: "globals@npm:15.15.0" - checksum: 10/7f561c87b2fd381b27fc2db7df8a4ea7a9bb378667b8a7193e61fd2ca3a876479174e2a303a74345fbea6e1242e16db48915c1fd3bf35adcf4060a795b425e18 - languageName: node - linkType: hard - "globals@npm:^16.4.0": version: 16.5.0 resolution: "globals@npm:16.5.0" @@ -26663,14 +26672,14 @@ __metadata: languageName: node linkType: hard -"katex@npm:^0.16.0, katex@npm:^0.16.22, katex@npm:^0.16.27": - version: 0.16.27 - resolution: "katex@npm:0.16.27" +"katex@npm:^0.16.0, katex@npm:^0.16.25, katex@npm:^0.16.27": + version: 0.16.38 + resolution: "katex@npm:0.16.38" dependencies: commander: "npm:^8.3.0" bin: katex: cli.js - checksum: 10/7666ae11c6c1238626bffaf1a526af6ff679114d62293bf2f0e29f8a34d8e961c0edcb686c5b628158ec92a143b4bef5d83539c81b29a63c7dcf0bdb4544eec9 + checksum: 10/e9103def114d9d08ab216864e66b68e6f50a6360fdc5aa29d8edeee430e1618dd7551b9f080e9c591b3ee24c18fe6910b8fe0c89c7c4b1109abd2b63e223fbc5 languageName: node linkType: hard @@ -26704,13 +26713,6 @@ __metadata: languageName: node linkType: hard -"kolorist@npm:^1.8.0": - version: 1.8.0 - resolution: "kolorist@npm:1.8.0" - checksum: 10/71d5d122951cc65f2f14c3e1d7f8fd91694b374647d4f6deec3816d018cd04a44edd9578d93e00c82c2053b925e5d30a0565746c4171f4ca9fce1a13bd5f3315 - languageName: node - linkType: hard - "kuler@npm:^2.0.0": version: 2.0.0 resolution: "kuler@npm:2.0.0" @@ -26718,16 +26720,16 @@ __metadata: languageName: node linkType: hard -"langium@npm:3.3.1": - version: 3.3.1 - resolution: "langium@npm:3.3.1" +"langium@npm:^4.0.0": + version: 4.2.1 + resolution: "langium@npm:4.2.1" dependencies: - chevrotain: "npm:~11.0.3" - chevrotain-allstar: "npm:~0.3.0" + chevrotain: "npm:~11.1.1" + chevrotain-allstar: "npm:~0.3.1" vscode-languageserver: "npm:~9.0.1" vscode-languageserver-textdocument: "npm:~1.0.11" - vscode-uri: "npm:~3.0.8" - checksum: 10/6b2e5bc1ff47c6048ec24471333f3397ddb4d6419f1c2262268faff00a8f0839ac4bd4877907261273e91e82f239951249155c3aff8d395ee5e3372dfc285e04 + vscode-uri: "npm:~3.1.0" + checksum: 10/9fd9208762ae9b551ec1deea25b6633605b06b59505a1ce6bf5b6c639779378bab35f813ffe549db57af95a5b71f9dcf61e553273a5d9d6ad2a3a99c5b7bfcc2 languageName: node linkType: hard @@ -27105,17 +27107,6 @@ __metadata: languageName: node linkType: hard -"local-pkg@npm:^1.1.1": - version: 1.1.2 - resolution: "local-pkg@npm:1.1.2" - dependencies: - mlly: "npm:^1.7.4" - pkg-types: "npm:^2.3.0" - quansync: "npm:^0.2.11" - checksum: 10/761d82f40849e4721fa50d86782cf75bc2befb0696f32ac99869fb6f3033b904e4018f4bb8cdfde994d710816480dc1aba8e462c67ec20fe89d4700a245d17f8 - languageName: node - linkType: hard - "locate-path@npm:^2.0.0": version: 2.0.0 resolution: "locate-path@npm:2.0.0" @@ -27153,14 +27144,7 @@ __metadata: languageName: node linkType: hard -"lodash-es@npm:4.17.21": - version: 4.17.21 - resolution: "lodash-es@npm:4.17.21" - checksum: 10/03f39878ea1e42b3199bd3f478150ab723f93cc8730ad86fec1f2804f4a07c6e30deaac73cad53a88e9c3db33348bb8ceeb274552390e7a75d7849021c02df43 - languageName: node - linkType: hard - -"lodash-es@npm:^4.17.21, lodash-es@npm:^4.17.23": +"lodash-es@npm:4.17.23, lodash-es@npm:^4.17.21, lodash-es@npm:^4.17.23": version: 4.17.23 resolution: "lodash-es@npm:4.17.23" checksum: 10/1feae200df22eb0bd93ca86d485e77784b8a9fb1d13e91b66e9baa7a7e5e04be088c12a7e20c2250fc0bd3db1bc0ef0affc7d9e3810b6af2455a3c6bf6dde59e @@ -27762,12 +27746,12 @@ __metadata: languageName: node linkType: hard -"marked@npm:^16.2.1": - version: 16.3.0 - resolution: "marked@npm:16.3.0" +"marked@npm:^16.3.0": + version: 16.4.2 + resolution: "marked@npm:16.4.2" bin: marked: bin/marked.js - checksum: 10/60497834b9acfb3b3994222509d359ecb9a197c885dfeb77e2050a287cd2f4ab19f00d5597172b47f9e0c54d9e1e13d8b2dd73322b7838599e1f16d1d6283f5b + checksum: 10/6e40e40661dce97e271198daa2054fc31e6445892a735e416c248fba046bdfa4573cafa08dc254529f105e7178a34485eb7f82573979cfb377a4530f66e79187 languageName: node linkType: hard @@ -28119,31 +28103,32 @@ __metadata: languageName: node linkType: hard -"mermaid@npm:^11.12.2": - version: 11.12.2 - resolution: "mermaid@npm:11.12.2" +"mermaid@npm:^11.13.0": + version: 11.13.0 + resolution: "mermaid@npm:11.13.0" dependencies: "@braintree/sanitize-url": "npm:^7.1.1" - "@iconify/utils": "npm:^3.0.1" - "@mermaid-js/parser": "npm:^0.6.3" + "@iconify/utils": "npm:^3.0.2" + "@mermaid-js/parser": "npm:^1.0.1" "@types/d3": "npm:^7.4.3" - cytoscape: "npm:^3.29.3" + "@upsetjs/venn.js": "npm:^2.0.0" + cytoscape: "npm:^3.33.1" cytoscape-cose-bilkent: "npm:^4.1.0" cytoscape-fcose: "npm:^2.2.0" d3: "npm:^7.9.0" d3-sankey: "npm:^0.12.3" - dagre-d3-es: "npm:7.0.13" - dayjs: "npm:^1.11.18" - dompurify: "npm:^3.2.5" - katex: "npm:^0.16.22" + dagre-d3-es: "npm:7.0.14" + dayjs: "npm:^1.11.19" + dompurify: "npm:^3.3.1" + katex: "npm:^0.16.25" khroma: "npm:^2.1.0" - lodash-es: "npm:^4.17.21" - marked: "npm:^16.2.1" + lodash-es: "npm:^4.17.23" + marked: "npm:^16.3.0" roughjs: "npm:^4.6.6" stylis: "npm:^4.3.6" ts-dedent: "npm:^2.2.0" uuid: "npm:^11.1.0" - checksum: 10/3c07c1be97a830904c7802933664abd132d626921c3aa82db8d0fbaad35832907cbaa2250747f17e110de5d6f4bdd1fcb9f0416b42c8e59a73653e809333d3da + checksum: 10/7bf2123b005925983eb4d528896665963002c3a617f13fe9d356e4910ff71d3ad0c3f817e717414828f9cdba147651f2ac28af15c60c085f4444f5a786691dd1 languageName: node linkType: hard @@ -28801,15 +28786,15 @@ __metadata: languageName: node linkType: hard -"mlly@npm:^1.4.2, mlly@npm:^1.7.1, mlly@npm:^1.7.4": - version: 1.7.4 - resolution: "mlly@npm:1.7.4" +"mlly@npm:^1.4.2, mlly@npm:^1.7.1, mlly@npm:^1.7.4, mlly@npm:^1.8.0": + version: 1.8.1 + resolution: "mlly@npm:1.8.1" dependencies: - acorn: "npm:^8.14.0" - pathe: "npm:^2.0.1" - pkg-types: "npm:^1.3.0" - ufo: "npm:^1.5.4" - checksum: 10/1b36163d38c2331f8ae480e6a11da3d15927a2148d729fcd9df6d0059ca74869aa693931bd1f762f82eb534b84c921bdfbc036eb0e4da4faeb55f1349d254f35 + acorn: "npm:^8.16.0" + pathe: "npm:^2.0.3" + pkg-types: "npm:^1.3.1" + ufo: "npm:^1.6.3" + checksum: 10/8e424f0615d09adfb7d59ad8f0c8245df275cd05e483a4631a1b2c5dd7e09913a9ce8182bc1562d569941ecee25ab03f4429284265471f562da1dd308008e237 languageName: node linkType: hard @@ -30088,9 +30073,9 @@ __metadata: linkType: hard "package-manager-detector@npm:^1.3.0": - version: 1.3.0 - resolution: "package-manager-detector@npm:1.3.0" - checksum: 10/b21155d53a8ab96d5be3bfae43cc1d397bf363782b922d1f6967d220d2a9f08234ebb76035318bf92822ce761d10451959f01019faebc08fdb4d4a8bc3103da6 + version: 1.6.0 + resolution: "package-manager-detector@npm:1.6.0" + checksum: 10/b38a9532198cefdb98a1b7131c42cbffa55d8b997d6117811cf83f00079fd57a572db2aa5e3db5e36bcd0af84d0bec5a7d6251142427314390ed99a3d76cd0a0 languageName: node linkType: hard @@ -30598,7 +30583,7 @@ __metadata: languageName: node linkType: hard -"pkg-types@npm:^1.2.0, pkg-types@npm:^1.3.0, pkg-types@npm:^1.3.1": +"pkg-types@npm:^1.2.0, pkg-types@npm:^1.3.1": version: 1.3.1 resolution: "pkg-types@npm:1.3.1" dependencies: @@ -30609,7 +30594,7 @@ __metadata: languageName: node linkType: hard -"pkg-types@npm:^2.0.0, pkg-types@npm:^2.1.0, pkg-types@npm:^2.3.0": +"pkg-types@npm:^2.0.0, pkg-types@npm:^2.1.0": version: 2.3.0 resolution: "pkg-types@npm:2.3.0" dependencies: @@ -31416,13 +31401,6 @@ __metadata: languageName: node linkType: hard -"quansync@npm:^0.2.11": - version: 0.2.11 - resolution: "quansync@npm:0.2.11" - checksum: 10/d4f0cc21a25052a8a6183f17752a6221829c4795b40641de67c06945b356841ff00296d3700d0332dfe8e86100fdcc02f4be7559f3f1774a753b05adb7800d01 - languageName: node - linkType: hard - "query-string@npm:^9.1.1": version: 9.2.0 resolution: "query-string@npm:9.2.0" @@ -34637,9 +34615,9 @@ __metadata: linkType: hard "tinyexec@npm:^1.0.0, tinyexec@npm:^1.0.1, tinyexec@npm:^1.0.2": - version: 1.0.2 - resolution: "tinyexec@npm:1.0.2" - checksum: 10/cb709ed4240e873d3816e67f851d445f5676e0ae3a52931a60ff571d93d388da09108c8057b62351766133ee05ff3159dd56c3a0fbd39a5933c6639ce8771405 + version: 1.0.4 + resolution: "tinyexec@npm:1.0.4" + checksum: 10/ccebe4044eef6fa5050929df7862fda70b4fb700f15d94aef8ae6109b9d194dbc3a990125d99944fd25b90fe2115e1927f055b909a604c571a81b647ede5757a languageName: node linkType: hard @@ -35169,10 +35147,10 @@ __metadata: languageName: node linkType: hard -"ufo@npm:^1.5.4": - version: 1.6.1 - resolution: "ufo@npm:1.6.1" - checksum: 10/088a68133b93af183b093e5a8730a40fe7fd675d3dc0656ea7512f180af45c92300c294f14d4d46d4b2b553e3e52d3b13d4856b9885e620e7001edf85531234e +"ufo@npm:^1.5.4, ufo@npm:^1.6.3": + version: 1.6.3 + resolution: "ufo@npm:1.6.3" + checksum: 10/79803984f3e414567273a666183d6a50d1bec0d852100a98f55c1e393cb705e3b88033e04029dd651714e6eec99e1b00f54fdc13f32404968251a16f8898cfe5 languageName: node linkType: hard @@ -36051,10 +36029,10 @@ __metadata: languageName: node linkType: hard -"vscode-uri@npm:~3.0.8": - version: 3.0.8 - resolution: "vscode-uri@npm:3.0.8" - checksum: 10/e882d6b679e0d053cbc042893c0951a135d899a192b62cd07f0a8924f11ae722067a8d6b1b5b147034becf57faf9fff9fb543b17b749fd0f17db1f54f783f07c +"vscode-uri@npm:~3.1.0": + version: 3.1.0 + resolution: "vscode-uri@npm:3.1.0" + checksum: 10/80c2a2421f44b64008ef1f91dfa52a2d68105cbb4dcea197dbf5b00c65ccaccf218b615e93ec587f26fc3ba04796898f3631a9406e3b04cda970c3ca8eadf646 languageName: node linkType: hard