diff --git a/.gitignore b/.gitignore index 9641838ee..2fba6111f 100644 --- a/.gitignore +++ b/.gitignore @@ -14,7 +14,6 @@ cli/turbo-new.exe cli/turbo.exe storybook-static/ .DS_Store -cache .env* vendor/ data diff --git a/.vscode/settings.json b/.vscode/settings.json index 3190ae975..9033eae85 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -10,9 +10,11 @@ "dotenv", "dotenvy", "fontsource", + "ianvs", "ipfs", "Keepsafe", "nodestate", + "normalise", "overscan", "pathctx", "prismjs", @@ -26,7 +28,6 @@ "tailwindcss", "tanstack", "titlebar", - "ianvs", "tsparticles", "unlisten", "upsert", diff --git a/Cargo.lock b/Cargo.lock index da214333e..f72c1a47d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -58,9 +58,9 @@ dependencies = [ [[package]] name = "aes-gcm" -version = "0.10.2" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "209b47e8954a928e1d72e86eca7000ebb6655fe1436d33eefc2201cad027e237" +checksum = "831010a0f742e1209b3bcea8fab6a8e149051ba6099432c8cb2cc117dec3ead1" dependencies = [ "aead", "aes 0.8.3", @@ -72,11 +72,11 @@ dependencies = [ [[package]] name = "ahash" -version = "0.7.6" +version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" +checksum = "5a824f2aa7e75a0c98c5a504fceb80649e9c35265d44525b5f94de4771a395cd" dependencies = [ - "getrandom 0.2.10", + "getrandom 0.2.11", "once_cell", "version_check", ] @@ -92,9 +92,9 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "1.0.5" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c378d78423fdad8089616f827526ee33c19f2fddbd5de1629152c9593ba4783" +checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" dependencies = [ "memchr", ] @@ -145,15 +145,15 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b84bf0a05bbb2a83e5eb6fa36bb6e87baa08193c35ff52bbf6b38d8af2890e46" +checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87" [[package]] name = "anstyle-parse" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "938874ff5980b03a87c5524b3ae5b59cf99b1d6bc836848df7bc5ada9643c333" +checksum = "317b9a89c1868f5ea6ff1d9539a69f45dffc21ce321ac1fd1160dfa48c8e2140" dependencies = [ "utf8parse", ] @@ -264,12 +264,12 @@ dependencies = [ [[package]] name = "async-channel" -version = "2.1.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d37875bd9915b7d67c2f117ea2c30a0989874d0b2cb694fe25403c85763c0c9e" +checksum = "1ca33f4bc4ed1babef42cad36cc1f51fa88be00420404e5b1e80ab1b18f7678c" dependencies = [ "concurrent-queue", - "event-listener 3.1.0", + "event-listener 4.0.0", "event-listener-strategy", "futures-core", "pin-project-lite", @@ -289,9 +289,9 @@ dependencies = [ "log", "parking", "polling", - "rustix 0.37.23", + "rustix 0.37.27", "slab", - "socket2 0.4.9", + "socket2 0.4.10", "waker-fn", ] @@ -312,7 +312,7 @@ checksum = "5fd55a5ba1179988837d24ab4c7cc8ed6efdeff578ede0416b4225a5fca35bd0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.39", ] [[package]] @@ -334,7 +334,7 @@ checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.39", ] [[package]] @@ -345,14 +345,14 @@ checksum = "a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.39", ] [[package]] name = "async-tungstenite" -version = "0.19.0" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e6acf7e4a267eecbb127ed696bb2d50572c22ba7f586a646321e1798d8336a1" +checksum = "a1e9efbe14612da0a19fb983059a0b621e9cf6225d7018ecab4f9988215540dc" dependencies = [ "futures-io", "futures-util", @@ -396,7 +396,7 @@ dependencies = [ "glib-sys", "gobject-sys", "libc", - "system-deps 6.1.1", + "system-deps 6.2.0", ] [[package]] @@ -529,12 +529,6 @@ version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" -[[package]] -name = "base64" -version = "0.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ea22880d78093b0cbe17c89f64a7d457941e65759157ec6cb31a31d652b05e5" - [[package]] name = "base64" version = "0.21.5" @@ -559,6 +553,19 @@ dependencies = [ "serde", ] +[[package]] +name = "bigdecimal" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06619be423ea5bb86c95f087d5707942791a08a85530df0db2209a3ecfb8bc9" +dependencies = [ + "autocfg", + "libm", + "num-bigint", + "num-integer", + "num-traits", +] + [[package]] name = "bincode" version = "1.3.3" @@ -598,7 +605,6 @@ dependencies = [ "clang-sys", "lazy_static", "lazycell", - "log", "peeking_take_while", "proc-macro2", "quote", @@ -606,6 +612,28 @@ dependencies = [ "rustc-hash", "shlex", "syn 1.0.109", +] + +[[package]] +name = "bindgen" +version = "0.69.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ffcebc3849946a7170a05992aac39da343a90676ab392c51a4280981d6379c2" +dependencies = [ + "bitflags 2.4.1", + "cexpr", + "clang-sys", + "lazy_static", + "lazycell", + "log", + "peeking_take_while", + "prettyplease", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex", + "syn 2.0.39", "which", ] @@ -623,9 +651,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.4.0" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" +checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" [[package]] name = "bitvec" @@ -704,9 +732,9 @@ checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae" [[package]] name = "brotli" -version = "3.3.4" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1a0b1dbcc8ae29329621f8d4f0d835787c1c38bb1401979b49d13b0b305ff68" +checksum = "516074a47ef4bce09577a3b379392300159ce5b1ba2e501ff1c819950066100f" dependencies = [ "alloc-no-stdlib", "alloc-stdlib", @@ -715,9 +743,9 @@ dependencies = [ [[package]] name = "brotli-decompressor" -version = "2.3.4" +version = "2.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b6561fd3f895a11e8f72af2cb7d22e08366bebc2b6b57f7744c4bda27034744" +checksum = "4e2e4afe60d7dd600fdd3de8d0f08c2b7ec039712e3b6137ff98b7004e82de4f" dependencies = [ "alloc-no-stdlib", "alloc-stdlib", @@ -734,12 +762,12 @@ dependencies = [ [[package]] name = "bstr" -version = "1.6.2" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c2f7349907b712260e64b0afe2f84692af14a454be26187d9df565c7f69266a" +checksum = "542f33a8835a0884b006a0c3df3dadd99c0c3f296ed26c2fdc8028e01ad6230c" dependencies = [ "memchr", - "regex-automata 0.3.8", + "regex-automata 0.4.3", "serde", ] @@ -750,8 +778,8 @@ source = "git+https://github.com/Brendonovich/prisma-engines?branch=new-4.14.0-p dependencies = [ "connection-string", "either", - "enumflags2 0.7.7", - "indoc 2.0.4", + "enumflags2 0.7.8", + "indoc", "lsp-types", "once_cell", "psl-core", @@ -760,15 +788,15 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.13.0" +version = "3.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1" +checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" [[package]] name = "bytecount" -version = "0.6.3" +version = "0.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c676a478f63e9fa2dd5368a42f28bba0d6c560b775f38583c8bbaa7fcd67c9c" +checksum = "e1e5f035d16fc623ae5f74981db80a439803888314e3a555fd6f04acd51a3205" [[package]] name = "bytemuck" @@ -812,7 +840,7 @@ checksum = "3c55d429bef56ac9172d25fecb85dc8068307d17acd74b377866b7a1ef25d3c8" dependencies = [ "glib-sys", "libc", - "system-deps 6.1.1", + "system-deps 6.2.0", ] [[package]] @@ -826,9 +854,9 @@ dependencies = [ [[package]] name = "cargo-platform" -version = "0.1.3" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cfa25e60aea747ec7e1124f238816749faa93759c6ff5b31f1ccdda137f4479" +checksum = "e34637b3140142bdf929fb439e8aa4ebad7651ebf7b1080b3930aa16ac1459ff" dependencies = [ "serde", ] @@ -1003,9 +1031,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.4.8" +version = "4.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2275f18819641850fa26c89acc84d465c1bf91ce57bc2748b28c420473352f64" +checksum = "41fffed7514f420abec6d183b1d3acfd9099c79c3a10a06ade4f8203f1411272" dependencies = [ "clap_builder", "clap_derive", @@ -1013,9 +1041,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.4.8" +version = "4.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07cdf1b148b25c1e1f7a42225e30a0d99a615cd4637eae7365548dd4529b95bc" +checksum = "63361bae7eef3771745f02d8d892bec2fee5f6e34af316ba556e7f97a7069ff1" dependencies = [ "anstream", "anstyle", @@ -1032,7 +1060,7 @@ dependencies = [ "heck 0.4.1", "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.39", ] [[package]] @@ -1059,15 +1087,14 @@ dependencies = [ [[package]] name = "cocoa-foundation" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "931d3837c286f56e3c58423ce4eba12d08db2374461a785c86f672b08b5650d6" +checksum = "8c6234cbb2e4c785b456c0644748b1ac416dd045799740356f8363dfe00c93f7" dependencies = [ "bitflags 1.3.2", "block", "core-foundation", "core-graphics-types", - "foreign-types", "libc", "objc", ] @@ -1120,9 +1147,9 @@ dependencies = [ [[package]] name = "concurrent-queue" -version = "2.2.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62ec6771ecfa0762d24683ee5a32ad78487a3d3afdc0fb8cae19d2c5deb50b7c" +checksum = "d16048cd947b08fa32c24458a22f5dc5e835264f689f4f5653210c69fd107363" dependencies = [ "crossbeam-utils", ] @@ -1188,9 +1215,9 @@ dependencies = [ [[package]] name = "cookie" -version = "0.16.2" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e859cd57d0710d9e06c381b550c06e76992472a8c6d527aecd2fc673dcc231fb" +checksum = "7efb37c3e1ccb1ff97164ad95ac1606e8ccd35b3fa0a7d99a304c7f4a428cc24" dependencies = [ "percent-encoding", "time", @@ -1199,9 +1226,9 @@ dependencies = [ [[package]] name = "core-foundation" -version = "0.9.3" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" dependencies = [ "core-foundation-sys", "libc", @@ -1209,9 +1236,9 @@ dependencies = [ [[package]] name = "core-foundation-sys" -version = "0.8.4" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" +checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" [[package]] name = "core-graphics" @@ -1228,9 +1255,9 @@ dependencies = [ [[package]] name = "core-graphics-types" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bb142d41022986c1d8ff29103a1411c8a3dfad3552f87a4f8dc50d61d4f4e33" +checksum = "45390e6114f68f718cc7a830514a96f903cccd70d02a8f6d9f643ac4ba45afaf" dependencies = [ "bitflags 1.3.2", "core-foundation", @@ -1248,9 +1275,9 @@ dependencies = [ [[package]] name = "cpufeatures" -version = "0.2.9" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1" +checksum = "ce420fe07aecd3e67c5f910618fe65e94158f6dcc0adf44e00d69ce2bdfe0fd0" dependencies = [ "libc", ] @@ -1315,9 +1342,9 @@ checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" [[package]] name = "crypto-bigint" -version = "0.5.3" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "740fe28e594155f10cfc383984cbefd529d7396050557148f79cb0f621204124" +checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" dependencies = [ "generic-array", "subtle", @@ -1368,17 +1395,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331" dependencies = [ "quote", - "syn 2.0.32", -] - -[[package]] -name = "ctor" -version = "0.1.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d2301688392eb071b0bf1a37be05c469d3cc4dbbd95df672fe28ab021e6a096" -dependencies = [ - "quote", - "syn 1.0.109", + "syn 2.0.39", ] [[package]] @@ -1388,7 +1405,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37e366bff8cd32dd8754b0991fb66b279dc48f598c3a18914852a6673deef583" dependencies = [ "quote", - "syn 2.0.32", + "syn 2.0.39", ] [[package]] @@ -1400,12 +1417,6 @@ dependencies = [ "cipher 0.4.4", ] -[[package]] -name = "cty" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b365fabc795046672053e29c954733ec3b05e4be654ab130fe8f1f94d7051f35" - [[package]] name = "cuid" version = "1.3.2" @@ -1441,9 +1452,9 @@ dependencies = [ [[package]] name = "curve25519-dalek" -version = "4.1.0" +version = "4.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "622178105f911d937a42cdb140730ba4a3ed2becd8ae6ce39c7d28b5d75d4588" +checksum = "e89b8c6a2e4b1f45971ad09761aafb85514a84744b67a95e32c3cc1352d1f65c" dependencies = [ "cfg-if", "cpufeatures", @@ -1458,13 +1469,13 @@ dependencies = [ [[package]] name = "curve25519-dalek-derive" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83fdaf97f4804dcebfa5862639bc9ce4121e82140bec2a987ac5140294865b5b" +checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.39", ] [[package]] @@ -1488,7 +1499,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.32", + "syn 2.0.39", ] [[package]] @@ -1499,7 +1510,7 @@ checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5" dependencies = [ "darling_core", "quote", - "syn 2.0.32", + "syn 2.0.39", ] [[package]] @@ -1509,23 +1520,23 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" dependencies = [ "cfg-if", - "hashbrown 0.14.0", + "hashbrown 0.14.3", "lock_api", "once_cell", - "parking_lot_core 0.9.8", + "parking_lot_core 0.9.9", ] [[package]] name = "data-encoding" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2e66c9d817f1720209181c316d28635c050fa304f9c79e47a520882661b7308" +checksum = "7e962a19be5cfc3f3bf6dd8f61eb50107f356ad6270fbb3ed41476571db78be5" [[package]] name = "data-encoding-macro" -version = "0.1.13" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c904b33cc60130e1aeea4956ab803d08a3f4a0ca82d64ed757afac3891f2bb99" +checksum = "20c01c06f5f429efdf2bae21eb67c28b3df3cf85b7dd2d8ef09c0838dac5d33e" dependencies = [ "data-encoding", "data-encoding-macro-internal", @@ -1533,9 +1544,9 @@ dependencies = [ [[package]] name = "data-encoding-macro-internal" -version = "0.1.11" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fdf3fce3ce863539ec1d7fd1b6dcc3c645663376b43ed376bbf887733e4f772" +checksum = "0047d07f2c89b17dd631c80450d69841a6b5d7fb17278cbc43d7e4cfcf2576f3" dependencies = [ "data-encoding", "syn 1.0.109", @@ -1543,9 +1554,9 @@ dependencies = [ [[package]] name = "data-url" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41b319d1b62ffbd002e057f36bebd1f42b9f97927c9577461d855f3513c4289f" +checksum = "5c297a1c74b71ae29df00c3e22dd9534821d60eb9af5a0192823fa2acea70c2a" [[package]] name = "datamodel-renderer" @@ -1605,6 +1616,16 @@ dependencies = [ "rusticata-macros", ] +[[package]] +name = "deranged" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eb30d70a07a3b04884d2677f06bec33509dc67ca60d92949e5535352d3191dc" +dependencies = [ + "powerfmt", + "serde", +] + [[package]] name = "derivative" version = "2.2.0" @@ -1635,7 +1656,7 @@ version = "0.1.0" source = "git+https://github.com/Brendonovich/prisma-engines?branch=new-4.14.0-pcr#45b026c8b64ed0b60cb03deed5f478c457de645b" dependencies = [ "colored", - "indoc 2.0.4", + "indoc", "pest", ] @@ -1735,7 +1756,7 @@ checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.39", ] [[package]] @@ -1743,7 +1764,7 @@ name = "dmmf" version = "0.1.0" source = "git+https://github.com/Brendonovich/prisma-engines?branch=new-4.14.0-pcr#45b026c8b64ed0b60cb03deed5f478c457de645b" dependencies = [ - "bigdecimal", + "bigdecimal 0.3.1", "indexmap 1.9.3", "prisma-models", "psl", @@ -1752,15 +1773,6 @@ dependencies = [ "serde_json", ] -[[package]] -name = "document-features" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e493c573fce17f00dcab13b6ac057994f3ce17d1af4dc39bfd482b83c6eb6157" -dependencies = [ - "litrs", -] - [[package]] name = "dotenv" version = "0.15.0" @@ -1790,9 +1802,9 @@ checksum = "56ce8c6da7551ec6c462cbaf3bfbc75131ebbfa1c944aeaa9dab51ca1c5f0c3b" [[package]] name = "ed25519" -version = "2.2.2" +version = "2.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60f6d271ca33075c88028be6f04d502853d63a5ece419d269c15315d4fc1cf1d" +checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" dependencies = [ "pkcs8", "signature", @@ -1800,15 +1812,16 @@ dependencies = [ [[package]] name = "ed25519-dalek" -version = "2.0.0" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7277392b266383ef8396db7fdeb1e77b6c52fed775f5df15bb24f35b72156980" +checksum = "1f628eaec48bfd21b865dc2950cfa014450c01d2fa2b69a86c2fd5844ec523c0" dependencies = [ "curve25519-dalek", "ed25519", "rand_core 0.6.4", "serde", "sha2 0.10.8", + "subtle", "zeroize", ] @@ -1820,13 +1833,13 @@ checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" [[package]] name = "embed-resource" -version = "2.3.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd0a2c9b742a980060d22545a7a83b573acd6b73045b9de6370c9530ce652f27" +checksum = "f54cc3e827ee1c3812239a9a41dede7b4d7d5d5464faa32d71bd7cba28ce2cb2" dependencies = [ "cc", "rustc_version", - "toml 0.7.8", + "toml 0.8.8", "vswhom", "winreg 0.51.0", ] @@ -1873,7 +1886,7 @@ dependencies = [ "heck 0.4.1", "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.39", ] [[package]] @@ -1888,11 +1901,11 @@ dependencies = [ [[package]] name = "enumflags2" -version = "0.7.7" +version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c041f5090df68b32bcd905365fd51769c8b9d553fe87fde0b683534f10c01bd2" +checksum = "5998b4f30320c9d93aed72f63af821bfdac50465b75428fce77b48ec482c3939" dependencies = [ - "enumflags2_derive 0.7.7", + "enumflags2_derive 0.7.8", "serde", ] @@ -1909,13 +1922,13 @@ dependencies = [ [[package]] name = "enumflags2_derive" -version = "0.7.7" +version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e9a1f9f7d83e59740248a6e14ecf93929ade55027844dfcea78beafccc15745" +checksum = "f95e2801cd355d4a1a3e3953ce6ee5ae9603a5c833455343a8bfe3f44d418246" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.39", ] [[package]] @@ -1926,7 +1939,7 @@ checksum = "c2ad8cef1d801a4686bfd8919f0b30eac4c8e48968c437a6405ded4fb5272d2b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.39", ] [[package]] @@ -1937,23 +1950,12 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" -version = "0.3.3" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "136526188508e25c6fef639d7927dfb3e0e3084488bf202267829cf7fc23dbdd" +checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" dependencies = [ - "errno-dragonfly", - "libc", - "windows-sys 0.48.0", -] - -[[package]] -name = "errno-dragonfly" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" -dependencies = [ - "cc", "libc", + "windows-sys 0.52.0", ] [[package]] @@ -1973,9 +1975,9 @@ checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" [[package]] name = "event-listener" -version = "3.1.0" +version = "4.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d93877bcde0eb80ca09131a08d23f0a5c18a620b01db137dba666d18cd9b30c2" +checksum = "770d968249b5d99410d61f5bf89057f3199a077a04d087092f58e7d10692baae" dependencies = [ "concurrent-queue", "parking", @@ -1984,22 +1986,22 @@ dependencies = [ [[package]] name = "event-listener-strategy" -version = "0.3.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d96b852f1345da36d551b9473fa1e2b1eb5c5195585c6c018118bc92a8d91160" +checksum = "958e4d70b6d5e81971bebec42271ec641e7ff4e170a6fa605f2b8a8b65cb97d3" dependencies = [ - "event-listener 3.1.0", + "event-listener 4.0.0", "pin-project-lite", ] [[package]] name = "exr" -version = "1.7.0" +version = "1.71.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1e481eb11a482815d3e9d618db8c42a93207134662873809335a92327440c18" +checksum = "832a761f35ab3e6664babfbdc6cef35a4860e816ec3916dcfd0882954e98a8a8" dependencies = [ "bit_field", - "flume", + "flume 0.11.0", "half", "lebe", "miniz_oxide", @@ -2053,26 +2055,26 @@ dependencies = [ [[package]] name = "fastrand" -version = "2.0.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6999dc1837253364c2ebb0704ba97994bd874e8f195d665c50b7548f6ea92764" +checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" [[package]] name = "fdeflate" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d329bdeac514ee06249dabc27877490f17f5d371ec693360768b838e19f3ae10" +checksum = "64d6dafc854908ff5da46ff3f8f473c6984119a2876a383a860246dd7841a868" dependencies = [ "simd-adler32", ] [[package]] name = "ffmpeg-sys-next" -version = "6.0.1" +version = "6.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf650f461ccf130f4eef4927affed703cc387b183bfc4a7dfee86a076c131127" +checksum = "c2529ad916d08c3562c754c21bc9b17a26c7882c0f5706cc2cd69472175f1620" dependencies = [ - "bindgen", + "bindgen 0.64.0", "cc", "libc", "num_cpus", @@ -2082,9 +2084,9 @@ dependencies = [ [[package]] name = "fiat-crypto" -version = "0.2.1" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0870c84016d4b481be5c9f323c24f65e31e901ae618f0e80f4308fb00de1d2d" +checksum = "27573eac26f4dd11e2b1916c3fe1baa56407c83c71a773a8ba17ec0bca03b6b7" [[package]] name = "field-offset" @@ -2143,6 +2145,15 @@ dependencies = [ "spin 0.9.8", ] +[[package]] +name = "flume" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55ac459de2512911e4b674ce33cf20befaba382d05b62b008afc1c8b57cbf181" +dependencies = [ + "spin 0.9.8", +] + [[package]] name = "fnv" version = "1.0.7" @@ -2189,9 +2200,9 @@ checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" [[package]] name = "form_urlencoded" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" dependencies = [ "percent-encoding", ] @@ -2329,7 +2340,7 @@ checksum = "53b153fd91e4b0147f4aced87be237c98248656bb01050b96bf3ee89220a8ddb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.39", ] [[package]] @@ -2437,7 +2448,7 @@ dependencies = [ "glib-sys", "gobject-sys", "libc", - "system-deps 6.1.1", + "system-deps 6.2.0", ] [[package]] @@ -2454,7 +2465,7 @@ dependencies = [ "libc", "pango-sys", "pkg-config", - "system-deps 6.1.1", + "system-deps 6.2.0", ] [[package]] @@ -2468,7 +2479,7 @@ dependencies = [ "gobject-sys", "libc", "pkg-config", - "system-deps 6.1.1", + "system-deps 6.2.0", ] [[package]] @@ -2480,7 +2491,7 @@ dependencies = [ "gdk-sys", "glib-sys", "libc", - "system-deps 6.1.1", + "system-deps 6.2.0", "x11", ] @@ -2520,9 +2531,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.10" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f" dependencies = [ "cfg-if", "js-sys", @@ -2553,9 +2564,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.28.0" +version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0" +checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" [[package]] name = "gio" @@ -2583,7 +2594,7 @@ dependencies = [ "glib-sys", "gobject-sys", "libc", - "system-deps 6.1.1", + "system-deps 6.2.0", "winapi", ] @@ -2629,7 +2640,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef4b192f8e65e9cf76cbf4ea71fa8e3be4a0e18ffe3d68b8da6836974cc5bad4" dependencies = [ "libc", - "system-deps 6.1.1", + "system-deps 6.2.0", ] [[package]] @@ -2640,15 +2651,15 @@ checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" [[package]] name = "globset" -version = "0.4.13" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "759c97c1e17c55525b57192c06a267cda0ac5210b222d6b82189a2338fa1c13d" +checksum = "57da3b9b5b85bd66f31093f8c408b90a74431672542466497dcbdfdc02034be1" dependencies = [ - "aho-corasick 1.0.5", + "aho-corasick 1.1.2", "bstr", - "fnv", "log", - "regex", + "regex-automata 0.4.3", + "regex-syntax 0.8.2", "serde", ] @@ -2660,7 +2671,7 @@ checksum = "0d57ce44246becd17153bd035ab4d32cfee096a657fc01f2231c9278378d1e0a" dependencies = [ "glib-sys", "libc", - "system-deps 6.1.1", + "system-deps 6.2.0", ] [[package]] @@ -2711,7 +2722,7 @@ dependencies = [ "gobject-sys", "libc", "pango-sys", - "system-deps 6.1.1", + "system-deps 6.2.0", ] [[package]] @@ -2730,9 +2741,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.3.21" +version = "0.3.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91fc23aa11be92976ef4729127f1a74adf36d8436f7816b185d18df956790833" +checksum = "4d6250322ef6e60f93f9a2162799302cd6f68f79f6e5d85c8c16f14d1d958178" dependencies = [ "bytes", "fnv", @@ -2740,11 +2751,11 @@ dependencies = [ "futures-sink", "futures-util", "http", - "indexmap 1.9.3", + "indexmap 2.1.0", "slab", "tokio", "tokio-util", - "tracing 0.1.37", + "tracing 0.1.40", ] [[package]] @@ -2776,9 +2787,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.14.0" +version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" +checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" [[package]] name = "hashlink" @@ -2830,9 +2841,9 @@ checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" [[package]] name = "hermit-abi" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b" +checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" [[package]] name = "hex" @@ -2884,6 +2895,15 @@ dependencies = [ "digest 0.10.7", ] +[[package]] +name = "home" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5444c27eef6923071f7ebcc33e3444508466a76f7a2b93da00ed6e19f30c1ddb" +dependencies = [ + "windows-sys 0.48.0", +] + [[package]] name = "hostname" version = "0.3.1" @@ -2925,9 +2945,9 @@ dependencies = [ [[package]] name = "http" -version = "0.2.9" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482" +checksum = "8947b1a6fad4393052c7ba1f4cd97bed3e953a95c79c92ad9b051a04611d9fbb" dependencies = [ "bytes", "fnv", @@ -2965,13 +2985,12 @@ checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] name = "httpz" -version = "0.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6769d2cb10425c442c41a787d1a3719744770a188cfa7885cd4d8126fa13f37a" +version = "0.0.6" +source = "git+https://github.com/spacedriveapp/rspc.git?rev=f3347e2e8bfe3f37bfacc437ca329fe71cdcb048#f3347e2e8bfe3f37bfacc437ca329fe71cdcb048" dependencies = [ "async-tungstenite", "axum", - "base64 0.20.0", + "base64 0.21.5", "cookie", "form_urlencoded", "futures", @@ -3005,10 +3024,10 @@ dependencies = [ "httpdate", "itoa 1.0.9", "pin-project-lite", - "socket2 0.4.9", + "socket2 0.4.10", "tokio", "tower-service", - "tracing 0.1.37", + "tracing 0.1.40", "want", ] @@ -3027,16 +3046,16 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.57" +version = "0.1.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fad5b825842d2b38bd206f3e81d6957625fd7f0a361e345c30e01a0ae2dd613" +checksum = "8326b86b6cff230b97d0d312a6c40a60726df3332e721f72a1b035f451663b20" dependencies = [ "android_system_properties", "core-foundation-sys", "iana-time-zone-haiku", "js-sys", "wasm-bindgen", - "windows 0.48.0", + "windows-core", ] [[package]] @@ -3085,6 +3104,16 @@ dependencies = [ "unicode-normalization", ] +[[package]] +name = "idna" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + [[package]] name = "if-addrs" version = "0.7.0" @@ -3097,12 +3126,12 @@ dependencies = [ [[package]] name = "if-addrs" -version = "0.10.1" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cfc4a06638d2fd0dda83b01126fefd38ef9f04f54d2fc717a938df68b83a68d" +checksum = "cabb0019d51a643781ff15c9c8a3e5dedc365c47211270f4e8f82812fedd8f0a" dependencies = [ "libc", - "windows-sys 0.45.0", + "windows-sys 0.48.0", ] [[package]] @@ -3144,18 +3173,16 @@ dependencies = [ [[package]] name = "ignore" -version = "0.4.18" +version = "0.4.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "713f1b139373f96a2e0ce3ac931cd01ee973c3c5dd7c40c0c2efe96ad2b6751d" +checksum = "747ad1b4ae841a78e8aba0d63adbfbeaea26b517b63705d47856b73015d27060" dependencies = [ - "crossbeam-utils", + "crossbeam-deque", "globset", - "lazy_static", "log", "memchr", - "regex", + "regex-automata 0.4.3", "same-file", - "thread_local", "walkdir", "winapi-util", ] @@ -3217,21 +3244,15 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.0.0" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d" +checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" dependencies = [ "equivalent", - "hashbrown 0.14.0", + "hashbrown 0.14.3", "serde", ] -[[package]] -name = "indoc" -version = "1.0.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa799dd5ed20a7e349f3b4639aa80d74549c81716d9ec4f994c9b5815598306" - [[package]] name = "indoc" version = "2.0.4" @@ -3240,9 +3261,9 @@ checksum = "1e186cfbae8084e513daff4240b4797e342f988cecda4fb6c939150f96315fd8" [[package]] name = "infer" -version = "0.12.0" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a898e4b7951673fce96614ce5751d13c40fc5674bc2d759288e46c3ab62598b3" +checksum = "f551f8c3a39f68f986517db0d1759de85881894fdc7db798bd2a9df9cb04b7fc" dependencies = [ "cfb", ] @@ -3331,9 +3352,9 @@ dependencies = [ [[package]] name = "ipnet" -version = "2.8.0" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28b29a3cd74f0f4598934efe3aeba42bae0eb4680554128851ebbecb02af14e6" +checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" [[package]] name = "is-terminal" @@ -3342,7 +3363,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" dependencies = [ "hermit-abi", - "rustix 0.38.21", + "rustix 0.38.26", "windows-sys 0.48.0", ] @@ -3446,9 +3467,9 @@ checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" [[package]] name = "jobserver" -version = "0.1.26" +version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "936cfd212a0155903bcbc060e316fb6cc7cbf2e1907329391ebadc1fe0ce77c2" +checksum = "8c37f63953c4c63420ed5fd3d6d398c719489b9f872b9fa683262f8edd363c7d" dependencies = [ "libc", ] @@ -3464,18 +3485,18 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.64" +version = "0.3.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" +checksum = "cee9c64da59eae3b50095c18d3e74f8b73c0b86d2792824ff01bbce68ba229ca" dependencies = [ "wasm-bindgen", ] [[package]] name = "json-patch" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f7765dccf8c39c3a470fc694efe322969d791e713ca46bc7b5c506886157572" +checksum = "55ff1e1486799e3f64129f8ccad108b38290df9cd7015cd31bed17239f0789d6" dependencies = [ "serde", "serde_json", @@ -3629,9 +3650,9 @@ dependencies = [ [[package]] name = "libheif-sys" -version = "2.0.0+1.16.2" +version = "2.1.0+1.17.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d48ca341b8042e9522ff1ab892a0f049ec28d3a9a6924b48aa9f3e32ae73aab" +checksum = "01b9d5bf9cf5c3d24fd875f09817810cd33b7dd1e13d6c52a0148f221224cd22" dependencies = [ "libc", "pkg-config", @@ -3651,14 +3672,20 @@ dependencies = [ [[package]] name = "libloading" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d580318f95776505201b28cf98eb1fa5e4be3b689633ba6a3e6cd880ff22d8cb" +checksum = "c571b676ddfc9a8c12f1f3d3085a7b163966a8fd8098a90640953ce5f6170161" dependencies = [ "cfg-if", "windows-sys 0.48.0", ] +[[package]] +name = "libm" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" + [[package]] name = "libp2p" version = "0.52.4" @@ -3669,7 +3696,7 @@ dependencies = [ "either", "futures", "futures-timer", - "getrandom 0.2.10", + "getrandom 0.2.11", "instant", "libp2p-allow-block-list", "libp2p-connection-limits", @@ -3772,7 +3799,7 @@ dependencies = [ "fnv", "futures", "futures-ticker", - "getrandom 0.2.10", + "getrandom 0.2.11", "hex_fmt", "instant", "libp2p-core", @@ -3806,7 +3833,7 @@ dependencies = [ "serde", "sha2 0.10.8", "thiserror", - "tracing 0.1.37", + "tracing 0.1.40", "zeroize", ] @@ -3878,7 +3905,7 @@ dependencies = [ "parking_lot 0.12.1", "quinn", "rand 0.8.5", - "ring", + "ring 0.16.20", "rustls", "socket2 0.5.5", "thiserror", @@ -3935,7 +3962,7 @@ dependencies = [ "libp2p-core", "libp2p-identity", "rcgen", - "ring", + "ring 0.16.20", "rustls", "rustls-webpki", "thiserror", @@ -3959,6 +3986,17 @@ dependencies = [ "void", ] +[[package]] +name = "libredox" +version = "0.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8" +dependencies = [ + "bitflags 2.4.1", + "libc", + "redox_syscall 0.4.1", +] + [[package]] name = "libsqlite3-sys" version = "0.22.2" @@ -4003,21 +4041,15 @@ checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" [[package]] name = "linux-raw-sys" -version = "0.4.11" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "969488b55f8ac402214f3f5fd243ebb7206cf82de60d3172994707a4bcc2b829" - -[[package]] -name = "litrs" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9275e0933cf8bb20f008924c0cb07a0692fe54d8064996520bf998de9eb79aa" +checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456" [[package]] name = "lock_api" -version = "0.4.10" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16" +checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" dependencies = [ "autocfg", "scopeguard", @@ -4040,8 +4072,8 @@ dependencies = [ "scoped-tls", "serde", "serde_json", - "tracing 0.1.37", - "tracing-subscriber 0.3.17", + "tracing 0.1.40", + "tracing-subscriber 0.3.18", ] [[package]] @@ -4166,9 +4198,9 @@ checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" [[package]] name = "matchit" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed1202b2a6f884ae56f04cff409ab315c5ce26b5e58d7412e484f01fd52f52ef" +checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" [[package]] name = "maybe-owned" @@ -4188,18 +4220,18 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c97183f9949c1f97921e4dda6bc059dfc30a6da5e4460a4f5218847dbe2ae1f" dependencies = [ - "flume", - "if-addrs 0.10.1", + "flume 0.10.14", + "if-addrs 0.10.2", "log", "polling", - "socket2 0.4.9", + "socket2 0.4.10", ] [[package]] name = "memchr" -version = "2.6.3" +version = "2.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f232d6ef707e1956a43342693d2a31e72989554d58299d7a88738cc95b0d35c" +checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" [[package]] name = "memmap2" @@ -4263,7 +4295,7 @@ dependencies = [ "quanta", "thiserror", "tokio", - "tracing 0.1.37", + "tracing 0.1.40", ] [[package]] @@ -4382,9 +4414,9 @@ dependencies = [ [[package]] name = "mobc" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bdeff49b387edef305eccfe166af3e1483bb57902dbf369dddc42dc824df23b" +checksum = "90eb49dc5d193287ff80e72a86f34cfb27aae562299d22fea215e06ea1059dd3" dependencies = [ "async-trait", "futures-channel", @@ -4395,15 +4427,15 @@ dependencies = [ "metrics 0.18.1", "thiserror", "tokio", - "tracing 0.1.37", - "tracing-subscriber 0.3.17", + "tracing 0.1.40", + "tracing-subscriber 0.3.18", ] [[package]] name = "multiaddr" -version = "0.18.0" +version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92a651988b3ed3ad1bc8c87d016bb92f6f395b84ed1db9b926b32b1fc5a2c8b5" +checksum = "8b852bc02a2da5feed68cd14fa50d0774b92790a5bdbfa932a813926c8472070" dependencies = [ "arrayref", "byteorder", @@ -4475,7 +4507,7 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a51313c5820b0b02bd422f4b44776fbf47961755c74ce64afc73bfad10226c3" dependencies = [ - "getrandom 0.2.10", + "getrandom 0.2.11", ] [[package]] @@ -4503,7 +4535,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b1bb540dc6ef51cfe1916ec038ce7a620daf3a111e2502d745197cd53d6bca15" dependencies = [ "libc", - "socket2 0.4.9", + "socket2 0.4.10", ] [[package]] @@ -4790,9 +4822,9 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2" +checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" dependencies = [ "autocfg", ] @@ -4828,15 +4860,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "num_threads" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2819ce041d2ee131036f4fc9d6ae7ae125a3a40e97ba64d04fe799ad9dabbb44" -dependencies = [ - "libc", -] - [[package]] name = "objc" version = "0.2.7" @@ -4935,7 +4958,7 @@ version = "0.10.57" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bac25ee399abb46215765b1cb35bc0212377e58a061560d8b29b024fd0430e7c" dependencies = [ - "bitflags 2.4.0", + "bitflags 2.4.1", "cfg-if", "foreign-types", "libc", @@ -4952,7 +4975,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.39", ] [[package]] @@ -4963,9 +4986,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-src" -version = "300.1.3+3.1.2" +version = "300.1.6+3.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd2c101a165fff9935e34def4669595ab1c7847943c42be86e21503e482be107" +checksum = "439fac53e092cd7442a3660c85dde4643ab3b5bd39040912388dcdabf6b88085" dependencies = [ "cc", ] @@ -5013,9 +5036,9 @@ checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" [[package]] name = "ordered-float" -version = "2.10.0" +version = "2.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7940cf2ca942593318d07fcf2596cdca60a85c9e7fab408a5e21a4f9dcd40d87" +checksum = "68f19d67e5a2795c94e73e0bb1cc1a7edeb2e28efd39e2e1c9b7a40c1108b11c" dependencies = [ "num-traits", ] @@ -5084,14 +5107,14 @@ dependencies = [ "glib-sys", "gobject-sys", "libc", - "system-deps 6.1.1", + "system-deps 6.2.0", ] [[package]] name = "parking" -version = "2.1.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14f2252c834a40ed9bb5422029649578e63aa341ac401f74e719dd1afda8394e" +checksum = "bb813b8af86854136c6922af0598d719255ecb2179515e6e7730d468f05c9cae" [[package]] name = "parking_lot" @@ -5121,7 +5144,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" dependencies = [ "lock_api", - "parking_lot_core 0.9.8", + "parking_lot_core 0.9.9", ] [[package]] @@ -5152,13 +5175,13 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.8" +version = "0.9.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447" +checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.3.5", + "redox_syscall 0.4.1", "smallvec 1.11.2", "windows-targets 0.48.5", ] @@ -5170,7 +5193,7 @@ source = "git+https://github.com/Brendonovich/prisma-engines?branch=new-4.14.0-p dependencies = [ "diagnostics", "either", - "enumflags2 0.7.7", + "enumflags2 0.7.8", "indexmap 1.9.3", "schema-ast", ] @@ -5200,12 +5223,12 @@ checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd" [[package]] name = "pdfium-render" -version = "0.8.15" +version = "0.8.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b09ef9c34c66ce232d7af3562dcffe8801b2d0665d2c2770d06cdc46e0d2aff" +checksum = "d2b19ea0c0c7816b6a29fae48f4c5dece59814394e272a7e80ea8f8e8eb37a6e" dependencies = [ - "bindgen", - "bitflags 2.4.0", + "bindgen 0.69.1", + "bitflags 2.4.1", "bytemuck", "bytes", "chrono", @@ -5214,7 +5237,7 @@ dependencies = [ "image", "iter_tools", "js-sys", - "libloading 0.8.0", + "libloading 0.8.1", "log", "maybe-owned", "once_cell", @@ -5242,15 +5265,15 @@ dependencies = [ [[package]] name = "percent-encoding" -version = "2.3.0" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pest" -version = "2.7.3" +version = "2.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7a4d085fd991ac8d5b05a147b437791b4260b76326baf0fc60cf7c9c27ecd33" +checksum = "ae9cee2a55a544be8b89dc6848072af97a20f2422603c10865be2a42b580fff5" dependencies = [ "memchr", "thiserror", @@ -5259,9 +5282,9 @@ dependencies = [ [[package]] name = "pest_derive" -version = "2.7.3" +version = "2.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2bee7be22ce7918f641a33f08e3f43388c7656772244e2bbb2477f44cc9021a" +checksum = "81d78524685f5ef2a3b3bd1cafbc9fcabb036253d9b1463e726a91cd16e2dfc2" dependencies = [ "pest", "pest_generator", @@ -5269,22 +5292,22 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.7.3" +version = "2.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1511785c5e98d79a05e8a6bc34b4ac2168a0e3e92161862030ad84daa223141" +checksum = "68bd1206e71118b5356dae5ddc61c8b11e28b09ef6a31acbd15ea48a28e0c227" dependencies = [ "pest", "pest_meta", "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.39", ] [[package]] name = "pest_meta" -version = "2.7.3" +version = "2.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b42f0394d3123e33353ca5e1e89092e533d2cc490389f2bd6131c43c634ebc5f" +checksum = "7c747191d4ad9e4a4ab9c8798f1e82a39affe7ef9648390b7e5548d18e099de6" dependencies = [ "once_cell", "pest", @@ -5318,9 +5341,17 @@ version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fabbf1ead8a5bcbc20f5f8b939ee3f5b0f6f281b6ad3468b84656b658b455259" dependencies = [ - "phf_macros 0.10.0", "phf_shared 0.10.0", - "proc-macro-hack", +] + +[[package]] +name = "phf" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc" +dependencies = [ + "phf_macros 0.11.2", + "phf_shared 0.11.2", ] [[package]] @@ -5363,6 +5394,16 @@ dependencies = [ "rand 0.8.5", ] +[[package]] +name = "phf_generator" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0" +dependencies = [ + "phf_shared 0.11.2", + "rand 0.8.5", +] + [[package]] name = "phf_macros" version = "0.8.0" @@ -5379,16 +5420,15 @@ dependencies = [ [[package]] name = "phf_macros" -version = "0.10.0" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58fdf3184dd560f160dd73922bea2d5cd6e8f064bf4b13110abd81b03697b4e0" +checksum = "3444646e286606587e49f3bcf1679b8cef1dc2c5ecc29ddacaffc305180d464b" dependencies = [ - "phf_generator 0.10.0", - "phf_shared 0.10.0", - "proc-macro-hack", + "phf_generator 0.11.2", + "phf_shared 0.11.2", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.39", ] [[package]] @@ -5409,6 +5449,15 @@ dependencies = [ "siphasher", ] +[[package]] +name = "phf_shared" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b" +dependencies = [ + "siphasher", +] + [[package]] name = "pico-args" version = "0.5.0" @@ -5432,7 +5481,7 @@ checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.39", ] [[package]] @@ -5471,18 +5520,18 @@ checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" [[package]] name = "platforms" -version = "3.1.2" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4503fa043bf02cee09a9582e9554b4c6403b2ef55e4612e96561d294419429f8" +checksum = "14e6ab3f592e6fb464fc9712d8d6e6912de6473954635fd76a589d832cffcbb0" [[package]] name = "plist" -version = "1.5.0" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdc0001cfea3db57a2e24bc0d818e9e20e554b5f97fabb9bc231dc240269ae06" +checksum = "e5699cc8a63d1aa2b1ee8e12b9ad70ac790d65788cd36101fa37f87ea46c4cef" dependencies = [ "base64 0.21.5", - "indexmap 1.9.3", + "indexmap 2.1.0", "line-wrap", "quick-xml", "serde", @@ -5541,6 +5590,12 @@ dependencies = [ "universal-hash", ] +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + [[package]] name = "ppv-lite86" version = "0.2.17" @@ -5553,6 +5608,16 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" +[[package]] +name = "prettyplease" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae005bd773ab59b4725093fd7df83fd7892f7d8eafb48dbd7de6e024e4215f9d" +dependencies = [ + "proc-macro2", + "syn 2.0.39", +] + [[package]] name = "prisma-cli" version = "0.1.0" @@ -5564,10 +5629,10 @@ dependencies = [ [[package]] name = "prisma-client-rust" version = "0.6.8" -source = "git+https://github.com/Brendonovich/prisma-client-rust?branch=spacedrive#b93c4597daa40ca87e7b63c9b6b5d1b517d9df0b" +source = "git+https://github.com/spacedriveapp/prisma-client-rust?rev=9f8ac122e8f2b2e4957b71f48a37e06565adba40#9f8ac122e8f2b2e4957b71f48a37e06565adba40" dependencies = [ "base64 0.13.1", - "bigdecimal", + "bigdecimal 0.3.1", "chrono", "diagnostics", "dotenv", @@ -5589,7 +5654,7 @@ dependencies = [ "tempdir", "thiserror", "tokio", - "tracing 0.1.37", + "tracing 0.1.40", "user-facing-errors", "uuid", ] @@ -5597,7 +5662,7 @@ dependencies = [ [[package]] name = "prisma-client-rust-cli" version = "0.6.8" -source = "git+https://github.com/Brendonovich/prisma-client-rust?branch=spacedrive#b93c4597daa40ca87e7b63c9b6b5d1b517d9df0b" +source = "git+https://github.com/spacedriveapp/prisma-client-rust?rev=9f8ac122e8f2b2e4957b71f48a37e06565adba40#9f8ac122e8f2b2e4957b71f48a37e06565adba40" dependencies = [ "directories 4.0.1", "flate2", @@ -5617,7 +5682,7 @@ dependencies = [ [[package]] name = "prisma-client-rust-generator" version = "0.6.8" -source = "git+https://github.com/Brendonovich/prisma-client-rust?branch=spacedrive#b93c4597daa40ca87e7b63c9b6b5d1b517d9df0b" +source = "git+https://github.com/spacedriveapp/prisma-client-rust?rev=9f8ac122e8f2b2e4957b71f48a37e06565adba40#9f8ac122e8f2b2e4957b71f48a37e06565adba40" dependencies = [ "directories 4.0.1", "flate2", @@ -5637,7 +5702,7 @@ dependencies = [ [[package]] name = "prisma-client-rust-macros" version = "0.6.8" -source = "git+https://github.com/Brendonovich/prisma-client-rust?branch=spacedrive#b93c4597daa40ca87e7b63c9b6b5d1b517d9df0b" +source = "git+https://github.com/spacedriveapp/prisma-client-rust?rev=9f8ac122e8f2b2e4957b71f48a37e06565adba40#9f8ac122e8f2b2e4957b71f48a37e06565adba40" dependencies = [ "convert_case 0.6.0", "proc-macro2", @@ -5649,7 +5714,7 @@ dependencies = [ [[package]] name = "prisma-client-rust-sdk" version = "0.6.8" -source = "git+https://github.com/Brendonovich/prisma-client-rust?branch=spacedrive#b93c4597daa40ca87e7b63c9b6b5d1b517d9df0b" +source = "git+https://github.com/spacedriveapp/prisma-client-rust?rev=9f8ac122e8f2b2e4957b71f48a37e06565adba40#9f8ac122e8f2b2e4957b71f48a37e06565adba40" dependencies = [ "convert_case 0.5.0", "dmmf", @@ -5671,7 +5736,7 @@ name = "prisma-models" version = "0.0.0" source = "git+https://github.com/Brendonovich/prisma-engines?branch=new-4.14.0-pcr#45b026c8b64ed0b60cb03deed5f478c457de645b" dependencies = [ - "bigdecimal", + "bigdecimal 0.3.1", "chrono", "cuid", "itertools 0.10.5", @@ -5688,7 +5753,7 @@ version = "0.1.0" source = "git+https://github.com/Brendonovich/prisma-engines?branch=new-4.14.0-pcr#45b026c8b64ed0b60cb03deed5f478c457de645b" dependencies = [ "base64 0.13.1", - "bigdecimal", + "bigdecimal 0.3.1", "chrono", "once_cell", "regex", @@ -5713,7 +5778,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" dependencies = [ "once_cell", - "toml_edit", + "toml_edit 0.19.15", ] [[package]] @@ -5748,9 +5813,9 @@ checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" [[package]] name = "proc-macro2" -version = "1.0.66" +version = "1.0.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" +checksum = "39278fbbf5fb4f646ce651690877f89d1c5811a3d4acb27700c1cb3cdb78fd3b" dependencies = [ "unicode-ident", ] @@ -5775,7 +5840,7 @@ checksum = "440f724eba9f6996b75d63681b0a92b06947f1457076d503a4d2e2c8f56442b8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.39", ] [[package]] @@ -5792,11 +5857,11 @@ name = "psl-core" version = "0.1.0" source = "git+https://github.com/Brendonovich/prisma-engines?branch=new-4.14.0-pcr#45b026c8b64ed0b60cb03deed5f478c457de645b" dependencies = [ - "bigdecimal", + "bigdecimal 0.3.1", "chrono", "diagnostics", - "enumflags2 0.7.7", - "indoc 2.0.4", + "enumflags2 0.7.8", + "indoc", "itertools 0.10.5", "lsp-types", "once_cell", @@ -5836,7 +5901,7 @@ source = "git+https://github.com/Brendonovich/prisma-engines?branch=new-4.14.0-p dependencies = [ "async-trait", "base64 0.12.3", - "bigdecimal", + "bigdecimal 0.3.1", "chrono", "connection-string", "futures", @@ -5851,8 +5916,8 @@ dependencies = [ "sqlformat", "thiserror", "tokio", - "tracing 0.1.37", - "tracing-core 0.1.31", + "tracing 0.1.40", + "tracing-core 0.1.32", "url", "uuid", ] @@ -5899,12 +5964,12 @@ version = "0.1.0" source = "git+https://github.com/Brendonovich/prisma-engines?branch=new-4.14.0-pcr#45b026c8b64ed0b60cb03deed5f478c457de645b" dependencies = [ "async-trait", - "bigdecimal", + "bigdecimal 0.3.1", "chrono", "connection-string", "crossbeam-channel", "cuid", - "enumflags2 0.7.7", + "enumflags2 0.7.8", "futures", "indexmap 1.9.3", "itertools 0.10.5", @@ -5921,10 +5986,10 @@ dependencies = [ "serde_json", "thiserror", "tokio", - "tracing 0.1.37", + "tracing 0.1.40", "tracing-futures", "tracing-opentelemetry", - "tracing-subscriber 0.3.17", + "tracing-subscriber 0.3.18", "user-facing-errors", "uuid", ] @@ -5941,9 +6006,9 @@ dependencies = [ "parking_lot 0.12.1", "serde", "serde_json", - "tracing 0.1.37", + "tracing 0.1.40", "tracing-futures", - "tracing-subscriber 0.3.17", + "tracing-subscriber 0.3.18", ] [[package]] @@ -5976,9 +6041,9 @@ dependencies = [ [[package]] name = "quick-xml" -version = "0.29.0" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81b9228215d82c7b61490fec1de287136b5de6f5700f6e58ea9ad61a7964ca51" +checksum = "1004a344b30a54e2ee58d66a71b32d2db2feb0a31f9a2d302bf0536f15de2a33" dependencies = [ "memchr", ] @@ -5998,24 +6063,24 @@ dependencies = [ "rustls", "thiserror", "tokio", - "tracing 0.1.37", + "tracing 0.1.40", ] [[package]] name = "quinn-proto" -version = "0.10.4" +version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13f81c9a9d574310b8351f8666f5a93ac3b0069c45c28ad52c10291389a7cf9" +checksum = "141bf7dfde2fbc246bfd3fe12f2455aa24b0fbd9af535d8c86c7bd1381ff2b1a" dependencies = [ "bytes", "rand 0.8.5", - "ring", + "ring 0.16.20", "rustc-hash", "rustls", "slab", "thiserror", "tinyvec", - "tracing 0.1.37", + "tracing 0.1.40", ] [[package]] @@ -6027,7 +6092,7 @@ dependencies = [ "bytes", "libc", "socket2 0.5.5", - "tracing 0.1.37", + "tracing 0.1.40", "windows-sys 0.48.0", ] @@ -6144,7 +6209,7 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.10", + "getrandom 0.2.11", ] [[package]] @@ -6176,18 +6241,15 @@ dependencies = [ [[package]] name = "raw-window-handle" -version = "0.5.0" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed7e3d950b66e19e0c372f3fa3fbbcf85b1746b571f74e0c2af6042a5c93420a" -dependencies = [ - "cty", -] +checksum = "f2ff9a1f06a88b01621b7ae906ef0211290d1c8a168a15542486a8f61c0833b9" [[package]] name = "rayon" -version = "1.7.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d2df5196e37bcc87abebc0053e20787d73847bb33134a69841207dd0a47f03b" +checksum = "9c27db03db7734835b3f53954b534c91069375ce6ccaa2e065441e07d9b6cdb1" dependencies = [ "either", "rayon-core", @@ -6195,14 +6257,12 @@ dependencies = [ [[package]] name = "rayon-core" -version = "1.11.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b8f95bd6966f5c87776639160a66bd8ab9895d9d4ab01ddba9fc60661aebe8d" +checksum = "5ce3fb6ad83f861aac485e76e1985cd109d9a3713802152be56c3b1f0e0658ed" dependencies = [ - "crossbeam-channel", "crossbeam-deque", "crossbeam-utils", - "num_cpus", ] [[package]] @@ -6212,7 +6272,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ffbe84efe2f38dea12e9bfc1f65377fdf03e53a18cb3b995faedf7934c7e785b" dependencies = [ "pem", - "ring", + "ring 0.16.20", "time", "yasna", ] @@ -6261,12 +6321,12 @@ dependencies = [ [[package]] name = "redox_users" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" +checksum = "a18479200779601e498ada4e8c1e1f50e3ee19deb0259c25825a98b5603b2cb4" dependencies = [ - "getrandom 0.2.10", - "redox_syscall 0.2.16", + "getrandom 0.2.11", + "libredox", "thiserror", ] @@ -6276,7 +6336,7 @@ version = "1.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" dependencies = [ - "aho-corasick 1.0.5", + "aho-corasick 1.1.2", "memchr", "regex-automata 0.4.3", "regex-syntax 0.8.2", @@ -6291,19 +6351,13 @@ dependencies = [ "regex-syntax 0.6.29", ] -[[package]] -name = "regex-automata" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2f401f4955220693b56f8ec66ee9c78abffd8d1c4f23dc41a23839eb88f0795" - [[package]] name = "regex-automata" version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" dependencies = [ - "aho-corasick 1.0.5", + "aho-corasick 1.1.2", "memchr", "regex-syntax 0.8.2", ] @@ -6334,7 +6388,7 @@ name = "request-handlers" version = "0.1.0" source = "git+https://github.com/Brendonovich/prisma-engines?branch=new-4.14.0-pcr#45b026c8b64ed0b60cb03deed5f478c457de645b" dependencies = [ - "bigdecimal", + "bigdecimal 0.3.1", "connection-string", "dmmf", "futures", @@ -6348,7 +6402,7 @@ dependencies = [ "serde_json", "sql-query-connector", "thiserror", - "tracing 0.1.37", + "tracing 0.1.40", "url", "user-facing-errors", ] @@ -6446,9 +6500,9 @@ dependencies = [ [[package]] name = "rgb" -version = "0.8.36" +version = "0.8.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20ec2d3e3fc7a92ced357df9cebd5a10b6fb2aa1ee797bf7e9ce2f17dffc8f59" +checksum = "05aaa8004b64fd573fc9d002f4e632d51ad4f026c2b5ba95fcb6c2f32c2c47d8" dependencies = [ "bytemuck", ] @@ -6463,11 +6517,25 @@ dependencies = [ "libc", "once_cell", "spin 0.5.2", - "untrusted", + "untrusted 0.7.1", "web-sys", "winapi", ] +[[package]] +name = "ring" +version = "0.17.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "684d5e6e18f669ccebf64a92236bb7db9a34f07be010e3627368182027180866" +dependencies = [ + "cc", + "getrandom 0.2.11", + "libc", + "spin 0.9.8", + "untrusted 0.9.0", + "windows-sys 0.48.0", +] + [[package]] name = "rmp" version = "0.8.12" @@ -6502,9 +6570,9 @@ dependencies = [ [[package]] name = "roxmltree" -version = "0.18.0" +version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8f595a457b6b8c6cda66a48503e92ee8d19342f905948f29c383200ec9eb1d8" +checksum = "862340e351ce1b271a378ec53f304a5558f7db87f3769dc655a8f6ecbb68b302" dependencies = [ "xmlparser", ] @@ -6512,7 +6580,7 @@ dependencies = [ [[package]] name = "rspc" version = "0.1.4" -source = "git+https://github.com/oscartbeaumont/rspc?rev=adebce542049b982dd251466d4144f4d57e92177#adebce542049b982dd251466d4144f4d57e92177" +source = "git+https://github.com/spacedriveapp/rspc.git?rev=f3347e2e8bfe3f37bfacc437ca329fe71cdcb048#f3347e2e8bfe3f37bfacc437ca329fe71cdcb048" dependencies = [ "futures", "futures-channel", @@ -6526,7 +6594,7 @@ dependencies = [ "tauri", "thiserror", "tokio", - "tracing 0.1.37", + "tracing 0.1.40", ] [[package]] @@ -6592,9 +6660,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.37.23" +version = "0.37.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d69718bf81c6127a49dc64e44a742e8bb9213c0ff8869a22c308f84c1d4ab06" +checksum = "fea8ca367a3a01fe35e6943c400addf443c0f57670e6ec51196f71a4b8762dd2" dependencies = [ "bitflags 1.3.2", "errno", @@ -6606,37 +6674,37 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.21" +version = "0.38.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b426b0506e5d50a7d8dafcf2e81471400deb602392c7dd110815afb4eaf02a3" +checksum = "9470c4bf8246c8daf25f9598dca807fb6510347b1e1cfa55749113850c79d88a" dependencies = [ - "bitflags 2.4.0", + "bitflags 2.4.1", "errno", "libc", - "linux-raw-sys 0.4.11", - "windows-sys 0.48.0", + "linux-raw-sys 0.4.12", + "windows-sys 0.52.0", ] [[package]] name = "rustls" -version = "0.21.7" +version = "0.21.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd8d6c9f025a446bc4d18ad9632e69aec8f287aa84499ee335599fabd20c3fd8" +checksum = "629648aced5775d558af50b2b4c7b02983a04b312126d45eeead26e7caa498b9" dependencies = [ "log", - "ring", + "ring 0.17.6", "rustls-webpki", "sct", ] [[package]] name = "rustls-webpki" -version = "0.101.5" +version = "0.101.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45a27e3b59326c16e23d30aeb7a36a24cc0d29e71d68ff611cdfb4a01d013bed" +checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" dependencies = [ - "ring", - "untrusted", + "ring 0.17.6", + "untrusted 0.9.0", ] [[package]] @@ -6729,13 +6797,13 @@ version = "0.1.0" source = "git+https://github.com/Brendonovich/prisma-engines?branch=new-4.14.0-pcr#45b026c8b64ed0b60cb03deed5f478c457de645b" dependencies = [ "chrono", - "enumflags2 0.7.7", + "enumflags2 0.7.8", "psl", "quaint", "serde", "serde_json", "sha2 0.9.9", - "tracing 0.1.37", + "tracing 0.1.40", "tracing-error", "user-facing-errors", ] @@ -6747,7 +6815,7 @@ source = "git+https://github.com/Brendonovich/prisma-engines?branch=new-4.14.0-p dependencies = [ "async-trait", "chrono", - "enumflags2 0.7.7", + "enumflags2 0.7.8", "json-rpc-api-build", "jsonrpc-core", "psl", @@ -6756,9 +6824,9 @@ dependencies = [ "serde_json", "sql-schema-connector", "tokio", - "tracing 0.1.37", + "tracing 0.1.40", "tracing-futures", - "tracing-subscriber 0.3.17", + "tracing-subscriber 0.3.18", "url", "user-facing-errors", ] @@ -6777,12 +6845,21 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "sct" -version = "0.7.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4" +checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" dependencies = [ - "ring", - "untrusted", + "ring 0.17.6", + "untrusted 0.9.0", +] + +[[package]] +name = "sd-cache" +version = "0.0.0" +dependencies = [ + "serde", + "serde_json", + "specta", ] [[package]] @@ -6792,7 +6869,7 @@ dependencies = [ "anyhow", "clap", "hex", - "indoc 2.0.4", + "indoc", "sd-crypto", "tokio", ] @@ -6811,7 +6888,7 @@ dependencies = [ "blake3", "bytes", "chrono", - "ctor 0.2.5", + "ctor", "directories 5.0.1", "flate2", "futures", @@ -6837,6 +6914,7 @@ dependencies = [ "rmp-serde", "rmpv", "rspc", + "sd-cache", "sd-core-sync", "sd-crypto", "sd-ffmpeg", @@ -6885,7 +6963,7 @@ dependencies = [ "serde_json", "tokio", "tracing 0.2.0", - "uhlc", + "uhlc 0.5.2", "uuid", ] @@ -7072,7 +7150,7 @@ version = "0.1.0" dependencies = [ "base64 0.21.5", "ed25519-dalek", - "flume", + "flume 0.10.14", "futures-core", "if-watch", "libp2p", @@ -7097,6 +7175,7 @@ name = "sd-prisma" version = "0.1.0" dependencies = [ "prisma-client-rust", + "sd-cache", "sd-sync", "serde", "serde_json", @@ -7124,7 +7203,7 @@ dependencies = [ "serde", "serde_json", "specta", - "uhlc", + "uhlc 0.5.2", "uuid", ] @@ -7210,18 +7289,18 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.18" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0293b4b29daaf487284529cc2f5675b8e57c61f70167ba415a463651fd6a918" +checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090" dependencies = [ "serde", ] [[package]] name = "serde" -version = "1.0.192" +version = "1.0.193" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bca2a08484b285dcb282d0f67b26cadc0df8b19f8c12502c13d966bf9482f001" +checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89" dependencies = [ "serde_derive", ] @@ -7256,22 +7335,22 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.192" +version = "1.0.193" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6c7207fbec9faa48073f3e3074cbe553af6ea512d7c21ba46e434e70ea9fbc1" +checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.39", ] [[package]] name = "serde_json" -version = "1.0.106" +version = "1.0.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cc66a619ed80bf7a0f6b17dd063a84b88f6dea1813737cf469aef1d081142c2" +checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" dependencies = [ - "indexmap 2.0.0", + "indexmap 2.1.0", "itoa 1.0.9", "ryu", "serde", @@ -7289,20 +7368,20 @@ dependencies = [ [[package]] name = "serde_repr" -version = "0.1.16" +version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8725e1dfadb3a50f7e5ce0b1a540466f6ed3fe7a0fca2ac2b8b831d31316bd00" +checksum = "3081f5ffbb02284dda55132aa26daecedd7372a42417bbbab6f14ab7d6bb9145" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.39", ] [[package]] name = "serde_spanned" -version = "0.6.3" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96426c9936fd7a0124915f9185ea1d20aa9445cc9821142f0a73bc9207a2e186" +checksum = "12022b835073e5b11e90a14f86838ceb1c8fb0325b72416845c487ac0fa95e80" dependencies = [ "serde", ] @@ -7329,7 +7408,7 @@ dependencies = [ "chrono", "hex", "indexmap 1.9.3", - "indexmap 2.0.0", + "indexmap 2.1.0", "serde", "serde_json", "serde_with_macros", @@ -7345,7 +7424,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.39", ] [[package]] @@ -7382,9 +7461,9 @@ dependencies = [ [[package]] name = "sha1" -version = "0.10.5" +version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" dependencies = [ "cfg-if", "cpufeatures", @@ -7427,9 +7506,9 @@ dependencies = [ [[package]] name = "sharded-slab" -version = "0.1.4" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" dependencies = [ "lazy_static", ] @@ -7461,9 +7540,12 @@ dependencies = [ [[package]] name = "signature" -version = "2.1.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e1788eed21689f9cf370582dfc467ef36ed9c707f073528ddafa8d83e3b8500" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "rand_core 0.6.4", +] [[package]] name = "simd-adler32" @@ -7518,9 +7600,9 @@ dependencies = [ [[package]] name = "slotmap" -version = "1.0.6" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1e08e261d0e8f5c43123b7adf3e4ca1690d655377ac93a03b2c9d3e98de1342" +checksum = "dbff4acf519f630b3a3ddcfaea6c06b42174d9a44bc70c620e9ed1649d58b82a" dependencies = [ "version_check", ] @@ -7548,9 +7630,9 @@ checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970" [[package]] name = "socket2" -version = "0.4.9" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662" +checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d" dependencies = [ "libc", "winapi", @@ -7596,14 +7678,13 @@ dependencies = [ [[package]] name = "specta" -version = "1.0.5" -source = "git+https://github.com/oscartbeaumont/specta?rev=4bc6e46fc8747cd8d8a07597c1fe13c52aa16a41#4bc6e46fc8747cd8d8a07597c1fe13c52aa16a41" +version = "2.0.0-rc.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18938fc0c7c0e8b7c8f4702e8cb53c218d4442f5b7420dd8b3d9640ca9a46712" dependencies = [ - "bigdecimal", + "bigdecimal 0.4.2", "chrono", - "document-features", - "indexmap 1.9.3", - "indoc 1.0.9", + "indexmap 2.1.0", "once_cell", "paste", "serde", @@ -7612,21 +7693,20 @@ dependencies = [ "tauri", "thiserror", "tokio", - "uhlc", + "uhlc 0.6.3", "uuid", ] [[package]] name = "specta-macros" -version = "1.0.5" -source = "git+https://github.com/oscartbeaumont/specta?rev=4bc6e46fc8747cd8d8a07597c1fe13c52aa16a41#4bc6e46fc8747cd8d8a07597c1fe13c52aa16a41" +version = "2.0.0-rc.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05080358d47cc706229b854d51c6477208de2b022ec0e16f1572c8cdc5263c8e" dependencies = [ "Inflector", - "itertools 0.10.5", "proc-macro2", "quote", "syn 1.0.109", - "termcolor", ] [[package]] @@ -7646,9 +7726,9 @@ dependencies = [ [[package]] name = "spki" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d1e996ef02c474957d681f1b05213dfb0abab947b446a62d37770b23500184a" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" dependencies = [ "base64ct", "der", @@ -7666,7 +7746,7 @@ source = "git+https://github.com/Brendonovich/prisma-engines?branch=new-4.14.0-p dependencies = [ "anyhow", "async-trait", - "bigdecimal", + "bigdecimal 0.3.1", "chrono", "cuid", "futures", @@ -7683,7 +7763,7 @@ dependencies = [ "serde_json", "thiserror", "tokio", - "tracing 0.1.37", + "tracing 0.1.40", "tracing-futures", "tracing-opentelemetry", "user-facing-errors", @@ -7699,8 +7779,8 @@ dependencies = [ "connection-string", "datamodel-renderer", "either", - "enumflags2 0.7.7", - "indoc 2.0.4", + "enumflags2 0.7.8", + "indoc", "once_cell", "prisma-value", "psl", @@ -7714,7 +7794,7 @@ dependencies = [ "sqlformat", "sqlparser", "tokio", - "tracing 0.1.37", + "tracing 0.1.40", "tracing-futures", "url", "user-facing-errors", @@ -7727,18 +7807,18 @@ version = "0.1.0" source = "git+https://github.com/Brendonovich/prisma-engines?branch=new-4.14.0-pcr#45b026c8b64ed0b60cb03deed5f478c457de645b" dependencies = [ "async-trait", - "bigdecimal", + "bigdecimal 0.3.1", "either", - "enumflags2 0.7.7", + "enumflags2 0.7.8", "indexmap 1.9.3", - "indoc 2.0.4", + "indoc", "once_cell", "prisma-value", "psl", "quaint", "regex", "serde", - "tracing 0.1.37", + "tracing 0.1.40", "tracing-error", "tracing-futures", ] @@ -7848,15 +7928,15 @@ dependencies = [ [[package]] name = "strum_macros" -version = "0.25.2" +version = "0.25.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad8d03b598d3d0fff69bf533ee3ef19b8eeb342729596df84bcc7e1f96ec4059" +checksum = "23dc1fa9ac9c169a78ba62f0b841814b7abae11bdd047b9c58f893439e309ea0" dependencies = [ "heck 0.4.1", "proc-macro2", "quote", "rustversion", - "syn 2.0.32", + "syn 2.0.39", ] [[package]] @@ -7899,9 +7979,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.32" +version = "2.0.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "239814284fd6f1a4ffe4ca893952cdd93c224b6a1571c9a9eadd670295c0c9e2" +checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a" dependencies = [ "proc-macro2", "quote", @@ -7941,9 +8021,9 @@ dependencies = [ [[package]] name = "sysinfo" -version = "0.29.10" +version = "0.29.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a18d114d420ada3a891e6bc8e96a2023402203296a47cdd65083377dad18ba5" +checksum = "cd727fc423c2060f6c92d9534cef765c65a6ed3f428a03d7def74a8c4348e666" dependencies = [ "cfg-if", "core-foundation-sys", @@ -7990,14 +8070,14 @@ dependencies = [ [[package]] name = "system-deps" -version = "6.1.1" +version = "6.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30c2de8a4d8f4b823d634affc9cd2a74ec98c53a756f317e529a48046cbf71f3" +checksum = "2a2d580ff6a20c55dfb86be5f9c238f67835d0e81cbdea8bf5680e0897320331" dependencies = [ "cfg-expr 0.15.5", "heck 0.4.1", "pkg-config", - "toml 0.7.8", + "toml 0.8.8", "version-compare 0.1.1", ] @@ -8009,9 +8089,9 @@ checksum = "7b2093cf4c8eb1e67749a6762251bc9cd836b6fc171623bd0a9d324d37af2417" [[package]] name = "tao" -version = "0.16.2" +version = "0.16.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a6d198e01085564cea63e976ad1566c1ba2c2e4cc79578e35d9f05521505e31" +checksum = "75f5aefd6be4cd3ad3f047442242fd9f57cbfb3e565379f66b5e14749364fa4f" dependencies = [ "bitflags 1.3.2", "cairo-rs", @@ -8084,15 +8164,15 @@ dependencies = [ [[package]] name = "target-lexicon" -version = "0.12.11" +version = "0.12.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d0e916b1148c8e263850e1ebcbd046f333e0683c724876bb0da63ea4373dc8a" +checksum = "14c39fd04924ca3a864207c66fc2cd7d22d7c016007f9ce846cbb9326331930a" [[package]] name = "tauri" -version = "1.5.2" +version = "1.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9bfe673cf125ef364d6f56b15e8ce7537d9ca7e4dae1cf6fbbdeed2e024db3d9" +checksum = "32d563b672acde8d0cc4c1b1f5b855976923f67e8d6fe1eba51df0211e197be2" dependencies = [ "anyhow", "base64 0.21.5", @@ -8193,9 +8273,9 @@ dependencies = [ [[package]] name = "tauri-macros" -version = "1.4.1" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613740228de92d9196b795ac455091d3a5fbdac2654abb8bb07d010b62ab43af" +checksum = "acea6445eececebd72ed7720cfcca46eee3b5bad8eb408be8f7ef2e3f7411500" dependencies = [ "heck 0.4.1", "proc-macro2", @@ -8240,9 +8320,9 @@ dependencies = [ [[package]] name = "tauri-runtime-wry" -version = "0.14.1" +version = "0.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8141d72b6b65f2008911e9ef5b98a68d1e3413b7a1464e8f85eb3673bb19a895" +checksum = "803a01101bc611ba03e13329951a1bde44287a54234189b9024b78619c1bc206" dependencies = [ "cocoa", "gtk", @@ -8260,26 +8340,40 @@ dependencies = [ [[package]] name = "tauri-specta" -version = "1.0.2" -source = "git+https://github.com/oscartbeaumont/tauri-specta?rev=c964bef228a90a66effc18cefcba6859c45a8e08#c964bef228a90a66effc18cefcba6859c45a8e08" +version = "2.0.0-rc.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c9c8e4e35bb01f7b53df4bd7f747626e45c67f41bf40b51a648c953ec779b5c" dependencies = [ "heck 0.4.1", - "indoc 2.0.4", + "indoc", "serde", "serde_json", "specta", "tauri", + "tauri-specta-macros", "thiserror", ] [[package]] -name = "tauri-utils" -version = "1.5.0" +name = "tauri-specta-macros" +version = "2.0.0-rc.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34d55e185904a84a419308d523c2c6891d5e2dbcee740c4997eb42e75a7b0f46" +checksum = "2098cb9333e5ae46629ef74ce89b2fce3978bdcaf9dea6dd0fcb1aca85934ddd" +dependencies = [ + "heck 0.4.1", + "proc-macro2", + "quote", + "syn 2.0.39", +] + +[[package]] +name = "tauri-utils" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a52165bb340e6f6a75f1f5eeeab1bb49f861c12abe3a176067d53642b5454986" dependencies = [ "brotli", - "ctor 0.1.26", + "ctor", "dunce", "glob", "heck 0.4.1", @@ -8289,7 +8383,7 @@ dependencies = [ "kuchikiki", "log", "memchr", - "phf 0.10.1", + "phf 0.11.2", "proc-macro2", "quote", "semver", @@ -8299,7 +8393,7 @@ dependencies = [ "thiserror", "url", "walkdir", - "windows 0.39.0", + "windows-version", ] [[package]] @@ -8329,9 +8423,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ef1adac450ad7f4b3c28589471ade84f25f731a7a0fe30d71dfa9f60fd808e5" dependencies = [ "cfg-if", - "fastrand 2.0.0", + "fastrand 2.0.1", "redox_syscall 0.4.1", - "rustix 0.38.21", + "rustix 0.38.26", "windows-sys 0.48.0", ] @@ -8346,15 +8440,6 @@ dependencies = [ "utf-8", ] -[[package]] -name = "termcolor" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" -dependencies = [ - "winapi-util", -] - [[package]] name = "thin-slice" version = "0.1.1" @@ -8378,7 +8463,7 @@ checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.39", ] [[package]] @@ -8404,28 +8489,38 @@ dependencies = [ [[package]] name = "time" -version = "0.3.15" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d634a985c4d4238ec39cacaed2e7ae552fbd3c476b552c1deac3021b7d7eaf0c" +checksum = "c4a34ab300f2dee6e562c10a046fc05e358b29f9bf92277f30c3c8d82275f6f5" dependencies = [ + "deranged", "itoa 1.0.9", - "libc", - "num_threads", + "powerfmt", "serde", + "time-core", "time-macros", ] [[package]] -name = "time-macros" -version = "0.2.4" +name = "time-core" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42657b1a6f4d817cda8e7a0ace261fe0cc946cf3a80314390b22cc61ae080792" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" + +[[package]] +name = "time-macros" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ad70d68dba9e1f8aceda7aa6711965dfec1cac869f311a51bd08b3a2ccbce20" +dependencies = [ + "time-core", +] [[package]] name = "tiny-skia" -version = "0.11.2" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b72a92a05db376db09fe6d50b7948d106011761c05a6a45e23e17ee9b556222" +checksum = "b6a067b809476893fce6a254cf285850ff69c847e6cfbade6a20b655b6c7e80d" dependencies = [ "arrayref", "arrayvec", @@ -8438,9 +8533,9 @@ dependencies = [ [[package]] name = "tiny-skia-path" -version = "0.11.2" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ac3865b9708fc7e1961a65c3a4fa55e984272f33092d3c859929f887fceb647" +checksum = "5de35e8a90052baaaf61f171680ac2f8e925a1e43ea9d2e3a00514772250e541" dependencies = [ "arrayref", "bytemuck", @@ -8489,7 +8584,7 @@ checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.39", ] [[package]] @@ -8526,7 +8621,7 @@ dependencies = [ "futures-sink", "pin-project-lite", "tokio", - "tracing 0.1.37", + "tracing 0.1.40", ] [[package]] @@ -8547,14 +8642,26 @@ dependencies = [ "serde", "serde_spanned", "toml_datetime", - "toml_edit", + "toml_edit 0.19.15", +] + +[[package]] +name = "toml" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1a195ec8c9da26928f773888e0742ca3ca1040c6cd859c919c9f59c1954ab35" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit 0.21.0", ] [[package]] name = "toml_datetime" -version = "0.6.3" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" +checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" dependencies = [ "serde", ] @@ -8565,7 +8672,20 @@ version = "0.19.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ - "indexmap 2.0.0", + "indexmap 2.1.0", + "serde", + "serde_spanned", + "toml_datetime", + "winnow", +] + +[[package]] +name = "toml_edit" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d34d383cd00a163b4a5b85053df514d45bc330f6de7737edfe0a93311d1eaa03" +dependencies = [ + "indexmap 2.1.0", "serde", "serde_spanned", "toml_datetime", @@ -8585,7 +8705,7 @@ dependencies = [ "tokio", "tower-layer", "tower-service", - "tracing 0.1.37", + "tracing 0.1.40", ] [[package]] @@ -8602,15 +8722,14 @@ checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" [[package]] name = "tracing" -version = "0.1.37" +version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ - "cfg-if", "log", "pin-project-lite", - "tracing-attributes 0.1.26", - "tracing-core 0.1.31", + "tracing-attributes 0.1.27", + "tracing-core 0.1.32", ] [[package]] @@ -8636,13 +8755,13 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.26" +version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.39", ] [[package]] @@ -8652,14 +8771,14 @@ source = "git+https://github.com/tokio-rs/tracing?rev=29146260fb4615d271d2e899ad dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.39", ] [[package]] name = "tracing-core" -version = "0.1.31" +version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" dependencies = [ "once_cell", "valuable", @@ -8679,8 +8798,8 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d686ec1c0f384b1277f097b2f279a2ecc11afe8c133c1aabf036a27cb4cd206e" dependencies = [ - "tracing 0.1.37", - "tracing-subscriber 0.3.17", + "tracing 0.1.40", + "tracing-subscriber 0.3.18", ] [[package]] @@ -8690,18 +8809,29 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2" dependencies = [ "pin-project", - "tracing 0.1.37", + "tracing 0.1.40", ] [[package]] name = "tracing-log" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ddad33d2d10b1ed7eb9d1f518a5674713876e97e5bb9b7345a7984fbb4f922" +checksum = "f751112709b4e791d8ce53e32c4ed2d353565a795ce84da2285393f41557bdf2" dependencies = [ - "lazy_static", "log", - "tracing-core 0.1.31", + "once_cell", + "tracing-core 0.1.32", +] + +[[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 0.1.32", ] [[package]] @@ -8722,10 +8852,10 @@ checksum = "fbbe89715c1dbbb790059e2565353978564924ee85017b5fff365c872ff6721f" dependencies = [ "once_cell", "opentelemetry", - "tracing 0.1.37", - "tracing-core 0.1.31", - "tracing-log 0.1.3", - "tracing-subscriber 0.3.17", + "tracing 0.1.40", + "tracing-core 0.1.32", + "tracing-log 0.1.4", + "tracing-subscriber 0.3.18", ] [[package]] @@ -8742,14 +8872,14 @@ dependencies = [ "thread_local", "tracing 0.2.0", "tracing-core 0.2.0", - "tracing-log 0.2.0", + "tracing-log 0.2.0 (git+https://github.com/tokio-rs/tracing?rev=29146260fb4615d271d2e899ad95a753bb42915e)", ] [[package]] name = "tracing-subscriber" -version = "0.3.17" +version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30a651bc37f915e81f087d86e62a18eec5f79550c7faff886f7090b4ea757c77" +checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" dependencies = [ "matchers", "nu-ansi-term", @@ -8758,9 +8888,9 @@ dependencies = [ "sharded-slab", "smallvec 1.11.2", "thread_local", - "tracing 0.1.37", - "tracing-core 0.1.31", - "tracing-log 0.1.3", + "tracing 0.1.40", + "tracing-core 0.1.32", + "tracing-log 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -8770,8 +8900,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3a2c0ff408fe918a94c428a3f2ad04e4afd5c95bbc08fcf868eff750c15728a4" dependencies = [ "lazy_static", - "tracing-core 0.1.31", - "tracing-subscriber 0.3.17", + "tracing-core 0.1.32", + "tracing-subscriber 0.3.18", "tracing-test-macro", ] @@ -8797,9 +8927,9 @@ dependencies = [ [[package]] name = "triomphe" -version = "0.1.9" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eee8098afad3fb0c54a9007aab6804558410503ad676d4633f9c2559a00ac0f" +checksum = "859eb650cfee7434994602c3a68b25d77ad9e68c8a6cd491616ef86661382eb3" [[package]] name = "trust-dns-proto" @@ -8819,11 +8949,11 @@ dependencies = [ "lazy_static", "rand 0.8.5", "smallvec 1.11.2", - "socket2 0.4.9", + "socket2 0.4.10", "thiserror", "tinyvec", "tokio", - "tracing 0.1.37", + "tracing 0.1.40", "url", ] @@ -8848,7 +8978,7 @@ dependencies = [ "thiserror", "tinyvec", "tokio", - "tracing 0.1.37", + "tracing 0.1.40", "url", ] @@ -8869,7 +8999,7 @@ dependencies = [ "smallvec 1.11.2", "thiserror", "tokio", - "tracing 0.1.37", + "tracing 0.1.40", "trust-dns-proto 0.23.2", ] @@ -8881,19 +9011,19 @@ checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" [[package]] name = "ttf-parser" -version = "0.19.1" +version = "0.19.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a464a4b34948a5f67fddd2b823c62d9d92e44be75058b99939eae6c5b6960b33" +checksum = "49d64318d8311fc2668e48b63969f4343e0a85c4a109aa8460d6672e364b8bd1" [[package]] name = "tungstenite" -version = "0.18.0" +version = "0.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30ee6ab729cd4cf0fd55218530c4522ed30b7b6081752839b68fcec8d0960788" +checksum = "9e3dac10fd62eaf6617d3a904ae222845979aec67c615d1c842b4002c7666fb9" dependencies = [ - "base64 0.13.1", "byteorder", "bytes", + "data-encoding", "http", "httparse", "log", @@ -8906,9 +9036,9 @@ dependencies = [ [[package]] name = "typenum" -version = "1.16.0" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] name = "ucd-trie" @@ -8931,6 +9061,17 @@ dependencies = [ "uuid", ] +[[package]] +name = "uhlc" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1eadef1fa26cbbae1276c46781e8f4d888bdda434779c18ae6c2a0e69991885" +dependencies = [ + "rand 0.8.5", + "serde", + "spin 0.9.8", +] + [[package]] name = "uint" version = "0.9.5" @@ -8972,9 +9113,9 @@ checksum = "cc2520efa644f8268dce4dcd3050eaa7fc044fca03961e9998ac7e2e92b77cf1" [[package]] name = "unicode-ident" -version = "1.0.11" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "unicode-normalization" @@ -9057,13 +9198,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" [[package]] -name = "url" -version = "2.4.1" +name = "untrusted" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "143b538f18257fac9cad154828a57c6bf5157e1aa604d4816b5995bf6de87ae5" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "url" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" dependencies = [ "form_urlencoded", - "idna 0.4.0", + "idna 0.5.0", "percent-encoding", "serde", ] @@ -9084,12 +9231,12 @@ version = "0.1.0" source = "git+https://github.com/Brendonovich/prisma-engines?branch=new-4.14.0-pcr#45b026c8b64ed0b60cb03deed5f478c457de645b" dependencies = [ "backtrace", - "indoc 2.0.4", + "indoc", "itertools 0.10.5", "quaint", "serde", "serde_json", - "tracing 0.1.37", + "tracing 0.1.40", "user-facing-error-macros", ] @@ -9177,11 +9324,11 @@ checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" [[package]] name = "uuid" -version = "1.5.0" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88ad59a7560b41a70d191093a945f0b87bc1deeda46fb237479708a1d6b6cdfc" +checksum = "5e395fcf16a7a3d8127ec99782007af141946b4795001f876d54fb0d55978560" dependencies = [ - "getrandom 0.2.10", + "getrandom 0.2.11", "serde", ] @@ -9258,9 +9405,9 @@ dependencies = [ [[package]] name = "waker-fn" -version = "1.1.0" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d5b2c62b4012a3e1eca5a7e077d13b3bf498c4073e33ccd58626607748ceeca" +checksum = "f3c4517f54858c779bbcbf228f4fca63d121bf85fbecb2dc578cdf4a39395690" [[package]] name = "walkdir" @@ -9301,9 +9448,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.87" +version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" +checksum = "0ed0d4f68a3015cc185aff4db9506a015f4b96f95303897bfa23f846db54064e" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -9311,24 +9458,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.87" +version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" +checksum = "1b56f625e64f3a1084ded111c4d5f477df9f8c92df113852fa5a374dbda78826" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.39", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.37" +version = "0.4.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c02dbc21516f9f1f04f187958890d7e6026df8d16540b7ad9492bc34a67cea03" +checksum = "ac36a15a220124ac510204aec1c3e5db8a22ab06fd6706d881dc6149f8ed9a12" dependencies = [ "cfg-if", "js-sys", @@ -9338,9 +9485,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.87" +version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" +checksum = "0162dbf37223cd2afce98f3d0785506dcb8d266223983e4b5b525859e6e182b2" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -9348,22 +9495,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.87" +version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" +checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.39", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.87" +version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" +checksum = "7ab9b36309365056cd639da3134bf87fa8f3d86008abf99e612384a6eecd459f" [[package]] name = "wasm-streams" @@ -9380,9 +9527,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.64" +version = "0.3.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b" +checksum = "50c24a44ec86bb68fbecd1b3efed7e85ea5621b39b35ef2766b66cd984f8010f" dependencies = [ "js-sys", "wasm-bindgen", @@ -9432,7 +9579,7 @@ dependencies = [ "pango-sys", "pkg-config", "soup2-sys", - "system-deps 6.1.1", + "system-deps 6.2.0", ] [[package]] @@ -9491,13 +9638,14 @@ checksum = "9193164d4de03a926d909d3bc7c30543cecb35400c02114792c2cae20d5e2dbb" [[package]] name = "which" -version = "4.4.0" +version = "4.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2441c784c52b289a054b7201fc93253e288f094e2f4be9058343127c4226a269" +checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" dependencies = [ "either", - "libc", + "home", "once_cell", + "rustix 0.38.26", ] [[package]] @@ -9651,6 +9799,15 @@ dependencies = [ "windows-targets 0.48.5", ] +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.0", +] + [[package]] name = "windows-targets" version = "0.42.2" @@ -9681,12 +9838,36 @@ dependencies = [ "windows_x86_64_msvc 0.48.5", ] +[[package]] +name = "windows-targets" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" +dependencies = [ + "windows_aarch64_gnullvm 0.52.0", + "windows_aarch64_msvc 0.52.0", + "windows_i686_gnu 0.52.0", + "windows_i686_msvc 0.52.0", + "windows_x86_64_gnu 0.52.0", + "windows_x86_64_gnullvm 0.52.0", + "windows_x86_64_msvc 0.52.0", +] + [[package]] name = "windows-tokens" version = "0.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f838de2fe15fe6bac988e74b798f26499a8b21a9d97edec321e79b28d1d7f597" +[[package]] +name = "windows-version" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75aa004c988e080ad34aff5739c39d0312f4684699d6d71fc8a198d057b8b9b4" +dependencies = [ + "windows-targets 0.52.0", +] + [[package]] name = "windows_aarch64_gnullvm" version = "0.42.2" @@ -9699,6 +9880,12 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" + [[package]] name = "windows_aarch64_msvc" version = "0.37.0" @@ -9723,6 +9910,12 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" + [[package]] name = "windows_i686_gnu" version = "0.37.0" @@ -9747,6 +9940,12 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" +[[package]] +name = "windows_i686_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" + [[package]] name = "windows_i686_msvc" version = "0.37.0" @@ -9771,6 +9970,12 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" +[[package]] +name = "windows_i686_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" + [[package]] name = "windows_x86_64_gnu" version = "0.37.0" @@ -9795,6 +10000,12 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" + [[package]] name = "windows_x86_64_gnullvm" version = "0.42.2" @@ -9807,6 +10018,12 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" + [[package]] name = "windows_x86_64_msvc" version = "0.37.0" @@ -9832,10 +10049,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] -name = "winnow" -version = "0.5.15" +name = "windows_x86_64_msvc" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c2e3184b9c4e92ad5167ca73039d0c42476302ab603e2fec4487511f38ccefc" +checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" + +[[package]] +name = "winnow" +version = "0.5.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "829846f3e3db426d4cee4510841b71a8e58aa2a76b1132579487ae430ccd9c7b" dependencies = [ "memchr", ] @@ -9862,9 +10085,9 @@ dependencies = [ [[package]] name = "wry" -version = "0.24.4" +version = "0.24.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88ef04bdad49eba2e01f06e53688c8413bd6a87b0bc14b72284465cf96e3578e" +checksum = "64a70547e8f9d85da0f5af609143f7bde3ac7457a6e1073104d9b73d6c5ac744" dependencies = [ "base64 0.13.1", "block", @@ -9962,9 +10185,9 @@ checksum = "0fcb9cbac069e033553e8bb871be2fbdffcab578eb25bd0f7c508cedc6dcd75a" [[package]] name = "xmlparser" -version = "0.13.5" +version = "0.13.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d25c75bf9ea12c4040a97f829154768bbbce366287e2dc044af160cd79a13fd" +checksum = "66fee0b777b0f5ac1c69bb06d361268faafa61cd4682ae064a171c16c433e9e4" [[package]] name = "xmltree" @@ -10027,9 +10250,9 @@ dependencies = [ [[package]] name = "zeroize" -version = "1.6.0" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9" +checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" [[package]] name = "zip" diff --git a/Cargo.toml b/Cargo.toml index e5a46afda..40ab00c8f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,19 +21,19 @@ edition = "2021" repository = "https://github.com/spacedriveapp/spacedrive" [workspace.dependencies] -prisma-client-rust = { git = "https://github.com/Brendonovich/prisma-client-rust", branch = "spacedrive", features = [ +prisma-client-rust = { git = "https://github.com/spacedriveapp/prisma-client-rust", rev = "9f8ac122e8f2b2e4957b71f48a37e06565adba40", features = [ "rspc", "sqlite-create-many", "migrations", "sqlite", ], default-features = false } -prisma-client-rust-cli = { git = "https://github.com/Brendonovich/prisma-client-rust", branch = "spacedrive", features = [ +prisma-client-rust-cli = { git = "https://github.com/spacedriveapp/prisma-client-rust", rev = "9f8ac122e8f2b2e4957b71f48a37e06565adba40", features = [ "rspc", "sqlite-create-many", "migrations", "sqlite", ], default-features = false } -prisma-client-rust-sdk = { git = "https://github.com/Brendonovich/prisma-client-rust", branch = "spacedrive", features = [ +prisma-client-rust-sdk = { git = "https://github.com/spacedriveapp/prisma-client-rust", rev = "9f8ac122e8f2b2e4957b71f48a37e06565adba40", features = [ "sqlite", ], default-features = false } @@ -44,8 +44,8 @@ tracing-subscriber = { git = "https://github.com/tokio-rs/tracing", rev = "29146 tracing-appender = { git = "https://github.com/tokio-rs/tracing", rev = "29146260fb4615d271d2e899ad95a753bb42915e" } # Unreleased changes for rolling log deletion rspc = { version = "0.1.4" } -specta = { version = "1.0.5" } -tauri-specta = { version = "1.0.2" } +specta = { version = "=2.0.0-rc.7" } +tauri-specta = { version = "=2.0.0-rc.4" } swift-rs = { version = "1.0.6" } @@ -59,6 +59,4 @@ serde_json = { version = "1.0" } if-watch = { git = "https://github.com/oscartbeaumont/if-watch.git", rev = "f732786057e57250e863a9ea0b1874e4cc9907c2" } # Beta features -specta = { git = "https://github.com/oscartbeaumont/specta", rev = "4bc6e46fc8747cd8d8a07597c1fe13c52aa16a41" } -rspc = { git = "https://github.com/oscartbeaumont/rspc", rev = "adebce542049b982dd251466d4144f4d57e92177" } -tauri-specta = { git = "https://github.com/oscartbeaumont/tauri-specta", rev = "c964bef228a90a66effc18cefcba6859c45a8e08" } +rspc = { git = "https://github.com/spacedriveapp/rspc.git", rev = "f3347e2e8bfe3f37bfacc437ca329fe71cdcb048" } diff --git a/apps/desktop/src-tauri/src/main.rs b/apps/desktop/src-tauri/src/main.rs index f0803f797..d1a244239 100644 --- a/apps/desktop/src-tauri/src/main.rs +++ b/apps/desktop/src-tauri/src/main.rs @@ -13,6 +13,7 @@ use tauri::{ WindowEvent, }; use tauri_plugins::{sd_error_plugin, sd_server_plugin}; +use tauri_specta::ts; use tokio::time::sleep; use tracing::error; @@ -143,16 +144,6 @@ async fn open_logs_dir(node: tauri::State<'_, Arc>) -> Result<(), ()> { }) } -// TODO(@Oscar): A helper like this should probs exist in tauri-specta -macro_rules! tauri_handlers { - ($($name:path),+) => {{ - #[cfg(debug_assertions)] - tauri_specta::ts::export(specta::collect_types![$($name),+], "../src/commands.ts").unwrap(); - - tauri::generate_handler![$($name),+] - }}; -} - const CLIENT_ID: &str = "2abb241e-40b8-4517-a3e3-5594375c8fbb"; #[tokio::main] @@ -219,9 +210,41 @@ async fn main() -> tauri::Result<()> { } }); + let specta_builder = { + let specta_builder = ts::builder() + .commands(tauri_specta::collect_commands![ + app_ready, + reset_spacedrive, + open_logs_dir, + refresh_menu_bar, + reload_webview, + set_menu_bar_item_state, + request_fda_macos, + file::open_file_paths, + file::open_ephemeral_files, + file::get_file_path_open_with_apps, + file::get_ephemeral_files_open_with_apps, + file::open_file_path_with, + file::open_ephemeral_file_with, + file::reveal_items, + theme::lock_app_theme, + // TODO: move to plugin w/tauri-specta + updater::check_for_update, + updater::install_update + ]) + // .events(tauri_specta::collect_events![]) + .config(specta::ts::ExportConfig::default().formatter(specta::ts::formatter::prettier)); + + #[cfg(debug_assertions)] + let specta_builder = specta_builder.path("../src/commands.ts"); + + specta_builder.into_plugin() + }; + let app = app .plugin(updater::plugin()) .plugin(tauri_plugin_window_state::Builder::default().build()) + .plugin(specta_builder) .setup(move |app| { let app = app.handle(); @@ -300,26 +323,6 @@ async fn main() -> tauri::Result<()> { }) .menu(menu::get_menu()) .manage(updater::State::default()) - .invoke_handler(tauri_handlers![ - app_ready, - reset_spacedrive, - open_logs_dir, - refresh_menu_bar, - reload_webview, - set_menu_bar_item_state, - request_fda_macos, - file::open_file_paths, - file::open_ephemeral_files, - file::get_file_path_open_with_apps, - file::get_ephemeral_files_open_with_apps, - file::open_file_path_with, - file::open_ephemeral_file_with, - file::reveal_items, - theme::lock_app_theme, - // TODO: move to plugin w/tauri-specta - updater::check_for_update, - updater::install_update - ]) .build(tauri::generate_context!())?; app.run(|_, _| {}); diff --git a/apps/desktop/src/App.tsx b/apps/desktop/src/App.tsx index cc680e652..536cfa256 100644 --- a/apps/desktop/src/App.tsx +++ b/apps/desktop/src/App.tsx @@ -4,7 +4,7 @@ import { listen } from '@tauri-apps/api/event'; import { appWindow } from '@tauri-apps/api/window'; import { startTransition, useEffect, useMemo, useRef, useState } from 'react'; import { createPortal } from 'react-dom'; -import { RspcProvider } from '@sd/client'; +import { CacheProvider, createCache, RspcProvider } from '@sd/client'; import { createRoutes, ErrorPage, @@ -19,7 +19,7 @@ import { getSpacedropState } from '@sd/interface/hooks/useSpacedropState'; import '@sd/ui/style/style.scss'; -import * as commands from './commands'; +import { commands } from './commands'; import { platform } from './platform'; import { queryClient } from './query'; import { createMemoryRouterWithHistory } from './router'; @@ -80,7 +80,9 @@ export default function App() { // we have a minimum delay between creating new tabs as react router can't handle creating tabs super fast const TAB_CREATE_DELAY = 150; -const routes = createRoutes(platform); +const cache = createCache(); + +const routes = createRoutes(platform, cache); function AppInner() { const [tabs, setTabs] = useState(() => [createTab()]); @@ -142,84 +144,86 @@ function AppInner() { }, [tab.element]); return ( - ({ - setTitle(title) { - setTabs((oldTabs) => { - const tabs = [...oldTabs]; - const tab = tabs[tabIndex]; - if (!tab) return tabs; - - tabs[tabIndex] = { ...tab, title }; - - return tabs; - }); - } - }), - [tabIndex] - )} - > - ({ router, title })), - createTab() { - createTabPromise.current = createTabPromise.current.then( - () => - new Promise((res) => { - startTransition(() => { - setTabs((tabs) => { - const newTabs = [...tabs, createTab()]; - - setTabIndex(newTabs.length - 1); - - return newTabs; - }); - }); - - setTimeout(res, TAB_CREATE_DELAY); - }) - ); - }, - removeTab(index: number) { - startTransition(() => { - setTabs((tabs) => { - const tab = tabs[index]; + + ({ + setTitle(title) { + setTabs((oldTabs) => { + const tabs = [...oldTabs]; + const tab = tabs[tabIndex]; if (!tab) return tabs; - tab.dispose(); + tabs[tabIndex] = { ...tab, title }; - tabs.splice(index, 1); - - setTabIndex(Math.min(tabIndex, tabs.length - 1)); - - return [...tabs]; + return tabs; }); - }); - } - }} + } + }), + [tabIndex] + )} > - - {tabs.map((tab) => - createPortal( - , - tab.element - ) - )} -
- - - + ({ router, title })), + createTab() { + createTabPromise.current = createTabPromise.current.then( + () => + new Promise((res) => { + startTransition(() => { + setTabs((tabs) => { + const newTabs = [...tabs, createTab()]; + + setTabIndex(newTabs.length - 1); + + return newTabs; + }); + }); + + setTimeout(res, TAB_CREATE_DELAY); + }) + ); + }, + removeTab(index: number) { + startTransition(() => { + setTabs((tabs) => { + const tab = tabs[index]; + if (!tab) return tabs; + + tab.dispose(); + + tabs.splice(index, 1); + + setTabIndex(Math.min(tabIndex, tabs.length - 1)); + + return [...tabs]; + }); + }); + } + }} + > + + {tabs.map((tab) => + createPortal( + , + tab.element + ) + )} +
+ + + + ); } diff --git a/apps/desktop/src/commands.ts b/apps/desktop/src/commands.ts index 69b428610..d3860a850 100644 --- a/apps/desktop/src/commands.ts +++ b/apps/desktop/src/commands.ts @@ -1,86 +1,230 @@ -/* eslint-disable */ +/** tauri-specta globals **/ + +import { invoke as TAURI_INVOKE } from '@tauri-apps/api'; +import * as TAURI_API_EVENT from '@tauri-apps/api/event'; +import { type WebviewWindowHandle as __WebviewWindowHandle__ } from '@tauri-apps/api/window'; + // This file was generated by [tauri-specta](https://github.com/oscartbeaumont/tauri-specta). Do not edit this file manually. -declare global { - interface Window { - __TAURI_INVOKE__(cmd: string, args?: Record): Promise; - } +export const commands = { + async appReady(): Promise { + return await TAURI_INVOKE('plugin:tauri-specta|app_ready'); + }, + async resetSpacedrive(): Promise { + return await TAURI_INVOKE('plugin:tauri-specta|reset_spacedrive'); + }, + async openLogsDir(): Promise<__Result__> { + try { + return { status: 'ok', data: await TAURI_INVOKE('plugin:tauri-specta|open_logs_dir') }; + } catch (e) { + if (e instanceof Error) throw e; + else return { status: 'error', error: e as any }; + } + }, + async refreshMenuBar(): Promise<__Result__> { + try { + return { + status: 'ok', + data: await TAURI_INVOKE('plugin:tauri-specta|refresh_menu_bar') + }; + } catch (e) { + if (e instanceof Error) throw e; + else return { status: 'error', error: e as any }; + } + }, + async reloadWebview(): Promise { + return await TAURI_INVOKE('plugin:tauri-specta|reload_webview'); + }, + async setMenuBarItemState(id: string, enabled: boolean): Promise { + return await TAURI_INVOKE('plugin:tauri-specta|set_menu_bar_item_state', { id, enabled }); + }, + async requestFdaMacos(): Promise { + return await TAURI_INVOKE('plugin:tauri-specta|request_fda_macos'); + }, + async openFilePaths( + library: string, + ids: number[] + ): Promise< + __Result__< + ( + | { t: 'NoLibrary' } + | { t: 'NoFile'; c: number } + | { t: 'OpenError'; c: [number, string] } + | { t: 'AllGood'; c: number } + | { t: 'Internal'; c: string } + )[], + null + > + > { + try { + return { + status: 'ok', + data: await TAURI_INVOKE('plugin:tauri-specta|open_file_paths', { library, ids }) + }; + } catch (e) { + if (e instanceof Error) throw e; + else return { status: 'error', error: e as any }; + } + }, + async openEphemeralFiles( + paths: string[] + ): Promise<__Result__<({ t: 'Ok'; c: string } | { t: 'Err'; c: string })[], null>> { + try { + return { + status: 'ok', + data: await TAURI_INVOKE('plugin:tauri-specta|open_ephemeral_files', { paths }) + }; + } catch (e) { + if (e instanceof Error) throw e; + else return { status: 'error', error: e as any }; + } + }, + async getFilePathOpenWithApps( + library: string, + ids: number[] + ): Promise<__Result__<{ url: string; name: string }[], null>> { + try { + return { + status: 'ok', + data: await TAURI_INVOKE('plugin:tauri-specta|get_file_path_open_with_apps', { + library, + ids + }) + }; + } catch (e) { + if (e instanceof Error) throw e; + else return { status: 'error', error: e as any }; + } + }, + async getEphemeralFilesOpenWithApps( + paths: string[] + ): Promise<__Result__<{ url: string; name: string }[], null>> { + try { + return { + status: 'ok', + data: await TAURI_INVOKE('plugin:tauri-specta|get_ephemeral_files_open_with_apps', { + paths + }) + }; + } catch (e) { + if (e instanceof Error) throw e; + else return { status: 'error', error: e as any }; + } + }, + async openFilePathWith( + library: string, + fileIdsAndUrls: [number, string][] + ): Promise<__Result__> { + try { + return { + status: 'ok', + data: await TAURI_INVOKE('plugin:tauri-specta|open_file_path_with', { + library, + fileIdsAndUrls + }) + }; + } catch (e) { + if (e instanceof Error) throw e; + else return { status: 'error', error: e as any }; + } + }, + async openEphemeralFileWith(pathsAndUrls: [string, string][]): Promise<__Result__> { + try { + return { + status: 'ok', + data: await TAURI_INVOKE('plugin:tauri-specta|open_ephemeral_file_with', { + pathsAndUrls + }) + }; + } catch (e) { + if (e instanceof Error) throw e; + else return { status: 'error', error: e as any }; + } + }, + async revealItems(library: string, items: RevealItem[]): Promise<__Result__> { + try { + return { + status: 'ok', + data: await TAURI_INVOKE('plugin:tauri-specta|reveal_items', { library, items }) + }; + } catch (e) { + if (e instanceof Error) throw e; + else return { status: 'error', error: e as any }; + } + }, + async lockAppTheme(themeType: AppThemeType): Promise { + return await TAURI_INVOKE('plugin:tauri-specta|lock_app_theme', { themeType }); + }, + async checkForUpdate(): Promise< + __Result__<{ version: string; body: string | null } | null, string> + > { + try { + return { + status: 'ok', + data: await TAURI_INVOKE('plugin:tauri-specta|check_for_update') + }; + } catch (e) { + if (e instanceof Error) throw e; + else return { status: 'error', error: e as any }; + } + }, + async installUpdate(): Promise<__Result__> { + try { + return { status: 'ok', data: await TAURI_INVOKE('plugin:tauri-specta|install_update') }; + } catch (e) { + if (e instanceof Error) throw e; + else return { status: 'error', error: e as any }; + } + } +}; + +/** user-defined types **/ + +export type AppThemeType = 'Auto' | 'Light' | 'Dark'; +export type RevealItem = + | { Location: { id: number } } + | { FilePath: { id: number } } + | { Ephemeral: { path: string } }; + +type __EventObj__ = { + listen: (cb: TAURI_API_EVENT.EventCallback) => ReturnType>; + once: (cb: TAURI_API_EVENT.EventCallback) => ReturnType>; + emit: T extends null + ? (payload?: T) => ReturnType + : (payload: T) => ReturnType; +}; + +type __Result__ = { status: 'ok'; data: T } | { status: 'error'; error: E }; + +function __makeEvents__>(mappings: Record) { + return new Proxy( + {} as unknown as { + [K in keyof T]: __EventObj__ & { + (handle: __WebviewWindowHandle__): __EventObj__; + }; + }, + { + get: (_, event) => { + const name = mappings[event as keyof T]; + + return new Proxy((() => {}) as any, { + apply: (_, __, [window]: [__WebviewWindowHandle__]) => ({ + listen: (arg: any) => window.listen(name, arg), + once: (arg: any) => window.once(name, arg), + emit: (arg: any) => window.emit(name, arg) + }), + get: (_, command: keyof __EventObj__) => { + switch (command) { + case 'listen': + return (arg: any) => TAURI_API_EVENT.listen(name, arg); + case 'once': + return (arg: any) => TAURI_API_EVENT.once(name, arg); + case 'emit': + return (arg: any) => TAURI_API_EVENT.emit(name, arg); + } + } + }); + } + } + ); } - -// Function avoids 'window not defined' in SSR -const invoke = () => window.__TAURI_INVOKE__; - -export function appReady() { - return invoke()("app_ready") -} - -export function resetSpacedrive() { - return invoke()("reset_spacedrive") -} - -export function openLogsDir() { - return invoke()("open_logs_dir") -} - -export function refreshMenuBar() { - return invoke()("refresh_menu_bar") -} - -export function reloadWebview() { - return invoke()("reload_webview") -} - -export function setMenuBarItemState(id: string, enabled: boolean) { - return invoke()("set_menu_bar_item_state", { id,enabled }) -} - -export function requestFdaMacos() { - return invoke()("request_fda_macos") -} - -export function openFilePaths(library: string, ids: number[]) { - return invoke()("open_file_paths", { library,ids }) -} - -export function openEphemeralFiles(paths: string[]) { - return invoke()("open_ephemeral_files", { paths }) -} - -export function getFilePathOpenWithApps(library: string, ids: number[]) { - return invoke()("get_file_path_open_with_apps", { library,ids }) -} - -export function getEphemeralFilesOpenWithApps(paths: string[]) { - return invoke()("get_ephemeral_files_open_with_apps", { paths }) -} - -export function openFilePathWith(library: string, fileIdsAndUrls: ([number, string])[]) { - return invoke()("open_file_path_with", { library,fileIdsAndUrls }) -} - -export function openEphemeralFileWith(pathsAndUrls: ([string, string])[]) { - return invoke()("open_ephemeral_file_with", { pathsAndUrls }) -} - -export function revealItems(library: string, items: RevealItem[]) { - return invoke()("reveal_items", { library,items }) -} - -export function lockAppTheme(themeType: AppThemeType) { - return invoke()("lock_app_theme", { themeType }) -} - -export function checkForUpdate() { - return invoke()("check_for_update") -} - -export function installUpdate() { - return invoke()("install_update") -} - -export type Update = { version: string; body: string | null } -export type OpenWithApplication = { url: string; name: string } -export type AppThemeType = "Auto" | "Light" | "Dark" -export type EphemeralFileOpenResult = { t: "Ok"; c: string } | { t: "Err"; c: string } -export type OpenFilePathResult = { t: "NoLibrary" } | { t: "NoFile"; c: number } | { t: "OpenError"; c: [number, string] } | { t: "AllGood"; c: number } | { t: "Internal"; c: string } -export type RevealItem = { Location: { id: number } } | { FilePath: { id: number } } | { Ephemeral: { path: string } } diff --git a/apps/desktop/src/platform.ts b/apps/desktop/src/platform.ts index 40f8ebe24..d5f2831a1 100644 --- a/apps/desktop/src/platform.ts +++ b/apps/desktop/src/platform.ts @@ -4,7 +4,7 @@ import { homeDir } from '@tauri-apps/api/path'; import { open } from '@tauri-apps/api/shell'; import { OperatingSystem, Platform } from '@sd/interface'; -import * as commands from './commands'; +import { commands } from './commands'; import { env } from './env'; import { createUpdater } from './updater'; diff --git a/apps/desktop/src/updater.tsx b/apps/desktop/src/updater.tsx index 7a5a640a8..2bc2c757a 100644 --- a/apps/desktop/src/updater.tsx +++ b/apps/desktop/src/updater.tsx @@ -3,7 +3,7 @@ import { proxy, useSnapshot } from 'valtio'; import { UpdateStore } from '@sd/interface'; import { toast, ToastId } from '@sd/ui'; -import * as commands from './commands'; +import { commands } from './commands'; declare global { interface Window { @@ -27,9 +27,15 @@ export function createUpdater() { const onInstallCallbacks = new Set<() => void>(); async function checkForUpdate() { - const update = await commands.checkForUpdate(); + const result = await commands.checkForUpdate(); - if (!update) return null; + if (result.status === 'error') { + console.error('UPDATER ERROR', result.error); + // TODO: Show some UI? + return null; + } + if (!result.data) return null; + const update = result.data; let id: ToastId | null = null; diff --git a/apps/mobile/src/components/drawer/DrawerLocations.tsx b/apps/mobile/src/components/drawer/DrawerLocations.tsx index e1612495d..af26e6fe9 100644 --- a/apps/mobile/src/components/drawer/DrawerLocations.tsx +++ b/apps/mobile/src/components/drawer/DrawerLocations.tsx @@ -2,7 +2,7 @@ import { DrawerNavigationHelpers } from '@react-navigation/drawer/lib/typescript import { useNavigation } from '@react-navigation/native'; import { useRef } from 'react'; import { Pressable, Text, View } from 'react-native'; -import { useLibraryQuery } from '@sd/client'; +import { useCache, useLibraryQuery, useNodes } from '@sd/client'; import { ModalRef } from '~/components/layout/Modal'; import { tw, twStyle } from '~/lib/tailwind'; @@ -39,7 +39,9 @@ const DrawerLocations = ({ stackName }: DrawerLocationsProp) => { const modalRef = useRef(null); - const { data: locations } = useLibraryQuery(['locations.list'], { keepPreviousData: true }); + const result = useLibraryQuery(['locations.list'], { keepPreviousData: true }); + useNodes(result.data?.nodes); + const locations = useCache(result.data?.items); return ( <> diff --git a/apps/mobile/src/components/drawer/DrawerTags.tsx b/apps/mobile/src/components/drawer/DrawerTags.tsx index 1e6c6aa8a..6ce411c74 100644 --- a/apps/mobile/src/components/drawer/DrawerTags.tsx +++ b/apps/mobile/src/components/drawer/DrawerTags.tsx @@ -2,7 +2,7 @@ import { DrawerNavigationHelpers } from '@react-navigation/drawer/lib/typescript import { useNavigation } from '@react-navigation/native'; import { useRef } from 'react'; import { ColorValue, Pressable, Text, View } from 'react-native'; -import { useLibraryQuery } from '@sd/client'; +import { useCache, useLibraryQuery, useNodes } from '@sd/client'; import { ModalRef } from '~/components/layout/Modal'; import { tw, twStyle } from '~/lib/tailwind'; @@ -37,6 +37,8 @@ const DrawerTags = ({ stackName }: DrawerTagsProp) => { const navigation = useNavigation(); const tags = useLibraryQuery(['tags.list']); + useNodes(tags.data?.nodes); + const tagData = useCache(tags.data?.items); const modalRef = useRef(null); @@ -47,7 +49,7 @@ const DrawerTags = ({ stackName }: DrawerTagsProp) => { containerStyle={tw`mb-3 ml-1 mt-6`} > - {tags.data?.map((tag) => ( + {tagData?.map((tag) => ( { const tagsQuery = useLibraryQuery(['tags.getForObject', objectData?.id ?? -1], { enabled: objectData != null }); + useNodes(tagsQuery.data?.nodes); + const items = useCache(tagsQuery.data?.items); const isDir = data && isPath(data) ? data.item.is_dir : false; @@ -35,7 +39,7 @@ const InfoTagPills = ({ data, style }: Props) => { )} {/* TODO: What happens if I have too many? */} - {tagsQuery.data?.map((tag) => ( + {items?.map((tag) => ( ((_, ref) => { const modalRef = useForwardedRef(ref); const queryClient = useQueryClient(); + const cache = useNormalisedCache(); const [libName, setLibName] = useState(''); const submitPlausibleEvent = usePlausibleEvent(); @@ -20,17 +26,15 @@ const CreateLibraryModal = forwardRef((_, ref) => { const { mutate: createLibrary, isLoading: createLibLoading } = useBridgeMutation( 'library.create', { - onSuccess: (lib) => { + onSuccess: (libRaw) => { + cache.withNodes(libRaw.nodes); + const lib = cache.withCache(libRaw.item); + // Reset form setLibName(''); // We do this instead of invalidating the query because it triggers a full app re-render?? - queryClient.setQueryData(['library.list'], (libraries: any) => { - // The invalidation system beat us to it - if (libraries.find((l: any) => l.uuid === lib.uuid)) return libraries; - - return [...(libraries || []), lib]; - }); + insertLibrary(queryClient, lib); // Switch to the new library currentLibraryStore.id = lib.uuid; diff --git a/apps/mobile/src/components/modal/inspector/FileInfoModal.tsx b/apps/mobile/src/components/modal/inspector/FileInfoModal.tsx index d9d2e59d3..74bc5e584 100644 --- a/apps/mobile/src/components/modal/inspector/FileInfoModal.tsx +++ b/apps/mobile/src/components/modal/inspector/FileInfoModal.tsx @@ -61,9 +61,9 @@ const FileInfoModal = forwardRef((props, ref) => { const objectData = data && getItemObject(data); const filePathData = data && getItemFilePath(data); - const fullObjectData = useLibraryQuery(['files.get', { id: objectData?.id || -1 }], { - enabled: objectData?.id !== undefined - }); + // const fullObjectData = useLibraryQuery(['files.get', objectData?.id || -1], { + // enabled: objectData?.id !== undefined + // }); return ( data?.items ?? [], [data]); + const pathsItems = useCache(pathsItemsReferences); useEffect(() => { // Set screen title to location. @@ -36,15 +40,15 @@ export default function LocationScreen({ navigation, route }: SharedScreenProps< }); } else { navigation.setOptions({ - title: location.data?.name ?? 'Location' + title: locationData?.name ?? 'Location' }); } - }, [location.data?.name, navigation, path]); + }, [locationData?.name, navigation, path]); useEffect(() => { getExplorerStore().locationId = id; getExplorerStore().path = path ?? ''; }, [id, path]); - return ; + return ; } diff --git a/apps/mobile/src/screens/Search.tsx b/apps/mobile/src/screens/Search.tsx index 161c928d1..702663393 100644 --- a/apps/mobile/src/screens/Search.tsx +++ b/apps/mobile/src/screens/Search.tsx @@ -2,7 +2,7 @@ import { MagnifyingGlass } from 'phosphor-react-native'; import { Suspense, useDeferredValue, useMemo, useState } from 'react'; import { ActivityIndicator, Pressable, Text, TextInput, View } from 'react-native'; import { useSafeAreaInsets } from 'react-native-safe-area-context'; -import { getExplorerItemData, SearchFilterArgs, useLibraryQuery } from '@sd/client'; +import { getExplorerItemData, SearchFilterArgs, useCache, useLibraryQuery } from '@sd/client'; import Explorer from '~/components/explorer/Explorer'; import { tw, twStyle } from '~/lib/tailwind'; import { RootStackScreenProps } from '~/navigation'; @@ -45,19 +45,20 @@ const SearchScreen = ({ navigation }: RootStackScreenProps<'Search'>) => { } ); - const items = useMemo(() => { - const items = query.data?.items; + const pathsItemsReferences = useMemo(() => query.data?.items ?? [], [query.data]); + const pathsItems = useCache(pathsItemsReferences); + const items = useMemo(() => { // Mobile does not thave media layout - // if (explorerStore.layoutMode !== 'media') return items; + // if (explorerStore.layoutMode !== 'media') return pathsItems; return ( - items?.filter((item) => { + pathsItems?.filter((item) => { const { kind } = getExplorerItemData(item); return kind === 'Video' || kind === 'Image'; }) ?? [] ); - }, [query.data]); + }, [pathsItems]); return ( diff --git a/apps/mobile/src/screens/Tag.tsx b/apps/mobile/src/screens/Tag.tsx index a613ea9cb..c70790b49 100644 --- a/apps/mobile/src/screens/Tag.tsx +++ b/apps/mobile/src/screens/Tag.tsx @@ -1,5 +1,5 @@ import { useEffect } from 'react'; -import { useLibraryQuery } from '@sd/client'; +import { useCache, useLibraryQuery, useNodes } from '@sd/client'; import Explorer from '~/components/explorer/Explorer'; import { SharedScreenProps } from '~/navigation/SharedScreens'; @@ -13,15 +13,19 @@ export default function TagScreen({ navigation, route }: SharedScreenProps<'Tag' take: 100 } ]); + useNodes(search.data?.nodes); + const searchData = useCache(search.data?.items); const tag = useLibraryQuery(['tags.get', id]); + useNodes(tag.data?.nodes); + const tagData = useCache(tag.data?.item); useEffect(() => { // Set screen title to tag name. navigation.setOptions({ - title: tag.data?.name ?? 'Tag' + title: tagData?.name ?? 'Tag' }); - }, [tag.data?.name, navigation]); + }, [tagData?.name, navigation]); - return ; + return ; } diff --git a/apps/mobile/src/screens/onboarding/context.tsx b/apps/mobile/src/screens/onboarding/context.tsx index 6bd4c3151..869fb90ea 100644 --- a/apps/mobile/src/screens/onboarding/context.tsx +++ b/apps/mobile/src/screens/onboarding/context.tsx @@ -5,11 +5,13 @@ import { z } from 'zod'; import { currentLibraryCache, getOnboardingStore, + insertLibrary, resetOnboardingStore, telemetryStore, useBridgeMutation, useCachedLibraries, useMultiZodForm, + useNormalisedCache, useOnboardingStore, usePlausibleEvent } from '@sd/client'; @@ -66,13 +68,14 @@ const useFormState = () => { const submitPlausibleEvent = usePlausibleEvent(); const queryClient = useQueryClient(); + const cache = useNormalisedCache(); const createLibrary = useBridgeMutation('library.create', { - onSuccess: (lib) => { + onSuccess: (libRaw) => { + cache.withNodes(libRaw.nodes); + const lib = cache.withCache(libRaw.item); + // We do this instead of invalidating the query because it triggers a full app re-render?? - queryClient.setQueryData(['library.list'], (libraries: any) => [ - ...(libraries || []), - lib - ]); + insertLibrary(queryClient, lib); } }); @@ -86,13 +89,15 @@ const useFormState = () => { try { // show creation screen for a bit for smoothness - const [library] = await Promise.all([ + const [libraryRaw] = await Promise.all([ createLibrary.mutateAsync({ name: data.NewLibrary.name, default_locations: null }), new Promise((res) => setTimeout(res, 500)) ]); + cache.withNodes(libraryRaw.nodes); + const library = cache.withCache(libraryRaw.item); if (telemetryStore.shareFullTelemetry) { submitPlausibleEvent({ event: { type: 'libraryCreate' } }); diff --git a/apps/mobile/src/screens/settings/client/LibrarySettings.tsx b/apps/mobile/src/screens/settings/client/LibrarySettings.tsx index a136462ea..16061dca3 100644 --- a/apps/mobile/src/screens/settings/client/LibrarySettings.tsx +++ b/apps/mobile/src/screens/settings/client/LibrarySettings.tsx @@ -2,7 +2,7 @@ import { CaretRight, Pen, Trash } from 'phosphor-react-native'; import React, { useEffect, useRef } from 'react'; import { Animated, FlatList, Text, View } from 'react-native'; import { Swipeable } from 'react-native-gesture-handler'; -import { LibraryConfigWrapped, useBridgeQuery } from '@sd/client'; +import { LibraryConfigWrapped, useBridgeQuery, useCache, useNodes } from '@sd/client'; import { ModalRef } from '~/components/layout/Modal'; import DeleteLibraryModal from '~/components/modal/confirmModals/DeleteLibraryModal'; import { AnimatedButton, FakeButton } from '~/components/primitive/Button'; @@ -68,7 +68,9 @@ function LibraryItem({ } const LibrarySettingsScreen = ({ navigation }: SettingsStackScreenProps<'LibrarySettings'>) => { - const { data: libraries } = useBridgeQuery(['library.list']); + const libraryList = useBridgeQuery(['library.list']); + useNodes(libraryList.data?.nodes); + const libraries = useCache(libraryList.data?.items); useEffect(() => { navigation.setOptions({ diff --git a/apps/mobile/src/screens/settings/library/EditLocationSettings.tsx b/apps/mobile/src/screens/settings/library/EditLocationSettings.tsx index 2f1a28c14..3029c58e5 100644 --- a/apps/mobile/src/screens/settings/library/EditLocationSettings.tsx +++ b/apps/mobile/src/screens/settings/library/EditLocationSettings.tsx @@ -4,7 +4,7 @@ import { useEffect } from 'react'; import { Controller } from 'react-hook-form'; import { Alert, ScrollView, Text, View } from 'react-native'; import { z } from 'zod'; -import { useLibraryMutation, useLibraryQuery, useZodForm } from '@sd/client'; +import { useLibraryMutation, useLibraryQuery, useNormalisedCache, useZodForm } from '@sd/client'; import { Input } from '~/components/form/Input'; import { Switch } from '~/components/form/Switch'; import DeleteLocationModal from '~/components/modal/confirmModals/DeleteLocationModal'; @@ -36,6 +36,7 @@ const EditLocationSettingsScreen = ({ const { id } = route.params; const queryClient = useQueryClient(); + const cache = useNormalisedCache(); const form = useZodForm({ schema }); @@ -93,12 +94,15 @@ const EditLocationSettingsScreen = ({ }, [form, navigation, onSubmit]); useLibraryQuery(['locations.getWithRules', id], { - onSuccess: (data) => { + onSuccess: (dataRaw) => { + cache.withNodes(dataRaw?.nodes); + const data = cache.withCache(dataRaw?.item); + if (data && !form.formState.isDirty) form.reset({ displayName: data.name, localPath: data.path, - indexer_rules_ids: data.indexer_rules.map((i) => i.indexer_rule.id.toString()), + indexer_rules_ids: data.indexer_rules.map((i) => i.id.toString()), generatePreviewMedia: data.generate_preview_media, syncPreviewMedia: data.sync_preview_media, hidden: data.hidden diff --git a/apps/mobile/src/screens/settings/library/LocationSettings.tsx b/apps/mobile/src/screens/settings/library/LocationSettings.tsx index 760653fc1..3b5fc9e7c 100644 --- a/apps/mobile/src/screens/settings/library/LocationSettings.tsx +++ b/apps/mobile/src/screens/settings/library/LocationSettings.tsx @@ -5,8 +5,10 @@ import { Swipeable } from 'react-native-gesture-handler'; import { arraysEqual, Location, + useCache, useLibraryMutation, useLibraryQuery, + useNodes, useOnlineLocations } from '@sd/client'; import FolderIcon from '~/components/icons/FolderIcon'; @@ -130,7 +132,9 @@ function LocationItem({ location, index, navigation }: LocationItemProps) { } const LocationSettingsScreen = ({ navigation }: SettingsStackScreenProps<'LocationSettings'>) => { - const { data: locations } = useLibraryQuery(['locations.list']); + const result = useLibraryQuery(['locations.list']); + useNodes(result.data?.nodes); + const locations = useCache(result.data?.items); useEffect(() => { navigation.setOptions({ diff --git a/apps/mobile/src/screens/settings/library/TagsSettings.tsx b/apps/mobile/src/screens/settings/library/TagsSettings.tsx index d92a06af5..8b02f85d5 100644 --- a/apps/mobile/src/screens/settings/library/TagsSettings.tsx +++ b/apps/mobile/src/screens/settings/library/TagsSettings.tsx @@ -2,7 +2,7 @@ import { ArrowLeft, CaretRight, Pen, Trash } from 'phosphor-react-native'; import { useEffect, useRef } from 'react'; import { Animated, FlatList, Text, View } from 'react-native'; import { Swipeable } from 'react-native-gesture-handler'; -import { Tag, useLibraryQuery } from '@sd/client'; +import { Tag, useCache, useLibraryQuery, useNodes } from '@sd/client'; import { ModalRef } from '~/components/layout/Modal'; import DeleteTagModal from '~/components/modal/confirmModals/DeleteTagModal'; import CreateTagModal from '~/components/modal/tag/CreateTagModal'; @@ -70,7 +70,9 @@ function TagItem({ tag, index }: { tag: Tag; index: number }) { // TODO: Add "New Tag" button const TagsSettingsScreen = ({ navigation }: SettingsStackScreenProps<'TagsSettings'>) => { - const { data: tags } = useLibraryQuery(['tags.list']); + const result = useLibraryQuery(['tags.list']); + useNodes(result.data?.nodes); + const tags = useCache(result.data?.items); useEffect(() => { navigation.setOptions({ diff --git a/apps/web/src/App.tsx b/apps/web/src/App.tsx index 21881a543..6dfc03aff 100644 --- a/apps/web/src/App.tsx +++ b/apps/web/src/App.tsx @@ -1,7 +1,7 @@ import { hydrate, QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { useEffect, useRef, useState } from 'react'; import { createBrowserRouter } from 'react-router-dom'; -import { RspcProvider } from '@sd/client'; +import { CacheProvider, createCache, RspcProvider } from '@sd/client'; import { createRoutes, Platform, @@ -81,7 +81,9 @@ const queryClient = new QueryClient({ } }); -const routes = createRoutes(platform); +const cache = createCache(); + +const routes = createRoutes(platform, cache); function App() { const router = useRouter(); @@ -102,21 +104,23 @@ function App() { return (
- - - - - - - - - + + + + + + + + + + +
); @@ -126,7 +130,7 @@ export default App; function useRouter() { const [router, setRouter] = useState(() => { - const router = createBrowserRouter(createRoutes(platform)); + const router = createBrowserRouter(routes); router.subscribe((event) => { setRouter((router) => { diff --git a/core/Cargo.toml b/core/Cargo.toml index 79f3bb795..36d7d5bd9 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -22,16 +22,16 @@ sd-media-metadata = { path = "../crates/media-metadata" } sd-prisma = { path = "../crates/prisma" } sd-ffmpeg = { path = "../crates/ffmpeg", optional = true } sd-crypto = { path = "../crates/crypto", features = [ - "rspc", - "specta", - "serde", - "keymanager", + "rspc", + "specta", + "serde", + "keymanager", ] } - +sd-cache = { path = "../crates/cache" } sd-images = { path = "../crates/images", features = [ - "rspc", - "serde", - "specta", + "rspc", + "serde", + "specta", ] } sd-file-ext = { path = "../crates/file-ext" } sd-sync = { path = "../crates/sync" } @@ -40,21 +40,21 @@ sd-utils = { path = "../crates/utils" } sd-core-sync = { path = "./crates/sync" } rspc = { workspace = true, features = [ - "uuid", - "chrono", - "tracing", - "alpha", - "unstable", + "uuid", + "chrono", + "tracing", + "alpha", + "unstable", ] } prisma-client-rust = { workspace = true } specta = { workspace = true } tokio = { workspace = true, features = [ - "sync", - "rt-multi-thread", - "io-util", - "macros", - "time", - "process", + "sync", + "rt-multi-thread", + "io-util", + "macros", + "time", + "process", ] } serde = { version = "1.0", features = ["derive"] } chrono = { version = "0.4.31", features = ["serde"] } @@ -82,7 +82,7 @@ http-range = "0.1.5" mini-moka = "0.10.2" serde_with = "3.4.0" notify = { version = "=5.2.0", default-features = false, features = [ - "macos_fsevent", + "macos_fsevent", ], optional = true } static_assertions = "1.1.0" serde-hashkey = "0.4.5" diff --git a/core/src/api/backups.rs b/core/src/api/backups.rs index a911b08a2..412d257c5 100644 --- a/core/src/api/backups.rs +++ b/core/src/api/backups.rs @@ -115,12 +115,17 @@ pub(crate) fn mount() -> AlphaRouter { }) .procedure("backup", { R.with2(library()) - .mutation(|(node, library), _: ()| start_backup(node, library)) + .mutation( + |(node, library), _: ()| async move { Ok(start_backup(node, library).await) }, + ) }) .procedure("restore", { R // TODO: Paths as strings is bad but here we want the flexibility of the frontend allowing any path - .mutation(|node, path: String| start_restore(node, path.into())) + .mutation(|node, path: String| async move { + start_restore(node, path.into()).await; + Ok(()) + }) }) .procedure("delete", { R diff --git a/core/src/api/categories.rs b/core/src/api/categories.rs index 8fa14e9fb..5f6a8fdf2 100644 --- a/core/src/api/categories.rs +++ b/core/src/api/categories.rs @@ -1,47 +1,49 @@ -use crate::library::Category; +// TODO: Ensure this file has normalised caching setup before reenabling -use std::{collections::BTreeMap, str::FromStr}; +// use crate::library::Category; -use rspc::{alpha::AlphaRouter, ErrorCode}; -use strum::VariantNames; +// use std::{collections::BTreeMap, str::FromStr}; -use super::{utils::library, Ctx, R}; +// use rspc::{alpha::AlphaRouter, ErrorCode}; +// use strum::VariantNames; -pub(crate) fn mount() -> AlphaRouter { - R.router().procedure("list", { - R.with2(library()).query(|(_, library), _: ()| async move { - let (categories, queries): (Vec<_>, Vec<_>) = Category::VARIANTS - .iter() - .map(|category| { - let category = Category::from_str(category) - .expect("it's alright this category string exists"); - ( - category, - library.db.object().count(vec![category.to_where_param()]), - ) - }) - .unzip(); +// use super::{utils::library, Ctx, R}; - Ok(categories - .into_iter() - .zip( - library - .db - ._batch(queries) - .await? - .into_iter() - // TODO(@Oscar): rspc bigint support - .map(|count| { - i32::try_from(count).map_err(|_| { - rspc::Error::new( - ErrorCode::InternalServerError, - "category item count overflowed 'i32'!".into(), - ) - }) - }) - .collect::, _>>()?, - ) - .collect::>()) - }) - }) -} +// pub(crate) fn mount() -> AlphaRouter { +// R.router().procedure("list", { +// R.with2(library()).query(|(_, library), _: ()| async move { +// let (categories, queries): (Vec<_>, Vec<_>) = Category::VARIANTS +// .iter() +// .map(|category| { +// let category = Category::from_str(category) +// .expect("it's alright this category string exists"); +// ( +// category, +// library.db.object().count(vec![category.to_where_param()]), +// ) +// }) +// .unzip(); + +// Ok(categories +// .into_iter() +// .zip( +// library +// .db +// ._batch(queries) +// .await? +// .into_iter() +// // TODO(@Oscar): rspc bigint support +// .map(|count| { +// i32::try_from(count).map_err(|_| { +// rspc::Error::new( +// ErrorCode::InternalServerError, +// "category item count overflowed 'i32'!".into(), +// ) +// }) +// }) +// .collect::, _>>()?, +// ) +// .collect::>()) +// }) +// }) +// } diff --git a/core/src/api/cloud.rs b/core/src/api/cloud.rs index 71744182f..3b17d416e 100644 --- a/core/src/api/cloud.rs +++ b/core/src/api/cloud.rs @@ -28,7 +28,7 @@ pub(crate) fn mount() -> AlphaRouter { } mod library { - use chrono::{DateTime, Utc}; + use chrono::Utc; use crate::api::libraries::LibraryConfigWrapped; diff --git a/core/src/api/ephemeral_files.rs b/core/src/api/ephemeral_files.rs index 54da3e7bc..504f24a3f 100644 --- a/core/src/api/ephemeral_files.rs +++ b/core/src/api/ephemeral_files.rs @@ -52,7 +52,7 @@ pub(crate) fn mount() -> AlphaRouter { return Ok(None); } - match extract_media_data(full_path).await { + match extract_media_data(full_path.clone()).await { Ok(img_media_data) => Ok(Some(MediaMetadata::Image(Box::new(img_media_data)))), Err(MediaDataError::MediaData(sd_media_metadata::Error::NoExifDataOnPath( _, diff --git a/core/src/api/files.rs b/core/src/api/files.rs index 58a137a57..fbe75fde8 100644 --- a/core/src/api/files.rs +++ b/core/src/api/files.rs @@ -1,5 +1,5 @@ use crate::{ - api::utils::library, + api::{locations::object_with_file_paths, utils::library}, invalidate_query, job::Job, library::Library, @@ -21,6 +21,7 @@ use crate::{ util::{db::maybe_missing, error::FileIOError}, }; +use sd_cache::{CacheNode, Model, NormalisedResult, Reference}; use sd_file_ext::kind::ObjectKind; use sd_images::ConvertableExtension; use sd_media_metadata::MediaMetadata; @@ -31,11 +32,11 @@ use std::{ sync::Arc, }; -use chrono::Utc; +use chrono::{DateTime, FixedOffset, Utc}; use futures::future::join_all; use regex::Regex; use rspc::{alpha::AlphaRouter, ErrorCode}; -use serde::Deserialize; +use serde::{Deserialize, Serialize}; use specta::Type; use tokio::{fs, io, task::spawn_blocking}; use tracing::{error, warn}; @@ -47,19 +48,76 @@ const UNTITLED_FOLDER_STR: &str = "Untitled Folder"; pub(crate) fn mount() -> AlphaRouter { R.router() .procedure("get", { - #[derive(Type, Deserialize)] - pub struct GetArgs { + #[derive(Type, Serialize)] + pub struct ObjectWithFilePaths2 { pub id: i32, + pub pub_id: Vec, + pub kind: Option, + pub key_id: Option, + pub hidden: Option, + pub favorite: Option, + pub important: Option, + pub note: Option, + pub date_created: Option>, + pub date_accessed: Option>, + pub file_paths: Vec>, } + + impl Model for ObjectWithFilePaths2 { + fn name() -> &'static str { + "Object" // is a duplicate because it's the same entity but with a relation + } + } + + impl ObjectWithFilePaths2 { + pub fn from_db( + nodes: &mut Vec, + item: object_with_file_paths::Data, + ) -> Reference { + let this = Self { + id: item.id, + pub_id: item.pub_id, + kind: item.kind, + key_id: item.key_id, + hidden: item.hidden, + favorite: item.favorite, + important: item.important, + note: item.note, + date_created: item.date_created, + date_accessed: item.date_accessed, + file_paths: item + .file_paths + .into_iter() + .map(|i| { + let id = i.id.to_string(); + nodes.push(CacheNode::new(id.clone(), i)); + Reference::new(id) + }) + .collect(), + }; + + let id = this.id.to_string(); + nodes.push(CacheNode::new(id.clone(), this)); + Reference::new(id) + } + } + R.with2(library()) - .query(|(_, library), args: GetArgs| async move { + .query(|(_, library), object_id: i32| async move { Ok(library .db .object() - .find_unique(object::id::equals(args.id)) - .include(object::include!({ file_paths })) + .find_unique(object::id::equals(object_id)) + .include(object_with_file_paths::include()) .exec() - .await?) + .await? + .map(|item| { + let mut nodes = Vec::new(); + NormalisedResult { + item: ObjectWithFilePaths2::from_db(&mut nodes, item), + nodes, + } + })) }) }) .procedure("getMediaData", { diff --git a/core/src/api/keys.rs b/core/src/api/keys.rs index 3799431aa..890e7d35b 100644 --- a/core/src/api/keys.rs +++ b/core/src/api/keys.rs @@ -1,3 +1,5 @@ +// TODO: Ensure this file has normalised caching setup before reenabling + // use rspc::alpha::AlphaRouter; // use rspc::ErrorCode; // use sd_crypto::keys::keymanager::{StoredKey, StoredKeyType}; diff --git a/core/src/api/libraries.rs b/core/src/api/libraries.rs index c774dbe95..9394ea626 100644 --- a/core/src/api/libraries.rs +++ b/core/src/api/libraries.rs @@ -6,6 +6,7 @@ use crate::{ Node, }; +use sd_cache::{Model, Normalise, NormalisedResult, NormalisedResults}; use sd_p2p::spacetunnel::RemoteIdentity; use sd_prisma::prisma::{indexer_rule, statistics}; @@ -35,6 +36,12 @@ pub struct LibraryConfigWrapped { pub config: LibraryConfig, } +impl Model for LibraryConfigWrapped { + fn name() -> &'static str { + "LibraryConfigWrapped" + } +} + impl LibraryConfigWrapped { pub async fn from_library(library: &Library) -> Self { Self { @@ -50,7 +57,8 @@ pub(crate) fn mount() -> AlphaRouter { R.router() .procedure("list", { R.query(|node, _: ()| async move { - node.libraries + let libraries = node + .libraries .get_all() .await .into_iter() @@ -64,7 +72,11 @@ pub(crate) fn mount() -> AlphaRouter { }) .collect::>() .join() - .await + .await; + + let (nodes, items) = libraries.normalise(|i| i.uuid.to_string()); + + Ok(NormalisedResults { nodes, items }) }) }) .procedure("statistics", { @@ -279,7 +291,10 @@ pub(crate) fn mount() -> AlphaRouter { .await?; } - Ok(LibraryConfigWrapped::from_library(&library).await) + Ok(NormalisedResult::from( + LibraryConfigWrapped::from_library(&library).await, + |l| l.uuid.to_string(), + )) }, ) }) diff --git a/core/src/api/locations.rs b/core/src/api/locations.rs index 9eefd9f29..9385cb277 100644 --- a/core/src/api/locations.rs +++ b/core/src/api/locations.rs @@ -17,9 +17,10 @@ use crate::{ use std::path::{Path, PathBuf}; -use chrono::{DateTime, Utc}; +use chrono::{DateTime, FixedOffset, Utc}; use directories::UserDirs; use rspc::{self, alpha::AlphaRouter, ErrorCode}; +use sd_cache::{CacheNode, Model, Normalise, NormalisedResult, NormalisedResults, Reference}; use serde::{Deserialize, Serialize}; use specta::Type; use tracing::error; @@ -58,6 +59,34 @@ pub enum ExplorerItem { item: PeerMetadata, }, } + +// TODO: Really this shouldn't be a `Model` but it's easy for now. +// In the future we should store the inner data of the variant on behalf of it's existing model so it works cross queries. +impl Model for ExplorerItem { + fn name() -> &'static str { + "ExplorerItem" + } +} + +impl ExplorerItem { + pub fn id(&self) -> String { + let ty = match self { + ExplorerItem::Path { .. } => "FilePath", + ExplorerItem::Object { .. } => "Object", + ExplorerItem::Location { .. } => "Location", + ExplorerItem::NonIndexedPath { .. } => "NonIndexedPath", + ExplorerItem::SpacedropPeer { .. } => "SpacedropPeer", + }; + match self { + ExplorerItem::Path { item, .. } => format!("{ty}:{}", item.id), + ExplorerItem::Object { item, .. } => format!("{ty}:{}", item.id), + ExplorerItem::Location { item, .. } => format!("{ty}:{}", item.id), + ExplorerItem::NonIndexedPath { item, .. } => format!("{ty}:{}", item.path), + ExplorerItem::SpacedropPeer { item, .. } => format!("{ty}:{}", item.name), // TODO: Use a proper primary key + } + } +} + #[derive(Serialize, Type, Debug)] pub struct SystemLocations { desktop: Option, @@ -172,13 +201,17 @@ pub(crate) fn mount() -> AlphaRouter { R.router() .procedure("list", { R.with2(library()).query(|(_, library), _: ()| async move { - Ok(library + let locations = library .db .location() .find_many(vec![]) .order_by(location::date_created::order(SortOrder::Desc)) .exec() - .await?) + .await?; + + let (nodes, items) = locations.normalise(|i| i.id.to_string()); + + Ok(NormalisedResults { items, nodes }) }) }) .procedure("get", { @@ -189,10 +222,72 @@ pub(crate) fn mount() -> AlphaRouter { .location() .find_unique(location::id::equals(location_id)) .exec() - .await?) + .await? + .map(|i| NormalisedResult::from(i, |i| i.id.to_string()))) }) }) .procedure("getWithRules", { + #[derive(Type, Serialize)] + struct LocationWithIndexerRule { + pub id: i32, + pub pub_id: Vec, + pub name: Option, + pub path: Option, + pub total_capacity: Option, + pub available_capacity: Option, + pub size_in_bytes: Option>, + pub is_archived: Option, + pub generate_preview_media: Option, + pub sync_preview_media: Option, + pub hidden: Option, + pub date_created: Option>, + pub instance_id: Option, + pub indexer_rules: Vec>, + } + + impl Model for LocationWithIndexerRule { + fn name() -> &'static str { + "Location" // This is a duplicate identifier as `location::Data` but it's fine because because they are the same entity + } + } + + impl LocationWithIndexerRule { + pub fn from_db( + nodes: &mut Vec, + value: location_with_indexer_rules::Data, + ) -> Reference { + let this = Self { + id: value.id, + pub_id: value.pub_id, + name: value.name, + path: value.path, + total_capacity: value.total_capacity, + available_capacity: value.available_capacity, + size_in_bytes: value.size_in_bytes, + is_archived: value.is_archived, + generate_preview_media: value.generate_preview_media, + sync_preview_media: value.sync_preview_media, + hidden: value.hidden, + date_created: value.date_created, + instance_id: value.instance_id, + indexer_rules: value + .indexer_rules + .into_iter() + .map(|i| { + let id = i.indexer_rule.id.to_string(); + + nodes.push(CacheNode::new(id.clone(), i.indexer_rule)); + Reference::new(id) + }) + .collect(), + }; + + let id = this.id.to_string(); + nodes.push(CacheNode::new(id.clone(), this)); + Reference::new(id) + } + } + R.with2(library()) .query(|(_, library), location_id: location::id::Type| async move { Ok(library @@ -201,7 +296,14 @@ pub(crate) fn mount() -> AlphaRouter { .find_unique(location::id::equals(location_id)) .include(location_with_indexer_rules::include()) .exec() - .await?) + .await? + .map(|location| { + let mut nodes = Vec::new(); + NormalisedResult { + item: LocationWithIndexerRule::from_db(&mut nodes, location), + nodes, + } + })) }) }) .procedure("create", { @@ -477,32 +579,34 @@ fn mount_indexer_rule_routes() -> AlphaRouter { format!("Indexer rule not found"), ) }) + .map(|i| NormalisedResult::from(i, |i| i.id.to_string())) }) }) .procedure("list", { R.with2(library()).query(|(_, library), _: ()| async move { - library - .db - .indexer_rule() - .find_many(vec![]) - .exec() - .await - .map_err(Into::into) + let rules = library.db.indexer_rule().find_many(vec![]).exec().await?; + + let (nodes, items) = rules.normalise(|i| i.id.to_string()); + + Ok(NormalisedResults { items, nodes }) }) }) // list indexer rules for location, returning the indexer rule .procedure("listForLocation", { R.with2(library()) .query(|(_, library), location_id: location::id::Type| async move { - library + let rules = library .db .indexer_rule() .find_many(vec![indexer_rule::locations::some(vec![ indexer_rules_in_location::location_id::equals(location_id), ])]) .exec() - .await - .map_err(Into::into) + .await?; + + let (nodes, items) = rules.normalise(|i| i.id.to_string()); + + Ok(NormalisedResults { items, nodes }) }) }) } diff --git a/core/src/api/mod.rs b/core/src/api/mod.rs index 922200b61..23aa21fd3 100644 --- a/core/src/api/mod.rs +++ b/core/src/api/mod.rs @@ -1,14 +1,14 @@ +use std::sync::{atomic::Ordering, Arc}; + use crate::{ invalidate_query, job::JobProgressEvent, node::config::{NodeConfig, NodePreferences}, Node, }; - +use sd_cache::patch_typedef; use sd_p2p::P2PStatus; -use std::sync::{atomic::Ordering, Arc}; - use itertools::Itertools; use rspc::{alpha::Rspc, Config, ErrorCode}; use serde::{Deserialize, Serialize}; @@ -121,9 +121,11 @@ pub(crate) fn mount() -> Arc { commit: &'static str, } - R.query(|_, _: ()| BuildInfo { - version: env!("CARGO_PKG_VERSION"), - commit: env!("GIT_HASH"), + R.query(|_, _: ()| { + Ok(BuildInfo { + version: env!("CARGO_PKG_VERSION"), + commit: env!("GIT_HASH"), + }) }) }) .procedure("nodeState", { @@ -198,6 +200,18 @@ pub(crate) fn mount() -> Arc { .merge("notifications.", notifications::mount()) .merge("backups.", backups::mount()) .merge("invalidation.", utils::mount_invalidate()) + .sd_patch_types_dangerously(|type_map| { + patch_typedef(type_map); + + let def = + ::definition_named_data_type( + type_map, + ); + type_map.insert( + ::SID, + def, + ); + }) .build( #[allow(clippy::let_and_return)] { diff --git a/core/src/api/notifications.rs b/core/src/api/notifications.rs index 7b96183fd..ec8fa8a13 100644 --- a/core/src/api/notifications.rs +++ b/core/src/api/notifications.rs @@ -162,6 +162,8 @@ pub(crate) fn mount() -> AlphaRouter { .procedure("test", { R.mutation(|node, _: ()| async move { node.emit_notification(NotificationData::Test, None).await; + + Ok(()) }) }) .procedure("testLibrary", { @@ -170,6 +172,8 @@ pub(crate) fn mount() -> AlphaRouter { library .emit_notification(NotificationData::Test, None) .await; + + Ok(()) }) }) } diff --git a/core/src/api/p2p.rs b/core/src/api/p2p.rs index 38f4e6101..28bad7051 100644 --- a/core/src/api/p2p.rs +++ b/core/src/api/p2p.rs @@ -51,9 +51,10 @@ pub(crate) fn mount() -> AlphaRouter { }) }) }) - .procedure("state", { - R.query(|node, _: ()| async move { node.p2p.state() }) - }) + // TODO: This has a potentially invalid map key and Specta don't like that. Can bring back in another PR. + // .procedure("state", { + // R.query(|node, _: ()| async move { Ok(node.p2p.state()) }) + // }) .procedure("spacedrop", { #[derive(Type, Deserialize)] pub struct SpacedropArgs { @@ -81,20 +82,23 @@ pub(crate) fn mount() -> AlphaRouter { match path { Some(path) => node.p2p.accept_spacedrop(id, path).await, None => node.p2p.reject_spacedrop(id).await, - } + }; + + Ok(()) }) }) .procedure("cancelSpacedrop", { - R.mutation(|node, id: Uuid| async move { node.p2p.cancel_spacedrop(id).await }) + R.mutation(|node, id: Uuid| async move { Ok(node.p2p.cancel_spacedrop(id).await) }) }) .procedure("pair", { R.mutation(|node, id: RemoteIdentity| async move { - node.p2p.pairing.clone().originator(id, node).await + Ok(node.p2p.pairing.clone().originator(id, node).await) }) }) .procedure("pairingResponse", { R.mutation(|node, (pairing_id, decision): (u16, PairingDecision)| { node.p2p.pairing.decision(pairing_id, decision); + Ok(()) }) }) } diff --git a/core/src/api/search/mod.rs b/core/src/api/search/mod.rs index 16556abfe..79cbbeaee 100644 --- a/core/src/api/search/mod.rs +++ b/core/src/api/search/mod.rs @@ -19,6 +19,7 @@ use crate::{ use std::path::PathBuf; use rspc::{alpha::AlphaRouter, ErrorCode}; +use sd_cache::{CacheNode, Model, Normalise, Reference}; use sd_prisma::prisma::{self, PrismaClient}; use serde::{Deserialize, Serialize}; use specta::Type; @@ -28,9 +29,16 @@ use super::{Ctx, R}; const MAX_TAKE: u8 = 100; #[derive(Serialize, Type, Debug)] -struct SearchData { +struct SearchData { cursor: Option>, - items: Vec, + items: Vec>, + nodes: Vec, +} + +impl Model for SearchData { + fn name() -> &'static str { + T::name() + } } #[derive(Serialize, Deserialize, Type, Debug, Clone)] @@ -91,6 +99,13 @@ pub fn mount() -> AlphaRouter { order: Option, } + #[derive(Serialize, Type, Debug)] + struct EphemeralPathsResult { + pub entries: Vec>, + pub errors: Vec, + pub nodes: Vec, + } + R.with2(library()).query( |(node, library), EphemeralPathSearchArgs { @@ -133,7 +148,13 @@ pub fn mount() -> AlphaRouter { ) } - Ok(paths) + let (nodes, entries) = paths.entries.normalise(|item| item.id()); + + Ok(EphemeralPathsResult { + entries, + errors: paths.errors, + nodes, + }) }, ) }) @@ -217,9 +238,12 @@ pub fn mount() -> AlphaRouter { }) } + let (nodes, items) = items.normalise(|item| item.id()); + Ok(SearchData { items, cursor: None, + nodes, }) }, ) @@ -333,7 +357,13 @@ pub fn mount() -> AlphaRouter { }); } - Ok(SearchData { items, cursor }) + let (nodes, items) = items.normalise(|item| item.id()); + + Ok(SearchData { + nodes, + items, + cursor, + }) }, ) }) diff --git a/core/src/api/tags.rs b/core/src/api/tags.rs index c682aa4c1..2e4cb5066 100644 --- a/core/src/api/tags.rs +++ b/core/src/api/tags.rs @@ -1,13 +1,14 @@ use std::collections::BTreeMap; -use chrono::Utc; +use chrono::{DateTime, Utc}; use itertools::{Either, Itertools}; use rspc::{alpha::AlphaRouter, ErrorCode}; +use sd_cache::{CacheNode, Normalise, NormalisedResult, NormalisedResults, Reference}; use sd_file_ext::kind::ObjectKind; use sd_prisma::{prisma, prisma_sync}; use sd_sync::OperationFactory; use sd_utils::uuid_to_bytes; -use serde::Deserialize; +use serde::{Deserialize, Serialize}; use specta::Type; use serde_json::json; @@ -26,23 +27,43 @@ pub(crate) fn mount() -> AlphaRouter { R.router() .procedure("list", { R.with2(library()).query(|(_, library), _: ()| async move { - Ok(library.db.tag().find_many(vec![]).exec().await?) + let tags = library.db.tag().find_many(vec![]).exec().await?; + + let (nodes, items) = tags.normalise(|i| i.id.to_string()); + + Ok(NormalisedResults { nodes, items }) }) }) .procedure("getForObject", { R.with2(library()) .query(|(_, library), object_id: i32| async move { - Ok(library + let tags = library .db .tag() .find_many(vec![tag::tag_objects::some(vec![ tag_on_object::object_id::equals(object_id), ])]) .exec() - .await?) + .await?; + + let (nodes, items) = tags.normalise(|i| i.id.to_string()); + + Ok(NormalisedResults { nodes, items }) }) }) .procedure("getWithObjects", { + #[derive(Serialize, Type)] + pub struct GetWithObjectsResult { + pub data: BTreeMap>>, + pub nodes: Vec, + } + + #[derive(Serialize, Type)] + pub struct ObjectWithDateCreated { + object: Reference, + date_created: DateTime, + } + R.with2(library()).query( |(_, library), object_ids: Vec| async move { let Library { db, .. } = library.as_ref(); @@ -64,6 +85,7 @@ pub(crate) fn mount() -> AlphaRouter { .exec() .await?; + // This doesn't need normalised caching because it doesn't return whole models. Ok(tags_with_objects .into_iter() .map(|tag| (tag.id, tag.tag_objects)) @@ -79,7 +101,8 @@ pub(crate) fn mount() -> AlphaRouter { .tag() .find_unique(tag::id::equals(tag_id)) .exec() - .await?) + .await? + .map(|tag| NormalisedResult::from(tag, |i| i.id.to_string()))) }) }) .procedure("create", { diff --git a/core/src/api/utils/invalidate.rs b/core/src/api/utils/invalidate.rs index 404510677..e8957c8cd 100644 --- a/core/src/api/utils/invalidate.rs +++ b/core/src/api/utils/invalidate.rs @@ -282,7 +282,7 @@ pub(crate) fn mount_invalidate() -> AlphaRouter { R.router() .procedure( "test-invalidate", - R.query(move |_, _: ()| count.fetch_add(1, Ordering::SeqCst)), + R.query(move |_, _: ()| Ok(count.fetch_add(1, Ordering::SeqCst))), ) .procedure( "test-invalidate-mutation", diff --git a/core/src/api/volumes.rs b/core/src/api/volumes.rs index 07adaaa00..cf4aee31d 100644 --- a/core/src/api/volumes.rs +++ b/core/src/api/volumes.rs @@ -1,4 +1,5 @@ use rspc::alpha::AlphaRouter; +use sd_cache::{Normalise, NormalisedResults}; use crate::volume::get_volumes; @@ -6,6 +7,23 @@ use super::{Ctx, R}; pub(crate) fn mount() -> AlphaRouter { R.router().procedure("list", { - R.query(|_, _: ()| async move { Ok(get_volumes().await) }) + R.query(|_, _: ()| async move { + let volumes = get_volumes().await; + + let (nodes, items) = volumes.normalise(|i| { + // TODO: This is a really bad key. Once we hook up volumes with the DB fix this! + blake3::hash( + &i.mount_points + .iter() + .map(|mp| mp.as_os_str().to_string_lossy().as_bytes().to_vec()) + .flatten() + .collect::>(), + ) + .to_hex() + .to_string() + }); + + Ok(NormalisedResults { nodes, items }) + }) }) } diff --git a/core/src/p2p/peer_metadata.rs b/core/src/p2p/peer_metadata.rs index 4a84c4051..6cd3a1483 100644 --- a/core/src/p2p/peer_metadata.rs +++ b/core/src/p2p/peer_metadata.rs @@ -8,9 +8,9 @@ use crate::node::Platform; #[derive(Debug, Clone, Type, Serialize, Deserialize)] pub struct PeerMetadata { - pub(super) name: String, - pub(super) operating_system: Option, - pub(super) version: Option, + pub name: String, + pub operating_system: Option, + pub version: Option, } impl Metadata for PeerMetadata { diff --git a/core/src/volume/mod.rs b/core/src/volume/mod.rs index 3622c1ee3..734b4c5bc 100644 --- a/core/src/volume/mod.rs +++ b/core/src/volume/mod.rs @@ -7,6 +7,7 @@ use std::{ sync::OnceLock, }; +use sd_cache::Model; use serde::{Deserialize, Serialize}; use serde_with::{serde_as, DisplayFromStr}; use specta::Type; @@ -56,6 +57,12 @@ pub struct Volume { pub is_root_filesystem: bool, } +impl Model for Volume { + fn name() -> &'static str { + "Volume" + } +} + impl Hash for Volume { fn hash(&self, state: &mut H) { self.name.hash(state); diff --git a/crates/cache/Cargo.toml b/crates/cache/Cargo.toml new file mode 100644 index 000000000..279c194ef --- /dev/null +++ b/crates/cache/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "sd-cache" +version = "0.0.0" +license.workspace = true +edition.workspace = true +repository.workspace = true + +[dependencies] +serde.workspace = true +serde_json.workspace = true +specta.workspace = true diff --git a/crates/cache/src/lib.rs b/crates/cache/src/lib.rs new file mode 100644 index 000000000..2f798688a --- /dev/null +++ b/crates/cache/src/lib.rs @@ -0,0 +1,198 @@ +use std::{marker::PhantomData, sync::Arc}; + +use serde::{ser::SerializeMap, Serialize, Serializer}; +use specta::{Any, DataType, NamedType, Type, TypeMap}; + +/// A type that can be used to return a group of `Reference` and `CacheNode`'s +/// +/// You don't need to use this, it's just a shortcut to avoid having to write out the full type everytime. +#[derive(Serialize, Type, Debug)] +pub struct NormalisedResults { + pub items: Vec>, + pub nodes: Vec, +} + +/// A type that can be used to return a group of `Reference` and `CacheNode`'s +/// +/// You don't need to use this, it's just a shortcut to avoid having to write out the full type everytime. +#[derive(Serialize, Type, Debug)] +pub struct NormalisedResult { + pub item: Reference, + pub nodes: Vec, +} + +impl NormalisedResult { + pub fn from(item: T, id_fn: impl Fn(&T) -> String) -> Self { + let id = id_fn(&item); + Self { + item: Reference::new(id.clone()), + nodes: vec![CacheNode::new(id, item)], + } + } +} + +/// A type which can be stored in the cache. +pub trait Model { + /// Must return a unique identifier for this model within the cache. + fn name() -> &'static str; +} + +/// A reference to a `CacheNode`. +/// +/// This does not contain the actual data, but instead a reference to it. +/// This allows the CacheNode's to be switched out and the query recomputed without any backend communication. +/// +/// If you use a `Reference` in a query, you *must* ensure the corresponding `CacheNode` is also in the query. +#[derive(Type, Debug, Clone, Hash, PartialEq, Eq)] +pub struct Reference { + __type: &'static str, + __id: String, + #[specta(rename = "#type")] + ty: PhantomType, +} + +impl Reference { + pub fn new(key: String) -> Self { + Self { + __type: "", // This is just to fake the field for Specta + __id: key, + ty: PhantomType(PhantomData), + } + } +} + +impl Serialize for Reference { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + let mut map = serializer.serialize_map(Some(2))?; + map.serialize_entry("__type", T::name())?; + map.serialize_entry("__id", &self.__id)?; + map.end() + } +} + +/// A node in the cache. +/// This holds the data and is identified by it's type and id. +#[derive(Debug, Clone)] // TODO: `Hash, PartialEq, Eq` +pub struct CacheNode( + &'static str, + serde_json::Value, + Result>, +); + +impl CacheNode { + pub fn new(key: String, value: T) -> Self { + Self( + T::name(), + key.into(), + serde_json::to_value(value).map_err(Arc::new), + ) + } +} + +#[derive(Type, Default)] +#[specta(rename = "CacheNode", remote = CacheNode)] +#[allow(unused)] +struct CacheNodeTy { + __type: String, + __id: String, + #[specta(rename = "#node")] + node: Any, +} + +#[derive(Serialize)] +struct NodeSerdeRepr<'a> { + __type: &'static str, + __id: &'a serde_json::Value, + #[serde(flatten)] + v: &'a serde_json::Value, +} + +impl Serialize for CacheNode { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + NodeSerdeRepr { + __type: self.0, + __id: &self.1, + v: self.2.as_ref().map_err(|err| { + serde::ser::Error::custom(format!("Failed to serialise node: {}", err)) + })?, + } + .serialize(serializer) + } +} + +/// A helper for easily normalising data. +pub trait Normalise { + type Item: Model + Type; + + fn normalise( + self, + id_fn: impl Fn(&Self::Item) -> String, + ) -> (Vec, Vec>); +} + +impl Normalise for Vec { + type Item = T; + + fn normalise( + self, + id_fn: impl Fn(&Self::Item) -> String, + ) -> (Vec, Vec>) { + let mut nodes = Vec::with_capacity(self.len()); + let mut references = Vec::with_capacity(self.len()); + + for item in self.into_iter() { + let id = id_fn(&item); + nodes.push(CacheNode::new(id.clone(), item)); + references.push(Reference::new(id)); + } + + (nodes, references) + } +} + +/// Basically `PhantomData`. +/// +/// With Specta `PhantomData` is exported as `null`. +/// This will export as `T` but serve the same purpose as `PhantomData` (holding a type without it being instantiated). +#[derive(Debug, Clone, Hash, PartialEq, Eq)] +pub struct PhantomType(PhantomData); + +/// WARNING: This type is surgically updated within `Reference` in the final typedefs due it being impossible to properly implement. +/// Be careful changing it! + +impl Type for PhantomType { + fn inline(type_map: &mut TypeMap, generics: &[DataType]) -> DataType { + T::inline(type_map, generics) + } + + fn reference(type_map: &mut TypeMap, generics: &[DataType]) -> specta::reference::Reference { + T::reference(type_map, generics) + } + + fn definition(type_map: &mut TypeMap) -> DataType { + T::definition(type_map) + } +} + +// This function is cursed. +pub fn patch_typedef(type_map: &mut TypeMap) { + #[derive(Type)] + #[specta(rename = "Reference")] + #[allow(unused)] + struct ReferenceTy { + __type: &'static str, + __id: String, + #[specta(rename = "#type")] + ty: T, + } + + let mut def = as NamedType>::definition_named_data_type(type_map); + def.inner = ReferenceTy::::definition(type_map); + type_map.insert( as NamedType>::SID, def) +} diff --git a/crates/p2p/src/spacetunnel/identity.rs b/crates/p2p/src/spacetunnel/identity.rs index 42d4c0fea..66e41e477 100644 --- a/crates/p2p/src/spacetunnel/identity.rs +++ b/crates/p2p/src/spacetunnel/identity.rs @@ -62,8 +62,9 @@ impl Identity { } } -#[derive(Copy, Clone, PartialEq, Eq)] -pub struct RemoteIdentity(ed25519_dalek::VerifyingKey); +#[derive(Copy, Clone, PartialEq, Eq, Type)] +#[specta(transparent)] +pub struct RemoteIdentity(#[specta(type = String)] ed25519_dalek::VerifyingKey); impl Hash for RemoteIdentity { fn hash(&self, state: &mut H) { @@ -141,15 +142,6 @@ impl FromStr for RemoteIdentity { } } -impl Type for RemoteIdentity { - fn inline( - _: specta::DefOpts, - _: &[specta::DataType], - ) -> Result { - Ok(specta::DataType::Primitive(specta::PrimitiveType::String)) - } -} - impl RemoteIdentity { pub fn from_bytes(bytes: &[u8]) -> Result { Ok(Self(ed25519_dalek::VerifyingKey::from_bytes( diff --git a/crates/prisma/Cargo.toml b/crates/prisma/Cargo.toml index 5a6e7ab73..d57dfd69d 100644 --- a/crates/prisma/Cargo.toml +++ b/crates/prisma/Cargo.toml @@ -8,3 +8,4 @@ prisma-client-rust = { workspace = true } serde = "1.0" serde_json = "1.0" sd-sync = { path = "../sync" } +sd-cache = { path = "../cache" } diff --git a/crates/prisma/src/lib.rs b/crates/prisma/src/lib.rs index 8fc4cadc3..a2ecc0253 100644 --- a/crates/prisma/src/lib.rs +++ b/crates/prisma/src/lib.rs @@ -2,3 +2,33 @@ pub mod prisma; #[allow(warnings, unused)] pub mod prisma_sync; + +impl sd_cache::Model for prisma::tag::Data { + fn name() -> &'static str { + "Tag" + } +} + +impl sd_cache::Model for prisma::object::Data { + fn name() -> &'static str { + "Object" + } +} + +impl sd_cache::Model for prisma::location::Data { + fn name() -> &'static str { + "Location" + } +} + +impl sd_cache::Model for prisma::indexer_rule::Data { + fn name() -> &'static str { + "IndexerRule" + } +} + +impl sd_cache::Model for prisma::file_path::Data { + fn name() -> &'static str { + "FilePath" + } +} diff --git a/interface/app/$libraryId/Explorer/ContextMenu/AssignTagMenuItems.tsx b/interface/app/$libraryId/Explorer/ContextMenu/AssignTagMenuItems.tsx index f59e2e1f0..307d2263c 100644 --- a/interface/app/$libraryId/Explorer/ContextMenu/AssignTagMenuItems.tsx +++ b/interface/app/$libraryId/Explorer/ContextMenu/AssignTagMenuItems.tsx @@ -2,9 +2,9 @@ import { Plus } from '@phosphor-icons/react'; import { useQueryClient } from '@tanstack/react-query'; import { useVirtualizer } from '@tanstack/react-virtual'; import clsx from 'clsx'; -import { forwardRef, MutableRefObject, RefObject, useMemo, useRef } from 'react'; +import { RefObject, useMemo, useRef } from 'react'; import { ErrorBoundary } from 'react-error-boundary'; -import { ExplorerItem, useLibraryQuery } from '@sd/client'; +import { ExplorerItem, useCache, useLibraryQuery, useNodes } from '@sd/client'; import { Button, dialogManager, ModifierKeys, tw } from '@sd/ui'; import CreateDialog, { AssignTagItems, @@ -23,6 +23,7 @@ interface Props { function useData({ items }: Props) { const tags = useLibraryQuery(['tags.list'], { suspense: true }); + useNodes(tags.data?.nodes); // Map> const tagsWithObjects = useLibraryQuery( @@ -38,7 +39,13 @@ function useData({ items }: Props) { { suspense: true } ); - return { tags, tagsWithObjects }; + return { + tags: { + ...tags, + data: useCache(tags.data?.items) + }, + tagsWithObjects + }; } export default (props: Props) => { diff --git a/interface/app/$libraryId/Explorer/Inspector/index.tsx b/interface/app/$libraryId/Explorer/Inspector/index.tsx index 2e5e444a2..8285c333e 100644 --- a/interface/app/$libraryId/Explorer/Inspector/index.tsx +++ b/interface/app/$libraryId/Explorer/Inspector/index.tsx @@ -37,8 +37,10 @@ import { ObjectKindEnum, ObjectWithFilePaths, useBridgeQuery, + useCache, useItemsAsObjects, useLibraryQuery, + useNodes, type ExplorerItem } from '@sd/client'; import { Button, Divider, DropdownMenu, toast, Tooltip, tw } from '@sd/ui'; @@ -172,7 +174,9 @@ export const SingleItemMetadata = ({ item }: { item: ExplorerItem }) => { let filePathData: FilePath | FilePathWithObject | null = null; let ephemeralPathData: NonIndexedPathItem | null = null; - const locations = useLibraryQuery(['locations.list']); + const result = useLibraryQuery(['locations.list']); + useNodes(result.data?.nodes); + const locations = useCache(result.data?.items); switch (item.type) { case 'NonIndexedPath': { @@ -209,12 +213,15 @@ export const SingleItemMetadata = ({ item }: { item: ExplorerItem }) => { }, [item]); const fileLocations = - locations.data?.filter((location) => uniqueLocationIds.includes(location.id)) || []; + locations?.filter((location) => uniqueLocationIds.includes(location.id)) || []; const readyToFetch = useIsFetchReady(item); - const tags = useLibraryQuery(['tags.getForObject', objectData?.id ?? -1], { + const tagsQuery = useLibraryQuery(['tags.getForObject', objectData?.id ?? -1], { enabled: objectData != null && readyToFetch }); + useNodes(tagsQuery.data?.nodes); + const tags = useCache(tagsQuery.data?.items); + const { libraryId } = useZodRouteParams(LibraryIdParamsSchema); const queriedFullPath = useLibraryQuery(['files.getPath', filePathData?.id ?? -1], { @@ -332,7 +339,7 @@ export const SingleItemMetadata = ({ item }: { item: ExplorerItem }) => { {extension && {extension}} - {tags.data?.map((tag) => ( + {tags?.map((tag) => ( { const { libraryId } = useZodRouteParams(LibraryIdParamsSchema); - const tags = useLibraryQuery(['tags.list'], { + const tagsQuery = useLibraryQuery(['tags.list'], { enabled: readyToFetch && !explorerStore.isDragging, suspense: true }); + useNodes(tagsQuery.data?.nodes); + const tags = useCache(tagsQuery.data?.items); const tagsWithObjects = useLibraryQuery( ['tags.getWithObjects', selectedObjects.map(({ id }) => id)], @@ -487,7 +496,7 @@ const MultiItemMetadata = ({ items }: { items: ExplorerItem[] }) => { {`${kind} (${items.length})`} ))} - {tags.data?.map((tag) => { + {tags?.map((tag) => { const objectsWithTag = tagsWithObjects.data?.[tag.id] || []; if (objectsWithTag.length === 0) return null; diff --git a/interface/app/$libraryId/Explorer/queries/useExplorerQuery.ts b/interface/app/$libraryId/Explorer/queries/useExplorerQuery.ts index cef450742..cec82d0c3 100644 --- a/interface/app/$libraryId/Explorer/queries/useExplorerQuery.ts +++ b/interface/app/$libraryId/Explorer/queries/useExplorerQuery.ts @@ -1,6 +1,6 @@ import { UseInfiniteQueryResult, UseQueryResult } from '@tanstack/react-query'; import { useCallback, useMemo } from 'react'; -import { SearchData } from '@sd/client'; +import { SearchData, useCache } from '@sd/client'; export function useExplorerQuery( query: UseInfiniteQueryResult>, @@ -14,7 +14,7 @@ export function useExplorerQuery( } }, [query.hasNextPage, query.isFetchingNextPage, query.fetchNextPage]); - return { query, items, loadMore, count: count.data }; + return { query, items: useCache(items), loadMore, count: count.data }; } export type UseExplorerQuery = ReturnType>; diff --git a/interface/app/$libraryId/Explorer/queries/useObjectsInfiniteQuery.ts b/interface/app/$libraryId/Explorer/queries/useObjectsInfiniteQuery.ts index 4da209df8..ae75148b3 100644 --- a/interface/app/$libraryId/Explorer/queries/useObjectsInfiniteQuery.ts +++ b/interface/app/$libraryId/Explorer/queries/useObjectsInfiniteQuery.ts @@ -1,10 +1,12 @@ import { useInfiniteQuery } from '@tanstack/react-query'; +import { useMemo } from 'react'; import { ExplorerItem, ObjectCursor, ObjectOrder, ObjectSearchArgs, useLibraryContext, + useNodes, useRspcLibraryContext } from '@sd/client'; @@ -23,7 +25,7 @@ export function useObjectsInfiniteQuery({ arg.orderAndPagination = { orderOnly: settings.order }; } - return useInfiniteQuery({ + const query = useInfiniteQuery({ queryKey: ['search.objects', { library_id: library.uuid, arg }] as const, queryFn: ({ pageParam, queryKey: [_, { arg }] }) => { const cItem: Extract = pageParam; @@ -66,4 +68,13 @@ export function useObjectsInfiniteQuery({ }, ...args }); + + const nodes = useMemo( + () => query.data?.pages.flatMap((page) => page.nodes) ?? [], + [query.data?.pages] + ); + + useNodes(nodes); + + return query; } diff --git a/interface/app/$libraryId/Explorer/queries/usePathsInfiniteQuery.ts b/interface/app/$libraryId/Explorer/queries/usePathsInfiniteQuery.ts index 3e722a7ca..85dbafd9c 100644 --- a/interface/app/$libraryId/Explorer/queries/usePathsInfiniteQuery.ts +++ b/interface/app/$libraryId/Explorer/queries/usePathsInfiniteQuery.ts @@ -1,4 +1,5 @@ import { useInfiniteQuery } from '@tanstack/react-query'; +import { useMemo } from 'react'; import { ExplorerItem, FilePathCursorVariant, @@ -6,6 +7,8 @@ import { FilePathOrder, FilePathSearchArgs, useLibraryContext, + useNodes, + useNormalisedCache, useRspcLibraryContext } from '@sd/client'; @@ -20,15 +23,16 @@ export function usePathsInfiniteQuery({ const { library } = useLibraryContext(); const ctx = useRspcLibraryContext(); const settings = explorerSettings.useSettingsSnapshot(); + const cache = useNormalisedCache(); if (settings.order) { arg.orderAndPagination = { orderOnly: settings.order }; if (arg.orderAndPagination.orderOnly.field === 'sizeInBytes') delete arg.take; } - return useInfiniteQuery({ + const query = useInfiniteQuery({ queryKey: ['search.paths', { library_id: library.uuid, arg }] as const, - queryFn: ({ pageParam, queryKey: [_, { arg }] }) => { + queryFn: async ({ pageParam, queryKey: [_, { arg }] }) => { const cItem: Extract = pageParam; const { order } = settings; @@ -120,7 +124,9 @@ export function usePathsInfiniteQuery({ arg.orderAndPagination = orderAndPagination; - return ctx.client.query(['search.paths', arg]); + const result = await ctx.client.query(['search.paths', arg]); + cache.withNodes(result.nodes); + return result; }, getNextPageParam: (lastPage) => { if (arg.take === null || arg.take === undefined) return undefined; @@ -130,4 +136,13 @@ export function usePathsInfiniteQuery({ onSuccess: () => getExplorerStore().resetNewThumbnails(), ...args }); + + const nodes = useMemo( + () => query.data?.pages.flatMap((page) => page.nodes) ?? [], + [query.data?.pages] + ); + + useNodes(nodes); + + return query; } diff --git a/interface/app/$libraryId/Layout/Sidebar/DebugPopover.tsx b/interface/app/$libraryId/Layout/Sidebar/DebugPopover.tsx index 33ed43cbe..673809a23 100644 --- a/interface/app/$libraryId/Layout/Sidebar/DebugPopover.tsx +++ b/interface/app/$libraryId/Layout/Sidebar/DebugPopover.tsx @@ -1,4 +1,5 @@ import { CheckSquare } from '@phosphor-icons/react'; +import { useNavigate } from 'react-router'; import { backendFeatures, features, @@ -31,6 +32,7 @@ export default () => { const debugState = useDebugState(); const platform = usePlatform(); + const navigate = useNavigate(); return ( { + {/* {platform.showDevtools && ( { }; export const EphemeralSection = () => { - const locations = useLibraryQuery(['locations.list']); + const locationsQuery = useLibraryQuery(['locations.list']); + useNodes(locationsQuery.data?.nodes); + const locations = useCache(locationsQuery.data?.items); const homeDir = useHomeDir(); - const volumes = useBridgeQuery(['volumes.list']); + const result = useBridgeQuery(['volumes.list']); + useNodes(result.data?.nodes); + const volumes = useCache(result.data?.items); // this will return an array of location ids that are also volumes // { "/Mount/Point": 1, "/Mount/Point2": 2"} const locationIdsForVolumes = useMemo(() => { - if (!locations.data || !volumes.data) return {}; + if (!locations || !volumes) return {}; - const volumePaths = volumes.data.map((volume) => volume.mount_points[0] ?? null); + const volumePaths = volumes.map((volume) => volume.mount_points[0] ?? null); - const matchedLocations = locations.data.filter((location) => + const matchedLocations = locations.filter((location) => volumePaths.includes(location.path) ); @@ -57,9 +61,9 @@ export const EphemeralSection = () => { ); return locationIdsMap; - }, [locations.data, volumes.data]); + }, [locations, volumes]); - const mountPoints = (volumes.data || []).flatMap((volume, volumeIndex) => + const mountPoints = (volumes || []).flatMap((volume, volumeIndex) => volume.mount_points.map((mountPoint, index) => mountPoint !== homeDir.data ? { type: 'volume', volume, mountPoint, volumeIndex, index } diff --git a/interface/app/$libraryId/Layout/Sidebar/LibrarySection.tsx b/interface/app/$libraryId/Layout/Sidebar/LibrarySection.tsx index e6dbbef52..46ceccfa9 100644 --- a/interface/app/$libraryId/Layout/Sidebar/LibrarySection.tsx +++ b/interface/app/$libraryId/Layout/Sidebar/LibrarySection.tsx @@ -5,9 +5,11 @@ import { Link, NavLink } from 'react-router-dom'; import { arraysEqual, useBridgeQuery, + useCache, useFeatureFlag, useLibraryMutation, useLibraryQuery, + useNodes, useOnlineLocations } from '@sd/client'; import { Button, Tooltip } from '@sd/ui'; @@ -138,6 +140,8 @@ function Devices() { function Locations() { const locationsQuery = useLibraryQuery(['locations.list'], { keepPreviousData: true }); + useNodes(locationsQuery.data?.nodes); + const locations = useCache(locationsQuery.data?.items); const onlineLocations = useOnlineLocations(); return ( @@ -150,7 +154,7 @@ function Locations() { } > - {locationsQuery.data?.map((location) => ( + {locations?.map((location) => ( - {tags.data?.map((tag) => ( + {tags?.map((tag) => ( { const query = useLibraryQuery(['locations.list'], { keepPreviousData: true }); + useNodes(query.data?.nodes); + const locations = useCache(query.data?.items); - return (query.data ?? []).map((location) => ({ + return (locations ?? []).map((location) => ({ name: location.name!, value: location.id, icon: 'Folder' // Spacedrive folder icon @@ -455,8 +465,10 @@ export const filterRegistry = [ }, useOptions: () => { const query = useLibraryQuery(['tags.list'], { keepPreviousData: true }); + useNodes(query.data?.nodes); + const tags = useCache(query.data?.items); - return (query.data ?? []).map((tag) => ({ + return (tags ?? []).map((tag) => ({ name: tag.name!, value: tag.id, icon: tag.color || 'CircleDashed' diff --git a/interface/app/$libraryId/debug.tsx b/interface/app/$libraryId/debug.tsx deleted file mode 100644 index 6fd222ff0..000000000 --- a/interface/app/$libraryId/debug.tsx +++ /dev/null @@ -1,46 +0,0 @@ -import { useBridgeQuery, useLibraryQuery } from '@sd/client'; -import { CodeBlock } from '~/components/Codeblock'; -import { useRouteTitle } from '~/hooks/useRouteTitle'; - -// TODO: Bring this back with a button in the sidebar near settings at the bottom -export const Component = () => { - useRouteTitle('Debug'); - - const { data: nodeState } = useBridgeQuery(['nodeState']); - const { data: libraryState } = useBridgeQuery(['library.list']); - // const { data: jobs } = useLibraryQuery(['jobs.getRunning']); - // const { data: jobHistory } = useLibraryQuery(['jobs.getHistory']); - // const { mutate: purgeDB } = useBridgeCommand('PurgeDatabase', { - // onMutate: () => { - // alert('Database purged'); - // } - // }); - // const { mutate: identifyFiles } = useLibraryMutation('jobs.identifyUniqueFiles'); - return ( -
-

Developer Debugger

- {/*
- -
*/} - {/*

Running Jobs

- -

Job History

- */} -

Node State

- -

Libraries

- -
- ); -}; diff --git a/interface/app/$libraryId/debug/cache.tsx b/interface/app/$libraryId/debug/cache.tsx new file mode 100644 index 000000000..4f6bdd304 --- /dev/null +++ b/interface/app/$libraryId/debug/cache.tsx @@ -0,0 +1,13 @@ +import { snapshot } from 'valtio'; +import { useNormalisedCache } from '@sd/client'; + +export function Component() { + const cache = useNormalisedCache(); + const data = snapshot(cache['#cache']); + return ( +
+

Cache Debug

+
{JSON.stringify(data, null, 2)}
+
+ ); +} diff --git a/interface/app/$libraryId/debug/index.ts b/interface/app/$libraryId/debug/index.ts new file mode 100644 index 000000000..7c6058b2e --- /dev/null +++ b/interface/app/$libraryId/debug/index.ts @@ -0,0 +1,5 @@ +import { RouteObject } from 'react-router'; + +export const debugRoutes: RouteObject = { + children: [{ path: 'cache', lazy: () => import('./cache') }] +}; diff --git a/interface/app/$libraryId/ephemeral.tsx b/interface/app/$libraryId/ephemeral.tsx index 310f0b3d3..2ad3fba27 100644 --- a/interface/app/$libraryId/ephemeral.tsx +++ b/interface/app/$libraryId/ephemeral.tsx @@ -7,7 +7,9 @@ import { useLocation } from 'react-router'; import { ExplorerItem, getExplorerItemData, + useCache, useLibraryQuery, + useNodes, type EphemeralPathOrder } from '@sd/client'; import { Button, Tooltip } from '@sd/ui'; @@ -189,13 +191,15 @@ const EphemeralExplorer = memo((props: { args: PathParams }) => { onSuccess: () => getExplorerStore().resetNewThumbnails() } ); + useNodes(query.data?.nodes); + const entries = useCache(query.data?.entries); const items = useMemo(() => { - if (!query.data) return []; + if (!entries) return []; const ret: ExplorerItem[] = []; - for (const item of query.data.entries) { + for (const item of entries) { if (settingsSnapshot.layoutMode !== 'media') ret.push(item); else { const { kind } = getExplorerItemData(item); @@ -205,7 +209,7 @@ const EphemeralExplorer = memo((props: { args: PathParams }) => { } return ret; - }, [query.data, settingsSnapshot.layoutMode]); + }, [entries, settingsSnapshot.layoutMode]); const explorer = useExplorer({ items, diff --git a/interface/app/$libraryId/index.tsx b/interface/app/$libraryId/index.tsx index 9c22e5ebd..77b89f949 100644 --- a/interface/app/$libraryId/index.tsx +++ b/interface/app/$libraryId/index.tsx @@ -3,6 +3,7 @@ import { Navigate, type RouteObject } from 'react-router-dom'; import { useHomeDir } from '~/hooks/useHomeDir'; import { Platform } from '~/util/Platform'; +import { debugRoutes } from './debug'; import settingsRoutes from './settings'; // Routes that should be contained within the standard Page layout @@ -12,9 +13,9 @@ const pageRoutes: RouteObject = { { path: 'people', lazy: () => import('./people') }, { path: 'media', lazy: () => import('./media') }, { path: 'spaces', lazy: () => import('./spaces') }, - { path: 'debug', lazy: () => import('./debug') }, { path: 'sync', lazy: () => import('./sync') }, - { path: 'cloud', lazy: () => import('./cloud') } + { path: 'cloud', lazy: () => import('./cloud') }, + { path: 'debug', children: [debugRoutes] } ] }; diff --git a/interface/app/$libraryId/location/$id.tsx b/interface/app/$libraryId/location/$id.tsx index 222899c26..4d3b02897 100644 --- a/interface/app/$libraryId/location/$id.tsx +++ b/interface/app/$libraryId/location/$id.tsx @@ -7,9 +7,11 @@ import { FilePathOrder, Location, ObjectKindEnum, + useCache, useLibraryMutation, useLibraryQuery, useLibrarySubscription, + useNodes, useOnlineLocations, useRspcLibraryContext } from '@sd/client'; @@ -41,12 +43,14 @@ import LocationOptions from './LocationOptions'; export const Component = () => { const { id: locationId } = useZodRouteParams(LocationIdParamsSchema); - const location = useLibraryQuery(['locations.get', locationId], { + const result = useLibraryQuery(['locations.get', locationId], { keepPreviousData: true, suspense: true }); + useNodes(result.data?.nodes); + const location = useCache(result.data?.item); - return ; + return ; }; const LocationExplorer = ({ location }: { location: Location; path?: string }) => { diff --git a/interface/app/$libraryId/saved-search/$id.tsx b/interface/app/$libraryId/saved-search/$id.tsx index d47d4e9d6..023c8cdd2 100644 --- a/interface/app/$libraryId/saved-search/$id.tsx +++ b/interface/app/$libraryId/saved-search/$id.tsx @@ -1,7 +1,13 @@ import { MagnifyingGlass } from '@phosphor-icons/react'; import { getIcon, iconNames } from '@sd/assets/util'; import { useMemo } from 'react'; -import { FilePathOrder, SearchFilterArgs, useLibraryMutation, useLibraryQuery } from '@sd/client'; +import { + FilePathOrder, + SearchFilterArgs, + useCache, + useLibraryMutation, + useLibraryQuery +} from '@sd/client'; import { Button } from '@sd/ui'; import { SearchIdParamsSchema } from '~/app/route-schemas'; import { useRouteTitle, useZodRouteParams } from '~/hooks'; diff --git a/interface/app/$libraryId/settings/client/usage.tsx b/interface/app/$libraryId/settings/client/usage.tsx index 9508a9a44..4e8e336c5 100644 --- a/interface/app/$libraryId/settings/client/usage.tsx +++ b/interface/app/$libraryId/settings/client/usage.tsx @@ -1,6 +1,6 @@ import { iconNames } from '@sd/assets/util'; import { memo, useEffect, useMemo, useState } from 'react'; -import { byteSize, useDiscoveredPeers, useLibraryQuery } from '@sd/client'; +import { byteSize, useDiscoveredPeers, useLibraryQuery, useNodes } from '@sd/client'; import { Card } from '@sd/ui'; import { Icon } from '~/components'; import { useCounter } from '~/hooks'; @@ -15,6 +15,9 @@ export const Component = () => { const locations = useLibraryQuery(['locations.list'], { refetchOnWindowFocus: false }); + useNodes(locations.data?.nodes); + // const locations = useCache(result.data?.items); + const discoveredPeers = useDiscoveredPeers(); const info = useMemo(() => { if (locations.data && discoveredPeers) { @@ -33,8 +36,8 @@ export const Component = () => { }[] = [ { icon: 'Folder', - title: locations.data.length === 1 ? 'Location' : 'Locations', - titleCount: locations.data?.length ?? 0, + title: locations.data?.items.length === 1 ? 'Location' : 'Locations', + titleCount: locations.data?.items.length ?? 0, sub: 'indexed directories' }, { diff --git a/interface/app/$libraryId/settings/library/locations/$id.tsx b/interface/app/$libraryId/settings/library/locations/$id.tsx index aa0655f0b..706ee1b88 100644 --- a/interface/app/$libraryId/settings/library/locations/$id.tsx +++ b/interface/app/$libraryId/settings/library/locations/$id.tsx @@ -3,7 +3,7 @@ import { useQueryClient } from '@tanstack/react-query'; import { Suspense } from 'react'; import { Controller } from 'react-hook-form'; import { useNavigate } from 'react-router'; -import { useLibraryMutation, useLibraryQuery, useZodForm } from '@sd/client'; +import { useCache, useLibraryMutation, useLibraryQuery, useNodes, useZodForm } from '@sd/client'; import { Button, dialogManager, @@ -54,21 +54,22 @@ const EditLocationForm = () => { const fullRescan = useLibraryMutation('locations.fullRescan'); const queryClient = useQueryClient(); - const locationData = useLibraryQuery(['locations.getWithRules', locationId], { + const locationDataQuery = useLibraryQuery(['locations.getWithRules', locationId], { suspense: true }); + useNodes(locationDataQuery.data?.nodes); + const locationData = useCache(locationDataQuery.data?.item); const form = useZodForm({ schema, defaultValues: { - indexerRulesIds: - locationData.data?.indexer_rules.map((rule) => rule.indexer_rule.id) ?? [], + indexerRulesIds: locationData?.indexer_rules.map((rule) => rule.id) ?? [], locationType: 'normal', - name: locationData.data?.name ?? '', - path: locationData.data?.path ?? '', - hidden: locationData.data?.hidden ?? false, - syncPreviewMedia: locationData.data?.sync_preview_media ?? false, - generatePreviewMedia: locationData.data?.generate_preview_media ?? false + name: locationData?.name ?? '', + path: locationData?.path ?? '', + hidden: locationData?.hidden ?? false, + syncPreviewMedia: locationData?.sync_preview_media ?? false, + generatePreviewMedia: locationData?.generate_preview_media ?? false } }); diff --git a/interface/app/$libraryId/settings/library/locations/AddLocationDialog.tsx b/interface/app/$libraryId/settings/library/locations/AddLocationDialog.tsx index b8229982b..323af33a8 100644 --- a/interface/app/$libraryId/settings/library/locations/AddLocationDialog.tsx +++ b/interface/app/$libraryId/settings/library/locations/AddLocationDialog.tsx @@ -4,8 +4,10 @@ import { useDebouncedCallback } from 'use-debounce'; import { extractInfoRSPCError, UnionToTuple, + useCache, useLibraryMutation, useLibraryQuery, + useNodes, usePlausibleEvent, useZodForm } from '@sd/client'; @@ -57,13 +59,15 @@ export const AddLocationDialog = ({ const listLocations = useLibraryQuery(['locations.list']); const createLocation = useLibraryMutation('locations.create'); const relinkLocation = useLibraryMutation('locations.relink'); - const listIndexerRules = useLibraryQuery(['locations.indexer_rules.list']); + const listIndexerRulesQuery = useLibraryQuery(['locations.indexer_rules.list']); + useNodes(listIndexerRulesQuery.data?.nodes); + const listIndexerRules = useCache(listIndexerRulesQuery.data?.items); const addLocationToLibrary = useLibraryMutation('locations.addLibrary'); // This is required because indexRules is undefined on first render const indexerRulesIds = useMemo( - () => listIndexerRules.data?.filter((rule) => rule.default).map((rule) => rule.id) ?? [], - [listIndexerRules.data] + () => listIndexerRules?.filter((rule) => rule.default).map((rule) => rule.id) ?? [], + [listIndexerRules] ); const form = useZodForm({ diff --git a/interface/app/$libraryId/settings/library/locations/IndexerRuleEditor/index.tsx b/interface/app/$libraryId/settings/library/locations/IndexerRuleEditor/index.tsx index 4801cb50a..ff1880869 100644 --- a/interface/app/$libraryId/settings/library/locations/IndexerRuleEditor/index.tsx +++ b/interface/app/$libraryId/settings/library/locations/IndexerRuleEditor/index.tsx @@ -2,7 +2,7 @@ import { Trash } from '@phosphor-icons/react'; import clsx from 'clsx'; import { MouseEventHandler, useState } from 'react'; import { ControllerRenderProps } from 'react-hook-form'; -import { IndexerRule, useLibraryMutation, useLibraryQuery } from '@sd/client'; +import { IndexerRule, useCache, useLibraryMutation, useLibraryQuery, useNodes } from '@sd/client'; import { Button, Divider, Label, toast } from '@sd/ui'; import { InfoText } from '@sd/ui/src/forms'; import { showAlertDialog } from '~/components'; @@ -33,7 +33,8 @@ export default function IndexerRuleEditor({ ...props }: IndexerRuleEditorProps) { const listIndexerRules = useLibraryQuery(['locations.indexer_rules.list']); - const indexRules = listIndexerRules.data; + useNodes(listIndexerRules.data?.nodes); + const indexRules = useCache(listIndexerRules.data?.items); const [isDeleting, setIsDeleting] = useState(false); const [selectedRule, setSelectedRule] = useState(undefined); const [toggleNewRule, setToggleNewRule] = useState(false); diff --git a/interface/app/$libraryId/settings/library/locations/index.tsx b/interface/app/$libraryId/settings/library/locations/index.tsx index 948780d03..da71c6f43 100644 --- a/interface/app/$libraryId/settings/library/locations/index.tsx +++ b/interface/app/$libraryId/settings/library/locations/index.tsx @@ -1,6 +1,6 @@ import { useMemo, useState } from 'react'; import { useDebounce } from 'use-debounce'; -import { useLibraryQuery } from '@sd/client'; +import { useCache, useLibraryQuery, useNodes } from '@sd/client'; import { SearchInput } from '@sd/ui'; import { Heading } from '../../Layout'; @@ -8,17 +8,19 @@ import { AddLocationButton } from './AddLocationButton'; import ListItem from './ListItem'; export const Component = () => { - const locations = useLibraryQuery(['locations.list']); + const locationsQuery = useLibraryQuery(['locations.list']); + useNodes(locationsQuery.data?.nodes); + const locations = useCache(locationsQuery.data?.items); const [search, setSearch] = useState(''); const [debouncedSearch] = useDebounce(search, 200); const filteredLocations = useMemo( () => - locations.data?.filter( + locations?.filter( (location) => location.name?.toLowerCase().includes(debouncedSearch.toLowerCase()) ) ?? [], - [debouncedSearch, locations.data] + [debouncedSearch, locations] ); return ( diff --git a/interface/app/$libraryId/settings/library/nodes.tsx b/interface/app/$libraryId/settings/library/nodes.tsx index 8ac974ca5..22b5b32f7 100644 --- a/interface/app/$libraryId/settings/library/nodes.tsx +++ b/interface/app/$libraryId/settings/library/nodes.tsx @@ -1,9 +1,11 @@ import { useBridgeMutation, useBridgeQuery, + useCache, useConnectedPeers, useDiscoveredPeers, - useFeatureFlag + useFeatureFlag, + useNodes } from '@sd/client'; import { Button } from '@sd/ui'; import { startPairing } from '~/app/p2p/pairing'; @@ -41,10 +43,17 @@ function IncorrectP2PPairingPane() { console.log(data); } }); - const nlmState = useBridgeQuery(['p2p.state'], { - refetchInterval: 1000 - }); - const libraries = useBridgeQuery(['library.list']); + + const nlmState = { + data: JSON.stringify('lol no') + }; + // TODO: Bring this back + // useBridgeQuery(['p2p.state'], { + // refetchInterval: 1000 + // }); + const result = useBridgeQuery(['library.list']); + useNodes(result.data?.nodes); + const libraries = useCache(result.data?.items); return ( <> @@ -86,7 +95,7 @@ function IncorrectP2PPairingPane() {

Libraries:

- {libraries.data?.map((v) => ( + {libraries?.map((v) => (

{v.config.name} - {v.uuid} diff --git a/interface/app/$libraryId/settings/library/tags/index.tsx b/interface/app/$libraryId/settings/library/tags/index.tsx index 2fd95f89f..6ad489964 100644 --- a/interface/app/$libraryId/settings/library/tags/index.tsx +++ b/interface/app/$libraryId/settings/library/tags/index.tsx @@ -1,6 +1,6 @@ import clsx from 'clsx'; import { useEffect, useState } from 'react'; -import { Tag, useLibraryQuery } from '@sd/client'; +import { Tag, useCache, useLibraryQuery, useNodes } from '@sd/client'; import { Button, Card, dialogManager } from '@sd/ui'; import { Heading } from '~/app/$libraryId/settings/Layout'; import { TagsSettingsParamsSchema } from '~/app/route-schemas'; @@ -10,11 +10,14 @@ import CreateDialog from './CreateDialog'; import EditForm from './EditForm'; export const Component = () => { - const tags = useLibraryQuery(['tags.list']); + const result = useLibraryQuery(['tags.list']); + useNodes(result.data?.nodes); + const tags = useCache(result.data?.items); + const { id: locationId } = useZodRouteParams(TagsSettingsParamsSchema); - const tagSelectedParam = tags.data?.find((tag) => tag.id === locationId); + const tagSelectedParam = tags?.find((tag) => tag.id === locationId); const [selectedTag, setSelectedTag] = useState( - tagSelectedParam ?? tags.data?.[0] ?? null + tagSelectedParam ?? tags?.[0] ?? null ); // Update selected tag when the route param changes @@ -24,7 +27,7 @@ export const Component = () => { // Set the first tag as selected when the tags list data is first loaded useEffect(() => { - if (tags?.data?.length || (0 > 1 && !selectedTag)) setSelectedTag(tags.data?.[0] ?? null); + if (tags?.length || (0 > 1 && !selectedTag)) setSelectedTag(tags?.[0] ?? null); // eslint-disable-next-line react-hooks/exhaustive-deps }, []); @@ -49,7 +52,7 @@ export const Component = () => { />

- {tags.data?.map((tag) => ( + {tags?.map((tag) => (
setSelectedTag(tag.id === selectedTag?.id ? null : tag)} key={tag.id} diff --git a/interface/app/$libraryId/settings/node/libraries/CreateDialog.tsx b/interface/app/$libraryId/settings/node/libraries/CreateDialog.tsx index 919ef5de0..62c6370ca 100644 --- a/interface/app/$libraryId/settings/node/libraries/CreateDialog.tsx +++ b/interface/app/$libraryId/settings/node/libraries/CreateDialog.tsx @@ -1,6 +1,12 @@ import { useQueryClient } from '@tanstack/react-query'; import { useNavigate } from 'react-router-dom'; -import { LibraryConfigWrapped, useBridgeMutation, usePlausibleEvent, useZodForm } from '@sd/client'; +import { + insertLibrary, + useBridgeMutation, + useNormalisedCache, + usePlausibleEvent, + useZodForm +} from '@sd/client'; import { Dialog, InputField, useDialog, UseDialogProps, z } from '@sd/ui'; import { usePlatform } from '~/util/Platform'; @@ -23,18 +29,18 @@ export default (props: UseDialogProps) => { const createLibrary = useBridgeMutation('library.create'); const form = useZodForm({ schema }); + const cache = useNormalisedCache(); const onSubmit = form.handleSubmit(async (data) => { try { - const library = await createLibrary.mutateAsync({ + const libraryRaw = await createLibrary.mutateAsync({ name: data.name, default_locations: null }); + cache.withNodes(libraryRaw.nodes); + const library = cache.withCache(libraryRaw.item); - queryClient.setQueryData(['library.list'], (libraries) => [ - ...(libraries || []), - library - ]); + insertLibrary(queryClient, library); submitPlausibleEvent({ event: { type: 'libraryCreate' } diff --git a/interface/app/$libraryId/settings/node/libraries/index.tsx b/interface/app/$libraryId/settings/node/libraries/index.tsx index 1889f2adb..5b551d226 100644 --- a/interface/app/$libraryId/settings/node/libraries/index.tsx +++ b/interface/app/$libraryId/settings/node/libraries/index.tsx @@ -1,4 +1,4 @@ -import { useBridgeQuery, useLibraryContext } from '@sd/client'; +import { useBridgeQuery, useCache, useLibraryContext, useNodes } from '@sd/client'; import { Button, dialogManager } from '@sd/ui'; import { Heading } from '../../Layout'; @@ -6,7 +6,9 @@ import CreateDialog from './CreateDialog'; import ListItem from './ListItem'; export const Component = () => { - const libraries = useBridgeQuery(['library.list']); + const librariesQuery = useBridgeQuery(['library.list']); + useNodes(librariesQuery.data?.nodes); + const libraries = useCache(librariesQuery.data?.items); const { library } = useLibraryContext(); @@ -31,7 +33,7 @@ export const Component = () => { />
- {libraries.data + {libraries ?.sort((a, b) => { if (a.uuid === library.uuid) return -1; if (b.uuid === library.uuid) return 1; diff --git a/interface/app/$libraryId/sync.tsx b/interface/app/$libraryId/sync.tsx index 45c53ce6c..9564fac83 100644 --- a/interface/app/$libraryId/sync.tsx +++ b/interface/app/$libraryId/sync.tsx @@ -114,7 +114,7 @@ function calculateGroups(messages: CRDTOperation[]) { const { typ } = curr; if ('model' in typ) { - const id = stringify(typ.record_id.pub_id); + const id = stringify((typ.record_id as any).pub_id); const latest = (() => { const latest = acc[acc.length - 1]; @@ -146,8 +146,8 @@ function calculateGroups(messages: CRDTOperation[]) { }); } else { const id = { - item: stringify(typ.relation_item.pub_id), - group: stringify(typ.relation_group.pub_id) + item: stringify((typ.relation_item as any).pub_id), + group: stringify((typ.relation_group as any).pub_id) }; const latest = (() => { diff --git a/interface/app/$libraryId/tag/$id.tsx b/interface/app/$libraryId/tag/$id.tsx index 95aa9e2e2..d8ac07d3e 100644 --- a/interface/app/$libraryId/tag/$id.tsx +++ b/interface/app/$libraryId/tag/$id.tsx @@ -1,5 +1,5 @@ import { useMemo } from 'react'; -import { ObjectKindEnum, ObjectOrder, useLibraryQuery } from '@sd/client'; +import { ObjectKindEnum, ObjectOrder, useCache, useLibraryQuery, useNodes } from '@sd/client'; import { LocationIdParamsSchema } from '~/app/route-schemas'; import { Icon } from '~/components'; import { useRouteTitle, useZodRouteParams } from '~/hooks'; @@ -17,9 +17,11 @@ import { TopBarPortal } from '../TopBar/Portal'; export function Component() { const { id: tagId } = useZodRouteParams(LocationIdParamsSchema); - const tag = useLibraryQuery(['tags.get', tagId], { suspense: true }); + const result = useLibraryQuery(['tags.get', tagId], { suspense: true }); + useNodes(result.data?.nodes); + const tag = useCache(result.data?.item); - useRouteTitle(tag.data!.name ?? 'Tag'); + useRouteTitle(tag!.name ?? 'Tag'); const explorerSettings = useExplorerSettings({ settings: useMemo(() => { @@ -32,12 +34,12 @@ export function Component() { const fixedFilters = useMemo( () => [ - { object: { tags: { in: [tag.data!.id] } } }, + { object: { tags: { in: [tag!.id] } } }, ...(explorerSettingsSnapshot.layoutMode === 'media' ? [{ object: { kind: { in: [ObjectKindEnum.Image, ObjectKindEnum.Video] } } }] : []) ], - [tag.data, explorerSettingsSnapshot.layoutMode] + [tag, explorerSettingsSnapshot.layoutMode] ); const search = useSearch({ @@ -53,7 +55,7 @@ export function Component() { ...objects, isFetchingNextPage: objects.query.isFetchingNextPage, settings: explorerSettings, - parent: { type: 'Tag', tag: tag.data! } + parent: { type: 'Tag', tag: tag! } }); return ( @@ -65,9 +67,9 @@ export function Component() {
- {tag?.data?.name} + {tag?.name}
} right={} diff --git a/interface/app/index.tsx b/interface/app/index.tsx index 4f8ba6957..f0e3ae68f 100644 --- a/interface/app/index.tsx +++ b/interface/app/index.tsx @@ -1,9 +1,13 @@ import { useMemo } from 'react'; import { Navigate, Outlet, redirect, useMatches, type RouteObject } from 'react-router-dom'; -import { currentLibraryCache, getCachedLibraries, useCachedLibraries } from '@sd/client'; +import { + currentLibraryCache, + getCachedLibraries, + NormalisedCache, + useCachedLibraries +} from '@sd/client'; import { Dialogs, Toaster } from '@sd/ui'; import { RouterErrorBoundary } from '~/ErrorFallback'; -import { useOperatingSystem } from '~/hooks'; import { useRoutingContext } from '~/RoutingContext'; import { Platform } from '..'; @@ -17,7 +21,7 @@ import './style.scss'; // the `usePlausiblePageViewMonitor` hook, as early as possible (ideally within the layout itself). // the hook should only be included if there's a valid `ClientContext` (so not onboarding) -export const createRoutes = (platform: Platform) => +export const createRoutes = (platform: Platform, cache: NormalisedCache) => [ { Component: () => { @@ -54,7 +58,7 @@ export const createRoutes = (platform: Platform) => return ; }, loader: async () => { - const libraries = await getCachedLibraries(); + const libraries = await getCachedLibraries(cache); const currentLibrary = libraries.find( (l) => l.uuid === currentLibraryCache.id @@ -76,7 +80,7 @@ export const createRoutes = (platform: Platform) => path: ':libraryId', lazy: () => import('./$libraryId/Layout'), loader: async ({ params: { libraryId } }) => { - const libraries = await getCachedLibraries(); + const libraries = await getCachedLibraries(cache); const library = libraries.find((l) => l.uuid === libraryId); if (!library) { diff --git a/interface/app/onboarding/context.tsx b/interface/app/onboarding/context.tsx index 041d79876..9e3b42c63 100644 --- a/interface/app/onboarding/context.tsx +++ b/interface/app/onboarding/context.tsx @@ -5,11 +5,13 @@ import { currentLibraryCache, getOnboardingStore, getUnitFormatStore, + insertLibrary, resetOnboardingStore, telemetryStore, useBridgeMutation, useCachedLibraries, useMultiZodForm, + useNormalisedCache, useOnboardingStore, usePlausibleEvent } from '@sd/client'; @@ -95,6 +97,7 @@ const useFormState = () => { } const createLibrary = useBridgeMutation('library.create'); + const cache = useNormalisedCache(); const submit = handleSubmit( async (data) => { @@ -106,20 +109,16 @@ const useFormState = () => { try { // show creation screen for a bit for smoothness - const [library] = await Promise.all([ + const [libraryRaw] = await Promise.all([ createLibrary.mutateAsync({ name: data['new-library'].name, default_locations: data.locations.locations }), new Promise((res) => setTimeout(res, 500)) ]); - - queryClient.setQueryData(['library.list'], (libraries: any) => { - // The invalidation system beat us to it - if (libraries.find((l: any) => l.uuid === library.uuid)) return libraries; - - return [...(libraries || []), library]; - }); + cache.withNodes(libraryRaw.nodes); + const library = cache.withCache(libraryRaw.item); + insertLibrary(queryClient, library); platform.refreshMenuBar && platform.refreshMenuBar(); diff --git a/interface/components/Devtools.tsx b/interface/components/Devtools.tsx new file mode 100644 index 000000000..acb72e803 --- /dev/null +++ b/interface/components/Devtools.tsx @@ -0,0 +1,24 @@ +import { defaultContext } from '@tanstack/react-query'; +import { ReactQueryDevtools } from '@tanstack/react-query-devtools'; +import { useDebugState } from '@sd/client'; + +export const Devtools = () => { + const debugState = useDebugState(); + + return ( + <> + {debugState.reactQueryDevtools !== 'disabled' ? ( + + ) : null} + + ); +}; diff --git a/interface/hooks/useIsLocationIndexing.ts b/interface/hooks/useIsLocationIndexing.ts index 45c7cbd1e..70308895a 100644 --- a/interface/hooks/useIsLocationIndexing.ts +++ b/interface/hooks/useIsLocationIndexing.ts @@ -16,7 +16,7 @@ export const useIsLocationIndexing = (locationId: number): boolean => { group.jobs.some((job) => { if ( job.name === 'indexer' && - job.metadata?.location.id === locationId && + (job.metadata as any)?.location.id === locationId && (job.status === 'Running' || job.status === 'Queued') ) { return job.completed_task_count === 0; diff --git a/interface/hooks/useRedirectToNewLocation.ts b/interface/hooks/useRedirectToNewLocation.ts index 2b3fe8a42..7101ebbcf 100644 --- a/interface/hooks/useRedirectToNewLocation.ts +++ b/interface/hooks/useRedirectToNewLocation.ts @@ -25,7 +25,7 @@ export const useRedirectToNewLocation = () => { .some( (j) => j.name === 'indexer' && - j.metadata?.location.id === newLocation && + (j.metadata as any)?.location.id === newLocation && (j.completed_task_count > 0 || j.completed_at != null) ); diff --git a/interface/index.tsx b/interface/index.tsx index b1225b7c6..b832df5d4 100644 --- a/interface/index.tsx +++ b/interface/index.tsx @@ -1,8 +1,6 @@ import '@fontsource/inter/variable.css'; import { init, Integrations } from '@sentry/browser'; -import { defaultContext } from '@tanstack/react-query'; -import { ReactQueryDevtools } from '@tanstack/react-query-devtools'; import dayjs from 'dayjs'; import advancedFormat from 'dayjs/plugin/advancedFormat'; import duration from 'dayjs/plugin/duration'; @@ -10,9 +8,9 @@ import relativeTime from 'dayjs/plugin/relativeTime'; import { PropsWithChildren, Suspense } from 'react'; import { RouterProvider, RouterProviderProps } from 'react-router-dom'; import { + CacheProvider, NotificationContextProvider, P2PContextProvider, - useDebugState, useInvalidateQuery, useLoadBackendFeatureFlags } from '@sd/client'; @@ -20,6 +18,7 @@ import { TooltipProvider } from '@sd/ui'; import { createRoutes } from './app'; import { P2P, useP2PErrorToast } from './app/p2p'; +import { Devtools } from './components/Devtools'; import { WithPrismTheme } from './components/TextViewer/prism'; import ErrorFallback, { BetterErrorBoundary } from './ErrorFallback'; import { useTheme } from './hooks'; @@ -42,23 +41,6 @@ init({ integrations: [new Integrations.HttpContext(), new Integrations.Dedupe()] }); -const Devtools = () => { - const debugState = useDebugState(); - - // The `context={defaultContext}` part is required for this to work on Windows. - // Why, idk, don't question it - return debugState.reactQueryDevtools !== 'disabled' ? ( - - ) : null; -}; - export type Router = RouterProviderProps['router']; export function SpacedriveRouterProvider(props: { diff --git a/packages/client/src/cache.tsx b/packages/client/src/cache.tsx new file mode 100644 index 000000000..09952a2d5 --- /dev/null +++ b/packages/client/src/cache.tsx @@ -0,0 +1,251 @@ +import { useQueryClient } from '@tanstack/react-query'; +import { + createContext, + PropsWithChildren, + useContext, + useEffect, + useMemo, + useRef, + useState, + useSyncExternalStore +} from 'react'; +import { proxy, snapshot, subscribe } from 'valtio'; + +import { type CacheNode } from './core'; + +declare global { + interface Window { + __REDUX_DEVTOOLS_EXTENSION__: any; + } +} + +type Store = ReturnType; +type Context = ReturnType; +export type NormalisedCache = ReturnType; + +const defaultStore = () => ({ + nodes: {} as Record> +}); + +const Context = createContext(undefined!); + +export function createCache() { + const cache = proxy(defaultStore()); + return { + cache, + withNodes(data: CacheNode[] | undefined) { + updateNodes(cache, data); + }, + withCache(data: T | undefined): UseCacheResult { + return restore(cache, new Map(), data) as any; + } + }; +} + +export function CacheProvider({ cache, children }: PropsWithChildren<{ cache: NormalisedCache }>) { + useEffect(() => { + if ('__REDUX_DEVTOOLS_EXTENSION__' in window === false) return; + + const devtools = window.__REDUX_DEVTOOLS_EXTENSION__.connect({}); + + const unsub = devtools.subscribe((_message: any) => { + // console.log(message); + }); + + devtools.init(); + subscribe(cache.cache, () => devtools.send('change', snapshot(cache.cache))); + + return () => { + unsub(); + window.__REDUX_DEVTOOLS_EXTENSION__.disconnect(); + }; + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + const queryClient = useQueryClient(); + useEffect(() => { + const interval = setInterval(() => { + const requiredKeys = new StableSet<[string, string]>(); + for (const query of queryClient.getQueryCache().getAll()) { + if (query.state.data) scanDataForKeys(cache.cache, requiredKeys, query.state.data); + } + + const existingKeys = new StableSet<[string, string]>(); + Object.entries(cache.cache.nodes).map(([type, value]) => { + Object.keys(value).map((id) => existingKeys.add([type, id])); + }); + + for (const [type, id] of existingKeys.entries()) { + // If key is not required. Eg. not in any query within the React Query cache. + if (!requiredKeys.has([type, id])) { + // Yeet the imposter + console.debug('Removing Cache Key: ', type, id); + delete cache.cache.nodes?.[type]?.[id]; + } + } + + console.debug('Normalised Cache Cleanup', requiredKeys.size, existingKeys.size); + }, 60 * 1000); + return () => clearInterval(interval); + }, [cache.cache, queryClient]); + + return {children}; +} + +export function useCacheContext() { + const context = useContext(Context); + if (!context) throw new Error('Missing `CacheContext` provider!'); + return context; +} + +function scanDataForKeys(cache: Store, keys: StableSet<[string, string]>, item: unknown) { + if (item === undefined || item === null) return; + if (Array.isArray(item)) { + for (const v of item) { + scanDataForKeys(cache, keys, v); + } + } else if (typeof item === 'object') { + if ('__type' in item && '__id' in item) { + if (typeof item.__type !== 'string') throw new Error('Invalid `__type`'); + if (typeof item.__id !== 'string') throw new Error('Invalid `__id`'); + keys.add([item.__type, item.__id]); + const result = cache.nodes?.[item.__type]?.[item.__id]; + if (result) scanDataForKeys(cache, keys, result); + } + + for (const [_k, value] of Object.entries(item)) { + scanDataForKeys(cache, keys, value); + } + } +} + +function restore(cache: Store, subscribed: Map>, item: unknown): unknown { + if (item === undefined || item === null) { + return item; + } else if (Array.isArray(item)) { + return item.map((v) => restore(cache, subscribed, v)); + } else if (typeof item === 'object') { + if ('__type' in item && '__id' in item) { + if (typeof item.__type !== 'string') throw new Error('Invalid `__type`'); + if (typeof item.__id !== 'string') throw new Error('Invalid `__id`'); + const result = cache.nodes?.[item.__type]?.[item.__id]; + if (!result) + throw new Error(`Missing node for id '${item.__id}' of type '${item.__type}'`); + + const v = subscribed.get(item.__type); + if (v) { + v.add(item.__id); + } else { + subscribed.set(item.__type, new Set([item.__id])); + } + + return result; + } + + return Object.fromEntries( + Object.entries(item).map(([key, value]) => [key, restore(cache, subscribed, value)]) + ); + } + + return item; +} + +export function useNodes(data: CacheNode[] | undefined) { + const cache = useCacheContext(); + + // `useMemo` instead of `useEffect` here is cursed but it needs to run before the `useMemo` in the `useCache` hook. + useMemo(() => { + updateNodes(cache.cache, data); + }, [cache, data]); +} + +// Methods to interact with the cache outside of the React lifecycle. +export function useNormalisedCache() { + const cache = useCacheContext(); + + return { + '#cache': cache.cache, + 'withNodes': cache.withNodes, + 'withCache': cache.withCache + }; +} + +function updateNodes(cache: Store, data: CacheNode[] | undefined) { + if (!data) return; + + for (const item of data) { + if (!('__type' in item && '__id' in item)) throw new Error('Missing `__type` or `__id`'); + if (typeof item.__type !== 'string') throw new Error('Invalid `__type`'); + if (typeof item.__id !== 'string') throw new Error('Invalid `__id`'); + + const copy = { ...item } as any; + delete copy.__type; + delete copy.__id; + + if (!cache.nodes[item.__type]) cache.nodes[item.__type] = {}; + // TODO: This should be a deepmerge but that would break stuff like `size_in_bytes` or `inode` as the arrays are joined. + cache.nodes[item.__type]![item.__id] = copy; + } +} + +export type UseCacheResult = T extends (infer A)[] + ? UseCacheResult[] + : T extends object + ? T extends { '__type': any; '__id': string; '#type': infer U } + ? UseCacheResult + : { [K in keyof T]: UseCacheResult } + : { [K in keyof T]: UseCacheResult }; + +export function useCache(data: T | undefined) { + const cache = useCacheContext(); + const subscribed = useRef(new Map>()).current; + const [i, setI] = useState(0); // TODO: Remove this + + const state = useMemo( + () => restore(cache.cache, subscribed, data) as UseCacheResult, + // eslint-disable-next-line react-hooks/exhaustive-deps + [cache, data, i] + ); + + return useSyncExternalStore( + (onStoreChange) => { + return subscribe(cache.cache, (ops) => { + for (const [_, key] of ops) { + const key_type = key[1] as string; + const key_id = key[2] as string; + + const v = subscribed.get(key_type); + if (v && v.has(key_id)) { + setI((i) => i + 1); + onStoreChange(); + + break; // We only need to trigger re-render once so we can break + } + } + }); + }, + () => state + ); +} + +class StableSet { + set = new Set(); + + get size() { + return this.set.size; + } + + add(value: T) { + this.set.add(JSON.stringify(value)); + } + + has(value: T) { + return this.set.has(JSON.stringify(value)); + } + + *entries() { + for (const v of this.set) { + yield JSON.parse(v); + } + } +} diff --git a/packages/client/src/core.ts b/packages/client/src/core.ts index 75b7280e7..cea0b4381 100644 --- a/packages/client/src/core.ts +++ b/packages/client/src/core.ts @@ -8,43 +8,42 @@ export type Procedures = { { key: "buildInfo", input: never, result: BuildInfo } | { key: "cloud.library.get", input: LibraryArgs, result: { uuid: string; name: string; ownerId: string; instances: { id: string; uuid: string; identity: string }[] } | null } | { key: "cloud.library.list", input: never, result: { uuid: string; name: string; ownerId: string; instances: { id: string; uuid: string }[] }[] } | - { key: "ephemeralFiles.getMediaData", input: string, result: MediaMetadata | null } | - { key: "files.get", input: LibraryArgs, result: { id: number; pub_id: number[]; kind: number | null; key_id: number | null; hidden: boolean | null; favorite: boolean | null; important: boolean | null; note: string | null; date_created: string | null; date_accessed: string | null; file_paths: FilePath[] } | null } | + { key: "ephemeralFiles.getMediaData", input: string, result: ({ type: "Image" } & ImageMetadata) | ({ type: "Video" } & VideoMetadata) | ({ type: "Audio" } & AudioMetadata) | null } | + { key: "files.get", input: LibraryArgs, result: { item: Reference; nodes: CacheNode[] } | null } | { key: "files.getConvertableImageExtensions", input: never, result: string[] } | { key: "files.getMediaData", input: LibraryArgs, result: MediaMetadata } | { key: "files.getPath", input: LibraryArgs, result: string | null } | { key: "invalidation.test-invalidate", input: never, result: number } | { key: "jobs.isActive", input: LibraryArgs, result: boolean } | { key: "jobs.reports", input: LibraryArgs, result: JobGroup[] } | - { key: "library.list", input: never, result: LibraryConfigWrapped[] } | + { key: "library.list", input: never, result: NormalisedResults } | { key: "library.statistics", input: LibraryArgs, result: Statistics } | - { key: "locations.get", input: LibraryArgs, result: Location | null } | - { key: "locations.getWithRules", input: LibraryArgs, result: LocationWithIndexerRules | null } | - { key: "locations.indexer_rules.get", input: LibraryArgs, result: IndexerRule } | - { key: "locations.indexer_rules.list", input: LibraryArgs, result: IndexerRule[] } | - { key: "locations.indexer_rules.listForLocation", input: LibraryArgs, result: IndexerRule[] } | - { key: "locations.list", input: LibraryArgs, result: Location[] } | + { key: "locations.get", input: LibraryArgs, result: { item: Reference; nodes: CacheNode[] } | null } | + { key: "locations.getWithRules", input: LibraryArgs, result: { item: Reference; nodes: CacheNode[] } | null } | + { key: "locations.indexer_rules.get", input: LibraryArgs, result: NormalisedResult } | + { key: "locations.indexer_rules.list", input: LibraryArgs, result: NormalisedResults } | + { key: "locations.indexer_rules.listForLocation", input: LibraryArgs, result: NormalisedResults } | + { key: "locations.list", input: LibraryArgs, result: NormalisedResults } | { key: "locations.systemLocations", input: never, result: SystemLocations } | { key: "nodeState", input: never, result: NodeState } | { key: "nodes.listLocations", input: LibraryArgs, result: ExplorerItem[] } | { key: "notifications.dismiss", input: NotificationId, result: null } | { key: "notifications.dismissAll", input: never, result: null } | { key: "notifications.get", input: never, result: Notification[] } | - { key: "p2p.state", input: never, result: P2PState } | { key: "preferences.get", input: LibraryArgs, result: LibraryPreferences } | - { key: "search.ephemeralPaths", input: LibraryArgs, result: NonIndexedFileSystemEntries } | + { key: "search.ephemeralPaths", input: LibraryArgs, result: EphemeralPathsResult } | { key: "search.objects", input: LibraryArgs, result: SearchData } | { key: "search.objectsCount", input: LibraryArgs<{ filters?: SearchFilterArgs[] }>, result: number } | { key: "search.paths", input: LibraryArgs, result: SearchData } | { key: "search.pathsCount", input: LibraryArgs<{ filters?: SearchFilterArgs[] }>, result: number } | - { key: "search.saved.get", input: LibraryArgs, result: SavedSearch | null } | + { key: "search.saved.get", input: LibraryArgs, result: { id: number; pub_id: number[]; search: string | null; filters: string | null; name: string | null; icon: string | null; description: string | null; date_created: string | null; date_modified: string | null } | null } | { key: "search.saved.list", input: LibraryArgs, result: SavedSearch[] } | { key: "sync.messages", input: LibraryArgs, result: CRDTOperation[] } | - { key: "tags.get", input: LibraryArgs, result: Tag | null } | - { key: "tags.getForObject", input: LibraryArgs, result: Tag[] } | - { key: "tags.getWithObjects", input: LibraryArgs, result: { [key: number]: { date_created: string | null; object: { id: number } }[] } } | - { key: "tags.list", input: LibraryArgs, result: Tag[] } | - { key: "volumes.list", input: never, result: Volume[] }, + { key: "tags.get", input: LibraryArgs, result: { item: Reference; nodes: CacheNode[] } | null } | + { key: "tags.getForObject", input: LibraryArgs, result: NormalisedResults } | + { key: "tags.getWithObjects", input: LibraryArgs, result: { [key in number]: ({ date_created: string | null; object: { id: number } })[] } } | + { key: "tags.list", input: LibraryArgs, result: NormalisedResults } | + { key: "volumes.list", input: never, result: NormalisedResults }, mutations: { key: "api.sendFeedback", input: Feedback, result: null } | { key: "auth.logout", input: never, result: null } | @@ -78,7 +77,7 @@ export type Procedures = { { key: "jobs.objectValidator", input: LibraryArgs, result: null } | { key: "jobs.pause", input: LibraryArgs, result: null } | { key: "jobs.resume", input: LibraryArgs, result: null } | - { key: "library.create", input: CreateLibraryArgs, result: LibraryConfigWrapped } | + { key: "library.create", input: CreateLibraryArgs, result: NormalisedResult } | { key: "library.delete", input: string, result: null } | { key: "library.edit", input: EditLibraryArgs, result: null } | { key: "locations.addLibrary", input: LibraryArgs, result: number | null } | @@ -96,7 +95,7 @@ export type Procedures = { { key: "notifications.testLibrary", input: LibraryArgs, result: null } | { key: "p2p.acceptSpacedrop", input: [string, string | null], result: null } | { key: "p2p.cancelSpacedrop", input: string, result: null } | - { key: "p2p.pair", input: string, result: number } | + { key: "p2p.pair", input: RemoteIdentity, result: number } | { key: "p2p.pairingResponse", input: [number, PairingDecision], result: null } | { key: "p2p.spacedrop", input: SpacedropArgs, result: string } | { key: "preferences.update", input: LibraryArgs, result: null } | @@ -139,13 +138,31 @@ export type CRDTOperation = { instance: string; timestamp: number; id: string; t export type CRDTOperationType = SharedOperation | RelationOperation +export type CacheNode = { __type: string; __id: string; "#node": any } + export type CameraData = { device_make: string | null; device_model: string | null; color_space: string | null; color_profile: ColorProfile | null; focal_length: number | null; shutter_speed: number | null; flash: Flash | null; orientation: Orientation; lens_make: string | null; lens_model: string | null; bit_depth: number | null; red_eye: boolean | null; zoom: number | null; iso: number | null; software: string | null; serial_number: string | null; lens_serial_number: string | null; contrast: number | null; saturation: number | null; sharpness: number | null; composite: Composite | null } export type ChangeNodeNameArgs = { name: string | null; p2p_enabled: boolean | null; p2p_port: MaybeUndefined } export type ColorProfile = "Normal" | "Custom" | "HDRNoOriginal" | "HDRWithOriginal" | "OriginalForHDR" | "Panorama" | "PortraitHDR" | "Portrait" -export type Composite = "Unknown" | "False" | "General" | "Live" +export type Composite = +/** + * The data is present, but we're unable to determine what they mean + */ +"Unknown" | +/** + * Not a composite image + */ +"False" | +/** + * A general composite image + */ +"General" | +/** + * The composite image was captured while shooting + */ +"Live" export type ConvertImageArgs = { location_id: number; file_path_id: number; delete_src: boolean; desired_extension: ConvertableExtension; quality_percentage: number | null } @@ -173,6 +190,8 @@ export type EphemeralPathOrder = { field: "name"; value: SortOrder } | { field: export type EphemeralPathSearchArgs = { path: string; withHiddenFiles: boolean; order?: EphemeralPathOrder | null } +export type EphemeralPathsResult = { entries: Reference[]; errors: Error[]; nodes: CacheNode[] } + export type EphemeralRenameFileArgs = { kind: EphemeralRenameKind } export type EphemeralRenameKind = { One: EphemeralRenameOne } | { Many: EphemeralRenameMany } @@ -192,7 +211,7 @@ export type ExplorerItem = { type: "Path"; has_local_thumbnail: boolean; thumbna export type ExplorerLayout = "grid" | "list" | "media" -export type ExplorerSettings = { layoutMode: ExplorerLayout | null; gridItemSize: number | null; gridGap: number | null; mediaColumns: number | null; mediaAspectSquare: boolean | null; mediaViewWithDescendants: boolean | null; openOnDoubleClick: DoubleClickAction | null; showBytesInGridView: boolean | null; colVisibility: { [key: string]: boolean } | null; colSizes: { [key: string]: number } | null; order?: TOrder | null; showHiddenFiles?: boolean } +export type ExplorerSettings = { layoutMode: ExplorerLayout | null; gridItemSize: number | null; gridGap: number | null; mediaColumns: number | null; mediaAspectSquare: boolean | null; mediaViewWithDescendants: boolean | null; openOnDoubleClick: DoubleClickAction | null; showBytesInGridView: boolean | null; colVisibility: { [key in string]: boolean } | null; colSizes: { [key in string]: number } | null; order?: TOrder | null; showHiddenFiles?: boolean } export type Feedback = { message: string; emoji: number } @@ -218,11 +237,52 @@ export type FilePathOrder = { field: "name"; value: SortOrder } | { field: "size export type FilePathSearchArgs = { take?: number | null; orderAndPagination?: OrderAndPagination | null; filters?: SearchFilterArgs[]; groupDirectories?: boolean } -export type FilePathWithObject = { id: number; pub_id: number[]; is_dir: boolean | null; cas_id: string | null; integrity_checksum: string | null; location_id: number | null; materialized_path: string | null; name: string | null; extension: string | null; hidden: boolean | null; size_in_bytes: string | null; size_in_bytes_bytes: number[] | null; inode: number[] | null; object_id: number | null; key_id: number | null; date_created: string | null; date_modified: string | null; date_indexed: string | null; object: Object | null } +export type FilePathWithObject = { id: number; pub_id: number[]; is_dir: boolean | null; cas_id: string | null; integrity_checksum: string | null; location_id: number | null; materialized_path: string | null; name: string | null; extension: string | null; hidden: boolean | null; size_in_bytes: string | null; size_in_bytes_bytes: number[] | null; inode: number[] | null; object_id: number | null; key_id: number | null; date_created: string | null; date_modified: string | null; date_indexed: string | null; object: { id: number; pub_id: number[]; kind: number | null; key_id: number | null; hidden: boolean | null; favorite: boolean | null; important: boolean | null; note: string | null; date_created: string | null; date_accessed: string | null } | null } -export type Flash = { mode: FlashMode; fired: boolean | null; returned: boolean | null; red_eye_reduction: boolean | null } +export type Flash = { +/** + * Specifies how flash was used (on, auto, off, forced, onvalid) + * + * [`FlashMode::Unknown`] isn't a valid EXIF state, but it's included as the default, + * just in case we're unable to correctly match it to a known (valid) state. + * + * This type should only ever be evaluated if flash EXIF data is present, so having this as a non-option shouldn't be an issue. + */ +mode: FlashMode; +/** + * Did the flash actually fire? + */ +fired: boolean | null; +/** + * Did flash return to the camera? (Unsure of the meaning) + */ +returned: boolean | null; +/** + * Was red eye reduction used? + */ +red_eye_reduction: boolean | null } -export type FlashMode = "Unknown" | "On" | "Off" | "Auto" | "Forced" +export type FlashMode = +/** + * The data is present, but we're unable to determine what they mean + */ +"Unknown" | +/** + * FLash was on + */ +"On" | +/** + * Flash was off + */ +"Off" | +/** + * Flash was set to automatically fire in certain conditions + */ +"Auto" | +/** + * Flash was forcefully fired + */ +"Forced" export type FromPattern = { pattern: string; replace_all: boolean } @@ -232,10 +292,6 @@ export type GenerateThumbsForLocationArgs = { id: number; path: string; regenera export type GetAll = { backups: Backup[]; directory: string } -export type GetArgs = { id: number } - -export type Header = { id: string; timestamp: string; library_id: string; library_name: string } - export type IdentifyUniqueFilesArgs = { id: number; path: string } export type ImageMetadata = { resolution: Resolution; date_taken: MediaDate | null; location: MediaLocation | null; camera_data: CameraData; artist: string | null; description: string | null; copyright: string | null; exif_version: string | null } @@ -262,10 +318,12 @@ export type JobGroup = { id: string; action: string | null; status: JobStatus; c export type JobProgressEvent = { id: string; library_id: string; task_count: number; completed_task_count: number; phase: string; message: string; estimated_completion: string } -export type JobReport = { id: string; name: string; action: string | null; data: number[] | null; metadata: { [key: string]: any } | null; is_background: boolean; errors_text: string[]; created_at: string | null; started_at: string | null; completed_at: string | null; parent_id: string | null; status: JobStatus; task_count: number; completed_task_count: number; phase: string; message: string; estimated_completion: string } +export type JobReport = { id: string; name: string; action: string | null; data: number[] | null; metadata: { [key in string]: JsonValue } | null; is_background: boolean; errors_text: string[]; created_at: string | null; started_at: string | null; completed_at: string | null; parent_id: string | null; status: JobStatus; task_count: number; completed_task_count: number; phase: string; message: string; estimated_completion: string } export type JobStatus = "Queued" | "Running" | "Completed" | "Canceled" | "Failed" | "Paused" | "CompletedWithErrors" +export type JsonValue = null | boolean | number | string | JsonValue[] | { [key in string]: JsonValue } + /** * Can wrap a query argument to require it to contain a `library_id` and provide helpers for working with libraries. */ @@ -274,15 +332,27 @@ export type LibraryArgs = { library_id: string; arg: T } /** * LibraryConfig holds the configuration for a specific library. This is stored as a '{uuid}.sdlibrary' file. */ -export type LibraryConfig = { name: LibraryName; description: string | null; instance_id: number; version: LibraryConfigVersion } +export type LibraryConfig = { +/** + * name is the display name of the library. This is used in the UI and is set by the user. + */ +name: LibraryName; +/** + * description is a user set description of the library. This is used in the UI and is set by the user. + */ +description: string | null; +/** + * id of the current instance so we know who this `.db` is. This can be looked up within the `Instance` table. + */ +instance_id: number; version: LibraryConfigVersion } export type LibraryConfigVersion = "V0" | "V1" | "V2" | "V3" | "V4" | "V5" | "V6" | "V7" | "V8" | "V9" -export type LibraryConfigWrapped = { uuid: string; instance_id: string; instance_public_key: string; config: LibraryConfig } +export type LibraryConfigWrapped = { uuid: string; instance_id: string; instance_public_key: RemoteIdentity; config: LibraryConfig } export type LibraryName = string -export type LibraryPreferences = { location?: { [key: string]: LocationSettings } } +export type LibraryPreferences = { location?: { [key in string]: LocationSettings } } export type LightScanArgs = { location_id: number; sub_path: string } @@ -309,16 +379,9 @@ export type LocationSettings = { explorer: ExplorerSettings } */ export type LocationUpdateArgs = { id: number; name: string | null; generate_preview_media: boolean | null; sync_preview_media: boolean | null; hidden: boolean | null; indexer_rules_ids: number[]; path: string | null } -export type LocationWithIndexerRules = { id: number; pub_id: number[]; name: string | null; path: string | null; total_capacity: number | null; available_capacity: number | null; size_in_bytes: number[] | null; is_archived: boolean | null; generate_preview_media: boolean | null; sync_preview_media: boolean | null; hidden: boolean | null; date_created: string | null; instance_id: number | null; indexer_rules: { indexer_rule: IndexerRule }[] } +export type LocationWithIndexerRule = { id: number; pub_id: number[]; name: string | null; path: string | null; total_capacity: number | null; available_capacity: number | null; size_in_bytes: number[] | null; is_archived: boolean | null; generate_preview_media: boolean | null; sync_preview_media: boolean | null; hidden: boolean | null; date_created: string | null; instance_id: number | null; indexer_rules: Reference[] } -/** - * The configuration for the P2P Manager - * DO NOT MAKE BREAKING CHANGES - This is embedded in the `node_config.json` - * For future me: `Keypair` is not on here cause hot reloading it hard. - */ -export type ManagerConfig = { enabled: boolean; port?: number | null } - -export type MaybeUndefined = null | null | T +export type MaybeUndefined = null | T export type MediaDataOrder = { field: "epochTime"; value: SortOrder } @@ -326,7 +389,7 @@ export type MediaDataOrder = { field: "epochTime"; value: SortOrder } * This can be either naive with no TZ (`YYYY-MM-DD HH-MM-SS`) or UTC (`YYYY-MM-DD HH-MM-SS ±HHMM`), * where `±HHMM` is the timezone data. It may be negative if West of the Prime Meridian, or positive if East. */ -export type MediaDate = string | string +export type MediaDate = string export type MediaLocation = { latitude: number; longitude: number; pluscode: PlusCode; altitude: number | null; direction: number | null } @@ -334,12 +397,32 @@ export type MediaMetadata = ({ type: "Image" } & ImageMetadata) | ({ type: "Vide export type NodePreferences = { thumbnailer: ThumbnailerPreferences } -export type NodeState = ({ id: string; name: string; p2p_enabled: boolean; p2p_port: number | null; features: BackendFeature[]; preferences: NodePreferences }) & { data_path: string; p2p: P2PStatus } - -export type NonIndexedFileSystemEntries = { entries: ExplorerItem[]; errors: Error[] } +export type NodeState = ({ +/** + * id is a unique identifier for the current node. Each node has a public identifier (this one) and is given a local id for each library (done within the library code). + */ +id: string; +/** + * name is the display name of the current node. This is set by the user and is shown in the UI. // TODO: Length validation so it can fit in DNS record + */ +name: string; p2p_enabled: boolean; p2p_port: number | null; features: BackendFeature[]; preferences: NodePreferences }) & { data_path: string; p2p: P2PStatus } export type NonIndexedPathItem = { path: string; name: string; extension: string; kind: number; is_dir: boolean; date_created: string; date_modified: string; size_in_bytes_bytes: number[]; hidden: boolean } +/** + * A type that can be used to return a group of `Reference` and `CacheNode`'s + * + * You don't need to use this, it's just a shortcut to avoid having to write out the full type everytime. + */ +export type NormalisedResult = { item: Reference; nodes: CacheNode[] } + +/** + * A type that can be used to return a group of `Reference` and `CacheNode`'s + * + * You don't need to use this, it's just a shortcut to avoid having to write out the full type everytime. + */ +export type NormalisedResults = { items: Reference[]; nodes: CacheNode[] } + /** * Represents a single notification. */ @@ -369,6 +452,8 @@ export type ObjectValidatorArgs = { id: number; path: string } export type ObjectWithFilePaths = { id: number; pub_id: number[]; kind: number | null; key_id: number | null; hidden: boolean | null; favorite: boolean | null; important: boolean | null; note: string | null; date_created: string | null; date_accessed: string | null; file_paths: FilePath[] } +export type ObjectWithFilePaths2 = { id: number; pub_id: number[]; kind: number | null; key_id: number | null; hidden: boolean | null; favorite: boolean | null; important: boolean | null; note: string | null; date_created: string | null; date_accessed: string | null; file_paths: Reference[] } + /** * Represents the operating system which the remote peer is running. * This is not used internally and predominantly is designed to be used for display purposes by the embedding application. @@ -382,9 +467,7 @@ export type Orientation = "Normal" | "CW90" | "CW180" | "CW270" | "MirroredVerti /** * TODO: P2P event for the frontend */ -export type P2PEvent = { type: "DiscoveredPeer"; identity: string; metadata: PeerMetadata } | { type: "ExpiredPeer"; identity: string } | { type: "ConnectedPeer"; identity: string } | { type: "DisconnectedPeer"; identity: string } | { type: "SpacedropRequest"; id: string; identity: string; peer_name: string; files: string[] } | { type: "SpacedropProgress"; id: string; percent: number } | { type: "SpacedropTimedout"; id: string } | { type: "SpacedropRejected"; id: string } | { type: "PairingRequest"; id: number; name: string; os: OperatingSystem } | { type: "PairingProgress"; id: number; status: PairingStatus } - -export type P2PState = { node: { [key: string]: PeerStatus }; libraries: ([string, { [key: string]: PeerStatus }])[]; self_peer_id: PeerId; self_identity: string; config: ManagerConfig; manager_connected: { [key: PeerId]: string }; manager_connections: PeerId[]; dicovery_services: { [key: string]: { [key: string]: string } | null }; discovery_discovered: { [key: string]: { [key: string]: [PeerId, { [key: string]: string }, string[]] } }; discovery_known: { [key: string]: string[] } } +export type P2PEvent = { type: "DiscoveredPeer"; identity: RemoteIdentity; metadata: PeerMetadata } | { type: "ExpiredPeer"; identity: RemoteIdentity } | { type: "ConnectedPeer"; identity: RemoteIdentity } | { type: "DisconnectedPeer"; identity: RemoteIdentity } | { type: "SpacedropRequest"; id: string; identity: RemoteIdentity; peer_name: string; files: string[] } | { type: "SpacedropProgress"; id: string; percent: number } | { type: "SpacedropTimedout"; id: string } | { type: "SpacedropRejected"; id: string } | { type: "PairingRequest"; id: number; name: string; os: OperatingSystem } | { type: "PairingProgress"; id: number; status: PairingStatus } export type P2PStatus = { ipv4: ListenerStatus; ipv6: ListenerStatus } @@ -392,19 +475,27 @@ export type PairingDecision = { decision: "accept"; libraryId: string } | { deci export type PairingStatus = { type: "EstablishingConnection" } | { type: "PairingRequested" } | { type: "LibraryAlreadyExists" } | { type: "PairingDecisionRequest" } | { type: "PairingInProgress"; data: { library_name: string; library_description: string | null } } | { type: "InitialSyncProgress"; data: number } | { type: "PairingComplete"; data: string } | { type: "PairingRejected" } -export type PeerId = string - export type PeerMetadata = { name: string; operating_system: OperatingSystem | null; version: string | null } -export type PeerStatus = "Unavailable" | "Discovered" | "Connected" - export type PlusCode = string export type Range = { from: T } | { to: T } -export type RelationOperation = { relation_item: any; relation_group: any; relation: string; data: RelationOperationData } +/** + * A reference to a `CacheNode`. + * + * This does not contain the actual data, but instead a reference to it. + * This allows the CacheNode's to be switched out and the query recomputed without any backend communication. + * + * If you use a `Reference` in a query, you *must* ensure the corresponding `CacheNode` is also in the query. + */ +export type Reference = { __type: string; __id: string; "#type": T } -export type RelationOperationData = "c" | { u: { field: string; value: any } } | "d" +export type RelationOperation = { relation_item: JsonValue; relation_group: JsonValue; relation: string; data: RelationOperationData } + +export type RelationOperationData = "c" | { u: { field: string; value: JsonValue } } | "d" + +export type RemoteIdentity = string export type RenameFileArgs = { location_id: number; kind: RenameKind } @@ -422,11 +513,9 @@ export type Response = { Start: { user_code: string; verification_url: string; v export type RuleKind = "AcceptFilesByGlob" | "RejectFilesByGlob" | "AcceptIfChildrenDirectoriesArePresent" | "RejectIfChildrenDirectoriesArePresent" -export type SanitisedNodeConfig = { id: string; name: string; p2p_enabled: boolean; p2p_port: number | null; features: BackendFeature[]; preferences: NodePreferences } - export type SavedSearch = { id: number; pub_id: number[]; search: string | null; filters: string | null; name: string | null; icon: string | null; description: string | null; date_created: string | null; date_modified: string | null } -export type SearchData = { cursor: number[] | null; items: T[] } +export type SearchData = { cursor: number[] | null; items: Reference[]; nodes: CacheNode[] } export type SearchFilterArgs = { filePath: FilePathFilterArgs } | { object: ObjectFilterArgs } @@ -434,15 +523,19 @@ export type SetFavoriteArgs = { id: number; favorite: boolean } export type SetNoteArgs = { id: number; note: string | null } -export type SharedOperation = { record_id: any; model: string; data: SharedOperationData } +export type SharedOperation = { record_id: JsonValue; model: string; data: SharedOperationData } -export type SharedOperationData = "c" | { u: { field: string; value: any } } | "d" +export type SharedOperationData = "c" | { u: { field: string; value: JsonValue } } | "d" -export type SingleInvalidateOperationEvent = { key: string; arg: any; result: any | null } +export type SingleInvalidateOperationEvent = { +/** + * This fields are intentionally private. + */ +key: string; arg: JsonValue; result: JsonValue | null } export type SortOrder = "Asc" | "Desc" -export type SpacedropArgs = { identity: string; file_path: string[] } +export type SpacedropArgs = { identity: RemoteIdentity; file_path: string[] } export type Statistics = { id: number; date_captured: string; total_object_count: number; library_db_size: string; total_bytes_used: string; total_bytes_capacity: string; total_unique_bytes: string; total_bytes_free: string; preview_media_bytes: string } diff --git a/packages/client/src/hooks/useClientContext.tsx b/packages/client/src/hooks/useClientContext.tsx index f28d7976c..0eb9f064f 100644 --- a/packages/client/src/hooks/useClientContext.tsx +++ b/packages/client/src/hooks/useClientContext.tsx @@ -1,14 +1,15 @@ -import { createContext, PropsWithChildren, useContext, useMemo } from 'react'; +import { createContext, PropsWithChildren, useContext, useEffect, useMemo } from 'react'; +import { NormalisedCache, useCache, useNodes } from '../cache'; import { LibraryConfigWrapped } from '../core'; import { valtioPersist } from '../lib'; import { nonLibraryClient, useBridgeQuery } from '../rspc'; // The name of the localStorage key for caching library data -const libraryCacheLocalStorageKey = 'sd-library-list'; +const libraryCacheLocalStorageKey = 'sd-library-list2'; // `2` is because the format of this underwent a breaking change when introducing normalised caching -export const useCachedLibraries = () => - useBridgeQuery(['library.list'], { +export const useCachedLibraries = () => { + const result = useBridgeQuery(['library.list'], { keepPreviousData: true, initialData: () => { const cachedData = localStorage.getItem(libraryCacheLocalStorageKey); @@ -26,22 +27,33 @@ export const useCachedLibraries = () => }, onSuccess: (data) => localStorage.setItem(libraryCacheLocalStorageKey, JSON.stringify(data)) }); + useNodes(result.data?.nodes); -export async function getCachedLibraries() { + return { + ...result, + data: useCache(result.data?.items) + }; +}; + +export async function getCachedLibraries(cache: NormalisedCache) { const cachedData = localStorage.getItem(libraryCacheLocalStorageKey); if (cachedData) { // If we fail to load cached data, it's fine try { - return JSON.parse(cachedData) as LibraryConfigWrapped[]; + const data = JSON.parse(cachedData); + cache.withNodes(data.nodes); + return cache.withCache(data.items) as LibraryConfigWrapped[]; } catch (e) { console.error("Error loading cached 'sd-library-list' data", e); } } - const libraries = await nonLibraryClient.query(['library.list']); + const result = await nonLibraryClient.query(['library.list']); + cache.withNodes(result.nodes); + const libraries = cache.withCache(result.items); - localStorage.setItem(libraryCacheLocalStorageKey, JSON.stringify(libraries)); + localStorage.setItem(libraryCacheLocalStorageKey, JSON.stringify(result)); return libraries; } diff --git a/packages/client/src/index.ts b/packages/client/src/index.ts index 22b9eadee..888d3e8cc 100644 --- a/packages/client/src/index.ts +++ b/packages/client/src/index.ts @@ -27,3 +27,4 @@ export * from './core'; export * from './utils'; export * from './lib'; export * from './form'; +export * from './cache'; diff --git a/packages/client/src/rspc.tsx b/packages/client/src/rspc.tsx index 269da036f..a3574eedc 100644 --- a/packages/client/src/rspc.tsx +++ b/packages/client/src/rspc.tsx @@ -100,7 +100,7 @@ export function useInvalidateQuery() { for (const op of ops) { match(op) .with({ type: 'single', data: P.select() }, (op) => { - let key = [op.key]; + let key: any[] = [op.key]; if (op.arg !== null) { key = key.concat(op.arg); } diff --git a/packages/client/src/utils/explorerItem.ts b/packages/client/src/utils/explorerItem.ts index 35b3d10c5..eb2ab9d85 100644 --- a/packages/client/src/utils/explorerItem.ts +++ b/packages/client/src/utils/explorerItem.ts @@ -1,6 +1,7 @@ import { useMemo } from 'react'; -import type { ExplorerItem, FilePath, NonIndexedPathItem, Object } from '../core'; +import type { Object } from '..'; +import type { ExplorerItem, FilePath, NonIndexedPathItem } from '../core'; import { byteSize } from '../lib'; import { ObjectKind } from './objectKind'; diff --git a/packages/client/src/utils/index.ts b/packages/client/src/utils/index.ts index e97cd758d..d5a8f2503 100644 --- a/packages/client/src/utils/index.ts +++ b/packages/client/src/utils/index.ts @@ -1,4 +1,6 @@ -import { ExplorerItem } from '../core'; +import { QueryClient } from '@tanstack/react-query'; + +import { ExplorerItem, LibraryConfigWrapped } from '../core'; export * from './objectKind'; export * from './explorerItem'; @@ -39,3 +41,28 @@ export function formatNumber(n: number) { if (!n) return '0'; return Intl.NumberFormat().format(n); } + +export function insertLibrary(queryClient: QueryClient, library: LibraryConfigWrapped) { + queryClient.setQueryData(['library.list'], (libraries: any) => { + // The invalidation system beat us to it + if (libraries.items.find((l: any) => l.__id === library.uuid)) return libraries; + + return { + items: [ + ...(libraries.items || []), + { + __type: 'LibraryConfigWrapped', + __id: library.uuid + } + ], + nodes: [ + ...(libraries.nodes || []), + { + __type: 'LibraryConfigWrapped', + __id: library.uuid, + ...library + } + ] + }; + }); +} diff --git a/packages/client/src/utils/jobs/index.ts b/packages/client/src/utils/jobs/index.ts index b55ef0c9a..b5429dbdf 100644 --- a/packages/client/src/utils/jobs/index.ts +++ b/packages/client/src/utils/jobs/index.ts @@ -34,7 +34,7 @@ export function getTotalTasks(jobs: JobReport[]) { } export function getJobNiceActionName(action: string, completed: boolean, job?: JobReport) { - const name = job?.metadata?.location?.name || 'Unknown'; + const name = (job?.metadata?.location as any)?.name || 'Unknown'; switch (action) { case 'scan_location': return completed ? `Added location "${name}"` : `Adding location "${name}"`; diff --git a/packages/client/src/utils/jobs/useJobInfo.tsx b/packages/client/src/utils/jobs/useJobInfo.tsx index 4a716c9c2..c0e9fc9ff 100644 --- a/packages/client/src/utils/jobs/useJobInfo.tsx +++ b/packages/client/src/utils/jobs/useJobInfo.tsx @@ -20,12 +20,12 @@ export function useJobInfo(job: JobReport, realtimeUpdate: JobProgressEvent | nu const isRunning = job.status === 'Running', isQueued = job.status === 'Queued', isPaused = job.status === 'Paused', - indexedPath = job.metadata?.data?.location.path, + indexedPath = (job.metadata?.data as any)?.location.path, taskCount = realtimeUpdate?.task_count || job.task_count, completedTaskCount = realtimeUpdate?.completed_task_count || job.completed_task_count, phase = realtimeUpdate?.phase, meta = job.metadata, - output = meta?.output?.run_metadata; + output = (meta?.output as any)?.run_metadata; const data = { isRunning,