From 0c16d7110d8b00759456a3adc2ca4baefb801414 Mon Sep 17 00:00:00 2001 From: DarkSky <25152247+darkskygit@users.noreply.github.com> Date: Mon, 13 Jul 2026 03:23:08 +0800 Subject: [PATCH] feat: improve native preview (#15223) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #### PR Dependency Tree * **PR #15223** 👈 This tree was auto-generated by [Charcoal](https://github.com/danerwilliams/charcoal) ## Summary by CodeRabbit * **Improvements** * Updated Mermaid and Typst preview rendering in native/mobile apps to use a shared preview implementation. * Improved production Release builds with additional Rust release tuning and enhanced iOS Release stripping/symbol settings. * Enabled stronger release output optimization for the native package build. * **Bug Fixes** * Strengthened handling of unsupported self-hosted server versions during login preflight. * Refreshed unsupported-version messaging with localized text and a direct upgrade link. * **Tests** * Added coverage for login preflight behavior when the server version is unsupported. --- .github/workflows/build-test.yml | 15 + .github/workflows/copilot-test.yml | 2 + Cargo.lock | 862 +++++++++++++++++- Cargo.toml | 12 +- .../ios/App/App.xcodeproj/project.pbxproj | 4 +- .../use-selfhost-login-version-guard.tsx | 43 +- .../src/modules/cloud/stores/auth.spec.ts | 35 +- .../core/src/modules/cloud/stores/auth.ts | 35 +- packages/frontend/mobile-native/Cargo.toml | 7 +- .../frontend/mobile-native/src/preview.rs | 149 +-- packages/frontend/native/Cargo.toml | 5 +- packages/frontend/native/nbstore/Cargo.toml | 1 + .../frontend/native/nbstore/src/indexer.rs | 14 +- packages/frontend/native/package.json | 2 +- packages/frontend/native/src/preview.rs | 130 +-- 15 files changed, 997 insertions(+), 319 deletions(-) diff --git a/.github/workflows/build-test.yml b/.github/workflows/build-test.yml index 6ff1af7fb9..7580814c67 100644 --- a/.github/workflows/build-test.yml +++ b/.github/workflows/build-test.yml @@ -171,6 +171,10 @@ jobs: runs-on: ubuntu-latest needs: - mobile-native-build-filter + env: + CARGO_PROFILE_RELEASE_CODEGEN_UNITS: '16' + CARGO_PROFILE_RELEASE_DEBUG: '1' + CARGO_PROFILE_RELEASE_LTO: 'thin' steps: - uses: actions/checkout@v6 @@ -248,6 +252,9 @@ jobs: - mobile-native-build-filter env: AFFINE_ANDROID_NATIVE_TARGET: x86_64 + CARGO_PROFILE_RELEASE_CODEGEN_UNITS: '16' + CARGO_PROFILE_RELEASE_DEBUG: '1' + CARGO_PROFILE_RELEASE_LTO: 'thin' steps: - uses: actions/checkout@v6 @@ -656,7 +663,9 @@ jobs: name: Build AFFiNE native (x86_64-unknown-linux-gnu) runs-on: ubuntu-latest env: + CARGO_PROFILE_RELEASE_CODEGEN_UNITS: '16' CARGO_PROFILE_RELEASE_DEBUG: '1' + CARGO_PROFILE_RELEASE_LTO: 'thin' steps: - uses: actions/checkout@v6 - name: Setup Node.js @@ -688,7 +697,9 @@ jobs: name: Build AFFiNE native (${{ matrix.spec.target }}) runs-on: ${{ matrix.spec.os }} env: + CARGO_PROFILE_RELEASE_CODEGEN_UNITS: '16' CARGO_PROFILE_RELEASE_DEBUG: '1' + CARGO_PROFILE_RELEASE_LTO: 'thin' strategy: fail-fast: false matrix: @@ -729,7 +740,9 @@ jobs: name: Build AFFiNE native (${{ matrix.spec.target }}) runs-on: ${{ matrix.spec.os }} env: + CARGO_PROFILE_RELEASE_CODEGEN_UNITS: '16' CARGO_PROFILE_RELEASE_DEBUG: '1' + CARGO_PROFILE_RELEASE_LTO: 'thin' strategy: fail-fast: false matrix: @@ -776,7 +789,9 @@ jobs: name: Build Server native runs-on: ubuntu-latest env: + CARGO_PROFILE_RELEASE_CODEGEN_UNITS: '16' CARGO_PROFILE_RELEASE_DEBUG: '1' + CARGO_PROFILE_RELEASE_LTO: 'thin' steps: - uses: actions/checkout@v6 - name: Setup Node.js diff --git a/.github/workflows/copilot-test.yml b/.github/workflows/copilot-test.yml index 24773fca17..6bc4983a4c 100644 --- a/.github/workflows/copilot-test.yml +++ b/.github/workflows/copilot-test.yml @@ -8,7 +8,9 @@ jobs: name: Build Server native runs-on: ubuntu-latest env: + CARGO_PROFILE_RELEASE_CODEGEN_UNITS: '16' CARGO_PROFILE_RELEASE_DEBUG: '1' + CARGO_PROFILE_RELEASE_LTO: 'thin' steps: - uses: actions/checkout@v6 - name: Setup Node.js diff --git a/Cargo.lock b/Cargo.lock index 16c650ee6f..d0beda6f66 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -81,7 +81,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6af9fa0b8359900e4c150b717e837eec813f29ee6981fa72d83e671974c0f78f" dependencies = [ "nanoid 0.5.0", - "pulldown-cmark", + "pulldown-cmark 0.13.1", "serde", "serde_json", "thiserror 2.0.18", @@ -140,19 +140,16 @@ version = "0.0.0" dependencies = [ "affine_common", "affine_nbstore", + "affine_preview", "anyhow", "base64-simd", "chrono", "homedir", "lru 0.16.3", - "mermaid-rs-renderer", "objc2", "objc2-foundation", "thiserror 2.0.18", "tokio", - "typst", - "typst-as-lib", - "typst-svg", "uniffi", ] @@ -165,11 +162,11 @@ dependencies = [ "affine_importer", "affine_media_capture", "affine_nbstore", + "affine_preview", "affine_sqlite_v1", "chrono", "hex", "infer", - "mermaid-rs-renderer", "mimalloc", "napi", "napi-build", @@ -182,9 +179,6 @@ dependencies = [ "thiserror 2.0.18", "tokio", "typed-path", - "typst", - "typst-as-lib", - "typst-svg", "uuid", "zip", ] @@ -197,6 +191,7 @@ dependencies = [ "affine_doc_loader", "affine_schema", "anyhow", + "assert-json-diff", "bincode 2.0.1", "chrono", "dotenvy", @@ -215,6 +210,20 @@ dependencies = [ "zstd", ] +[[package]] +name = "affine_preview" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d5461ead262d12c44addf4d433d212a624c0d69af8e52d9b6a1f4c14ffe2d3c" +dependencies = [ + "merman", + "serde_json", + "thiserror 2.0.18", + "typst", + "typst-as-lib", + "typst-svg", +] + [[package]] name = "affine_schema" version = "0.0.0" @@ -438,6 +447,15 @@ version = "1.0.102" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" +[[package]] +name = "approx" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f2a05fd1bd10b2527e20a2cd32d8873d115b8b39fe219ee25f42a8aca6ba278" +dependencies = [ + "num-traits", +] + [[package]] name = "approx" version = "0.5.1" @@ -477,6 +495,15 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" +[[package]] +name = "ascii-canvas" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8824ecca2e851cec16968d54a01dd372ef8f95b244fb84b84e70128be347c3c6" +dependencies = [ + "term", +] + [[package]] name = "askama" version = "0.13.1" @@ -519,6 +546,16 @@ dependencies = [ "winnow 0.7.15", ] +[[package]] +name = "assert-json-diff" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47e4f2b81832e72834d7518d8487a0396a28cc408186a2e8854c0f98011faf12" +dependencies = [ + "serde", + "serde_json", +] + [[package]] name = "assetpack-core" version = "0.1.0" @@ -696,6 +733,12 @@ dependencies = [ "serde", ] +[[package]] +name = "beef" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a8241f3ebb85c056b509d4327ad0358fbbba6ffb340bf388f26350aeda225b1" + [[package]] name = "biblatex" version = "0.11.0" @@ -809,7 +852,7 @@ dependencies = [ "arrayvec", "bitcode_derive", "bytemuck", - "glam", + "glam 0.33.2", "serde", ] @@ -1149,6 +1192,16 @@ dependencies = [ "libc", ] +[[package]] +name = "cgmath" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a98d30140e3296250832bbaaff83b27dcd6fa3cc70fb6f1f3e5c9c0023b5317" +dependencies = [ + "approx 0.4.0", + "num-traits", +] + [[package]] name = "chacha20" version = "0.10.0" @@ -1277,7 +1330,7 @@ checksum = "714a53001bf66416adb0e2ef5ac857140e7dc3a0c48fb28b2f10762fc4b5069f" dependencies = [ "anstyle", "clap_lex", - "strsim", + "strsim 0.11.1", ] [[package]] @@ -1790,6 +1843,29 @@ dependencies = [ "hybrid-array", ] +[[package]] +name = "cssparser" +version = "0.36.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dae61cf9c0abb83bd659dab65b7e4e38d8236824c85f0f804f173567bda257d2" +dependencies = [ + "cssparser-macros", + "dtoa-short", + "itoa", + "phf 0.13.1", + "smallvec", +] + +[[package]] +name = "cssparser-macros" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331" +dependencies = [ + "quote", + "syn 2.0.117", +] + [[package]] name = "csv" version = "1.4.0" @@ -1845,6 +1921,41 @@ dependencies = [ "cmov", ] +[[package]] +name = "darling" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b750cb3417fd1b327431a470f388520309479ab0bf5e323505daf0290cd3850" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "109c1ca6e6b7f82cc233a97004ea8ed7ca123a9af07a8230878fcfda9b158bf0" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim 0.10.0", + "syn 1.0.109", +] + +[[package]] +name = "darling_macro" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4aab4dbc9f7611d8b55048a3a16d2d010c2c8334e46304b40ac1cc14bf3b48e" +dependencies = [ + "darling_core", + "quote", + "syn 1.0.109", +] + [[package]] name = "dary_heap" version = "0.3.8" @@ -1932,6 +2043,58 @@ dependencies = [ "syn 2.0.117", ] +[[package]] +name = "derive_builder" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d67778784b508018359cbc8696edb3db78160bab2c2a28ba7f56ef6932997f8" +dependencies = [ + "derive_builder_macro", +] + +[[package]] +name = "derive_builder_core" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c11bdc11a0c47bc7d37d582b5285da6849c96681023680b906673c5707af7b0f" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "derive_builder_macro" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebcda35c7a396850a55ffeac740804b40ffec779b98fffbb1738f4033f0ee79e" +dependencies = [ + "derive_builder_core", + "syn 1.0.109", +] + +[[package]] +name = "derive_more" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d751e9e49156b02b44f9c1815bcb94b984cdcc4396ecc32521c739452808b134" +dependencies = [ + "derive_more-impl", +] + +[[package]] +name = "derive_more-impl" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb" +dependencies = [ + "proc-macro2", + "quote", + "rustc_version", + "syn 2.0.117", +] + [[package]] name = "derive_utils" version = "0.15.1" @@ -1977,6 +2140,16 @@ dependencies = [ "dirs-sys", ] +[[package]] +name = "dirs-next" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" +dependencies = [ + "cfg-if", + "dirs-sys-next", +] + [[package]] name = "dirs-sys" version = "0.5.0" @@ -1985,10 +2158,21 @@ checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab" dependencies = [ "libc", "option-ext", - "redox_users", + "redox_users 0.5.2", "windows-sys 0.61.2", ] +[[package]] +name = "dirs-sys-next" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" +dependencies = [ + "libc", + "redox_users 0.4.6", + "winapi", +] + [[package]] name = "dispatch" version = "0.2.0" @@ -2052,6 +2236,21 @@ version = "0.15.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" +[[package]] +name = "dtoa" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c3cf4824e2d5f025c7b531afcb2325364084a16806f6d47fbc1f5fbd9960590" + +[[package]] +name = "dtoa-short" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd1511a7b6a56299bd043a9c167a6d2bfb37bf84a6dfceaba651168adfb43c87" +dependencies = [ + "dtoa", +] + [[package]] name = "dtor" version = "0.1.1" @@ -2067,6 +2266,31 @@ version = "0.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f678cf4a922c215c63e0de95eb1ff08a958a81d47e485cf9da1e27bf6305cfa5" +[[package]] +name = "dugong" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8182775cd5c441f69e5be06b29f1452503568c4270168cef67a557cd8fbcaba0" +dependencies = [ + "dugong-graphlib", + "rustc-hash 2.1.1", + "serde", + "serde_json", + "web-time", +] + +[[package]] +name = "dugong-graphlib" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "faffb9e2480ff1c6901e6376f143614df5331052e60e0dd5086f12399a18c61d" +dependencies = [ + "hashbrown 0.16.1", + "rustc-hash 2.1.1", + "serde", + "serde_json", +] + [[package]] name = "dunce" version = "1.0.5" @@ -2152,6 +2376,15 @@ version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d" +[[package]] +name = "ena" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eabffdaee24bd1bf95c5ef7cec31260444317e72ea56c4c91750e8b7ee58d5f1" +dependencies = [ + "log", +] + [[package]] name = "encoding_rs" version = "0.8.35" @@ -2404,6 +2637,12 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" +[[package]] +name = "fixedbitset" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" + [[package]] name = "flate2" version = "1.1.9" @@ -2796,6 +3035,114 @@ dependencies = [ "syn 2.0.117", ] +[[package]] +name = "glam" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "333928d5eb103c5d4050533cec0384302db6be8ef7d3cebd30ec6a35350353da" + +[[package]] +name = "glam" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3abb554f8ee44336b72d522e0a7fe86a29e09f839a36022fa869a7dfe941a54b" + +[[package]] +name = "glam" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4126c0479ccf7e8664c36a2d719f5f2c140fbb4f9090008098d2c291fa5b3f16" + +[[package]] +name = "glam" +version = "0.17.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e01732b97afd8508eee3333a541b9f7610f454bb818669e66e90f5f57c93a776" + +[[package]] +name = "glam" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "525a3e490ba77b8e326fb67d4b44b4bd2f920f44d4cc73ccec50adc68e3bee34" + +[[package]] +name = "glam" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b8509e6791516e81c1a630d0bd7fbac36d2fa8712a9da8662e716b52d5051ca" + +[[package]] +name = "glam" +version = "0.20.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f43e957e744be03f5801a55472f593d43fabdebf25a4585db250f04d86b1675f" + +[[package]] +name = "glam" +version = "0.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "518faa5064866338b013ff9b2350dc318e14cc4fcd6cb8206d7e7c9886c98815" + +[[package]] +name = "glam" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12f597d56c1bd55a811a1be189459e8fad2bbc272616375602443bdfb37fa774" + +[[package]] +name = "glam" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e4afd9ad95555081e109fe1d21f2a30c691b5f0919c67dfa690a2e1eb6bd51c" + +[[package]] +name = "glam" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5418c17512bdf42730f9032c74e1ae39afc408745ebb2acf72fbc4691c17945" + +[[package]] +name = "glam" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "151665d9be52f9bb40fc7966565d39666f2d1e69233571b71b87791c7e0528b3" + +[[package]] +name = "glam" +version = "0.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e05e7e6723e3455f4818c7b26e855439f7546cf617ef669d1adedb8669e5cb9" + +[[package]] +name = "glam" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "779ae4bf7e8421cf91c0b3b64e7e8b40b862fba4d393f59150042de7c4965a94" + +[[package]] +name = "glam" +version = "0.29.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8babf46d4c1c9d92deac9f7be466f76dfc4482b6452fc5024b5e8daf6ffeb3ee" + +[[package]] +name = "glam" +version = "0.30.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19fc433e8437a212d1b6f1e68c7824af3aed907da60afa994e7f542d18d12aa9" + +[[package]] +name = "glam" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "556f6b2ea90b8d15a74e0e7bb41671c9bdf38cd9f78c284d750b9ce58a2b5be7" + +[[package]] +name = "glam" +version = "0.32.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f70749695b063ecbf6b62949ccccde2e733ec3ecbbd71d467dca4e5c6c97cca0" + [[package]] name = "glam" version = "0.33.2" @@ -3173,6 +3520,19 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "htmlize" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e815d50d9e411ba2690d730e6ec139c08260dddb756df315dbd16d01a587226" +dependencies = [ + "memchr", + "pastey", + "phf 0.13.1", + "phf_codegen 0.13.1", + "serde_json", +] + [[package]] name = "http" version = "1.4.0" @@ -3591,6 +3951,12 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + [[package]] name = "idna" version = "1.1.0" @@ -3817,6 +4183,15 @@ dependencies = [ "either", ] +[[package]] +name = "itertools" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" +dependencies = [ + "either", +] + [[package]] name = "itertools" version = "0.13.0" @@ -3990,12 +4365,13 @@ dependencies = [ [[package]] name = "json5" -version = "1.3.1" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "733a844dbd6fef128e98cb4487b887cb55454d92cd9994b1bafe004fabbe670c" +checksum = "96b0db21af676c1ce64250b5f40f3ce2cf27e4e47cb91ed91eb6fe9350b430c1" dependencies = [ + "pest", + "pest_derive", "serde", - "ucd-trie", ] [[package]] @@ -4055,6 +4431,15 @@ dependencies = [ "cpufeatures 0.3.0", ] +[[package]] +name = "kurbo" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd85a5776cd9500c2e2059c8c76c3b01528566b7fcbaf8098b55a33fc298849b" +dependencies = [ + "arrayvec", +] + [[package]] name = "kurbo" version = "0.11.3" @@ -4089,6 +4474,37 @@ dependencies = [ "smallvec", ] +[[package]] +name = "lalrpop" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55cb077ad656299f160924eb2912aa147d7339ea7d69e1b5517326fdcec3c1ca" +dependencies = [ + "ascii-canvas", + "bit-set 0.5.3", + "ena", + "itertools 0.11.0", + "lalrpop-util", + "petgraph", + "pico-args", + "regex", + "regex-syntax", + "string_cache", + "term", + "tiny-keccak", + "unicode-xid", + "walkdir", +] + +[[package]] +name = "lalrpop-util" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "507460a910eb7b32ee961886ff48539633b788a36b65692b95f225b844c82553" +dependencies = [ + "regex-automata", +] + [[package]] name = "lazy_static" version = "1.5.0" @@ -4133,7 +4549,7 @@ dependencies = [ "git-version", "log", "thread-priority", - "wide", + "wide 0.8.3", ] [[package]] @@ -4338,6 +4754,58 @@ version = "0.4.29" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" +[[package]] +name = "logos" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7251356ef8cb7aec833ddf598c6cb24d17b689d20b993f9d11a3d764e34e6458" +dependencies = [ + "logos-derive", +] + +[[package]] +name = "logos-codegen" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59f80069600c0d66734f5ff52cc42f2dabd6b29d205f333d61fd7832e9e9963f" +dependencies = [ + "beef", + "fnv", + "lazy_static", + "proc-macro2", + "quote", + "regex-syntax", + "syn 2.0.117", +] + +[[package]] +name = "logos-derive" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24fb722b06a9dc12adb0963ed585f19fc61dc5413e6a9be9422ef92c091e731d" +dependencies = [ + "logos-codegen", +] + +[[package]] +name = "lol_html" +version = "2.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6888e8653f6e49cb2924c660fc367a8beeb6239b71e117fa082153c6ea44d427" +dependencies = [ + "bitflags 2.11.0", + "cfg-if", + "cssparser", + "encoding_rs", + "foldhash 0.2.0", + "hashbrown 0.16.1", + "memchr", + "mime", + "precomputed-hash", + "selectors", + "thiserror 2.0.18", +] + [[package]] name = "loom" version = "0.7.2" @@ -4416,6 +4884,19 @@ dependencies = [ "libc", ] +[[package]] +name = "manatee" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85f575aa9013f7fc6f6804dcc8fc47299ee61692c2a7cb017573dc5f3a85a5a4" +dependencies = [ + "indexmap", + "nalgebra", + "rustc-hash 2.1.1", + "thiserror 2.0.18", + "web-time", +] + [[package]] name = "markup5ever" version = "0.11.0" @@ -4451,6 +4932,16 @@ dependencies = [ "regex-automata", ] +[[package]] +name = "matrixmultiply" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06de3016e9fae57a36fd14dba131fccf49f74b40b7fbdb472f96e361ec71a08" +dependencies = [ + "autocfg", + "rawpointer", +] + [[package]] name = "matroska" version = "0.30.0" @@ -4508,26 +4999,74 @@ dependencies = [ "serde", "serde_json", "smol_str", - "strsim", + "strsim 0.11.1", "unicode-normalization", "unicode-script", ] [[package]] -name = "mermaid-rs-renderer" -version = "0.2.1" -source = "git+https://github.com/toeverything/mermaid-rs-renderer?rev=fba9097#fba9097574e424de0497a91c9dc1beeb0e27e4e0" +name = "merman" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "316af7de4c273fb450fa7db94441df29bd09d5dcc5fd7f31f946766dea7272b3" dependencies = [ - "anyhow", - "fontdb", + "chrono", + "merman-core", + "merman-render", + "thiserror 2.0.18", +] + +[[package]] +name = "merman-core" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b7ca468603ca22bad2578b3d3fbc0b436e28b5ccb726e2cf99d7bb75fa8c167" +dependencies = [ + "chrono", + "euclid", + "htmlize", + "indexmap", "json5", - "once_cell", + "lalrpop", + "lalrpop-util", + "logos", + "lol_html", "regex", + "rustc-hash 2.1.1", + "ryu-js", "serde", "serde_json", "serde_yaml", "thiserror 2.0.18", - "ttf-parser", + "tracing", + "url", + "uuid", + "web-time", +] + +[[package]] +name = "merman-render" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46cda864705a73dd80ec8985463d4bf735e991954d5bf63ca5604bf59287582a" +dependencies = [ + "base64", + "chrono", + "dugong", + "indexmap", + "manatee", + "merman-core", + "pulldown-cmark 0.12.2", + "roughr-merman", + "rustc-hash 2.1.1", + "ryu-js", + "serde", + "serde_json", + "svgtypes 0.11.0", + "thiserror 2.0.18", + "unicode-width", + "url", + "web-time", ] [[package]] @@ -4545,6 +5084,12 @@ dependencies = [ "libmimalloc-sys", ] +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + [[package]] name = "minimal-lexical" version = "0.2.1" @@ -4629,6 +5174,39 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13d2233c9842d08cfe13f9eac96e207ca6a2ea10b80259ebe8ad0268be27d2af" +[[package]] +name = "nalgebra" +version = "0.34.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df76ea0ff5c7e6b88689085804d6132ded0ddb9de5ca5b8aeb9eeadc0508a70a" +dependencies = [ + "approx 0.5.1", + "glam 0.14.0", + "glam 0.15.2", + "glam 0.16.0", + "glam 0.17.3", + "glam 0.18.0", + "glam 0.19.0", + "glam 0.20.5", + "glam 0.21.3", + "glam 0.22.0", + "glam 0.23.0", + "glam 0.24.2", + "glam 0.25.0", + "glam 0.27.0", + "glam 0.28.0", + "glam 0.29.3", + "glam 0.30.10", + "glam 0.31.1", + "glam 0.32.1", + "matrixmultiply", + "num-complex", + "num-rational", + "num-traits", + "simba", + "typenum", +] + [[package]] name = "nanoid" version = "0.4.0" @@ -5158,10 +5736,11 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4cbf71184cc5ecc2e4e1baccdb21026c20e5fc3dcf63028a086131b3ab00b6e6" dependencies = [ - "approx", + "approx 0.5.1", "fast-srgb8", "libm", "palette_derive", + "phf 0.11.3", ] [[package]] @@ -5214,6 +5793,12 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" +[[package]] +name = "pastey" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35fb2e5f958ec131621fdd531e9fc186ed768cbe395337403ae56c17a74c68ec" + [[package]] name = "path-ext" version = "0.1.2" @@ -5300,6 +5885,58 @@ version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" +[[package]] +name = "pest" +version = "2.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47627dd7305c6a2d6c8c6bcd24c5a4c17dbbf425f4f9c5313e724b38fc9782e9" +dependencies = [ + "memchr", + "ucd-trie", +] + +[[package]] +name = "pest_derive" +version = "2.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b4254325ecad416ab689e27ba51da03ba01a9632bc6e108f5fe7c3c4ad29d58" +dependencies = [ + "pest", + "pest_generator", +] + +[[package]] +name = "pest_generator" +version = "2.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c4c0e91ead7a8f7acecbca6f003fc2e8282b1dbe2dd9c9d2f16aba42995e0a7" +dependencies = [ + "pest", + "pest_meta", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "pest_meta" +version = "2.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9744bc48116fee06334924bb5f2bad41eed5e89bd26e29b0b799f9a3f82c210" +dependencies = [ + "pest", +] + +[[package]] +name = "petgraph" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" +dependencies = [ + "fixedbitset", + "indexmap", +] + [[package]] name = "phf" version = "0.10.1" @@ -5551,6 +6188,16 @@ dependencies = [ "miniz_oxide", ] +[[package]] +name = "points_on_curve" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca77ae128f56aad518f82cf0af3dcda13b874e59a608dbb287c7887fec97b505" +dependencies = [ + "euclid", + "num-traits", +] + [[package]] name = "polycool" version = "0.4.0" @@ -5765,6 +6412,19 @@ dependencies = [ "cc", ] +[[package]] +name = "pulldown-cmark" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f86ba2052aebccc42cbbb3ed234b8b13ce76f75c3551a303cb2bcffcff12bb14" +dependencies = [ + "bitflags 2.11.0", + "getopts", + "memchr", + "pulldown-cmark-escape", + "unicase", +] + [[package]] name = "pulldown-cmark" version = "0.13.1" @@ -6003,6 +6663,12 @@ dependencies = [ "rand 0.9.4", ] +[[package]] +name = "rawpointer" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3" + [[package]] name = "rayon" version = "1.11.0" @@ -6083,6 +6749,17 @@ dependencies = [ "bitflags 2.11.0", ] +[[package]] +name = "redox_users" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" +dependencies = [ + "getrandom 0.2.17", + "libredox", + "thiserror 1.0.69", +] + [[package]] name = "redox_users" version = "0.5.2" @@ -6242,6 +6919,23 @@ version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c85cd47a33a4510b1424fe796498e174c6a9cf94e606460ef022a19f3e4ff85e" +[[package]] +name = "roughr-merman" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e79c7d4d53683eb43d0263fb5e654bced83db4b51c42c2b08d386e658ff398e" +dependencies = [ + "derive_builder", + "euclid", + "getrandom 0.2.17", + "num-traits", + "palette", + "points_on_curve", + "rand 0.8.6", + "svg_path_ops", + "svgtypes 0.11.0", +] + [[package]] name = "roxmltree" version = "0.20.0" @@ -6464,6 +7158,21 @@ version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" +[[package]] +name = "ryu-js" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04d056b875a9d2e6cb9a61d127afee9ac5999b9f87bcb32079d1318e505be714" + +[[package]] +name = "safe_arch" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96b02de82ddbe1b636e6170c21be622223aea188ef2e139be0a5b219ec215323" +dependencies = [ + "bytemuck", +] + [[package]] name = "safe_arch" version = "0.9.3" @@ -6626,6 +7335,25 @@ dependencies = [ "libc", ] +[[package]] +name = "selectors" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fdfed56cd634f04fe8b9ddf947ae3dc493483e819593d2ba17df9ad05db8b2" +dependencies = [ + "bitflags 2.11.0", + "cssparser", + "derive_more", + "log", + "new_debug_unreachable", + "phf 0.13.1", + "phf_codegen 0.13.1", + "precomputed-hash", + "rustc-hash 2.1.1", + "servo_arc", + "smallvec", +] + [[package]] name = "semver" version = "1.0.27" @@ -6725,6 +7453,15 @@ dependencies = [ "unsafe-libyaml", ] +[[package]] +name = "servo_arc" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "170fb83ab34de17dc69aa7c67482b22218ddb85da56546f9bd6b929e32a05930" +dependencies = [ + "stable_deref_trait", +] + [[package]] name = "sha1" version = "0.10.6" @@ -6825,6 +7562,19 @@ dependencies = [ "rand_core 0.6.4", ] +[[package]] +name = "simba" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c99284beb21666094ba2b75bbceda012e610f5479dfcc2d6e2426f53197ffd95" +dependencies = [ + "approx 0.5.1", + "num-complex", + "num-traits", + "paste", + "wide 0.7.33", +] + [[package]] name = "simd-adler32" version = "0.3.8" @@ -7239,6 +7989,12 @@ dependencies = [ "unicode-properties", ] +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + [[package]] name = "strsim" version = "0.11.1" @@ -7305,6 +8061,26 @@ version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" +[[package]] +name = "svg_path_ops" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2ed183bad71dff813db12a317785a8565c9b44732cca3c2effd40a06eb9cd28" +dependencies = [ + "cgmath", + "svgtypes 0.11.0", +] + +[[package]] +name = "svgtypes" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed4b0611e7f3277f68c0fa18e385d9e2d26923691379690039548f867cef02a7" +dependencies = [ + "kurbo 0.9.5", + "siphasher 0.3.11", +] + [[package]] name = "svgtypes" version = "0.15.3" @@ -7637,6 +8413,17 @@ dependencies = [ "utf-8", ] +[[package]] +name = "term" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c59df8ac95d96ff9bede18eb7300b0fda5e5d8d90960e76f8e14ae765eedbf1f" +dependencies = [ + "dirs-next", + "rustversion", + "winapi", +] + [[package]] name = "text-splitter" version = "0.32.0" @@ -7650,7 +8437,7 @@ dependencies = [ "icu_segmenter 2.1.2", "itertools 0.14.0", "memchr", - "pulldown-cmark", + "pulldown-cmark 0.13.1", "strum 0.28.0", "thiserror 2.0.18", "tiktoken-rs 0.12.0", @@ -7810,6 +8597,15 @@ dependencies = [ "time-core", ] +[[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" +dependencies = [ + "crunchy", +] + [[package]] name = "tiny-skia-path" version = "0.11.4" @@ -8946,7 +9742,7 @@ dependencies = [ "simplecss", "siphasher 1.0.2", "strict-num", - "svgtypes", + "svgtypes 0.15.3", "tiny-skia-path", "unicode-bidi", "unicode-script", @@ -9311,6 +10107,16 @@ dependencies = [ "wasite", ] +[[package]] +name = "wide" +version = "0.7.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ce5da8ecb62bcd8ec8b7ea19f69a51275e91299be594ea5cc6ef7819e16cd03" +dependencies = [ + "bytemuck", + "safe_arch 0.7.4", +] + [[package]] name = "wide" version = "0.8.3" @@ -9318,7 +10124,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13ca908d26e4786149c48efcf6c0ea09ab0e06d1fe3c17dc1b4b0f1ca4a7e788" dependencies = [ "bytemuck", - "safe_arch", + "safe_arch 0.9.3", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 6534a1baec..1226484732 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,6 +19,7 @@ resolver = "3" affine_doc_loader = "0.1.2" affine_importer = "0.1.1" affine_nbstore = { path = "./packages/frontend/native/nbstore" } + affine_preview = { version = "0.1.0", default-features = false } anyhow = "1" assert-json-diff = "2.0" base64 = "0.22.1" @@ -52,7 +53,6 @@ resolver = "3" lru = "0.16" matroska = "0.30" memory-indexer = "0.3.1" - 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" @@ -96,14 +96,6 @@ resolver = "3" tiktoken-rs = "0.7" tokio = "1.45" typed-path = "0.12.3" - 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" @@ -129,7 +121,7 @@ opt-level = 3 [profile.release] codegen-units = 1 -lto = true +lto = "fat" opt-level = 3 strip = "symbols" diff --git a/packages/frontend/apps/ios/App/App.xcodeproj/project.pbxproj b/packages/frontend/apps/ios/App/App.xcodeproj/project.pbxproj index 9541054267..6472c65354 100644 --- a/packages/frontend/apps/ios/App/App.xcodeproj/project.pbxproj +++ b/packages/frontend/apps/ios/App/App.xcodeproj/project.pbxproj @@ -566,8 +566,9 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "Apple Distribution: TOEVERYTHING PTE. LTD. (73YMMDVT2M)"; CODE_SIGN_STYLE = Manual; - COPY_PHASE_STRIP = NO; + COPY_PHASE_STRIP = YES; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DEPLOYMENT_POSTPROCESSING = YES; DEVELOPMENT_TEAM = 73YMMDVT2M; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -587,6 +588,7 @@ SUPPORTED_PLATFORMS = "iphonesimulator iphoneos"; SWIFT_COMPILATION_MODE = wholemodule; SWIFT_OPTIMIZATION_LEVEL = "-O"; + STRIP_INSTALLED_PRODUCT = YES; VALIDATE_PRODUCT = YES; }; name = Release; diff --git a/packages/frontend/core/src/components/hooks/affine/use-selfhost-login-version-guard.tsx b/packages/frontend/core/src/components/hooks/affine/use-selfhost-login-version-guard.tsx index ec4daaa872..75ada08cb0 100644 --- a/packages/frontend/core/src/components/hooks/affine/use-selfhost-login-version-guard.tsx +++ b/packages/frontend/core/src/components/hooks/affine/use-selfhost-login-version-guard.tsx @@ -1,5 +1,6 @@ import type { Server } from '@affine/core/modules/cloud'; import { MIN_SUPPORTED_SERVER_VERSION } from '@affine/core/modules/cloud/stores/server-config'; +import { useI18n } from '@affine/i18n'; import { useLiveData } from '@toeverything/infra'; import { cssVarV2 } from '@toeverything/theme/v2'; import semver from 'semver'; @@ -7,7 +8,7 @@ import semver from 'semver'; const rules = [ { min: MIN_SUPPORTED_SERVER_VERSION, - tip: (receivedVersion: string, requiredVersion: string) => ( + tip: (message: string) => (

- Your server version{' '} - {receivedVersion} is not compatible - with current client. Please upgrade your server to{' '} - {requiredVersion} or higher to use - this client. + {message}

-
- Instructions: -
- - https://docs.affine.pro/self-host-affine/install/upgrade - -
+ + https://docs.affine.pro/self-host-affine/install/upgrade +
), }, @@ -45,12 +41,17 @@ const rules = [ * Return the error tip if the server version is not meet the requirement */ export const useSelfhostLoginVersionGuard = (server: Server) => { + const t = useI18n(); const serverVersion = useLiveData(server.config$.selector(c => c.version)) ?? '0.0.0'; for (const rule of rules) { if (semver.lt(serverVersion, rule.min)) { - return rule.tip(serverVersion, rule.min); + return rule.tip( + t['error.UNSUPPORTED_SERVER_VERSION']({ + requiredVersion: `>=${rule.min}`, + }) + ); } } diff --git a/packages/frontend/core/src/modules/cloud/stores/auth.spec.ts b/packages/frontend/core/src/modules/cloud/stores/auth.spec.ts index cb4e84ef89..a6f31c6676 100644 --- a/packages/frontend/core/src/modules/cloud/stores/auth.spec.ts +++ b/packages/frontend/core/src/modules/cloud/stores/auth.spec.ts @@ -19,7 +19,10 @@ function createStore({ framework.service(GraphQLService, {} as any); framework.impl(GlobalState, {} as any); framework.service(ServerService, { - server: { id: 'test-server' }, + server: { + id: 'test-server', + ['config$']: { value: { version: '0.27.0' } }, + }, } as any); framework.impl(AuthProvider, {} as any); framework.service(NbstoreService, { @@ -37,6 +40,36 @@ function createStore({ } describe('AuthStore', () => { + test('validates login preflight responses', async () => { + const validResponse = { + registered: true, + methods: { + password: { available: true }, + magicLink: { available: true }, + oauth: { available: false, providers: [] }, + passkey: { available: false, discoverable: false }, + }, + }; + const fetch = vi + .fn() + .mockResolvedValueOnce({ ok: true, json: async () => validResponse }) + .mockResolvedValueOnce({ + ok: true, + json: async () => ({ registered: true, methods: {} }), + }); + const store = createStore({ fetch, request: vi.fn() }); + + await expect(store.checkUserByEmail('user@affine.pro')).resolves.toEqual( + validResponse + ); + await expect( + store.checkUserByEmail('user@affine.pro') + ).rejects.toMatchObject({ + name: 'UNSUPPORTED_SERVER_VERSION', + data: { serverVersion: '0.27.0' }, + }); + }); + test('loads account profile from realtime after auth session bootstrap', async () => { const authMethods = { password: { bound: true }, diff --git a/packages/frontend/core/src/modules/cloud/stores/auth.ts b/packages/frontend/core/src/modules/cloud/stores/auth.ts index f5330f7e08..d34db9b2f6 100644 --- a/packages/frontend/core/src/modules/cloud/stores/auth.ts +++ b/packages/frontend/core/src/modules/cloud/stores/auth.ts @@ -7,6 +7,7 @@ import { } from '@affine/graphql'; import type { CurrentUserProfileSnapshot } from '@affine/realtime'; import { Store } from '@toeverything/infra'; +import { z } from 'zod'; import type { GlobalState, NbstoreService } from '../../storage'; import type { AuthSessionInfo } from '../entities/session'; @@ -14,6 +15,23 @@ import type { AuthProvider, SignInUserInfo } from '../provider/auth'; import type { FetchService } from '../services/fetch'; import type { GraphQLService } from '../services/graphql'; import type { ServerService } from '../services/server'; +import { createUnsupportedServerVersionError } from './server-config'; + +const AuthPreflightResponseSchema = z.object({ + registered: z.boolean(), + methods: z.object({ + password: z.object({ available: z.boolean() }), + magicLink: z.object({ available: z.boolean() }), + oauth: z.object({ + available: z.boolean(), + providers: z.array(z.string()), + }), + passkey: z.object({ + available: z.boolean(), + discoverable: z.boolean(), + }), + }), +}); export interface AccountProfile extends CurrentUserProfileSnapshot { authMethods?: { @@ -201,17 +219,14 @@ export class AuthStore extends Store { throw new Error(`Failed to check user by email: ${email}`); } - const data = (await res.json()) as { - registered: boolean; - methods: { - password: { available: boolean }; - magicLink: { available: boolean }; - oauth: { available: boolean; providers: string[] }; - passkey: { available: boolean; discoverable: boolean }; - }; - }; + const data = AuthPreflightResponseSchema.safeParse(await res.json()); + if (!data.success) { + throw createUnsupportedServerVersionError( + this.serverService.server.config$.value.version + ); + } - return data; + return data.data; } async deleteAccount() { diff --git a/packages/frontend/mobile-native/Cargo.toml b/packages/frontend/mobile-native/Cargo.toml index 2f89425017..e6d4486a61 100644 --- a/packages/frontend/mobile-native/Cargo.toml +++ b/packages/frontend/mobile-native/Cargo.toml @@ -40,11 +40,8 @@ objc2-foundation = { workspace = true, features = [ homedir = { workspace = true } [target.'cfg(any(target_os = "android", target_os = "ios"))'.dependencies] -lru = { workspace = true } -mermaid-rs-renderer = { workspace = true } -typst = { workspace = true } -typst-as-lib = { workspace = true } -typst-svg = { workspace = true } +affine_preview = { workspace = true, features = ["mermaid", "typst"] } +lru = { workspace = true } [build-dependencies] uniffi = { workspace = true, features = ["build"] } diff --git a/packages/frontend/mobile-native/src/preview.rs b/packages/frontend/mobile-native/src/preview.rs index d155f22d50..9b7a2c8f49 100644 --- a/packages/frontend/mobile-native/src/preview.rs +++ b/packages/frontend/mobile-native/src/preview.rs @@ -1,67 +1,9 @@ -use std::{borrow::Cow, path::PathBuf}; +use std::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 affine_preview::{MermaidRenderOptions, TypstRenderOptions}; 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(), - Some("dark") | Some("modern") => RenderOptions::modern(), - _ => 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, @@ -69,38 +11,15 @@ pub fn render_mermaid_preview_svg( 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 + affine_preview::render_mermaid_svg( + &code, + MermaidRenderOptions { + theme, + font_family, + font_size, + }, + ) + .map_err(|error| UniffiError::Err(error.to_string())) } fn resolve_typst_font_dirs(font_dirs: Option>) -> Vec { @@ -109,48 +28,18 @@ fn resolve_typst_font_dirs(font_dirs: Option>) -> Vec { .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)))) + affine_preview::render_typst_svg( + &code, + TypstRenderOptions { + font_dirs: resolve_typst_font_dirs(font_dirs), + cache_dir: cache_dir.map(PathBuf::from), + }, + ) + .map_err(|error| UniffiError::Err(error.to_string())) } diff --git a/packages/frontend/native/Cargo.toml b/packages/frontend/native/Cargo.toml index 8110bdab15..dc14c911f2 100644 --- a/packages/frontend/native/Cargo.toml +++ b/packages/frontend/native/Cargo.toml @@ -34,10 +34,7 @@ tokio = { workspace = true, features = ["full"] } typed-path = { workspace = true } [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 } +affine_preview = { workspace = true, features = ["mermaid", "typst"] } [target.'cfg(not(target_os = "linux"))'.dependencies] mimalloc = { workspace = true } diff --git a/packages/frontend/native/nbstore/Cargo.toml b/packages/frontend/native/nbstore/Cargo.toml index 259758bb9a..b9287a196c 100644 --- a/packages/frontend/native/nbstore/Cargo.toml +++ b/packages/frontend/native/nbstore/Cargo.toml @@ -53,5 +53,6 @@ tokio = { workspace = true, features = ["full"] } [dev-dependencies] +assert-json-diff = { workspace = true } serde_json = { workspace = true } uuid = { workspace = true, features = ["v4"] } diff --git a/packages/frontend/native/nbstore/src/indexer.rs b/packages/frontend/native/nbstore/src/indexer.rs index 95e2165ce9..e736d822de 100644 --- a/packages/frontend/native/nbstore/src/indexer.rs +++ b/packages/frontend/native/nbstore/src/indexer.rs @@ -277,6 +277,7 @@ mod tests { use std::path::{Path, PathBuf}; use affine_doc_loader::ParseError; + use assert_json_diff::assert_json_eq; use chrono::Utc; use serde_json::Value; use tokio::fs; @@ -319,9 +320,16 @@ mod tests { let result = storage.crawl_doc_data("demo-doc").await.unwrap(); - let expected: Value = serde_json::from_slice(DEMO_JSON).unwrap(); - let actual = serde_json::to_value(&result).unwrap(); - assert_eq!(expected, actual); + let mut expected: Value = serde_json::from_slice(DEMO_JSON).unwrap(); + let mut actual = serde_json::to_value(&result).unwrap(); + for document in [&mut expected, &mut actual] { + for block in document["blocks"].as_array_mut().unwrap() { + if let Some(additional) = block["additional"].as_str() { + block["additional"] = serde_json::from_str(additional).unwrap(); + } + } + } + assert_json_eq!(expected, actual); storage.close().await; cleanup(&db_path).await; diff --git a/packages/frontend/native/package.json b/packages/frontend/native/package.json index 0fffdd2dff..250c2738e7 100644 --- a/packages/frontend/native/package.json +++ b/packages/frontend/native/package.json @@ -37,7 +37,7 @@ }, "scripts": { "artifacts": "napi artifacts", - "build": "napi build -p affine_native --platform --release", + "build": "napi build -p affine_native --platform --release --strip", "build:debug": "napi build -p affine_native --platform", "universal": "napi universal", "test": "ava --no-worker-threads --concurrency=2", diff --git a/packages/frontend/native/src/preview.rs b/packages/frontend/native/src/preview.rs index aa3e6eaf4c..4a52deb7bc 100644 --- a/packages/frontend/native/src/preview.rs +++ b/packages/frontend/native/src/preview.rs @@ -1,10 +1,10 @@ use std::path::PathBuf; -use mermaid_rs_renderer::RenderOptions; +use affine_preview::{ + MermaidRenderOptions as PreviewMermaidRenderOptions, TypstRenderOptions as PreviewTypstRenderOptions, +}; 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 { @@ -24,31 +24,22 @@ 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(), - Some("dark") | Some("modern") => RenderOptions::modern(), - _ => 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()))?; + let options = request.options.unwrap_or(MermaidRenderOptions { + theme: None, + font_family: None, + font_size: None, + }); + let svg = affine_preview::render_mermaid_svg( + &request.code, + PreviewMermaidRenderOptions { + theme: options.theme, + font_family: options.font_family, + font_size: options.font_size, + }, + ) + .map_err(|error| Error::from_reason(error.to_string()))?; Ok(MermaidRenderResult { svg }) } @@ -106,87 +97,16 @@ fn resolve_typst_font_dirs(options: &Option) -> Vec 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))); + let svg = affine_preview::render_typst_svg( + &request.code, + PreviewTypstRenderOptions { + font_dirs, + cache_dir: None, + }, + ) + .map_err(|error| Error::from_reason(error.to_string()))?; 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 ""##)); - } -}