From 97cab2d70b3b1a489b51480397c05d58c094567e Mon Sep 17 00:00:00 2001 From: Huang Xin Date: Fri, 6 Mar 2026 04:00:15 +0800 Subject: [PATCH] feat(database): support turso fts in tauri apps (#3484) --- .gitmodules | 6 +- .prettierignore | 2 +- Cargo.lock | 1898 ++++++++++------- apps/readest-app/docs/testing.md | 4 +- apps/readest-app/src-tauri/Cargo.toml | 2 +- .../capabilities-extra/webdriver.json | 2 +- .../src-tauri/capabilities/default.json | 2 +- .../src-tauri/plugins/tauri-plugin-libsql | 1 - .../src-tauri/plugins/tauri-plugin-turso | 1 + apps/readest-app/src-tauri/src/lib.rs | 2 +- .../__tests__/database/libsql.tauri.test.ts | 366 ---- .../src/__tests__/database/mock.test.ts | 8 +- .../__tests__/database/suites/base-tests.ts | 175 ++ .../src/__tests__/database/turso-node.test.ts | 170 +- .../database/turso-rust.tauri.test.ts | 106 + .../database/turso-wasm.browser.test.ts | 166 +- .../database/nativeDatabaseService.ts | 2 +- .../services/database/nodeDatabaseService.ts | 2 +- apps/readest-app/tsconfig.json | 2 +- 19 files changed, 1482 insertions(+), 1435 deletions(-) delete mode 160000 apps/readest-app/src-tauri/plugins/tauri-plugin-libsql create mode 160000 apps/readest-app/src-tauri/plugins/tauri-plugin-turso delete mode 100644 apps/readest-app/src/__tests__/database/libsql.tauri.test.ts create mode 100644 apps/readest-app/src/__tests__/database/suites/base-tests.ts create mode 100644 apps/readest-app/src/__tests__/database/turso-rust.tauri.test.ts diff --git a/.gitmodules b/.gitmodules index b97beb38..00fccba7 100644 --- a/.gitmodules +++ b/.gitmodules @@ -10,6 +10,6 @@ [submodule "packages/simplecc-wasm"] path = packages/simplecc-wasm url = https://github.com/readest/simplecc-wasm.git -[submodule "apps/readest-app/src-tauri/plugins/tauri-plugin-libsql"] - path = apps/readest-app/src-tauri/plugins/tauri-plugin-libsql - url = https://github.com/readest/tauri-plugin-libsql.git +[submodule "apps/readest-app/src-tauri/plugins/tauri-plugin-turso"] + path = apps/readest-app/src-tauri/plugins/tauri-plugin-turso + url = https://github.com/readest/tauri-plugin-turso.git diff --git a/.prettierignore b/.prettierignore index 1e64d609..d465bd46 100644 --- a/.prettierignore +++ b/.prettierignore @@ -25,7 +25,7 @@ packages # Vendored Assets (Generated/External Code) apps/readest-app/public/*.js apps/readest-app/public/vendor -apps/readest-app/src-tauri/plugins/tauri-plugin-libsql +apps/readest-app/src-tauri/plugins/tauri-plugin-turso # Environment & Editor .env diff --git a/Cargo.lock b/Cargo.lock index 56e10282..98e2ec98 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -38,7 +38,6 @@ dependencies = [ "tauri-plugin-fs", "tauri-plugin-haptics", "tauri-plugin-http", - "tauri-plugin-libsql", "tauri-plugin-log", "tauri-plugin-native-bridge", "tauri-plugin-native-tts", @@ -51,6 +50,7 @@ dependencies = [ "tauri-plugin-shell", "tauri-plugin-sign-in-with-apple", "tauri-plugin-single-instance", + "tauri-plugin-turso", "tauri-plugin-updater", "tauri-plugin-webdriver", "tauri-plugin-websocket", @@ -77,6 +77,16 @@ dependencies = [ "generic-array", ] +[[package]] +name = "aegis" +version = "0.9.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ae1572243695de9c6c8d16c7889899abac907d14c148f1939d837122bbeca79" +dependencies = [ + "cc", + "softaes", +] + [[package]] name = "aes" version = "0.8.4" @@ -113,18 +123,6 @@ dependencies = [ "version_check", ] -[[package]] -name = "ahash" -version = "0.8.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" -dependencies = [ - "cfg-if", - "once_cell", - "version_check", - "zerocopy 0.8.40", -] - [[package]] name = "aho-corasick" version = "1.1.4" @@ -231,6 +229,22 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "antithesis_sdk" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18dbd97a5b6c21cc9176891cf715f7f0c273caf3959897f43b9bd1231939e675" +dependencies = [ + "libc", + "libloading 0.8.9", + "linkme", + "once_cell", + "rand 0.8.5", + "rustc_version_runtime", + "serde", + "serde_json", +] + [[package]] name = "anyhow" version = "1.0.102" @@ -246,12 +260,27 @@ dependencies = [ "derive_arbitrary", ] +[[package]] +name = "arc-swap" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9f3647c145568cec02c42054e07bdf9a5a698e15b466fb2341bfc393cd24aa5" +dependencies = [ + "rustversion", +] + [[package]] name = "arrayvec" version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" +[[package]] +name = "assoc" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfdc70193dadb9d7287fa4b633f15f90c876915b31f6af17da307fc59c9859a8" + [[package]] name = "async-broadcast" version = "0.7.2" @@ -366,28 +395,6 @@ dependencies = [ "windows-sys 0.61.2", ] -[[package]] -name = "async-stream" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476" -dependencies = [ - "async-stream-impl", - "futures-core", - "pin-project-lite", -] - -[[package]] -name = "async-stream-impl" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", -] - [[package]] name = "async-task" version = "4.7.1" @@ -440,51 +447,23 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" -[[package]] -name = "axum" -version = "0.6.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b829e4e32b91e643de6eafe82b1d90675f5874230191a4ffbc1b336dec4d6bf" -dependencies = [ - "async-trait", - "axum-core 0.3.4", - "bitflags 1.3.2", - "bytes", - "futures-util", - "http 0.2.12", - "http-body 0.4.6", - "hyper 0.14.32", - "itoa", - "matchit 0.7.3", - "memchr", - "mime", - "percent-encoding", - "pin-project-lite", - "rustversion", - "serde", - "sync_wrapper 0.1.2", - "tower 0.4.13", - "tower-layer", - "tower-service", -] - [[package]] name = "axum" version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b52af3cb4058c895d37317bb27508dccc8e5f2d39454016b297bf4a400597b8" dependencies = [ - "axum-core 0.5.6", + "axum-core", "bytes", "form_urlencoded", "futures-util", - "http 1.4.0", - "http-body 1.0.1", + "http", + "http-body", "http-body-util", - "hyper 1.8.1", + "hyper", "hyper-util", "itoa", - "matchit 0.8.4", + "matchit", "memchr", "mime", "percent-encoding", @@ -493,31 +472,14 @@ dependencies = [ "serde_json", "serde_path_to_error", "serde_urlencoded", - "sync_wrapper 1.0.2", + "sync_wrapper", "tokio", - "tower 0.5.3", + "tower", "tower-layer", "tower-service", "tracing", ] -[[package]] -name = "axum-core" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "759fa577a247914fd3f7f76d62972792636412fbfd634cd452f6a385a74d2d2c" -dependencies = [ - "async-trait", - "bytes", - "futures-util", - "http 0.2.12", - "http-body 0.4.6", - "mime", - "rustversion", - "tower-layer", - "tower-service", -] - [[package]] name = "axum-core" version = "0.5.6" @@ -526,12 +488,12 @@ checksum = "08c78f31d7b1291f7ee735c1c6780ccde7785daae9a9206026862dab7d8792d1" dependencies = [ "bytes", "futures-core", - "http 1.4.0", - "http-body 1.0.1", + "http", + "http-body", "http-body-util", "mime", "pin-project-lite", - "sync_wrapper 1.0.2", + "sync_wrapper", "tower-layer", "tower-service", "tracing", @@ -566,6 +528,19 @@ dependencies = [ "winapi", ] +[[package]] +name = "bigdecimal" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d6867f1565b3aad85681f1015055b087fcfd840d6aeee6eee7f2da317603695" +dependencies = [ + "autocfg", + "libm", + "num-bigint", + "num-integer", + "num-traits", +] + [[package]] name = "bincode" version = "1.3.3" @@ -577,17 +552,17 @@ dependencies = [ [[package]] name = "bindgen" -version = "0.66.1" +version = "0.69.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2b84e06fc203107bfbad243f4aba2af864eb7db3b1cf46ea0a023b0b433d2a7" +checksum = "271383c67ccabffb7381723dea0672a673f292304fcb45c01cc648c7a8d58088" dependencies = [ "bitflags 2.11.0", "cexpr", "clang-sys", + "itertools 0.12.1", "lazy_static", "lazycell", "log", - "peeking_take_while", "prettyplease", "proc-macro2", "quote", @@ -628,6 +603,15 @@ dependencies = [ "serde_core", ] +[[package]] +name = "bitpacking" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96a7139abd3d9cebf8cd6f920a389cf3dc9576172e32f4563f188cae3c3eb019" +dependencies = [ + "crunchy", +] + [[package]] name = "bitvec" version = "1.0.1" @@ -655,15 +639,6 @@ dependencies = [ "generic-array", ] -[[package]] -name = "block-padding" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8894febbff9f758034a5b8e12d87918f56dfc64a8e1fe757d65e29041538d93" -dependencies = [ - "generic-array", -] - [[package]] name = "block2" version = "0.6.2" @@ -686,6 +661,31 @@ dependencies = [ "piper", ] +[[package]] +name = "bon" +version = "3.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d13a61f2963b88eef9c1be03df65d42f6996dfeac1054870d950fcf66686f83" +dependencies = [ + "bon-macros", + "rustversion", +] + +[[package]] +name = "bon-macros" +version = "3.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d314cc62af2b6b0c65780555abb4d02a03dd3b799cd42419044f0c38d99738c0" +dependencies = [ + "darling 0.20.11", + "ident_case", + "prettyplease", + "proc-macro2", + "quote", + "rustversion", + "syn 2.0.117", +] + [[package]] name = "borsh" version = "1.6.0" @@ -709,6 +709,15 @@ dependencies = [ "syn 2.0.117", ] +[[package]] +name = "branches" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e426eb5cc1900033930ec955317b302e68f19f326cc7bb0c8a86865a826cdf0c" +dependencies = [ + "rustc_version", +] + [[package]] name = "brotli" version = "8.0.2" @@ -730,6 +739,15 @@ dependencies = [ "alloc-stdlib", ] +[[package]] +name = "built" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56ed6191a7e78c36abdb16ab65341eefd73d64d303fffccdbb00d51e4205967b" +dependencies = [ + "chrono", +] + [[package]] name = "bumpalo" version = "3.20.2" @@ -775,6 +793,20 @@ name = "bytemuck" version = "1.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" 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" @@ -864,15 +896,6 @@ dependencies = [ "toml 0.9.12+spec-1.1.0", ] -[[package]] -name = "cbc" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b52a9543ae338f279b96b0b9fed9c8093744685043739079ce85cd58f289a6" -dependencies = [ - "cipher", -] - [[package]] name = "cc" version = "1.2.56" @@ -880,9 +903,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aebf35691d1bfb0ac386a69bac2fde4dd276fb618cf8bf4f5318fe285e821bb2" dependencies = [ "find-msvc-tools", + "jobserver", + "libc", "shlex", ] +[[package]] +name = "census" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f4c707c6a209cbe82d10abd08e1ea8995e9ea937d2550646e02798948992be0" + [[package]] name = "cesu8" version = "1.1.0" @@ -941,6 +972,12 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" +[[package]] +name = "cfg_block" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18758054972164c3264f7c8386f5fc6da6114cb46b619fd365d4e3b2dc3ae487" + [[package]] name = "chrono" version = "0.4.44" @@ -1003,15 +1040,6 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3a822ea5bc7590f9d40f1ba12c0dc3c2760f3482c6984db1573ad11031420831" -[[package]] -name = "cmake" -version = "0.1.57" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75443c44cd6b379beb8c5b45d85d0773baf31cce901fe7bb252f4eff3008ef7d" -dependencies = [ - "cc", -] - [[package]] name = "cocoa" version = "0.25.0" @@ -1251,6 +1279,15 @@ dependencies = [ "libc", ] +[[package]] +name = "crc32c" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a47af21622d091a8f0fb295b88bc886ac74efcc613efc19f5d0b21de5c89e47" +dependencies = [ + "rustc_version", +] + [[package]] name = "crc32fast" version = "1.5.0" @@ -1269,6 +1306,35 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "crossbeam-deque" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-skiplist" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df29de440c58ca2cc6e587ec3d22347551a32435fbde9d2bff64e78a9ffa151b" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + [[package]] name = "crossbeam-utils" version = "0.8.21" @@ -1632,6 +1698,12 @@ dependencies = [ "litrs", ] +[[package]] +name = "downcast-rs" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "117240f60069e65410b3ae1bb213295bd828f707b5bec6596a1afc8793ce0cbc" + [[package]] name = "dpi" version = "0.1.2" @@ -1822,12 +1894,6 @@ dependencies = [ "pin-project-lite", ] -[[package]] -name = "fallible-iterator" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" - [[package]] name = "fallible-iterator" version = "0.3.0" @@ -1835,10 +1901,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" [[package]] -name = "fallible-streaming-iterator" -version = "0.1.9" +name = "fastbloom" +version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a" +checksum = "4e7f34442dbe69c60fe8eaf58a8cafff81a1f278816d8ab4db255b3bef4ac3c4" +dependencies = [ + "getrandom 0.3.4", + "libm", + "rand 0.9.2", + "siphasher 1.0.2", +] + +[[package]] +name = "fastdivide" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9afc2bd4d5a73106dd53d10d73d3401c2f32730ba2c0b93ddb888a8983680471" [[package]] name = "fastrand" @@ -1986,6 +2064,16 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "fs4" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8640e34b88f7652208ce9e88b1a37a2ae95227d84abec377ccd3c5cfeb141ed4" +dependencies = [ + "rustix 1.1.4", + "windows-sys 0.59.0", +] + [[package]] name = "funty" version = "2.0.0" @@ -2211,6 +2299,36 @@ dependencies = [ "x11", ] +[[package]] +name = "genawaiter" +version = "0.99.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c86bd0361bcbde39b13475e6e36cb24c329964aa2611be285289d1e4b751c1a0" +dependencies = [ + "genawaiter-macro", +] + +[[package]] +name = "genawaiter-macro" +version = "0.99.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b32dfe1fdfc0bbde1f22a5da25355514b5e450c33a6af6770884c8750aedfbc" + +[[package]] +name = "generator" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52f04ae4152da20c76fe800fa48659201d5cf627c5149ca0b707b69d7eef6cf9" +dependencies = [ + "cc", + "cfg-if", + "libc", + "log", + "rustversion", + "windows-link 0.2.1", + "windows-result 0.4.1", +] + [[package]] name = "generic-array" version = "0.14.7" @@ -2521,25 +2639,6 @@ dependencies = [ "syn 2.0.117", ] -[[package]] -name = "h2" -version = "0.3.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0beca50380b1fc32983fc1cb4587bfa4bb9e78fc259aad4a0032d2080309222d" -dependencies = [ - "bytes", - "fnv", - "futures-core", - "futures-sink", - "futures-util", - "http 0.2.12", - "indexmap 2.13.0", - "slab", - "tokio", - "tokio-util", - "tracing", -] - [[package]] name = "h2" version = "0.4.13" @@ -2551,7 +2650,7 @@ dependencies = [ "fnv", "futures-core", "futures-sink", - "http 1.4.0", + "http", "indexmap 2.13.0", "slab", "tokio", @@ -2565,7 +2664,7 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" dependencies = [ - "ahash 0.7.8", + "ahash", ] [[package]] @@ -2573,10 +2672,6 @@ name = "hashbrown" version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" -dependencies = [ - "ahash 0.8.12", - "allocator-api2", -] [[package]] name = "hashbrown" @@ -2584,6 +2679,8 @@ version = "0.15.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" dependencies = [ + "allocator-api2", + "equivalent", "foldhash", ] @@ -2593,15 +2690,6 @@ version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" -[[package]] -name = "hashlink" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8094feaf31ff591f651a2664fb9cfd92bba7a60ce3197265e9482ebe753c8f7" -dependencies = [ - "hashbrown 0.14.5", -] - [[package]] name = "heck" version = "0.4.1" @@ -2648,15 +2736,10 @@ dependencies = [ ] [[package]] -name = "http" -version = "0.2.12" +name = "htmlescape" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" -dependencies = [ - "bytes", - "fnv", - "itoa", -] +checksum = "e9025058dae765dee5070ec375f591e2ba14638c63feff74f13805a72e523163" [[package]] name = "http" @@ -2668,17 +2751,6 @@ dependencies = [ "itoa", ] -[[package]] -name = "http-body" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" -dependencies = [ - "bytes", - "http 0.2.12", - "pin-project-lite", -] - [[package]] name = "http-body" version = "1.0.1" @@ -2686,7 +2758,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ "bytes", - "http 1.4.0", + "http", ] [[package]] @@ -2697,8 +2769,8 @@ checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" dependencies = [ "bytes", "futures-core", - "http 1.4.0", - "http-body 1.0.1", + "http", + "http-body", "pin-project-lite", ] @@ -2708,12 +2780,6 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "21dec9db110f5f872ed9699c3ecf50cf16f423502706ba5c72462e28d3157573" -[[package]] -name = "http-range-header" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "add0ab9360ddbd88cfeb3bd9574a1d85cfdfa14db10b3e21d3700dbc4328758f" - [[package]] name = "httparse" version = "1.10.1" @@ -2726,30 +2792,6 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" -[[package]] -name = "hyper" -version = "0.14.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41dfc780fdec9373c01bae43289ea34c972e40ee3c9f6b3c8801a35f35586ce7" -dependencies = [ - "bytes", - "futures-channel", - "futures-core", - "futures-util", - "h2 0.3.27", - "http 0.2.12", - "http-body 0.4.6", - "httparse", - "httpdate", - "itoa", - "pin-project-lite", - "socket2 0.5.10", - "tokio", - "tower-service", - "tracing", - "want", -] - [[package]] name = "hyper" version = "1.8.1" @@ -2760,9 +2802,9 @@ dependencies = [ "bytes", "futures-channel", "futures-core", - "h2 0.4.13", - "http 1.4.0", - "http-body 1.0.1", + "h2", + "http", + "http-body", "httparse", "httpdate", "itoa", @@ -2773,53 +2815,23 @@ dependencies = [ "want", ] -[[package]] -name = "hyper-rustls" -version = "0.25.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "399c78f9338483cb7e630c8474b07268983c6bd5acee012e4211f9f7bb21b070" -dependencies = [ - "futures-util", - "http 0.2.12", - "hyper 0.14.32", - "log", - "rustls 0.22.4", - "rustls-native-certs 0.7.3", - "rustls-pki-types", - "tokio", - "tokio-rustls 0.25.0", - "webpki-roots 0.26.11", -] - [[package]] name = "hyper-rustls" version = "0.27.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" dependencies = [ - "http 1.4.0", - "hyper 1.8.1", + "http", + "hyper", "hyper-util", - "rustls 0.23.37", + "rustls", "rustls-pki-types", "tokio", - "tokio-rustls 0.26.4", + "tokio-rustls", "tower-service", "webpki-roots 1.0.6", ] -[[package]] -name = "hyper-timeout" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbb958482e8c7be4bc3cf272a766a2b0bf1a6755e7a6ae777f017a31d11b13b1" -dependencies = [ - "hyper 0.14.32", - "pin-project-lite", - "tokio", - "tokio-io-timeout", -] - [[package]] name = "hyper-tls" version = "0.6.0" @@ -2828,7 +2840,7 @@ checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" dependencies = [ "bytes", "http-body-util", - "hyper 1.8.1", + "hyper", "hyper-util", "native-tls", "tokio", @@ -2846,14 +2858,14 @@ dependencies = [ "bytes", "futures-channel", "futures-util", - "http 1.4.0", - "http-body 1.0.1", - "hyper 1.8.1", + "http", + "http-body", + "hyper", "ipnet", "libc", "percent-encoding", "pin-project-lite", - "socket2 0.6.2", + "socket2", "system-configuration 0.7.0", "tokio", "tower-service", @@ -2861,6 +2873,15 @@ dependencies = [ "windows-registry 0.6.1", ] +[[package]] +name = "hyperloglogplus" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "621debdf94dcac33e50475fdd76d34d5ea9c0362a834b9db08c3024696c1fbe3" +dependencies = [ + "serde", +] + [[package]] name = "iana-time-zone" version = "0.1.65" @@ -3060,10 +3081,29 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" dependencies = [ - "block-padding", "generic-array", ] +[[package]] +name = "intrusive-collections" +version = "0.9.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "189d0897e4cbe8c75efedf3502c18c887b05046e59d28404d4d8e46cbc4d1e86" +dependencies = [ + "memoffset", +] + +[[package]] +name = "io-uring" +version = "0.7.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdd7bddefd0a8833b88a4b68f90dae22c7450d11b354198baee3874fd811b344" +dependencies = [ + "bitflags 2.11.0", + "cfg-if", + "libc", +] + [[package]] name = "ipnet" version = "2.12.0" @@ -3114,6 +3154,15 @@ dependencies = [ "either", ] +[[package]] +name = "itertools" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.17" @@ -3165,6 +3214,16 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" +[[package]] +name = "jobserver" +version = "0.1.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" +dependencies = [ + "getrandom 0.3.4", + "libc", +] + [[package]] name = "js-sys" version = "0.3.91" @@ -3249,6 +3308,12 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" +[[package]] +name = "levenshtein_automata" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c2cdeb66e45e9f36bfad5bbdb4d2384e70936afbee843c6f6543f0c551ebb25" + [[package]] name = "libappindicator" version = "0.9.0" @@ -3299,6 +3364,12 @@ dependencies = [ "windows-link 0.2.1", ] +[[package]] +name = "libm" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" + [[package]] name = "libredox" version = "0.1.14" @@ -3311,142 +3382,6 @@ dependencies = [ "redox_syscall 0.7.3", ] -[[package]] -name = "libsql" -version = "0.9.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2329faffc510cc3c6b4f00169a39177cc7099d3ed7647fc92f7cf26e53a8d976" -dependencies = [ - "anyhow", - "async-stream", - "async-trait", - "base64 0.21.7", - "bincode", - "bitflags 2.11.0", - "bytes", - "chrono", - "crc32fast", - "fallible-iterator 0.3.0", - "futures", - "http 0.2.12", - "hyper 0.14.32", - "hyper-rustls 0.25.0", - "libsql-hrana", - "libsql-sqlite3-parser", - "libsql-sys", - "libsql_replication", - "parking_lot", - "serde", - "serde_json", - "thiserror 1.0.69", - "tokio", - "tokio-stream", - "tokio-util", - "tonic", - "tonic-web", - "tower 0.4.13", - "tower-http 0.4.4", - "tracing", - "uuid 1.21.0", - "zerocopy 0.7.35", -] - -[[package]] -name = "libsql-ffi" -version = "0.9.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6cd1c1662822495393327856774f6803be25d85bfdcd5b9d4af35458f5daaf75" -dependencies = [ - "bindgen", - "cc", - "cmake", - "glob", -] - -[[package]] -name = "libsql-hrana" -version = "0.9.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "646d0aa75e412769018422f0da798f72e93bd51964f0b2ddad4317aa779ae444" -dependencies = [ - "base64 0.21.7", - "bytes", - "prost", - "serde", -] - -[[package]] -name = "libsql-rusqlite" -version = "0.9.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a4ce3a78c6e3c2b23b02ab6272df8340e1c53380497979d456882254f348d5f" -dependencies = [ - "bitflags 2.11.0", - "fallible-iterator 0.2.0", - "fallible-streaming-iterator", - "hashlink", - "libsql-ffi", - "smallvec", -] - -[[package]] -name = "libsql-sqlite3-parser" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15a90128c708356af8f7d767c9ac2946692c9112b4f74f07b99a01a60680e413" -dependencies = [ - "bitflags 2.11.0", - "cc", - "fallible-iterator 0.3.0", - "indexmap 2.13.0", - "log", - "memchr", - "phf 0.11.3", - "phf_codegen 0.11.3", - "phf_shared 0.11.3", - "uncased", -] - -[[package]] -name = "libsql-sys" -version = "0.9.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a3c326fcfc36fe7578238d5ee6b58c529f8c76372acd61ec50267529cdaff95" -dependencies = [ - "bytes", - "libsql-ffi", - "libsql-rusqlite", - "once_cell", - "tracing", - "zerocopy 0.7.35", -] - -[[package]] -name = "libsql_replication" -version = "0.9.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d9a2e469ac8400659bd31f81a745908bcc5cb6b40be2f2ff8de90b15bec5501" -dependencies = [ - "aes", - "async-stream", - "async-trait", - "bytes", - "cbc", - "libsql-rusqlite", - "libsql-sys", - "parking_lot", - "prost", - "serde", - "thiserror 1.0.69", - "tokio", - "tokio-stream", - "tokio-util", - "tonic", - "tracing", - "uuid 1.21.0", - "zerocopy 0.7.35", -] - [[package]] name = "libxdo" version = "0.6.0" @@ -3466,6 +3401,26 @@ dependencies = [ "x11", ] +[[package]] +name = "linkme" +version = "0.3.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e3283ed2d0e50c06dd8602e0ab319bb048b6325d0bba739db64ed8205179898" +dependencies = [ + "linkme-impl", +] + +[[package]] +name = "linkme-impl" +version = "0.3.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5cec0ec4228b4853bb129c84dbf093a27e6c7a20526da046defc334a1b017f7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + [[package]] name = "linux-raw-sys" version = "0.4.15" @@ -3519,12 +3474,40 @@ dependencies = [ "value-bag", ] +[[package]] +name = "loom" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "419e0dc8046cb947daa77eb95ae174acfbddb7673b4151f56d1eed8e93fbfaca" +dependencies = [ + "cfg-if", + "generator", + "scoped-tls", + "tracing", + "tracing-subscriber", +] + +[[package]] +name = "lru" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38" +dependencies = [ + "hashbrown 0.15.5", +] + [[package]] name = "lru-slab" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" +[[package]] +name = "lz4_flex" +version = "0.11.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08ab2867e3eeeca90e844d1940eab391c9dc5228783db2ed999acbc0a9ed375a" + [[package]] name = "mac" version = "0.1.1" @@ -3574,24 +3557,36 @@ dependencies = [ "syn 2.0.117", ] +[[package]] +name = "matchers" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9" +dependencies = [ + "regex-automata", +] + [[package]] name = "matches" version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" -[[package]] -name = "matchit" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" - [[package]] name = "matchit" version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3" +[[package]] +name = "measure_time" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51c55d61e72fc3ab704396c5fa16f4c184db37978ae4e94ca8959693a235fc0e" +dependencies = [ + "log", +] + [[package]] name = "memalloc" version = "0.1.0" @@ -3604,6 +3599,15 @@ version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" +[[package]] +name = "memmap2" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "744133e4a0e0a658e1374cf3bf8e415c4052a15a111acd372764c55b4177d490" +dependencies = [ + "libc", +] + [[package]] name = "memoffset" version = "0.9.1" @@ -3613,6 +3617,28 @@ dependencies = [ "autocfg", ] +[[package]] +name = "miette" +version = "7.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f98efec8807c63c752b5bd61f862c165c115b0a35685bdcfd9238c7aeb592b7" +dependencies = [ + "cfg-if", + "miette-derive", + "unicode-width", +] + +[[package]] +name = "miette-derive" +version = "7.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db5b29714e950dbb20d5e6f74f9dcec4edbcc1067bb7f8ed198c097b8c1a818b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + [[package]] name = "mime" version = "0.3.17" @@ -3684,6 +3710,12 @@ dependencies = [ "windows-sys 0.60.2", ] +[[package]] +name = "murmurhash32" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2195bf6aa996a481483b29d62a7663eed3fe39600c460e323f8ff41e90bdd89b" + [[package]] name = "native-tls" version = "0.2.18" @@ -3693,10 +3725,10 @@ dependencies = [ "libc", "log", "openssl", - "openssl-probe 0.2.1", + "openssl-probe", "openssl-sys", "schannel", - "security-framework 3.7.0", + "security-framework", "security-framework-sys", "tempfile", ] @@ -3863,12 +3895,40 @@ dependencies = [ "winapi", ] +[[package]] +name = "nu-ansi-term" +version = "0.50.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" +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-conv" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf97ec579c3c42f953ef76dbf8d55ac91fb219dde70e49aa4a6b7d74e9919050" +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + [[package]] name = "num-traits" version = "0.2.19" @@ -3876,6 +3936,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", + "libm", ] [[package]] @@ -4220,6 +4281,12 @@ version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" +[[package]] +name = "oneshot" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "269bca4c2591a28585d6bf10d9ed0332b7d76900a1b02bec41bdc3a2cdcda107" + [[package]] name = "opaque-debug" version = "0.3.1" @@ -4264,12 +4331,6 @@ dependencies = [ "syn 2.0.117", ] -[[package]] -name = "openssl-probe" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" - [[package]] name = "openssl-probe" version = "0.2.1" @@ -4364,6 +4425,30 @@ dependencies = [ "thiserror 2.0.18", ] +[[package]] +name = "ownedbytes" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fbd56f7631767e61784dc43f8580f403f4475bd4aaa4da003e6295e1bab4a7e" +dependencies = [ + "stable_deref_trait", +] + +[[package]] +name = "owo-colors" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f" + +[[package]] +name = "pack1" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6e7cd9bd638dc2c831519a0caa1c006cab771a92b1303403a8322773c5b72d6" +dependencies = [ + "bytemuck", +] + [[package]] name = "pango" version = "0.18.3" @@ -4430,12 +4515,6 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3" -[[package]] -name = "peeking_take_while" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" - [[package]] name = "percent-encoding" version = "2.3.2" @@ -4617,27 +4696,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5" dependencies = [ "siphasher 1.0.2", - "uncased", -] - -[[package]] -name = "pin-project" -version = "1.1.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1749c7ed4bcaf4c3d0a3efc28538844fb29bcdd7d2b67b2be7e20ba861ff517" -dependencies = [ - "pin-project-internal", -] - -[[package]] -name = "pin-project-internal" -version = "1.1.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b20ed30f105399776b9c883e68e536ef602a16ae6f596d2c473591d6ad64c6" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", ] [[package]] @@ -4761,7 +4819,7 @@ version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" dependencies = [ - "zerocopy 0.8.40", + "zerocopy", ] [[package]] @@ -4891,9 +4949,9 @@ dependencies = [ [[package]] name = "prost" -version = "0.12.6" +version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "deb1435c188b76130da55f17a466d252ff7b1418b2ad3e037d127b94e3411f29" +checksum = "d2ea70524a2f82d518bce41317d0fae74151505651af45faf1ffbd6fd33f0568" dependencies = [ "bytes", "prost-derive", @@ -4901,12 +4959,12 @@ dependencies = [ [[package]] name = "prost-derive" -version = "0.12.6" +version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81bddcdb20abf9501610992b6759a4c888aef7d1a7247ef75e2404275ac24af1" +checksum = "27c6023962132f4b30eb4c172c91ce92d933da334c59c23cddee82358ddafb0b" dependencies = [ "anyhow", - "itertools", + "itertools 0.12.1", "proc-macro2", "quote", "syn 2.0.117", @@ -5003,8 +5061,8 @@ dependencies = [ "quinn-proto", "quinn-udp", "rustc-hash 2.1.1", - "rustls 0.23.37", - "socket2 0.6.2", + "rustls", + "socket2", "thiserror 2.0.18", "tokio", "tracing", @@ -5023,7 +5081,7 @@ dependencies = [ "rand 0.9.2", "ring", "rustc-hash 2.1.1", - "rustls 0.23.37", + "rustls", "rustls-pki-types", "slab", "thiserror 2.0.18", @@ -5041,7 +5099,7 @@ dependencies = [ "cfg_aliases", "libc", "once_cell", - "socket2 0.6.2", + "socket2", "tracing", "windows-sys 0.60.2", ] @@ -5084,7 +5142,7 @@ dependencies = [ "rand_chacha 0.2.2", "rand_core 0.5.1", "rand_hc", - "rand_pcg", + "rand_pcg 0.2.1", ] [[package]] @@ -5181,6 +5239,16 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c8d0fd677905edcbeedbf2edb6494d676f0e98d54d5cf9bda0b061cb8fb8aba" +[[package]] +name = "rand_distr" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32cb0b9bc82b0a0876c2dd994a7e7a2683d3e7390ca40e6886785ef0c7e3ee31" +dependencies = [ + "num-traits", + "rand 0.8.5", +] + [[package]] name = "rand_hc" version = "0.2.0" @@ -5199,6 +5267,15 @@ dependencies = [ "rand_core 0.5.1", ] +[[package]] +name = "rand_pcg" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59cad018caf63deb318e5a4586d99a24424a364f40f1e5778c29aca23f4fc73e" +dependencies = [ + "rand_core 0.6.4", +] + [[package]] name = "rand_xorshift" version = "0.4.0" @@ -5208,12 +5285,41 @@ dependencies = [ "rand_core 0.9.5", ] +[[package]] +name = "rapidhash" +version = "4.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e48930979c155e2f33aa36ab3119b5ee81332beb6482199a8ecd6029b80b59" +dependencies = [ + "rustversion", +] + [[package]] name = "raw-window-handle" version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539" +[[package]] +name = "rayon" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "368f01d005bf8fd9b1206fb6fa653e6c4a81ceb1466406b81792d87c5677a58f" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + [[package]] name = "read-progress-stream" version = "1.0.0" @@ -5325,12 +5431,12 @@ dependencies = [ "encoding_rs", "futures-core", "futures-util", - "h2 0.4.13", - "http 1.4.0", - "http-body 1.0.1", + "h2", + "http", + "http-body", "http-body-util", - "hyper 1.8.1", - "hyper-rustls 0.27.7", + "hyper", + "hyper-rustls", "hyper-util", "js-sys", "log", @@ -5338,17 +5444,17 @@ dependencies = [ "percent-encoding", "pin-project-lite", "quinn", - "rustls 0.23.37", + "rustls", "rustls-pki-types", "serde", "serde_json", "serde_urlencoded", - "sync_wrapper 1.0.2", + "sync_wrapper", "tokio", - "tokio-rustls 0.26.4", + "tokio-rustls", "tokio-util", - "tower 0.5.3", - "tower-http 0.6.8", + "tower", + "tower-http", "tower-service", "url", "wasm-bindgen", @@ -5368,11 +5474,11 @@ dependencies = [ "bytes", "futures-core", "futures-util", - "http 1.4.0", - "http-body 1.0.1", + "http", + "http-body", "http-body-util", - "hyper 1.8.1", - "hyper-rustls 0.27.7", + "hyper", + "hyper-rustls", "hyper-tls", "hyper-util", "js-sys", @@ -5380,18 +5486,18 @@ dependencies = [ "native-tls", "percent-encoding", "pin-project-lite", - "rustls 0.23.37", + "rustls", "rustls-pki-types", "rustls-platform-verifier", "serde", "serde_json", - "sync_wrapper 1.0.2", + "sync_wrapper", "tokio", "tokio-native-tls", - "tokio-rustls 0.26.4", + "tokio-rustls", "tokio-util", - "tower 0.5.3", - "tower-http 0.6.8", + "tower", + "tower-http", "tower-service", "url", "wasm-bindgen", @@ -5467,6 +5573,16 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "roaring" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ba9ce64a8f45d7fc86358410bb1a82e8c987504c0d4900e9141d69a9f26c885" +dependencies = [ + "bytemuck", + "byteorder", +] + [[package]] name = "rust-ini" version = "0.21.3" @@ -5477,6 +5593,16 @@ dependencies = [ "ordered-multimap", ] +[[package]] +name = "rust-stemmers" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e46a2036019fdb888131db7a4c847a1063a7493f971ed94ea82c67eada63ca54" +dependencies = [ + "serde", + "serde_derive", +] + [[package]] name = "rust_decimal" version = "1.40.0" @@ -5514,6 +5640,16 @@ dependencies = [ "semver", ] +[[package]] +name = "rustc_version_runtime" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dd18cd2bae1820af0b6ad5e54f4a51d0f3fcc53b05f845675074efcc7af071d" +dependencies = [ + "rustc_version", + "semver", +] + [[package]] name = "rustix" version = "0.38.44" @@ -5540,20 +5676,6 @@ dependencies = [ "windows-sys 0.61.2", ] -[[package]] -name = "rustls" -version = "0.22.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf4ef73721ac7bcd79b2b315da7779d8fc09718c6b3d2d1b2d94850eb8c18432" -dependencies = [ - "log", - "ring", - "rustls-pki-types", - "rustls-webpki 0.102.8", - "subtle", - "zeroize", -] - [[package]] name = "rustls" version = "0.23.37" @@ -5563,43 +5685,21 @@ dependencies = [ "once_cell", "ring", "rustls-pki-types", - "rustls-webpki 0.103.9", + "rustls-webpki", "subtle", "zeroize", ] -[[package]] -name = "rustls-native-certs" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5bfb394eeed242e909609f56089eecfe5fda225042e8b171791b9c95f5931e5" -dependencies = [ - "openssl-probe 0.1.6", - "rustls-pemfile", - "rustls-pki-types", - "schannel", - "security-framework 2.11.1", -] - [[package]] name = "rustls-native-certs" version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "612460d5f7bea540c490b2b6395d8e34a953e52b491accd6c86c8164c5932a63" dependencies = [ - "openssl-probe 0.2.1", + "openssl-probe", "rustls-pki-types", "schannel", - "security-framework 3.7.0", -] - -[[package]] -name = "rustls-pemfile" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" -dependencies = [ - "rustls-pki-types", + "security-framework", ] [[package]] @@ -5623,11 +5723,11 @@ dependencies = [ "jni", "log", "once_cell", - "rustls 0.23.37", - "rustls-native-certs 0.8.3", + "rustls", + "rustls-native-certs", "rustls-platform-verifier-android", - "rustls-webpki 0.103.9", - "security-framework 3.7.0", + "rustls-webpki", + "security-framework", "security-framework-sys", "webpki-root-certs", "windows-sys 0.61.2", @@ -5639,17 +5739,6 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f" -[[package]] -name = "rustls-webpki" -version = "0.102.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" -dependencies = [ - "ring", - "rustls-pki-types", - "untrusted", -] - [[package]] name = "rustls-webpki" version = "0.103.9" @@ -5763,6 +5852,12 @@ dependencies = [ "syn 2.0.117", ] +[[package]] +name = "scoped-tls" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" + [[package]] name = "scopeguard" version = "1.2.0" @@ -5781,19 +5876,6 @@ version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" -[[package]] -name = "security-framework" -version = "2.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" -dependencies = [ - "bitflags 2.11.0", - "core-foundation 0.9.4", - "core-foundation-sys 0.8.7", - "libc", - "security-framework-sys", -] - [[package]] name = "security-framework" version = "3.7.0" @@ -6063,6 +6145,12 @@ dependencies = [ "digest", ] +[[package]] +name = "sha1_smol" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbfa15b3dddfee50a0fff136974b3e1bde555604ba463834a7eb7deb6417705d" + [[package]] name = "sha2" version = "0.10.9" @@ -6074,6 +6162,15 @@ dependencies = [ "digest", ] +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + [[package]] name = "shared_child" version = "1.1.1" @@ -6091,6 +6188,26 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" +[[package]] +name = "shuttle" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ab17edba38d63047f46780cf7360acf7467fec2c048928689a5c1dd1c2b4e31" +dependencies = [ + "assoc", + "bitvec", + "cfg-if", + "generator", + "hex", + "owo-colors", + "rand 0.8.5", + "rand_core 0.6.4", + "rand_pcg 0.3.1", + "scoped-tls", + "smallvec", + "tracing", +] + [[package]] name = "sigchld" version = "0.2.4" @@ -6134,6 +6251,15 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" +[[package]] +name = "simsimd" +version = "6.5.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eccacd6981edc21fa50e79e0c13acd5552665e93a1c3c26f44ef636c0e2c3290" +dependencies = [ + "cc", +] + [[package]] name = "siphasher" version = "0.3.11" @@ -6146,6 +6272,15 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b2aa850e253778c88a04c3d7323b043aeda9d3e30d5971937c1855769763678e" +[[package]] +name = "sketches-ddsketch" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c6f73aeb92d671e0cc4dca167e59b2deb6387c375391bc99ee743f326994a2b" +dependencies = [ + "serde", +] + [[package]] name = "slab" version = "0.4.12" @@ -6158,16 +6293,6 @@ version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" -[[package]] -name = "socket2" -version = "0.5.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" -dependencies = [ - "libc", - "windows-sys 0.52.0", -] - [[package]] name = "socket2" version = "0.6.2" @@ -6178,6 +6303,12 @@ dependencies = [ "windows-sys 0.60.2", ] +[[package]] +name = "softaes" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fef461faaeb36c340b6c887167a9054a034f6acfc50a014ead26a02b4356b3de" + [[package]] name = "softbuffer" version = "0.4.8" @@ -6286,6 +6417,28 @@ version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" +[[package]] +name = "strum" +version = "0.26.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" +dependencies = [ + "strum_macros", +] + +[[package]] +name = "strum_macros" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" +dependencies = [ + "heck 0.5.0", + "proc-macro2", + "quote", + "rustversion", + "syn 2.0.117", +] + [[package]] name = "subtle" version = "2.6.1" @@ -6325,12 +6478,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "sync_wrapper" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" - [[package]] name = "sync_wrapper" version = "1.0.2" @@ -6441,6 +6588,152 @@ dependencies = [ "version-compare", ] +[[package]] +name = "tantivy" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "502915c7381c5cb2d2781503962610cb880ad8f1a0ca95df1bae645d5ebf2545" +dependencies = [ + "aho-corasick", + "arc-swap", + "base64 0.22.1", + "bitpacking", + "bon", + "byteorder", + "census", + "crc32fast", + "crossbeam-channel", + "downcast-rs", + "fastdivide", + "fnv", + "fs4", + "htmlescape", + "hyperloglogplus", + "itertools 0.14.0", + "levenshtein_automata", + "log", + "lru", + "lz4_flex", + "measure_time", + "memmap2", + "once_cell", + "oneshot", + "rayon", + "regex", + "rust-stemmers", + "rustc-hash 2.1.1", + "serde", + "serde_json", + "sketches-ddsketch", + "smallvec", + "tantivy-bitpacker", + "tantivy-columnar", + "tantivy-common", + "tantivy-fst", + "tantivy-query-grammar", + "tantivy-stacker", + "tantivy-tokenizer-api", + "tempfile", + "thiserror 2.0.18", + "time", + "uuid 1.21.0", + "winapi", +] + +[[package]] +name = "tantivy-bitpacker" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3b04eed5108d8283607da6710fe17a7663523440eaf7ea5a1a440d19a1448b6" +dependencies = [ + "bitpacking", +] + +[[package]] +name = "tantivy-columnar" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b628488ae936c83e92b5c4056833054ca56f76c0e616aee8339e24ac89119cd" +dependencies = [ + "downcast-rs", + "fastdivide", + "itertools 0.14.0", + "serde", + "tantivy-bitpacker", + "tantivy-common", + "tantivy-sstable", + "tantivy-stacker", +] + +[[package]] +name = "tantivy-common" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f880aa7cab0c063a47b62596d10991cdd0b6e0e0575d9c5eeb298b307a25de55" +dependencies = [ + "async-trait", + "byteorder", + "ownedbytes", + "serde", + "time", +] + +[[package]] +name = "tantivy-fst" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d60769b80ad7953d8a7b2c70cdfe722bbcdcac6bccc8ac934c40c034d866fc18" +dependencies = [ + "byteorder", + "regex-syntax", + "utf8-ranges", +] + +[[package]] +name = "tantivy-query-grammar" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "768fccdc84d60d86235d42d7e4c33acf43c418258ff5952abf07bd7837fcd26b" +dependencies = [ + "nom", + "serde", + "serde_json", +] + +[[package]] +name = "tantivy-sstable" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8292095d1a8a2c2b36380ec455f910ab52dde516af36321af332c93f20ab7d5" +dependencies = [ + "futures-util", + "itertools 0.14.0", + "tantivy-bitpacker", + "tantivy-common", + "tantivy-fst", + "zstd", +] + +[[package]] +name = "tantivy-stacker" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23d38a379411169f0b3002c9cba61cdfe315f757e9d4f239c00c282497a0749d" +dependencies = [ + "murmurhash32", + "rand_distr", + "tantivy-common", +] + +[[package]] +name = "tantivy-tokenizer-api" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23024f6aeb25ceb1a0e27740c84bdb0fae52626737b7e9a9de6ad5aa25c7b038" +dependencies = [ + "serde", +] + [[package]] name = "tao" version = "0.34.6" @@ -6535,7 +6828,7 @@ dependencies = [ "glob", "gtk", "heck 0.5.0", - "http 1.4.0", + "http", "http-range", "image", "jni", @@ -6555,7 +6848,7 @@ dependencies = [ "quickcheck_macros", "raw-window-handle", "reqwest 0.13.2", - "rustls 0.23.37", + "rustls", "serde", "serde_json", "serde_repr", @@ -6774,7 +7067,7 @@ dependencies = [ "bytes", "cookie_store 0.21.1", "data-url", - "http 1.4.0", + "http", "regex", "reqwest 0.12.28", "schemars 0.8.22", @@ -6789,22 +7082,6 @@ dependencies = [ "urlpattern", ] -[[package]] -name = "tauri-plugin-libsql" -version = "0.1.0" -dependencies = [ - "bytes", - "futures", - "indexmap 2.13.0", - "libsql", - "serde", - "serde_json", - "tauri", - "tauri-plugin", - "thiserror 2.0.18", - "tokio", -] - [[package]] name = "tauri-plugin-log" version = "2.8.0" @@ -7000,6 +7277,22 @@ dependencies = [ "zbus", ] +[[package]] +name = "tauri-plugin-turso" +version = "0.1.0" +dependencies = [ + "futures", + "indexmap 2.13.0", + "serde", + "serde_json", + "tauri", + "tauri-plugin", + "thiserror 2.0.18", + "tokio", + "turso", + "turso_core", +] + [[package]] name = "tauri-plugin-updater" version = "2.10.0" @@ -7010,14 +7303,14 @@ dependencies = [ "dirs", "flate2", "futures-util", - "http 1.4.0", + "http", "infer", "log", "minisign-verify", "osakit", "percent-encoding", "reqwest 0.13.2", - "rustls 0.23.37", + "rustls", "semver", "serde", "serde_json", @@ -7040,7 +7333,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a130e5cc896b52a87d618b53e1ba025954af7c004b8781a4ddee7298f7b3749a" dependencies = [ "async-trait", - "axum 0.8.8", + "axum", "base64 0.22.1", "block2", "cairo-rs", @@ -7073,10 +7366,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fe037be7e1c30be639fe12dc3077e8ec4709e6f30ca4a6016b7edc76232ae9ee" dependencies = [ "futures-util", - "http 1.4.0", + "http", "log", "rand 0.9.2", - "rustls 0.23.37", + "rustls", "serde", "serde_json", "tauri", @@ -7108,7 +7401,7 @@ dependencies = [ "cookie", "dpi", "gtk", - "http 1.4.0", + "http", "jni", "objc2", "objc2-ui-kit", @@ -7129,7 +7422,7 @@ name = "tauri-runtime-wry" version = "2.10.1" dependencies = [ "gtk", - "http 1.4.0", + "http", "jni", "log", "objc2", @@ -7162,7 +7455,7 @@ dependencies = [ "getrandom 0.3.4", "glob", "html5ever", - "http 1.4.0", + "http", "infer", "json-patch", "json5", @@ -7266,6 +7559,15 @@ dependencies = [ "syn 2.0.117", ] +[[package]] +name = "thread_local" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" +dependencies = [ + "cfg-if", +] + [[package]] name = "time" version = "0.3.47" @@ -7345,21 +7647,11 @@ dependencies = [ "parking_lot", "pin-project-lite", "signal-hook-registry", - "socket2 0.6.2", + "socket2", "tokio-macros", "windows-sys 0.61.2", ] -[[package]] -name = "tokio-io-timeout" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bd86198d9ee903fedd2f9a2e72014287c0d9167e4ae43b5853007205dda1b76" -dependencies = [ - "pin-project-lite", - "tokio", -] - [[package]] name = "tokio-macros" version = "2.6.1" @@ -7381,35 +7673,13 @@ dependencies = [ "tokio", ] -[[package]] -name = "tokio-rustls" -version = "0.25.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "775e0c0f0adb3a2f22a00c4745d728b479985fc15ee7ca6a2608388c5569860f" -dependencies = [ - "rustls 0.22.4", - "rustls-pki-types", - "tokio", -] - [[package]] name = "tokio-rustls" version = "0.26.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" dependencies = [ - "rustls 0.23.37", - "tokio", -] - -[[package]] -name = "tokio-stream" -version = "0.1.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32da49809aab5c3bc678af03902d4ccddea2a87d028d86392a4b1560c6906c70" -dependencies = [ - "futures-core", - "pin-project-lite", + "rustls", "tokio", ] @@ -7421,10 +7691,10 @@ checksum = "d25a406cddcc431a75d3d9afc6a7c0f7428d4891dd973e4d54c56b46127bf857" dependencies = [ "futures-util", "log", - "rustls 0.23.37", + "rustls", "rustls-pki-types", "tokio", - "tokio-rustls 0.26.4", + "tokio-rustls", "tungstenite", "webpki-roots 0.26.11", ] @@ -7547,73 +7817,6 @@ version = "1.0.6+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab16f14aed21ee8bfd8ec22513f7287cd4a91aa92e44edfe2c17ddd004e92607" -[[package]] -name = "tonic" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76c4eb7a4e9ef9d4763600161f12f5070b92a578e1b634db88a6887844c91a13" -dependencies = [ - "async-stream", - "async-trait", - "axum 0.6.20", - "base64 0.21.7", - "bytes", - "h2 0.3.27", - "http 0.2.12", - "http-body 0.4.6", - "hyper 0.14.32", - "hyper-timeout", - "percent-encoding", - "pin-project", - "prost", - "tokio", - "tokio-stream", - "tower 0.4.13", - "tower-layer", - "tower-service", - "tracing", -] - -[[package]] -name = "tonic-web" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc3b0e1cedbf19fdfb78ef3d672cb9928e0a91a9cb4629cc0c916e8cff8aaaa1" -dependencies = [ - "base64 0.21.7", - "bytes", - "http 0.2.12", - "http-body 0.4.6", - "hyper 0.14.32", - "pin-project", - "tokio-stream", - "tonic", - "tower-http 0.4.4", - "tower-layer", - "tower-service", - "tracing", -] - -[[package]] -name = "tower" -version = "0.4.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" -dependencies = [ - "futures-core", - "futures-util", - "indexmap 1.9.3", - "pin-project", - "pin-project-lite", - "rand 0.8.5", - "slab", - "tokio", - "tokio-util", - "tower-layer", - "tower-service", - "tracing", -] - [[package]] name = "tower" version = "0.5.3" @@ -7623,33 +7826,13 @@ dependencies = [ "futures-core", "futures-util", "pin-project-lite", - "sync_wrapper 1.0.2", + "sync_wrapper", "tokio", "tower-layer", "tower-service", "tracing", ] -[[package]] -name = "tower-http" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61c5bb1d698276a2443e5ecfabc1008bf15a36c12e6a7176e7bf089ea9131140" -dependencies = [ - "bitflags 2.11.0", - "bytes", - "futures-core", - "futures-util", - "http 0.2.12", - "http-body 0.4.6", - "http-range-header", - "pin-project-lite", - "tower 0.4.13", - "tower-layer", - "tower-service", - "tracing", -] - [[package]] name = "tower-http" version = "0.6.8" @@ -7659,11 +7842,11 @@ dependencies = [ "bitflags 2.11.0", "bytes", "futures-util", - "http 1.4.0", - "http-body 1.0.1", + "http", + "http-body", "iri-string", "pin-project-lite", - "tower 0.5.3", + "tower", "tower-layer", "tower-service", ] @@ -7692,6 +7875,18 @@ dependencies = [ "tracing-core", ] +[[package]] +name = "tracing-appender" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "786d480bce6247ab75f005b14ae1624ad978d3029d9113f0a22fa1ac773faeaf" +dependencies = [ + "crossbeam-channel", + "thiserror 2.0.18", + "time", + "tracing-subscriber", +] + [[package]] name = "tracing-attributes" version = "0.1.31" @@ -7710,6 +7905,36 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" dependencies = [ "once_cell", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f30143827ddab0d256fd843b7a66d164e9f271cfa0dde49142c5ca0ca291f1e" +dependencies = [ + "matchers", + "nu-ansi-term", + "once_cell", + "regex-automata", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", ] [[package]] @@ -7748,17 +7973,210 @@ checksum = "8628dcc84e5a09eb3d8423d6cb682965dea9133204e8fb3efee74c2a0c259442" dependencies = [ "bytes", "data-encoding", - "http 1.4.0", + "http", "httparse", "log", "rand 0.9.2", - "rustls 0.23.37", + "rustls", "rustls-pki-types", "sha1", "thiserror 2.0.18", "utf-8", ] +[[package]] +name = "turso" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1326cd4c1bb82501328aadee1ca5e0f44fdb5cfe2c7cdc53d3d96aeeecece61a" +dependencies = [ + "thiserror 2.0.18", + "tracing", + "tracing-subscriber", + "turso_sdk_kit", + "turso_sync_sdk_kit", +] + +[[package]] +name = "turso_core" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4befbe4e162cb691a5ff92ebcafc9028574f614cb82cf711d8ed5c89ebf23337" +dependencies = [ + "aegis", + "aes", + "aes-gcm", + "antithesis_sdk", + "arc-swap", + "bigdecimal", + "bitflags 2.11.0", + "branches", + "built", + "bumpalo", + "bytemuck", + "cfg_block", + "chrono", + "crc32c", + "crossbeam-skiplist", + "either", + "fallible-iterator", + "fastbloom", + "hex", + "intrusive-collections", + "io-uring", + "libc", + "libloading 0.8.9", + "libm", + "loom", + "miette", + "num-bigint", + "num-traits", + "pack1", + "parking_lot", + "paste", + "polling", + "rand 0.9.2", + "rapidhash", + "regex", + "regex-syntax", + "roaring", + "rustc-hash 2.1.1", + "rustix 1.1.4", + "ryu", + "serde_json", + "shuttle", + "simsimd", + "smallvec", + "strum", + "strum_macros", + "tantivy", + "tempfile", + "thiserror 2.0.18", + "tracing", + "tracing-subscriber", + "turso_ext", + "turso_macros", + "turso_parser", + "twox-hash", + "uncased", + "uuid 1.21.0", + "windows-sys 0.61.2", +] + +[[package]] +name = "turso_ext" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d314de12a937acadc6a0150433d2f9837f7c49b643d7d6da49275c0713fb8d9" +dependencies = [ + "chrono", + "getrandom 0.3.4", + "turso_macros", +] + +[[package]] +name = "turso_macros" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18687fe83de76951957ce1b3599af16a4627b94c9a17fd4e09c6a28f0bbe0ca7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "turso_parser" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c41725404271e703fc734d1b211c53541821dfa2701895ec2d89c85a10e8514d" +dependencies = [ + "bitflags 2.11.0", + "memchr", + "miette", + "strum", + "strum_macros", + "thiserror 2.0.18", + "turso_macros", +] + +[[package]] +name = "turso_sdk_kit" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01827272c218ba5eaa2bdca87cc33e62dbdd2d9d93571a0ea260c7651e61e139" +dependencies = [ + "bindgen", + "env_logger", + "parking_lot", + "tracing", + "tracing-appender", + "tracing-subscriber", + "turso_core", + "turso_sdk_kit_macros", +] + +[[package]] +name = "turso_sdk_kit_macros" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca793575b75a8a891f0d263c1051f60ab3ed2072bdd63fe3331959bf783ad0f3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "turso_sync_engine" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e040a526375f699f162dc75a64d21b43e193c3dc3f22fcb34e190db8f8ba39a" +dependencies = [ + "base64 0.22.1", + "bytes", + "genawaiter", + "http", + "libc", + "prost", + "roaring", + "serde", + "serde_json", + "thiserror 2.0.18", + "tracing", + "turso_core", + "turso_parser", + "uuid 1.21.0", +] + +[[package]] +name = "turso_sync_sdk_kit" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "547f4853402531c949b5c2d343b87b1b7ea709651695ccd207e6072504486cce" +dependencies = [ + "bindgen", + "env_logger", + "genawaiter", + "parking_lot", + "tracing", + "tracing-appender", + "tracing-subscriber", + "turso_core", + "turso_sdk_kit", + "turso_sdk_kit_macros", + "turso_sync_engine", +] + +[[package]] +name = "twox-hash" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ea3136b675547379c4bd395ca6b938e5ad3c3d20fad76e7fe85f9e0d011419c" +dependencies = [ + "rand 0.9.2", +] + [[package]] name = "typeid" version = "1.0.3" @@ -7856,6 +8274,12 @@ version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" +[[package]] +name = "unicode-width" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" + [[package]] name = "unicode-xid" version = "0.2.6" @@ -7919,6 +8343,12 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" +[[package]] +name = "utf8-ranges" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fcfc827f90e53a02eaef5e535ee14266c1d569214c6aa70133a624d8a3164ba" + [[package]] name = "utf8-width" version = "0.1.8" @@ -7955,9 +8385,16 @@ dependencies = [ "getrandom 0.4.2", "js-sys", "serde_core", + "sha1_smol", "wasm-bindgen", ] +[[package]] +name = "valuable" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" + [[package]] name = "value-bag" version = "1.12.0" @@ -9119,7 +9556,7 @@ dependencies = [ "gdkx11", "gtk", "html5ever", - "http 1.4.0", + "http", "javascriptcore-rs", "jni", "kuchikiki", @@ -9284,34 +9721,13 @@ dependencies = [ "zvariant", ] -[[package]] -name = "zerocopy" -version = "0.7.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" -dependencies = [ - "byteorder", - "zerocopy-derive 0.7.35", -] - [[package]] name = "zerocopy" version = "0.8.40" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a789c6e490b576db9f7e6b6d661bcc9799f7c0ac8352f56ea20193b2681532e5" dependencies = [ - "zerocopy-derive 0.8.40", -] - -[[package]] -name = "zerocopy-derive" -version = "0.7.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", + "zerocopy-derive", ] [[package]] @@ -9403,6 +9819,34 @@ version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" +[[package]] +name = "zstd" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e91ee311a569c327171651566e07972200e76fcfe2242a4fa446149a3881c08a" +dependencies = [ + "zstd-safe", +] + +[[package]] +name = "zstd-safe" +version = "7.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f49c4d5f0abb602a93fb8736af2a4f4dd9512e36f7f570d66e65ff867ed3b9d" +dependencies = [ + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "2.0.16+zstd.1.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e19ebc2adc8f83e43039e79776e3fda8ca919132d68a1fed6a5faca2683748" +dependencies = [ + "cc", + "pkg-config", +] + [[package]] name = "zvariant" version = "5.10.0" diff --git a/apps/readest-app/docs/testing.md b/apps/readest-app/docs/testing.md index f7798edf..d5275089 100644 --- a/apps/readest-app/docs/testing.md +++ b/apps/readest-app/docs/testing.md @@ -63,7 +63,7 @@ Vitest connects directly to the embedded WebDriver server (port 4445) in the run - **Config:** `vitest.tauri.config.mts` - **Pattern:** `src/**/*.tauri.test.ts` - **Browser provider:** `@vitest/browser-webdriverio` (connects to port 4445) -- **Use for:** Tauri plugin commands (libsql, native-tts, etc.), native filesystem, Tauri IPC. +- **Use for:** Tauri plugin commands (turso, native-tts, etc.), native filesystem, Tauri IPC. ### Writing Tauri Tests @@ -73,7 +73,7 @@ Tests access Tauri IPC via a shared helper: import { invoke } from '../tauri/tauri-invoke'; it('calls a plugin command', async () => { - const result = await invoke('plugin:libsql|load', { options: { path: 'sqlite::memory:' } }); + const result = await invoke('plugin:turso|load', { options: { path: 'sqlite::memory:' } }); expect(result).toBeDefined(); }); ``` diff --git a/apps/readest-app/src-tauri/Cargo.toml b/apps/readest-app/src-tauri/Cargo.toml index d357ca72..0445a874 100644 --- a/apps/readest-app/src-tauri/Cargo.toml +++ b/apps/readest-app/src-tauri/Cargo.toml @@ -58,7 +58,7 @@ tauri-plugin-native-tts = { path = "./plugins/tauri-plugin-native-tts" } tauri-plugin-websocket = "2" tauri-plugin-sharekit = "0.3" tauri-plugin-device-info = "1.0.1" -tauri-plugin-libsql = { path = "./plugins/tauri-plugin-libsql" } +tauri-plugin-turso = { path = "./plugins/tauri-plugin-turso" } tauri-plugin-webdriver = { version = "0.2", optional = true } [target."cfg(target_os = \"macos\")".dependencies] diff --git a/apps/readest-app/src-tauri/capabilities-extra/webdriver.json b/apps/readest-app/src-tauri/capabilities-extra/webdriver.json index 7170c4d2..57717883 100644 --- a/apps/readest-app/src-tauri/capabilities-extra/webdriver.json +++ b/apps/readest-app/src-tauri/capabilities-extra/webdriver.json @@ -16,7 +16,7 @@ "log:default", "shell:default", "process:default", - "libsql:default", + "turso:default", "native-tts:default", "native-bridge:default" ] diff --git a/apps/readest-app/src-tauri/capabilities/default.json b/apps/readest-app/src-tauri/capabilities/default.json index 5166e829..145e4b50 100644 --- a/apps/readest-app/src-tauri/capabilities/default.json +++ b/apps/readest-app/src-tauri/capabilities/default.json @@ -179,7 +179,7 @@ "deep-link:default", "sharekit:default", "device-info:default", - "libsql:default", + "turso:default", "native-tts:default", "native-bridge:default" ] diff --git a/apps/readest-app/src-tauri/plugins/tauri-plugin-libsql b/apps/readest-app/src-tauri/plugins/tauri-plugin-libsql deleted file mode 160000 index 4fc646e6..00000000 --- a/apps/readest-app/src-tauri/plugins/tauri-plugin-libsql +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 4fc646e66bbf51f2d9f4059709297797b3d4486d diff --git a/apps/readest-app/src-tauri/plugins/tauri-plugin-turso b/apps/readest-app/src-tauri/plugins/tauri-plugin-turso new file mode 160000 index 00000000..bb12a796 --- /dev/null +++ b/apps/readest-app/src-tauri/plugins/tauri-plugin-turso @@ -0,0 +1 @@ +Subproject commit bb12a796eba49843ae05261715b833831ac84259 diff --git a/apps/readest-app/src-tauri/src/lib.rs b/apps/readest-app/src-tauri/src/lib.rs index e4f7107b..81f8ce76 100644 --- a/apps/readest-app/src-tauri/src/lib.rs +++ b/apps/readest-app/src-tauri/src/lib.rs @@ -185,7 +185,7 @@ pub fn run() { .plugin(tauri_plugin_dialog::init()) .plugin(tauri_plugin_sharekit::init()) .plugin(tauri_plugin_device_info::init()) - .plugin(tauri_plugin_libsql::init()) + .plugin(tauri_plugin_turso::init()) .plugin(tauri_plugin_native_bridge::init()) .plugin(tauri_plugin_native_tts::init()); diff --git a/apps/readest-app/src/__tests__/database/libsql.tauri.test.ts b/apps/readest-app/src/__tests__/database/libsql.tauri.test.ts deleted file mode 100644 index 8ff1691e..00000000 --- a/apps/readest-app/src/__tests__/database/libsql.tauri.test.ts +++ /dev/null @@ -1,366 +0,0 @@ -import { describe, it, expect, beforeEach, afterEach } from 'vitest'; -import { invoke } from '../tauri/tauri-invoke'; - -/** - * Integration tests for tauri-plugin-libsql running inside the Tauri WebView. - * These call plugin IPC commands directly via __TAURI_INTERNALS__.invoke(). - */ -describe('libsql plugin (native Tauri)', () => { - const DB_PATH = 'sqlite::memory:'; - let dbPath: string; - - beforeEach(async () => { - dbPath = (await invoke('plugin:libsql|load', { - options: { path: DB_PATH }, - })) as string; - }); - - afterEach(async () => { - await invoke('plugin:libsql|close', { db: dbPath }); - }); - - // --------------------------------------------------------------------------- - // Connection lifecycle - // --------------------------------------------------------------------------- - - it('loads an in-memory database and returns a path', () => { - expect(typeof dbPath).toBe('string'); - expect(dbPath.length).toBeGreaterThan(0); - }); - - // --------------------------------------------------------------------------- - // Schema & basic operations - // --------------------------------------------------------------------------- - - it('creates a table and inserts a row', async () => { - await invoke('plugin:libsql|execute', { - db: dbPath, - query: 'CREATE TABLE items (id INTEGER PRIMARY KEY, name TEXT)', - values: [], - }); - - const result = (await invoke('plugin:libsql|execute', { - db: dbPath, - query: 'INSERT INTO items (name) VALUES (?)', - values: ['apple'], - })) as { rowsAffected: number; lastInsertId: number }; - - expect(result.rowsAffected).toBe(1); - expect(result.lastInsertId).toBe(1); - }); - - it('inserts multiple rows with auto-incrementing ids', async () => { - await invoke('plugin:libsql|execute', { - db: dbPath, - query: 'CREATE TABLE items (id INTEGER PRIMARY KEY, name TEXT)', - values: [], - }); - - const r1 = (await invoke('plugin:libsql|execute', { - db: dbPath, - query: 'INSERT INTO items (name) VALUES (?)', - values: ['a'], - })) as { lastInsertId: number }; - - const r2 = (await invoke('plugin:libsql|execute', { - db: dbPath, - query: 'INSERT INTO items (name) VALUES (?)', - values: ['b'], - })) as { lastInsertId: number }; - - const r3 = (await invoke('plugin:libsql|execute', { - db: dbPath, - query: 'INSERT INTO items (name) VALUES (?)', - values: ['c'], - })) as { lastInsertId: number }; - - expect(r1.lastInsertId).toBe(1); - expect(r2.lastInsertId).toBe(2); - expect(r3.lastInsertId).toBe(3); - }); - - // --------------------------------------------------------------------------- - // SELECT queries - // --------------------------------------------------------------------------- - - it('select returns typed rows', async () => { - await invoke('plugin:libsql|execute', { - db: dbPath, - query: 'CREATE TABLE items (id INTEGER PRIMARY KEY, name TEXT, qty INTEGER)', - values: [], - }); - await invoke('plugin:libsql|execute', { - db: dbPath, - query: 'INSERT INTO items (name, qty) VALUES (?, ?)', - values: ['apple', 10], - }); - await invoke('plugin:libsql|execute', { - db: dbPath, - query: 'INSERT INTO items (name, qty) VALUES (?, ?)', - values: ['banana', 20], - }); - - const rows = (await invoke('plugin:libsql|select', { - db: dbPath, - query: 'SELECT * FROM items ORDER BY id', - values: [], - })) as Array<{ id: number; name: string; qty: number }>; - - expect(rows).toHaveLength(2); - expect(rows[0]!.name).toBe('apple'); - expect(rows[0]!.qty).toBe(10); - expect(rows[1]!.name).toBe('banana'); - expect(rows[1]!.qty).toBe(20); - }); - - it('select with WHERE and params', async () => { - await invoke('plugin:libsql|execute', { - db: dbPath, - query: 'CREATE TABLE items (id INTEGER PRIMARY KEY, name TEXT)', - values: [], - }); - await invoke('plugin:libsql|execute', { - db: dbPath, - query: 'INSERT INTO items (name) VALUES (?)', - values: ['apple'], - }); - await invoke('plugin:libsql|execute', { - db: dbPath, - query: 'INSERT INTO items (name) VALUES (?)', - values: ['banana'], - }); - - const rows = (await invoke('plugin:libsql|select', { - db: dbPath, - query: 'SELECT * FROM items WHERE name = ?', - values: ['banana'], - })) as Array<{ id: number; name: string }>; - - expect(rows).toHaveLength(1); - expect(rows[0]!.name).toBe('banana'); - }); - - it('select returns empty array for no matching rows', async () => { - await invoke('plugin:libsql|execute', { - db: dbPath, - query: 'CREATE TABLE items (id INTEGER PRIMARY KEY, name TEXT)', - values: [], - }); - - const rows = (await invoke('plugin:libsql|select', { - db: dbPath, - query: 'SELECT * FROM items', - values: [], - })) as unknown[]; - - expect(rows).toEqual([]); - }); - - // --------------------------------------------------------------------------- - // UPDATE & DELETE - // --------------------------------------------------------------------------- - - it('UPDATE returns rowsAffected', async () => { - await invoke('plugin:libsql|execute', { - db: dbPath, - query: 'CREATE TABLE items (id INTEGER PRIMARY KEY, name TEXT)', - values: [], - }); - await invoke('plugin:libsql|execute', { - db: dbPath, - query: 'INSERT INTO items (name) VALUES (?)', - values: ['old'], - }); - await invoke('plugin:libsql|execute', { - db: dbPath, - query: 'INSERT INTO items (name) VALUES (?)', - values: ['old'], - }); - - const result = (await invoke('plugin:libsql|execute', { - db: dbPath, - query: 'UPDATE items SET name = ? WHERE name = ?', - values: ['new', 'old'], - })) as { rowsAffected: number }; - - expect(result.rowsAffected).toBe(2); - }); - - it('DELETE returns rowsAffected', async () => { - await invoke('plugin:libsql|execute', { - db: dbPath, - query: 'CREATE TABLE items (id INTEGER PRIMARY KEY, name TEXT)', - values: [], - }); - await invoke('plugin:libsql|execute', { - db: dbPath, - query: 'INSERT INTO items (name) VALUES (?)', - values: ['a'], - }); - await invoke('plugin:libsql|execute', { - db: dbPath, - query: 'INSERT INTO items (name) VALUES (?)', - values: ['b'], - }); - await invoke('plugin:libsql|execute', { - db: dbPath, - query: 'INSERT INTO items (name) VALUES (?)', - values: ['c'], - }); - - const result = (await invoke('plugin:libsql|execute', { - db: dbPath, - query: 'DELETE FROM items WHERE name IN (?, ?)', - values: ['a', 'c'], - })) as { rowsAffected: number }; - - expect(result.rowsAffected).toBe(2); - - const remaining = (await invoke('plugin:libsql|select', { - db: dbPath, - query: 'SELECT name FROM items', - values: [], - })) as Array<{ name: string }>; - - expect(remaining).toHaveLength(1); - expect(remaining[0]!.name).toBe('b'); - }); - - // --------------------------------------------------------------------------- - // Batch execution - // --------------------------------------------------------------------------- - - it('batch executes multiple statements atomically', async () => { - await invoke('plugin:libsql|batch', { - db: dbPath, - queries: [ - 'CREATE TABLE t1 (id INTEGER PRIMARY KEY, val TEXT)', - "INSERT INTO t1 (val) VALUES ('one')", - "INSERT INTO t1 (val) VALUES ('two')", - "INSERT INTO t1 (val) VALUES ('three')", - ], - }); - - const rows = (await invoke('plugin:libsql|select', { - db: dbPath, - query: 'SELECT val FROM t1 ORDER BY id', - values: [], - })) as Array<{ val: string }>; - - expect(rows).toHaveLength(3); - expect(rows.map((r) => r.val)).toEqual(['one', 'two', 'three']); - }); - - // --------------------------------------------------------------------------- - // Data types - // --------------------------------------------------------------------------- - - it('handles NULL values correctly', async () => { - await invoke('plugin:libsql|execute', { - db: dbPath, - query: 'CREATE TABLE t (id INTEGER PRIMARY KEY, val TEXT)', - values: [], - }); - await invoke('plugin:libsql|execute', { - db: dbPath, - query: 'INSERT INTO t (val) VALUES (?)', - values: [null], - }); - - const rows = (await invoke('plugin:libsql|select', { - db: dbPath, - query: 'SELECT * FROM t', - values: [], - })) as Array<{ id: number; val: string | null }>; - - expect(rows).toHaveLength(1); - expect(rows[0]!.val).toBeNull(); - }); - - it('handles integer and real types', async () => { - await invoke('plugin:libsql|execute', { - db: dbPath, - query: 'CREATE TABLE nums (i INTEGER, r REAL)', - values: [], - }); - await invoke('plugin:libsql|execute', { - db: dbPath, - query: 'INSERT INTO nums (i, r) VALUES (?, ?)', - values: [42, 3.14], - }); - - const rows = (await invoke('plugin:libsql|select', { - db: dbPath, - query: 'SELECT * FROM nums', - values: [], - })) as Array<{ i: number; r: number }>; - - expect(rows[0]!.i).toBe(42); - expect(rows[0]!.r).toBeCloseTo(3.14); - }); - - // --------------------------------------------------------------------------- - // Error handling - // --------------------------------------------------------------------------- - - it('throws on invalid SQL', async () => { - await expect( - invoke('plugin:libsql|execute', { - db: dbPath, - query: 'INVALID SQL STATEMENT', - values: [], - }), - ).rejects.toThrow(); - }); - - it('throws on constraint violation', async () => { - await invoke('plugin:libsql|execute', { - db: dbPath, - query: 'CREATE TABLE t (id INTEGER PRIMARY KEY, val TEXT UNIQUE)', - values: [], - }); - await invoke('plugin:libsql|execute', { - db: dbPath, - query: 'INSERT INTO t (val) VALUES (?)', - values: ['unique_val'], - }); - - await expect( - invoke('plugin:libsql|execute', { - db: dbPath, - query: 'INSERT INTO t (val) VALUES (?)', - values: ['unique_val'], - }), - ).rejects.toThrow(); - }); - - // --------------------------------------------------------------------------- - // Result contract - // --------------------------------------------------------------------------- - - it('execute result always has rowsAffected and lastInsertId as numbers', async () => { - await invoke('plugin:libsql|execute', { - db: dbPath, - query: 'CREATE TABLE t (id INTEGER PRIMARY KEY)', - values: [], - }); - - const result = (await invoke('plugin:libsql|execute', { - db: dbPath, - query: 'INSERT INTO t DEFAULT VALUES', - values: [], - })) as { rowsAffected: number; lastInsertId: number }; - - expect(typeof result.rowsAffected).toBe('number'); - expect(typeof result.lastInsertId).toBe('number'); - }); - - // --------------------------------------------------------------------------- - // Plugin config - // --------------------------------------------------------------------------- - - it('get_config returns encryption status', async () => { - const config = (await invoke('plugin:libsql|get_config')) as { encrypted: boolean }; - expect(typeof config.encrypted).toBe('boolean'); - }); -}); diff --git a/apps/readest-app/src/__tests__/database/mock.test.ts b/apps/readest-app/src/__tests__/database/mock.test.ts index 16d15270..e9178602 100644 --- a/apps/readest-app/src/__tests__/database/mock.test.ts +++ b/apps/readest-app/src/__tests__/database/mock.test.ts @@ -5,7 +5,7 @@ import { DatabaseService, DatabaseExecResult, DatabaseRow } from '@/types/databa // Mock: NativeDatabaseService // --------------------------------------------------------------------------- -vi.mock('tauri-plugin-libsql', () => { +vi.mock('tauri-plugin-turso', () => { const rows = new Map(); const mockDb = { @@ -99,7 +99,7 @@ describe('NativeDatabaseService', () => { beforeEach(async () => { vi.clearAllMocks(); - const mod = await import('tauri-plugin-libsql'); + const mod = await import('tauri-plugin-turso'); (mod as unknown as { __rows: Map }).__rows.clear(); const { NativeDatabaseService } = await import('@/services/database/nativeDatabaseService'); @@ -139,7 +139,7 @@ describe('NativeDatabaseService', () => { it('batch() delegates to underlying db.batch()', async () => { await db.batch(['CREATE TABLE t (id INTEGER)', 'INSERT INTO t VALUES (1)']); - const mod = await import('tauri-plugin-libsql'); + const mod = await import('tauri-plugin-turso'); const mockDb = (mod as unknown as { __mockDb: { batch: ReturnType } }).__mockDb; expect(mockDb.batch).toHaveBeenCalledWith([ 'CREATE TABLE t (id INTEGER)', @@ -149,7 +149,7 @@ describe('NativeDatabaseService', () => { it('close() delegates to underlying db.close()', async () => { await db.close(); - const mod = await import('tauri-plugin-libsql'); + const mod = await import('tauri-plugin-turso'); const mockDb = (mod as unknown as { __mockDb: { close: ReturnType } }).__mockDb; expect(mockDb.close).toHaveBeenCalled(); }); diff --git a/apps/readest-app/src/__tests__/database/suites/base-tests.ts b/apps/readest-app/src/__tests__/database/suites/base-tests.ts new file mode 100644 index 00000000..65530d79 --- /dev/null +++ b/apps/readest-app/src/__tests__/database/suites/base-tests.ts @@ -0,0 +1,175 @@ +import { it, expect } from 'vitest'; +import { DatabaseService } from '@/types/database'; + +/** + * Shared base database operation tests exercised against any DatabaseService. + * Covers CRUD, batch, data types, error handling, and result contract. + * + * Call inside a describe() block: + * describe('base ops', () => { baseTests(() => db); }); + */ +export function baseTests(getDb: () => DatabaseService) { + // --------------------------------------------------------------------------- + // Schema & basic operations + // --------------------------------------------------------------------------- + + it('creates a table and inserts a row', async () => { + const db = getDb(); + await db.execute('CREATE TABLE items (id INTEGER PRIMARY KEY, name TEXT)'); + const result = await db.execute('INSERT INTO items (name) VALUES (?)', ['apple']); + expect(result.rowsAffected).toBe(1); + expect(result.lastInsertId).toBe(1); + }); + + it('inserts multiple rows with auto-incrementing ids', async () => { + const db = getDb(); + await db.execute('CREATE TABLE items (id INTEGER PRIMARY KEY, name TEXT)'); + const r1 = await db.execute('INSERT INTO items (name) VALUES (?)', ['a']); + const r2 = await db.execute('INSERT INTO items (name) VALUES (?)', ['b']); + const r3 = await db.execute('INSERT INTO items (name) VALUES (?)', ['c']); + expect(r1.lastInsertId).toBe(1); + expect(r2.lastInsertId).toBe(2); + expect(r3.lastInsertId).toBe(3); + }); + + // --------------------------------------------------------------------------- + // SELECT queries + // --------------------------------------------------------------------------- + + it('select returns typed rows', async () => { + const db = getDb(); + await db.execute('CREATE TABLE items (id INTEGER PRIMARY KEY, name TEXT, qty INTEGER)'); + await db.execute('INSERT INTO items (name, qty) VALUES (?, ?)', ['apple', 10]); + await db.execute('INSERT INTO items (name, qty) VALUES (?, ?)', ['banana', 20]); + + const rows = await db.select<{ id: number; name: string; qty: number }>( + 'SELECT * FROM items ORDER BY id', + ); + expect(rows).toHaveLength(2); + expect(rows[0]!.name).toBe('apple'); + expect(rows[0]!.qty).toBe(10); + expect(rows[1]!.name).toBe('banana'); + expect(rows[1]!.qty).toBe(20); + }); + + it('select with WHERE and params', async () => { + const db = getDb(); + await db.execute('CREATE TABLE items (id INTEGER PRIMARY KEY, name TEXT)'); + await db.execute('INSERT INTO items (name) VALUES (?)', ['apple']); + await db.execute('INSERT INTO items (name) VALUES (?)', ['banana']); + await db.execute('INSERT INTO items (name) VALUES (?)', ['cherry']); + + const rows = await db.select<{ id: number; name: string }>( + 'SELECT * FROM items WHERE name = ?', + ['banana'], + ); + expect(rows).toHaveLength(1); + expect(rows[0]!.name).toBe('banana'); + }); + + it('select returns empty array for no matching rows', async () => { + const db = getDb(); + await db.execute('CREATE TABLE items (id INTEGER PRIMARY KEY, name TEXT)'); + const rows = await db.select('SELECT * FROM items'); + expect(rows).toEqual([]); + }); + + // --------------------------------------------------------------------------- + // UPDATE & DELETE + // --------------------------------------------------------------------------- + + it('UPDATE returns rowsAffected', async () => { + const db = getDb(); + await db.execute('CREATE TABLE items (id INTEGER PRIMARY KEY, name TEXT)'); + await db.execute('INSERT INTO items (name) VALUES (?)', ['old']); + await db.execute('INSERT INTO items (name) VALUES (?)', ['old']); + + const result = await db.execute('UPDATE items SET name = ? WHERE name = ?', ['new', 'old']); + expect(result.rowsAffected).toBe(2); + }); + + it('DELETE returns rowsAffected', async () => { + const db = getDb(); + await db.execute('CREATE TABLE items (id INTEGER PRIMARY KEY, name TEXT)'); + await db.execute('INSERT INTO items (name) VALUES (?)', ['a']); + await db.execute('INSERT INTO items (name) VALUES (?)', ['b']); + await db.execute('INSERT INTO items (name) VALUES (?)', ['c']); + + const result = await db.execute('DELETE FROM items WHERE name IN (?, ?)', ['a', 'c']); + expect(result.rowsAffected).toBe(2); + + const remaining = await db.select<{ name: string }>('SELECT name FROM items'); + expect(remaining).toHaveLength(1); + expect(remaining[0]!.name).toBe('b'); + }); + + // --------------------------------------------------------------------------- + // Batch execution + // --------------------------------------------------------------------------- + + it('batch executes multiple statements atomically', async () => { + const db = getDb(); + await db.batch([ + 'CREATE TABLE t1 (id INTEGER PRIMARY KEY, val TEXT)', + "INSERT INTO t1 (val) VALUES ('one')", + "INSERT INTO t1 (val) VALUES ('two')", + "INSERT INTO t1 (val) VALUES ('three')", + ]); + + const rows = await db.select<{ val: string }>('SELECT val FROM t1 ORDER BY id'); + expect(rows).toHaveLength(3); + expect(rows.map((r) => r.val)).toEqual(['one', 'two', 'three']); + }); + + // --------------------------------------------------------------------------- + // Data types + // --------------------------------------------------------------------------- + + it('handles NULL values correctly', async () => { + const db = getDb(); + await db.execute('CREATE TABLE t (id INTEGER PRIMARY KEY, val TEXT)'); + await db.execute('INSERT INTO t (val) VALUES (?)', [null]); + + const rows = await db.select<{ id: number; val: string | null }>('SELECT * FROM t'); + expect(rows).toHaveLength(1); + expect(rows[0]!.val).toBeNull(); + }); + + it('handles integer and real types', async () => { + const db = getDb(); + await db.execute('CREATE TABLE nums (i INTEGER, r REAL)'); + await db.execute('INSERT INTO nums (i, r) VALUES (?, ?)', [42, 3.14]); + + const rows = await db.select<{ i: number; r: number }>('SELECT * FROM nums'); + expect(rows[0]!.i).toBe(42); + expect(rows[0]!.r).toBeCloseTo(3.14); + }); + + // --------------------------------------------------------------------------- + // Error handling + // --------------------------------------------------------------------------- + + it('throws on invalid SQL', async () => { + const db = getDb(); + await expect(db.execute('INVALID SQL STATEMENT')).rejects.toThrow(); + }); + + it('throws on constraint violation', async () => { + const db = getDb(); + await db.execute('CREATE TABLE t (id INTEGER PRIMARY KEY, val TEXT UNIQUE)'); + await db.execute('INSERT INTO t (val) VALUES (?)', ['unique_val']); + await expect(db.execute('INSERT INTO t (val) VALUES (?)', ['unique_val'])).rejects.toThrow(); + }); + + // --------------------------------------------------------------------------- + // Result contract + // --------------------------------------------------------------------------- + + it('execute result always has rowsAffected and lastInsertId as numbers', async () => { + const db = getDb(); + await db.execute('CREATE TABLE t (id INTEGER PRIMARY KEY)'); + const result = await db.execute('INSERT INTO t DEFAULT VALUES'); + expect(typeof result.rowsAffected).toBe('number'); + expect(typeof result.lastInsertId).toBe('number'); + }); +} diff --git a/apps/readest-app/src/__tests__/database/turso-node.test.ts b/apps/readest-app/src/__tests__/database/turso-node.test.ts index 6e190d22..4dfe1514 100644 --- a/apps/readest-app/src/__tests__/database/turso-node.test.ts +++ b/apps/readest-app/src/__tests__/database/turso-node.test.ts @@ -1,14 +1,15 @@ -import { describe, it, expect, beforeEach, afterEach } from 'vitest'; +import { describe, beforeEach, afterEach } from 'vitest'; import { NodeDatabaseService } from '@/services/database/nodeDatabaseService'; -import { DatabaseService, DatabaseExecResult } from '@/types/database'; +import { DatabaseService } from '@/types/database'; +import { baseTests } from './suites/base-tests'; import { ftsTests } from './suites/fts-tests'; import { vectorTests } from './suites/vector-tests'; /** * Integration tests using a real in-memory SQLite database via @tursodatabase/database. - * These complement the mock-based tests in databaseService.test.ts by exercising + * These complement the mock-based tests in mock.test.ts by exercising * actual SQL execution through the DatabaseService interface using the same - * libsql engine that powers the browser-based @tursodatabase/database-wasm. + * turso engine that powers the browser-based @tursodatabase/database-wasm. */ describe('NodeDatabaseService (real in-memory SQLite)', () => { let db: DatabaseService; @@ -21,171 +22,14 @@ describe('NodeDatabaseService (real in-memory SQLite)', () => { await db.close(); }); - // ------------------------------------------------------------------------- - // Schema & basic operations - // ------------------------------------------------------------------------- - - it('creates a table and inserts a row', async () => { - await db.execute('CREATE TABLE items (id INTEGER PRIMARY KEY, name TEXT)'); - const result: DatabaseExecResult = await db.execute('INSERT INTO items (name) VALUES (?)', [ - 'apple', - ]); - expect(result.rowsAffected).toBe(1); - expect(result.lastInsertId).toBe(1); + describe('Base Operations', () => { + baseTests(() => db); }); - it('inserts multiple rows with auto-incrementing ids', async () => { - await db.execute('CREATE TABLE items (id INTEGER PRIMARY KEY, name TEXT)'); - const r1 = await db.execute('INSERT INTO items (name) VALUES (?)', ['a']); - const r2 = await db.execute('INSERT INTO items (name) VALUES (?)', ['b']); - const r3 = await db.execute('INSERT INTO items (name) VALUES (?)', ['c']); - expect(r1.lastInsertId).toBe(1); - expect(r2.lastInsertId).toBe(2); - expect(r3.lastInsertId).toBe(3); - }); - - // ------------------------------------------------------------------------- - // SELECT queries - // ------------------------------------------------------------------------- - - it('select() returns typed rows', async () => { - await db.execute('CREATE TABLE items (id INTEGER PRIMARY KEY, name TEXT, qty INTEGER)'); - await db.execute('INSERT INTO items (name, qty) VALUES (?, ?)', ['apple', 10]); - await db.execute('INSERT INTO items (name, qty) VALUES (?, ?)', ['banana', 20]); - - const rows = await db.select<{ id: number; name: string; qty: number }>( - 'SELECT * FROM items ORDER BY id', - ); - expect(rows).toHaveLength(2); - expect(rows[0]!.name).toBe('apple'); - expect(rows[0]!.qty).toBe(10); - expect(rows[1]!.name).toBe('banana'); - expect(rows[1]!.qty).toBe(20); - }); - - it('select() with WHERE and params', async () => { - await db.execute('CREATE TABLE items (id INTEGER PRIMARY KEY, name TEXT)'); - await db.execute('INSERT INTO items (name) VALUES (?)', ['apple']); - await db.execute('INSERT INTO items (name) VALUES (?)', ['banana']); - await db.execute('INSERT INTO items (name) VALUES (?)', ['cherry']); - - const rows = await db.select<{ id: number; name: string }>( - 'SELECT * FROM items WHERE name = ?', - ['banana'], - ); - expect(rows).toHaveLength(1); - expect(rows[0]!.name).toBe('banana'); - }); - - it('select() returns empty array for no matching rows', async () => { - await db.execute('CREATE TABLE items (id INTEGER PRIMARY KEY, name TEXT)'); - const rows = await db.select('SELECT * FROM items'); - expect(rows).toEqual([]); - }); - - // ------------------------------------------------------------------------- - // UPDATE & DELETE - // ------------------------------------------------------------------------- - - it('execute() UPDATE returns rowsAffected', async () => { - await db.execute('CREATE TABLE items (id INTEGER PRIMARY KEY, name TEXT)'); - await db.execute('INSERT INTO items (name) VALUES (?)', ['old']); - await db.execute('INSERT INTO items (name) VALUES (?)', ['old']); - - const result = await db.execute('UPDATE items SET name = ? WHERE name = ?', ['new', 'old']); - expect(result.rowsAffected).toBe(2); - }); - - it('execute() DELETE returns rowsAffected', async () => { - await db.execute('CREATE TABLE items (id INTEGER PRIMARY KEY, name TEXT)'); - await db.execute('INSERT INTO items (name) VALUES (?)', ['a']); - await db.execute('INSERT INTO items (name) VALUES (?)', ['b']); - await db.execute('INSERT INTO items (name) VALUES (?)', ['c']); - - const result = await db.execute('DELETE FROM items WHERE name IN (?, ?)', ['a', 'c']); - expect(result.rowsAffected).toBe(2); - - const remaining = await db.select<{ name: string }>('SELECT name FROM items'); - expect(remaining).toHaveLength(1); - expect(remaining[0]!.name).toBe('b'); - }); - - // ------------------------------------------------------------------------- - // Batch execution - // ------------------------------------------------------------------------- - - it('batch() executes multiple statements atomically', async () => { - await db.batch([ - 'CREATE TABLE t1 (id INTEGER PRIMARY KEY, val TEXT)', - "INSERT INTO t1 (val) VALUES ('one')", - "INSERT INTO t1 (val) VALUES ('two')", - "INSERT INTO t1 (val) VALUES ('three')", - ]); - - const rows = await db.select<{ val: string }>('SELECT val FROM t1 ORDER BY id'); - expect(rows).toHaveLength(3); - expect(rows.map((r) => r.val)).toEqual(['one', 'two', 'three']); - }); - - // ------------------------------------------------------------------------- - // Data types - // ------------------------------------------------------------------------- - - it('handles NULL values correctly', async () => { - await db.execute('CREATE TABLE t (id INTEGER PRIMARY KEY, val TEXT)'); - await db.execute('INSERT INTO t (val) VALUES (?)', [null]); - - const rows = await db.select<{ id: number; val: string | null }>('SELECT * FROM t'); - expect(rows).toHaveLength(1); - expect(rows[0]!.val).toBeNull(); - }); - - it('handles integer and real types', async () => { - await db.execute('CREATE TABLE nums (i INTEGER, r REAL)'); - await db.execute('INSERT INTO nums (i, r) VALUES (?, ?)', [42, 3.14]); - - const rows = await db.select<{ i: number; r: number }>('SELECT * FROM nums'); - expect(rows[0]!.i).toBe(42); - expect(rows[0]!.r).toBeCloseTo(3.14); - }); - - // ------------------------------------------------------------------------- - // Error handling - // ------------------------------------------------------------------------- - - it('throws on invalid SQL', async () => { - await expect(db.execute('INVALID SQL STATEMENT')).rejects.toThrow(); - }); - - it('throws on constraint violation', async () => { - await db.execute('CREATE TABLE t (id INTEGER PRIMARY KEY, val TEXT UNIQUE)'); - await db.execute('INSERT INTO t (val) VALUES (?)', ['unique_val']); - await expect(db.execute('INSERT INTO t (val) VALUES (?)', ['unique_val'])).rejects.toThrow(); - }); - - // ------------------------------------------------------------------------- - // DatabaseExecResult contract - // ------------------------------------------------------------------------- - - it('execute() result always has rowsAffected and lastInsertId as numbers', async () => { - await db.execute('CREATE TABLE t (id INTEGER PRIMARY KEY)'); - const result = await db.execute('INSERT INTO t DEFAULT VALUES'); - expect(typeof result.rowsAffected).toBe('number'); - expect(typeof result.lastInsertId).toBe('number'); - }); - - // ------------------------------------------------------------------------- - // Full-text search (Turso native FTS, Tantivy-based) - // ------------------------------------------------------------------------- - describe('Full-Text Search', () => { ftsTests(() => db); }); - // ------------------------------------------------------------------------- - // Vector search - // ------------------------------------------------------------------------- - describe('Vector Search', () => { vectorTests(() => db); }); diff --git a/apps/readest-app/src/__tests__/database/turso-rust.tauri.test.ts b/apps/readest-app/src/__tests__/database/turso-rust.tauri.test.ts new file mode 100644 index 00000000..b0b729c3 --- /dev/null +++ b/apps/readest-app/src/__tests__/database/turso-rust.tauri.test.ts @@ -0,0 +1,106 @@ +import { describe, it, expect, beforeEach, afterEach } from 'vitest'; +import { invoke } from '../tauri/tauri-invoke'; +import { DatabaseService, DatabaseExecResult, DatabaseRow } from '@/types/database'; +import { baseTests } from './suites/base-tests'; +import { ftsTests } from './suites/fts-tests'; +import { vectorTests } from './suites/vector-tests'; + +/** + * Thin DatabaseService adapter over raw Tauri IPC invoke() calls. + * Enables reuse of the shared test suites. + */ +class TauriDatabaseAdapter implements DatabaseService { + constructor(private dbPath: string) {} + + async execute(sql: string, params: unknown[] = []): Promise { + const result = (await invoke('plugin:turso|execute', { + db: this.dbPath, + query: sql, + values: params, + })) as { rowsAffected: number; lastInsertId: number }; + return { + rowsAffected: result.rowsAffected, + lastInsertId: result.lastInsertId, + }; + } + + async select( + sql: string, + params: unknown[] = [], + ): Promise { + return (await invoke('plugin:turso|select', { + db: this.dbPath, + query: sql, + values: params, + })) as T[]; + } + + async batch(statements: string[]): Promise { + await invoke('plugin:turso|batch', { + db: this.dbPath, + queries: statements, + }); + } + + async close(): Promise { + await invoke('plugin:turso|close', { db: this.dbPath }); + } +} + +/** + * Integration tests for the turso-backed tauri-plugin-turso running inside + * the Tauri WebView. Calls plugin IPC commands via __TAURI_INTERNALS__.invoke(). + * + * The database is opened with experimental index_method enabled so that + * FTS (Tantivy-based) CREATE INDEX ... USING fts works. + */ +describe('turso plugin (native Tauri)', () => { + const DB_PATH = 'sqlite::memory:'; + let dbPath: string; + let db: DatabaseService; + + beforeEach(async () => { + dbPath = (await invoke('plugin:turso|load', { + options: { path: DB_PATH, experimental: ['index_method'] }, + })) as string; + db = new TauriDatabaseAdapter(dbPath); + }); + + afterEach(async () => { + await db.close(); + }); + + // --------------------------------------------------------------------------- + // Connection lifecycle + // --------------------------------------------------------------------------- + + it('loads an in-memory database and returns a path', () => { + expect(typeof dbPath).toBe('string'); + expect(dbPath.length).toBeGreaterThan(0); + }); + + // --------------------------------------------------------------------------- + // Plugin config + // --------------------------------------------------------------------------- + + it('get_config returns encryption status', async () => { + const config = (await invoke('plugin:turso|get_config')) as { encrypted: boolean }; + expect(typeof config.encrypted).toBe('boolean'); + }); + + // --------------------------------------------------------------------------- + // Shared test suites + // --------------------------------------------------------------------------- + + describe('Base Operations', () => { + baseTests(() => db); + }); + + describe('Full-Text Search', () => { + ftsTests(() => db); + }); + + describe('Vector Search', () => { + vectorTests(() => db); + }); +}); diff --git a/apps/readest-app/src/__tests__/database/turso-wasm.browser.test.ts b/apps/readest-app/src/__tests__/database/turso-wasm.browser.test.ts index 5f8cdae1..092d2b5f 100644 --- a/apps/readest-app/src/__tests__/database/turso-wasm.browser.test.ts +++ b/apps/readest-app/src/__tests__/database/turso-wasm.browser.test.ts @@ -1,6 +1,7 @@ -import { describe, it, expect, beforeEach, afterEach } from 'vitest'; +import { describe, beforeEach, afterEach } from 'vitest'; import { WebDatabaseService } from '@/services/database/webDatabaseService'; -import { DatabaseService, DatabaseExecResult } from '@/types/database'; +import { DatabaseService } from '@/types/database'; +import { baseTests } from './suites/base-tests'; import { ftsTests } from './suites/fts-tests'; import { vectorTests } from './suites/vector-tests'; @@ -20,171 +21,14 @@ describe('WebDatabaseService (browser WASM, in-memory SQLite)', () => { await db.close(); }); - // ------------------------------------------------------------------------- - // Schema & basic operations - // ------------------------------------------------------------------------- - - it('creates a table and inserts a row', async () => { - await db.execute('CREATE TABLE items (id INTEGER PRIMARY KEY, name TEXT)'); - const result: DatabaseExecResult = await db.execute('INSERT INTO items (name) VALUES (?)', [ - 'apple', - ]); - expect(result.rowsAffected).toBe(1); - expect(result.lastInsertId).toBe(1); + describe('Base Operations', () => { + baseTests(() => db); }); - it('inserts multiple rows with auto-incrementing ids', async () => { - await db.execute('CREATE TABLE items (id INTEGER PRIMARY KEY, name TEXT)'); - const r1 = await db.execute('INSERT INTO items (name) VALUES (?)', ['a']); - const r2 = await db.execute('INSERT INTO items (name) VALUES (?)', ['b']); - const r3 = await db.execute('INSERT INTO items (name) VALUES (?)', ['c']); - expect(r1.lastInsertId).toBe(1); - expect(r2.lastInsertId).toBe(2); - expect(r3.lastInsertId).toBe(3); - }); - - // ------------------------------------------------------------------------- - // SELECT queries - // ------------------------------------------------------------------------- - - it('select() returns typed rows', async () => { - await db.execute('CREATE TABLE items (id INTEGER PRIMARY KEY, name TEXT, qty INTEGER)'); - await db.execute('INSERT INTO items (name, qty) VALUES (?, ?)', ['apple', 10]); - await db.execute('INSERT INTO items (name, qty) VALUES (?, ?)', ['banana', 20]); - - const rows = await db.select<{ id: number; name: string; qty: number }>( - 'SELECT * FROM items ORDER BY id', - ); - expect(rows).toHaveLength(2); - expect(rows[0]!.name).toBe('apple'); - expect(rows[0]!.qty).toBe(10); - expect(rows[1]!.name).toBe('banana'); - expect(rows[1]!.qty).toBe(20); - }); - - it('select() with WHERE and params', async () => { - await db.execute('CREATE TABLE items (id INTEGER PRIMARY KEY, name TEXT)'); - await db.execute('INSERT INTO items (name) VALUES (?)', ['apple']); - await db.execute('INSERT INTO items (name) VALUES (?)', ['banana']); - await db.execute('INSERT INTO items (name) VALUES (?)', ['cherry']); - - const rows = await db.select<{ id: number; name: string }>( - 'SELECT * FROM items WHERE name = ?', - ['banana'], - ); - expect(rows).toHaveLength(1); - expect(rows[0]!.name).toBe('banana'); - }); - - it('select() returns empty array for no matching rows', async () => { - await db.execute('CREATE TABLE items (id INTEGER PRIMARY KEY, name TEXT)'); - const rows = await db.select('SELECT * FROM items'); - expect(rows).toEqual([]); - }); - - // ------------------------------------------------------------------------- - // UPDATE & DELETE - // ------------------------------------------------------------------------- - - it('execute() UPDATE returns rowsAffected', async () => { - await db.execute('CREATE TABLE items (id INTEGER PRIMARY KEY, name TEXT)'); - await db.execute('INSERT INTO items (name) VALUES (?)', ['old']); - await db.execute('INSERT INTO items (name) VALUES (?)', ['old']); - - const result = await db.execute('UPDATE items SET name = ? WHERE name = ?', ['new', 'old']); - expect(result.rowsAffected).toBe(2); - }); - - it('execute() DELETE returns rowsAffected', async () => { - await db.execute('CREATE TABLE items (id INTEGER PRIMARY KEY, name TEXT)'); - await db.execute('INSERT INTO items (name) VALUES (?)', ['a']); - await db.execute('INSERT INTO items (name) VALUES (?)', ['b']); - await db.execute('INSERT INTO items (name) VALUES (?)', ['c']); - - const result = await db.execute('DELETE FROM items WHERE name IN (?, ?)', ['a', 'c']); - expect(result.rowsAffected).toBe(2); - - const remaining = await db.select<{ name: string }>('SELECT name FROM items'); - expect(remaining).toHaveLength(1); - expect(remaining[0]!.name).toBe('b'); - }); - - // ------------------------------------------------------------------------- - // Batch execution - // ------------------------------------------------------------------------- - - it('batch() executes multiple statements atomically', async () => { - await db.batch([ - 'CREATE TABLE t1 (id INTEGER PRIMARY KEY, val TEXT)', - "INSERT INTO t1 (val) VALUES ('one')", - "INSERT INTO t1 (val) VALUES ('two')", - "INSERT INTO t1 (val) VALUES ('three')", - ]); - - const rows = await db.select<{ val: string }>('SELECT val FROM t1 ORDER BY id'); - expect(rows).toHaveLength(3); - expect(rows.map((r) => r.val)).toEqual(['one', 'two', 'three']); - }); - - // ------------------------------------------------------------------------- - // Data types - // ------------------------------------------------------------------------- - - it('handles NULL values correctly', async () => { - await db.execute('CREATE TABLE t (id INTEGER PRIMARY KEY, val TEXT)'); - await db.execute('INSERT INTO t (val) VALUES (?)', [null]); - - const rows = await db.select<{ id: number; val: string | null }>('SELECT * FROM t'); - expect(rows).toHaveLength(1); - expect(rows[0]!.val).toBeNull(); - }); - - it('handles integer and real types', async () => { - await db.execute('CREATE TABLE nums (i INTEGER, r REAL)'); - await db.execute('INSERT INTO nums (i, r) VALUES (?, ?)', [42, 3.14]); - - const rows = await db.select<{ i: number; r: number }>('SELECT * FROM nums'); - expect(rows[0]!.i).toBe(42); - expect(rows[0]!.r).toBeCloseTo(3.14); - }); - - // ------------------------------------------------------------------------- - // Error handling - // ------------------------------------------------------------------------- - - it('throws on invalid SQL', async () => { - await expect(db.execute('INVALID SQL STATEMENT')).rejects.toThrow(); - }); - - it('throws on constraint violation', async () => { - await db.execute('CREATE TABLE t (id INTEGER PRIMARY KEY, val TEXT UNIQUE)'); - await db.execute('INSERT INTO t (val) VALUES (?)', ['unique_val']); - await expect(db.execute('INSERT INTO t (val) VALUES (?)', ['unique_val'])).rejects.toThrow(); - }); - - // ------------------------------------------------------------------------- - // DatabaseExecResult contract - // ------------------------------------------------------------------------- - - it('execute() result always has rowsAffected and lastInsertId as numbers', async () => { - await db.execute('CREATE TABLE t (id INTEGER PRIMARY KEY)'); - const result = await db.execute('INSERT INTO t DEFAULT VALUES'); - expect(typeof result.rowsAffected).toBe('number'); - expect(typeof result.lastInsertId).toBe('number'); - }); - - // ------------------------------------------------------------------------- - // Full-text search (Turso native FTS, Tantivy-based) - // ------------------------------------------------------------------------- - describe('Full-Text Search', () => { ftsTests(() => db); }); - // ------------------------------------------------------------------------- - // Vector search - // ------------------------------------------------------------------------- - describe('Vector Search', () => { vectorTests(() => db); }); diff --git a/apps/readest-app/src/services/database/nativeDatabaseService.ts b/apps/readest-app/src/services/database/nativeDatabaseService.ts index 05c5c813..d5c4a14e 100644 --- a/apps/readest-app/src/services/database/nativeDatabaseService.ts +++ b/apps/readest-app/src/services/database/nativeDatabaseService.ts @@ -1,4 +1,4 @@ -import { Database, QueryResult } from 'tauri-plugin-libsql'; +import { Database, QueryResult } from 'tauri-plugin-turso'; import { DatabaseService, DatabaseExecResult, DatabaseRow, DatabaseOpts } from '@/types/database'; export class NativeDatabaseService implements DatabaseService { diff --git a/apps/readest-app/src/services/database/nodeDatabaseService.ts b/apps/readest-app/src/services/database/nodeDatabaseService.ts index 3c40ee69..ce4b9f10 100644 --- a/apps/readest-app/src/services/database/nodeDatabaseService.ts +++ b/apps/readest-app/src/services/database/nodeDatabaseService.ts @@ -18,7 +18,7 @@ interface TursoDatabase { /** * DatabaseService implementation backed by @tursodatabase/database (Node.js native). - * Uses the same libsql engine and API surface as the browser-based + * Uses the same turso engine and API surface as the browser-based * @tursodatabase/database-wasm used by WebDatabaseService. */ export class NodeDatabaseService implements DatabaseService { diff --git a/apps/readest-app/tsconfig.json b/apps/readest-app/tsconfig.json index b0a7ccde..2708abaf 100644 --- a/apps/readest-app/tsconfig.json +++ b/apps/readest-app/tsconfig.json @@ -25,7 +25,7 @@ "@/components/ui/*": ["./src/components/primitives/*"], "@pdfjs/*": ["./public/vendor/pdfjs/*"], "@simplecc/*": ["./public/vendor/simplecc/*"], - "tauri-plugin-libsql": ["./src-tauri/plugins/tauri-plugin-libsql/guest-js"] + "tauri-plugin-turso": ["./src-tauri/plugins/tauri-plugin-turso/guest-js"] } }, "include": [