upgrade rspc

This commit is contained in:
Oscar Beaumont 2022-10-02 01:16:11 +08:00
parent 317ed2d7b0
commit 60e228ec94
43 changed files with 2496 additions and 2573 deletions

7
.vscode/extensions.json vendored Normal file
View file

@ -0,0 +1,7 @@
{
"recommendations": [
"tauri-apps.tauri-vscode",
"rust-lang.rust-analyzer",
"oscartbeaumont.rspc-vscode"
]
}

230
Cargo.lock generated
View file

@ -126,6 +126,20 @@ dependencies = [
"syn",
]
[[package]]
name = "async-tungstenite"
version = "0.17.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1b71b31561643aa8e7df3effe284fa83ab1a840e52294c5f4bd7bfd8b2becbb"
dependencies = [
"futures-io",
"futures-util",
"log",
"pin-project-lite",
"tokio",
"tungstenite",
]
[[package]]
name = "atk"
version = "0.15.1"
@ -200,7 +214,6 @@ checksum = "c9e3356844c4d6a6d6467b8da2cffb4a2820be256f50a3a386c9d152bab31043"
dependencies = [
"async-trait",
"axum-core",
"base64 0.13.0",
"bitflags",
"bytes",
"futures-util",
@ -216,10 +229,8 @@ dependencies = [
"serde",
"serde_json",
"serde_urlencoded",
"sha-1",
"sync_wrapper",
"tokio",
"tokio-tungstenite",
"tower",
"tower-http",
"tower-layer",
@ -509,7 +520,7 @@ dependencies = [
"num-integer",
"num-traits",
"serde",
"time 0.1.43",
"time 0.1.44",
"wasm-bindgen",
"winapi",
]
@ -627,6 +638,26 @@ version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fb4a24b1aaf0fd0ce8b45161144d6f42cd91677fd5940fd431183eb023b3a2b8"
[[package]]
name = "convert_case"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca"
dependencies = [
"unicode-segmentation",
]
[[package]]
name = "cookie"
version = "0.16.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "344adc371239ef32293cb1c4fe519592fcf21206c79c02854320afcdf3ab4917"
dependencies = [
"percent-encoding",
"time 0.3.14",
"version_check",
]
[[package]]
name = "core-foundation"
version = "0.9.3"
@ -709,15 +740,14 @@ dependencies = [
[[package]]
name = "crossbeam-epoch"
version = "0.9.10"
version = "0.9.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "045ebe27666471bb549370b4b0b3e51b07f56325befa4284db65fc89c02511b1"
checksum = "f916dfc5d356b0ed9dae65f1db9fc9770aa2851d2662b988ccf4fe3516e86348"
dependencies = [
"autocfg",
"cfg-if 1.0.0",
"crossbeam-utils",
"memoffset",
"once_cell",
"scopeguard",
]
@ -733,12 +763,11 @@ dependencies = [
[[package]]
name = "crossbeam-utils"
version = "0.8.11"
version = "0.8.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "51887d4adc7b564537b15adcfb307936f8075dfcd5f00dde9a9f1d29383682bc"
checksum = "edbafec5fa1f196ca66527c1b12c2ec4745ca14b50f1ad8f9f6f720b55d11fac"
dependencies = [
"cfg-if 1.0.0",
"once_cell",
]
[[package]]
@ -1831,6 +1860,24 @@ version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421"
[[package]]
name = "httpz"
version = "0.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "566824942ad0ee59fd23ded19025b37b51137eab4e467e48f7cab325a43efa50"
dependencies = [
"async-tungstenite",
"axum",
"base64 0.13.0",
"cookie",
"form_urlencoded",
"futures",
"http",
"hyper",
"sha1",
"tokio",
]
[[package]]
name = "hyper"
version = "0.14.20"
@ -1941,9 +1988,9 @@ dependencies = [
[[package]]
name = "image"
version = "0.24.3"
version = "0.24.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7e30ca2ecf7666107ff827a8e481de6a132a9b687ed3bb20bb1c144a36c00964"
checksum = "bd8e4fb07cf672b1642304e731ef8a6a4c7891d67bb4fd4f5ce58cd6ed86803c"
dependencies = [
"bytemuck",
"byteorder",
@ -2211,9 +2258,9 @@ checksum = "03087c2bad5e1034e8cace5926dec053fb3790248370865f5117a7d0213354c8"
[[package]]
name = "libc"
version = "0.2.133"
version = "0.2.134"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0f80d65747a3e43d1596c7c5492d95d5edddaabd45a7fcdb02b95f644164966"
checksum = "329c933548736bc49fd575ee68c89e8be4d260064184389a5b77517cddd99ffb"
[[package]]
name = "libdbus-sys"
@ -2596,15 +2643,6 @@ dependencies = [
"tracing-subscriber",
]
[[package]]
name = "nanoid"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3ffa00dec017b5b1a8b7cf5e2c008bfda1aa7e0697ac1508b491fdf2622fb4d8"
dependencies = [
"rand 0.8.5",
]
[[package]]
name = "nanorand"
version = "0.7.0"
@ -2714,9 +2752,9 @@ dependencies = [
[[package]]
name = "notify-rust"
version = "4.5.9"
version = "4.5.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89981320931e5f40cf7cf42a75de9ea445d2c61acd3a819fd4cd22cd8a610998"
checksum = "368e89ea58df747ce88be669ae44e79783c1d30bfd540ad0fc520b3f41f0b3b0"
dependencies = [
"dbus",
"mac-notification-sys",
@ -2725,9 +2763,9 @@ dependencies = [
[[package]]
name = "ntapi"
version = "0.3.7"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c28774a7fd2fbb4f0babd8237ce554b73af68021b5f695a3cebd6c59bac0980f"
checksum = "bc51db7b362b205941f71232e56c625156eb9a929f8cf74a428fd5bc094a4afc"
dependencies = [
"winapi",
]
@ -2896,9 +2934,9 @@ dependencies = [
[[package]]
name = "openssl"
version = "0.10.41"
version = "0.10.42"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "618febf65336490dfcf20b73f885f5651a0c89c64c2d4a8c3662585a70bf5bd0"
checksum = "12fc0523e3bd51a692c8850d075d74dc062ccf251c0110668cbd921917118a13"
dependencies = [
"bitflags",
"cfg-if 1.0.0",
@ -2928,17 +2966,18 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
[[package]]
name = "openssl-src"
version = "300.0.9+3.0.5"
version = "111.22.0+1.1.1q"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df52116687e2d276515a1cbf0b84d2fb646f519aebe65d2fa82f28c5d078f174"
checksum = "8f31f0d509d1c1ae9cada2f9539ff8f37933831fd5098879e482aa687d659853"
dependencies = [
"cc",
]
[[package]]
name = "openssl-sys"
version = "0.9.75"
source = "git+https://github.com/spacedriveapp/rust-openssl#f49328d2fc62e5ade3a321eed75cf4b250bda8b7"
version = "0.9.76"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5230151e44c0f05157effb743e8d517472843121cf9243e8b81393edb5acd9ce"
dependencies = [
"autocfg",
"cc",
@ -3143,9 +3182,9 @@ checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e"
[[package]]
name = "pest"
version = "2.3.1"
version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb779fcf4bb850fbbb0edc96ff6cf34fd90c4b1a112ce042653280d9a7364048"
checksum = "dbc7bc69c062e492337d74d59b120c274fd3d261b6bf6d3207d499b4b379c41a"
dependencies = [
"thiserror",
"ucd-trie",
@ -3153,9 +3192,9 @@ dependencies = [
[[package]]
name = "pest_derive"
version = "2.3.1"
version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "502b62a6d0245378b04ffe0a7fb4f4419a4815fce813bd8a0ec89a56e07d67b1"
checksum = "60b75706b9642ebcb34dab3bc7750f811609a0eb1dd8b88c2d15bf628c1c65b2"
dependencies = [
"pest",
"pest_generator",
@ -3163,9 +3202,9 @@ dependencies = [
[[package]]
name = "pest_generator"
version = "2.3.1"
version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "451e629bf49b750254da26132f1a5a9d11fd8a95a3df51d15c4abd1ba154cb6c"
checksum = "f4f9272122f5979a6511a749af9db9bfc810393f63119970d7085fed1c4ea0db"
dependencies = [
"pest",
"pest_meta",
@ -3176,9 +3215,9 @@ dependencies = [
[[package]]
name = "pest_meta"
version = "2.3.1"
version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bcec162c71c45e269dfc3fc2916eaeb97feab22993a21bcce4721d08cd7801a6"
checksum = "4c8717927f9b79515e565a64fe46c38b8cd0427e64c40680b14a7365ab09ac8d"
dependencies = [
"once_cell",
"pest",
@ -3391,7 +3430,7 @@ dependencies = [
[[package]]
name = "prisma-client-rust"
version = "0.6.1"
source = "git+https://github.com//Brendonovich/prisma-client-rust.git?rev=6b59d9f0a07c4c5df1f5c97f2c6c1df7082ccac6#6b59d9f0a07c4c5df1f5c97f2c6c1df7082ccac6"
source = "git+https://github.com//Brendonovich/prisma-client-rust.git?branch=rspc-0.1.1#c580af4195c7278c1fddf12149ae38cec2c9869e"
dependencies = [
"base64 0.13.0",
"bigdecimal",
@ -3420,7 +3459,7 @@ dependencies = [
[[package]]
name = "prisma-client-rust-cli"
version = "0.6.1"
source = "git+https://github.com//Brendonovich/prisma-client-rust.git?rev=6b59d9f0a07c4c5df1f5c97f2c6c1df7082ccac6#6b59d9f0a07c4c5df1f5c97f2c6c1df7082ccac6"
source = "git+https://github.com//Brendonovich/prisma-client-rust.git?branch=rspc-0.1.1#c580af4195c7278c1fddf12149ae38cec2c9869e"
dependencies = [
"datamodel",
"prisma-client-rust-sdk",
@ -3435,7 +3474,7 @@ dependencies = [
[[package]]
name = "prisma-client-rust-sdk"
version = "0.6.1"
source = "git+https://github.com//Brendonovich/prisma-client-rust.git?rev=6b59d9f0a07c4c5df1f5c97f2c6c1df7082ccac6#6b59d9f0a07c4c5df1f5c97f2c6c1df7082ccac6"
source = "git+https://github.com//Brendonovich/prisma-client-rust.git?branch=rspc-0.1.1#c580af4195c7278c1fddf12149ae38cec2c9869e"
dependencies = [
"convert_case 0.5.0",
"datamodel",
@ -3540,9 +3579,9 @@ checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5"
[[package]]
name = "proc-macro2"
version = "1.0.43"
version = "1.0.46"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0a2ca2c61bc9f3d74d2886294ab7b9853abd9c1ad903a3ac7815c58989bb7bab"
checksum = "94e2ef8dbfc347b10c094890f778ee2e36ca9bb4262e86dc99cd217e35f3470b"
dependencies = [
"unicode-ident",
]
@ -3594,7 +3633,7 @@ dependencies = [
"mach",
"once_cell",
"raw-cpuid",
"wasi 0.10.2+wasi-snapshot-preview1",
"wasi 0.10.0+wasi-snapshot-preview1",
"web-sys",
"winapi",
]
@ -3821,15 +3860,6 @@ dependencies = [
"bitflags",
]
[[package]]
name = "raw-window-handle"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b800beb9b6e7d2df1fe337c9e3d04e3af22a124460fb4c30fcc22c9117cefb41"
dependencies = [
"cty",
]
[[package]]
name = "raw-window-handle"
version = "0.5.0"
@ -4009,7 +4039,7 @@ dependencies = [
"objc",
"objc-foundation",
"objc_id",
"raw-window-handle 0.5.0",
"raw-window-handle",
"wasm-bindgen",
"wasm-bindgen-futures",
"web-sys",
@ -4044,9 +4074,9 @@ dependencies = [
[[package]]
name = "rmp-serde"
version = "1.1.0"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "25786b0d276110195fa3d6f3f31299900cf71dfbd6c28450f3f58a0e7f7a347e"
checksum = "c5b13be192e0220b8afb7222aa5813cb62cc269ebb5cac346ca6487681d2913e"
dependencies = [
"byteorder",
"rmp",
@ -4055,13 +4085,13 @@ dependencies = [
[[package]]
name = "rspc"
version = "0.0.5"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "443633b1d8808c9b4e27dce8797b9062f86ae214999c825fd9133a73d6550333"
checksum = "712fc4e2fc79297d308fa4575f19f6967bf7610e3292446dfb392738aeab5239"
dependencies = [
"axum",
"async-stream",
"futures",
"nanoid",
"httpz",
"serde",
"serde_json",
"specta",
@ -4655,12 +4685,12 @@ dependencies = [
[[package]]
name = "specta"
version = "0.0.3"
version = "0.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e4145d41e1881c57b714f979ef01c8add58a1984b46f8858ea67f35fd01ebd1e"
checksum = "5886f252f583ae32d4ae21c228c7a4ab3da40a7ebed646886b942f4085047394"
dependencies = [
"chrono",
"convert_case 0.5.0",
"convert_case 0.6.0",
"indexmap",
"serde_json",
"specta-macros",
@ -4900,9 +4930,9 @@ dependencies = [
[[package]]
name = "syn"
version = "1.0.100"
version = "1.0.101"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "52205623b1b0f064a4e71182c3b18ae902267282930c6d5462c91b859668426e"
checksum = "e90cde112c4b9690b8cbe810cba9ddd8bc1d7472e2cae317b69e9438c1cba7d2"
dependencies = [
"proc-macro2",
"quote",
@ -4921,9 +4951,9 @@ checksum = "20518fe4a4c9acf048008599e464deb21beeae3d3578418951a189c235a7a9a8"
[[package]]
name = "sysinfo"
version = "0.23.13"
version = "0.26.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3977ec2e0520829be45c8a2df70db2bf364714d8a748316a10c3c35d4d2b01c9"
checksum = "7890fff842b8db56f2033ebee8f6efe1921475c3830c115995552914fb967580"
dependencies = [
"cfg-if 1.0.0",
"core-foundation-sys",
@ -4996,7 +5026,7 @@ dependencies = [
"parking_lot 0.12.1",
"paste",
"png 0.17.6",
"raw-window-handle 0.5.0",
"raw-window-handle",
"scopeguard",
"serde",
"unicode-segmentation",
@ -5045,7 +5075,7 @@ dependencies = [
"os_pipe",
"percent-encoding",
"rand 0.8.5",
"raw-window-handle 0.5.0",
"raw-window-handle",
"regex",
"rfd",
"semver 1.0.14",
@ -5137,7 +5167,7 @@ dependencies = [
"http-range",
"infer",
"rand 0.8.5",
"raw-window-handle 0.5.0",
"raw-window-handle",
"serde",
"serde_json",
"tauri-utils",
@ -5157,7 +5187,7 @@ dependencies = [
"gtk",
"percent-encoding",
"rand 0.8.5",
"raw-window-handle 0.5.0",
"raw-window-handle",
"tauri-runtime",
"tauri-utils",
"uuid 1.1.2",
@ -5257,18 +5287,18 @@ checksum = "8eaa81235c7058867fa8c0e7314f33dcce9c215f535d1913822a2b3f5e289f3c"
[[package]]
name = "thiserror"
version = "1.0.35"
version = "1.0.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c53f98874615aea268107765aa1ed8f6116782501d18e53d08b471733bea6c85"
checksum = "10deb33631e3c9018b9baf9dcbbc4f737320d2b576bac10f6aefa048fa407e3e"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.35"
version = "1.0.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8b463991b4eab2d801e724172285ec4195c650e8ec79b149e6c2a8e6dd3f783"
checksum = "982d17546b47146b28f7c22e3d08465f6b8903d0ea13c1660d9d84a6e7adcdbb"
dependencies = [
"proc-macro2",
"quote",
@ -5306,11 +5336,12 @@ dependencies = [
[[package]]
name = "time"
version = "0.1.43"
version = "0.1.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438"
checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255"
dependencies = [
"libc",
"wasi 0.10.0+wasi-snapshot-preview1",
"winapi",
]
@ -5323,8 +5354,15 @@ dependencies = [
"itoa 1.0.3",
"libc",
"num_threads",
"time-macros",
]
[[package]]
name = "time-macros"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42657b1a6f4d817cda8e7a0ace261fe0cc946cf3a80314390b22cc61ae080792"
[[package]]
name = "tinyvec"
version = "1.6.0"
@ -5342,9 +5380,9 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c"
[[package]]
name = "tokio"
version = "1.21.1"
version = "1.21.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0020c875007ad96677dcc890298f4b942882c5d4eb7cc8f439fc3bf813dc9c95"
checksum = "a9e03c497dc955702ba729190dc4aac6f2a0ce97f913e5b1b5912fc5039d9099"
dependencies = [
"autocfg",
"bytes",
@ -5352,7 +5390,6 @@ dependencies = [
"memchr",
"mio",
"num_cpus",
"once_cell",
"pin-project-lite",
"signal-hook-registry",
"socket2",
@ -5381,18 +5418,6 @@ dependencies = [
"tokio",
]
[[package]]
name = "tokio-tungstenite"
version = "0.17.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f714dd15bead90401d77e04243611caec13726c2408afd5b31901dfcdcb3b181"
dependencies = [
"futures-util",
"log",
"tokio",
"tungstenite",
]
[[package]]
name = "tokio-util"
version = "0.7.4"
@ -5804,9 +5829,9 @@ checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
[[package]]
name = "wasi"
version = "0.10.2+wasi-snapshot-preview1"
version = "0.10.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f"
[[package]]
name = "wasi"
@ -6024,13 +6049,13 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "window-shadows"
version = "0.1.3"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "796156ad1a67853e927727809bb6138ddc1f19ebced0dc976c0d109d5e2576f7"
checksum = "6c69eb48aac2da0199ea148c6f2c2610db8a0572b32a3dc857dec40ca22f1cec"
dependencies = [
"cocoa",
"objc",
"raw-window-handle 0.4.3",
"raw-window-handle",
"windows-sys",
]
@ -6337,3 +6362,8 @@ name = "xml-rs"
version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2d7d3948613f75c98fd9328cfdcc45acc4d360655289d0a7d4ec931392200a3"
[[patch.unused]]
name = "openssl-sys"
version = "0.9.75"
source = "git+https://github.com/spacedriveapp/rust-openssl#f49328d2fc62e5ade3a321eed75cf4b250bda8b7"

View file

@ -13,5 +13,5 @@ resolver = "2"
openssl-sys = { git = "https://github.com/spacedriveapp/rust-openssl" }
[patch."https://github.com/Brendonovich/prisma-client-rust.git"]
prisma-client-rust = { git = "https://github.com//Brendonovich/prisma-client-rust.git", rev = "6b59d9f0a07c4c5df1f5c97f2c6c1df7082ccac6" }
prisma-client-rust-cli = { git = "https://github.com//Brendonovich/prisma-client-rust.git", rev = "6b59d9f0a07c4c5df1f5c97f2c6c1df7082ccac6" }
prisma-client-rust ={ git = "https://github.com//Brendonovich/prisma-client-rust.git", branch = "rspc-0.1.1" }
prisma-client-rust-cli = { git = "https://github.com//Brendonovich/prisma-client-rust.git", branch = "rspc-0.1.1" }

View file

@ -11,32 +11,32 @@
"build": "tauri build"
},
"dependencies": {
"@rspc/client": "^0.0.6",
"@rspc/tauri": "^0.0.6",
"@rspc/client": "^0.1.2",
"@rspc/tauri": "^0.1.2",
"@sd/client": "workspace:*",
"@sd/interface": "workspace:*",
"@sd/ui": "workspace:*",
"@tanstack/react-query": "^4.0.10",
"@tauri-apps/api": "1.0.2",
"@tanstack/react-query": "^4.8.0",
"@tauri-apps/api": "1.1.0",
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
"devDependencies": {
"@tauri-apps/cli": "1.0.5",
"@tauri-apps/cli": "1.1.1",
"@tauri-apps/tauricon": "github:tauri-apps/tauricon",
"@types/babel-core": "^6.25.7",
"@types/byte-size": "^8.1.0",
"@types/react": "^18.0.15",
"@types/react": "^18.0.21",
"@types/react-dom": "^18.0.6",
"@types/react-router-dom": "^5.3.3",
"@types/react-window": "^1.8.5",
"@types/tailwindcss": "^3.1.0",
"@vitejs/plugin-react": "^2.0.0",
"concurrently": "^7.3.0",
"@vitejs/plugin-react": "^2.1.0",
"concurrently": "^7.4.0",
"prettier": "^2.7.1",
"sass": "^1.54.0",
"typescript": "^4.7.4",
"vite": "^3.0.3",
"sass": "^1.55.0",
"typescript": "^4.8.4",
"vite": "^3.1.4",
"vite-plugin-filter-replace": "^0.1.9",
"vite-plugin-svgr": "^2.2.1"
}

View file

@ -10,19 +10,19 @@ edition = "2021"
build = "build.rs"
[dependencies]
tauri = { version = "1.0.4", features = ["api-all", "macos-private-api"] }
rspc = { version = "0.0.5", features = ["tauri"] }
tauri = { version = "1.1.1", features = ["api-all", "macos-private-api"] }
rspc = { version = "0.1.2", features = ["tauri"] }
sdcore = { path = "../../../core", features = ["ffmpeg"] }
tokio = { version = "1.17.0", features = ["sync"] }
window-shadows = "0.1.2"
tracing = "0.1.35"
serde = "1.0.144"
tokio = { version = "1.21.2", features = ["sync"] }
window-shadows = "0.2.0"
tracing = "0.1.36"
serde = "1.0.145"
[target.'cfg(target_os = "macos")'.dependencies]
swift-rs = { git = "https://github.com/Brendonovich/swift-rs.git", branch = "autorelease" }
[build-dependencies]
tauri-build = { version = "1.0.0", features = [] }
tauri-build = { version = "1.1.1", features = [] }
[target.'cfg(target_os = "macos")'.build-dependencies]
swift-rs = { git = "https://github.com/Brendonovich/swift-rs.git", branch = "autorelease", features = ["build"] }

View file

@ -1,6 +1,6 @@
import { createClient } from '@rspc/client';
import { TauriTransport } from '@rspc/tauri';
import { OperatingSystem, Operations, PlatformProvider, queryClient, rspc } from '@sd/client';
import { OperatingSystem, PlatformProvider, Procedures, queryClient, rspc } from '@sd/client';
import SpacedriveInterface, { Platform } from '@sd/interface';
import { KeybindEvent } from '@sd/interface';
import { dialog, invoke, os } from '@tauri-apps/api';
@ -10,7 +10,7 @@ import { createRoot } from 'react-dom/client';
import '@sd/ui/style';
const client = createClient<Operations>({
const client = createClient<Procedures>({
transport: new TauriTransport()
});

View file

@ -10,21 +10,21 @@
"lint": "eslint src/**/*.{ts,tsx} && tsc --noEmit"
},
"dependencies": {
"@headlessui/react": "^1.6.6",
"@headlessui/react": "^1.7.2",
"@heroicons/react": "^2.0.11",
"@icons-pack/react-simple-icons": "^5.2.0",
"@icons-pack/react-simple-icons": "^5.7.0",
"@sd/assets": "link:../../packages/assets",
"@sd/interface": "link:../../packages/interface",
"@sd/ui": "link:../../packages/ui",
"@tryghost/content-api": "^1.11.0",
"@tryghost/content-api": "^1.11.4",
"@types/compression": "^1.7.2",
"@types/express": "^4.17.13",
"@types/express": "^4.17.14",
"@types/marked": "^4.0.7",
"@types/node": "^17.0.31",
"@types/react": "^18.0.6",
"@types/node": "^18.7.23",
"@types/react": "^18.0.21",
"@types/react-burger-menu": "^2.8.3",
"@types/react-dom": "^18.0.3",
"@vitejs/plugin-react": "^1.3.2",
"@types/react-dom": "^18.0.6",
"@vitejs/plugin-react": "^2.1.0",
"clsx": "^1.2.1",
"compression": "^1.7.4",
"cross-env": "^7.0.3",
@ -32,32 +32,32 @@
"markdown-yaml-metadata-parser": "^3.0.0",
"marked": "^4.1.0",
"phosphor-react": "^1.4.1",
"prismjs": "^1.28.0",
"prismjs": "^1.29.0",
"react": "^18.2.0",
"react-burger-menu": "^3.0.8",
"react-dom": "^18.2.0",
"react-helmet": "^6.1.0",
"react-hook-form": "^7.33.1",
"react-tsparticles": "^2.1.3",
"react-hook-form": "^7.36.1",
"react-tsparticles": "^2.3.2",
"sirv": "^2.0.2",
"ts-node": "^10.7.0",
"tsparticles": "^2.1.3",
"typescript": "^4.6.4",
"vite": "^3.1.1",
"vite-plugin-ssr": "^0.4.28"
"ts-node": "^10.9.1",
"tsparticles": "^2.3.2",
"typescript": "^4.8.4",
"vite": "^3.1.4",
"vite-plugin-ssr": "^0.4.38"
},
"devDependencies": {
"@sd/config": "link:../../packages/config",
"@tailwindcss/line-clamp": "^0.4.0",
"@tailwindcss/typography": "^0.5.4",
"@tailwindcss/line-clamp": "^0.4.2",
"@tailwindcss/typography": "^0.5.7",
"@types/prismjs": "^1.26.0",
"@types/react-helmet": "^6.1.5",
"@types/tryghost__content-api": "^1.3.11",
"postcss": "^8.4.14",
"rollup-plugin-visualizer": "^5.8.1",
"sass": "^1.54.0",
"postcss": "^8.4.17",
"rollup-plugin-visualizer": "^5.8.2",
"sass": "^1.55.0",
"tailwind": "^4.0.0",
"vite-plugin-markdown": "^2.0.2",
"vite-plugin-markdown": "^2.1.0",
"vite-plugin-svgr": "^2.2.1"
}
}

View file

@ -17,8 +17,8 @@
"@react-navigation/drawer": "^6.4.4",
"@react-navigation/native": "^6.0.12",
"@react-navigation/stack": "^6.2.3",
"@rspc/client": "^0.0.6",
"@rspc/react": "^0.0.6",
"@rspc/client": "^0.1.2",
"@rspc/react": "^0.1.2",
"@sd/assets": "file:../../packages/assets",
"@tanstack/react-query": "^4.2.3",
"byte-size": "^8.1.0",

View file

@ -15,8 +15,8 @@ importers:
'@react-navigation/stack': ^6.2.3
'@rnx-kit/metro-config': ^1.2.37
'@rnx-kit/metro-resolver-symlinks': ^0.1.21
'@rspc/client': ^0.0.6
'@rspc/react': ^0.0.6
'@rspc/client': ^0.1.2
'@rspc/react': ^0.1.2
'@sd/assets': file:../../packages/assets
'@tanstack/react-query': ^4.2.3
'@types/react': ~18.0.0
@ -64,8 +64,8 @@ importers:
'@react-navigation/drawer': 6.4.4_ywqefi2mkvedjihbydxse4r6wi
'@react-navigation/native': 6.0.12_jk6ntyzimkrv4hwdmdgaaf5yaa
'@react-navigation/stack': 6.2.3_g6rcykmgspzf2j66bcli5dyok4
'@rspc/client': 0.0.6
'@rspc/react': 0.0.6_jk6ntyzimkrv4hwdmdgaaf5yaa
'@rspc/client': 0.1.2
'@rspc/react': 0.1.2_qxlhziqfutyqts5zm22lyyqixy
'@sd/assets': file:../../packages/assets
'@tanstack/react-query': 4.2.3_jk6ntyzimkrv4hwdmdgaaf5yaa
byte-size: 8.1.0
@ -81,7 +81,7 @@ importers:
moti: 0.18.0_react@18.0.0
phosphor-react-native: 1.1.2_ipumakbosk2s7ylysjmrulvctq
react: 18.0.0
react-native: 0.69.4_k6xwmnqmgysg6weibx66ue6pyi
react-native: 0.69.4_react@18.0.0
react-native-gesture-handler: 2.5.0_jk6ntyzimkrv4hwdmdgaaf5yaa
react-native-heroicons: 2.2.0_wxlif5cfng7xfd3uerlw46xcs4
react-native-reanimated: 2.10.0_s4gdcbt2zwshcgkhtvkmdoj3my
@ -1863,7 +1863,7 @@ packages:
invariant: 2.2.4
nanoid: 3.3.4
react: 18.0.0
react-native: 0.69.4_k6xwmnqmgysg6weibx66ue6pyi
react-native: 0.69.4_react@18.0.0
react-native-gesture-handler: 2.5.0_jk6ntyzimkrv4hwdmdgaaf5yaa
react-native-reanimated: 2.10.0_s4gdcbt2zwshcgkhtvkmdoj3my
react-native-redash: 16.3.0_vlgoh3gg3ptp2ic2mlqzb2jwsy
@ -1877,7 +1877,7 @@ packages:
dependencies:
nanoid: 3.3.4
react: 18.0.0
react-native: 0.69.4_k6xwmnqmgysg6weibx66ue6pyi
react-native: 0.69.4_react@18.0.0
dev: false
/@graphql-typed-document-node/core/3.1.1_graphql@15.8.0:
@ -2091,7 +2091,7 @@ packages:
react-native: ^0.0.0-0 || 0.60 - 0.69 || 1000.0.0
dependencies:
merge-options: 3.0.4
react-native: 0.69.4_k6xwmnqmgysg6weibx66ue6pyi
react-native: 0.69.4_react@18.0.0
dev: false
/@react-native-community/cli-clean/8.0.4:
@ -2184,7 +2184,7 @@ packages:
transitivePeerDependencies:
- encoding
/@react-native-community/cli-plugin-metro/8.0.4_@babel+core@7.18.10:
/@react-native-community/cli-plugin-metro/8.0.4:
resolution: {integrity: sha512-UWzY1eMcEr/6262R2+d0Is5M3L/7Y/xXSDIFMoc5Rv5Wucl3hJM/TxHXmByvHpuJf6fJAfqOskyt4bZCvbI+wQ==}
dependencies:
'@react-native-community/cli-server-api': 8.0.4
@ -2193,12 +2193,11 @@ packages:
metro: 0.70.3
metro-config: 0.70.3
metro-core: 0.70.3
metro-react-native-babel-transformer: 0.70.3_@babel+core@7.18.10
metro-react-native-babel-transformer: 0.70.3
metro-resolver: 0.70.3
metro-runtime: 0.70.3
readline: 1.3.0
transitivePeerDependencies:
- '@babel/core'
- bufferutil
- encoding
- supports-color
@ -2243,7 +2242,7 @@ packages:
dependencies:
joi: 17.6.0
/@react-native-community/cli/8.0.5_mqmjqcyqm4trh6m6pjidkcb5na:
/@react-native-community/cli/8.0.5_react-native@0.69.4:
resolution: {integrity: sha512-X0AMNK+sKDJQX8eQRkqgddJsZPWlHgLryX7O9usj78UFEK8VqVYtpv08piWecfAhC2mZU4/Lww4bKu9uJ1rdyQ==}
engines: {node: '>=12'}
hasBin: true
@ -2255,7 +2254,7 @@ packages:
'@react-native-community/cli-debugger-ui': 8.0.0
'@react-native-community/cli-doctor': 8.0.4
'@react-native-community/cli-hermes': 8.0.5
'@react-native-community/cli-plugin-metro': 8.0.4_@babel+core@7.18.10
'@react-native-community/cli-plugin-metro': 8.0.4
'@react-native-community/cli-server-api': 8.0.4
'@react-native-community/cli-tools': 8.0.4
'@react-native-community/cli-types': 8.0.0
@ -2269,10 +2268,9 @@ packages:
lodash: 4.17.21
minimist: 1.2.6
prompts: 2.4.2
react-native: 0.69.4_k6xwmnqmgysg6weibx66ue6pyi
react-native: 0.69.4_react@18.0.0
semver: 6.3.0
transitivePeerDependencies:
- '@babel/core'
- bufferutil
- encoding
- supports-color
@ -2285,7 +2283,7 @@ packages:
react-native: '>=0.57'
dependencies:
react: 18.0.0
react-native: 0.69.4_k6xwmnqmgysg6weibx66ue6pyi
react-native: 0.69.4_react@18.0.0
dev: false
/@react-native/assets/1.0.0:
@ -2310,7 +2308,7 @@ packages:
'@react-navigation/native': 6.0.12_jk6ntyzimkrv4hwdmdgaaf5yaa
color: 4.2.3
react: 18.0.0
react-native: 0.69.4_k6xwmnqmgysg6weibx66ue6pyi
react-native: 0.69.4_react@18.0.0
react-native-safe-area-context: 4.3.1_jk6ntyzimkrv4hwdmdgaaf5yaa
react-native-screens: 3.15.0_jk6ntyzimkrv4hwdmdgaaf5yaa
warn-once: 0.1.1
@ -2345,7 +2343,7 @@ packages:
'@react-navigation/native': 6.0.12_jk6ntyzimkrv4hwdmdgaaf5yaa
color: 4.2.3
react: 18.0.0
react-native: 0.69.4_k6xwmnqmgysg6weibx66ue6pyi
react-native: 0.69.4_react@18.0.0
react-native-gesture-handler: 2.5.0_jk6ntyzimkrv4hwdmdgaaf5yaa
react-native-reanimated: 2.10.0_s4gdcbt2zwshcgkhtvkmdoj3my
react-native-safe-area-context: 4.3.1_jk6ntyzimkrv4hwdmdgaaf5yaa
@ -2363,7 +2361,7 @@ packages:
dependencies:
'@react-navigation/native': 6.0.12_jk6ntyzimkrv4hwdmdgaaf5yaa
react: 18.0.0
react-native: 0.69.4_k6xwmnqmgysg6weibx66ue6pyi
react-native: 0.69.4_react@18.0.0
react-native-safe-area-context: 4.3.1_jk6ntyzimkrv4hwdmdgaaf5yaa
dev: false
@ -2378,7 +2376,7 @@ packages:
fast-deep-equal: 3.1.3
nanoid: 3.3.4
react: 18.0.0
react-native: 0.69.4_k6xwmnqmgysg6weibx66ue6pyi
react-native: 0.69.4_react@18.0.0
dev: false
/@react-navigation/routers/6.1.2:
@ -2401,7 +2399,7 @@ packages:
'@react-navigation/native': 6.0.12_jk6ntyzimkrv4hwdmdgaaf5yaa
color: 4.2.3
react: 18.0.0
react-native: 0.69.4_k6xwmnqmgysg6weibx66ue6pyi
react-native: 0.69.4_react@18.0.0
react-native-gesture-handler: 2.5.0_jk6ntyzimkrv4hwdmdgaaf5yaa
react-native-safe-area-context: 4.3.1_jk6ntyzimkrv4hwdmdgaaf5yaa
react-native-screens: 3.15.0_jk6ntyzimkrv4hwdmdgaaf5yaa
@ -2434,7 +2432,7 @@ packages:
'@rnx-kit/tools-node': 1.3.0
'@rnx-kit/tools-workspaces': 0.1.1
react: 18.0.0
react-native: 0.69.4_k6xwmnqmgysg6weibx66ue6pyi
react-native: 0.69.4_react@18.0.0
transitivePeerDependencies:
- '@babel/core'
- '@babel/plugin-transform-typescript'
@ -2478,21 +2476,19 @@ packages:
read-yaml-file: 2.1.0
dev: true
/@rspc/client/0.0.6:
resolution: {integrity: sha512-NcJbmObbf+BzFcYWGvZaP7+a+KWTbAk9CkBRqW1nIu7TamV7tZtkHVmibwPHTeFnpAKPlKV7SH5vodV4yYETcw==}
/@rspc/client/0.1.2:
resolution: {integrity: sha512-MfgSZkrqVzzqCN4GU3LKhfy4qG+PS1LpEz/MMays6rtz5EFNJIvEVMA5Ooc+DH8KLe5h4/3bf4dfyEs7czhA2w==}
dev: false
/@rspc/react/0.0.6_jk6ntyzimkrv4hwdmdgaaf5yaa:
resolution: {integrity: sha512-iU7DUbc0WkMW7q53sx0+t/gUhcShQ/a0KLpBmHGT6QTwhjnFsdqzW7GohCD4CTcT+RYUxirqHq6TvKPlmtKHcQ==}
/@rspc/react/0.1.2_qxlhziqfutyqts5zm22lyyqixy:
resolution: {integrity: sha512-uLyBPCx+Bwk2qkvIcVJQWHT1Z9WhvzbbX4zfEsrZdk2aVtwVb6q0anbIBM/eGc7QgLowaOcSi/o7MZTAL4Sbsw==}
peerDependencies:
'@tanstack/react-query': ^4.8.0
react: ^16.8.0 || ^17.0.0 || ^18.0.0
dependencies:
'@rspc/client': 0.0.6
'@rspc/client': 0.1.2
'@tanstack/react-query': 4.2.3_jk6ntyzimkrv4hwdmdgaaf5yaa
react: 18.0.0
transitivePeerDependencies:
- react-dom
- react-native
dev: false
/@segment/loosely-validate-event/2.0.0:
@ -2667,7 +2663,7 @@ packages:
'@tanstack/query-core': 4.2.3
'@types/use-sync-external-store': 0.0.3
react: 18.0.0
react-native: 0.69.4_k6xwmnqmgysg6weibx66ue6pyi
react-native: 0.69.4_react@18.0.0
use-sync-external-store: 1.2.0_react@18.0.0
dev: false
@ -3214,7 +3210,7 @@ packages:
'@babel/preset-env': 7.18.10_@babel+core@7.18.10
babel-plugin-module-resolver: 4.1.0
babel-plugin-react-native-web: 0.18.9
metro-react-native-babel-preset: 0.70.3_@babel+core@7.18.10
metro-react-native-babel-preset: 0.70.3
transitivePeerDependencies:
- '@babel/core'
- supports-color
@ -5912,7 +5908,7 @@ packages:
dependencies:
invariant: 2.2.4
react: 18.0.0
react-native: 0.69.4_k6xwmnqmgysg6weibx66ue6pyi
react-native: 0.69.4_react@18.0.0
react-native-safe-modules: 1.0.3_react-native@0.69.4
dev: false
@ -6069,10 +6065,8 @@ packages:
dependencies:
uglify-es: 3.3.9
/metro-react-native-babel-preset/0.70.3_@babel+core@7.18.10:
/metro-react-native-babel-preset/0.70.3:
resolution: {integrity: sha512-4Nxc1zEiHEu+GTdEMEsHnRgfaBkg8f/Td3+FcQ8NTSvs+xL3LBrQy6N07idWSQZHIdGFf+tTHvRfSIWLD8u8Tg==}
peerDependencies:
'@babel/core': '*'
dependencies:
'@babel/core': 7.18.10
'@babel/plugin-proposal-async-generator-functions': 7.18.10_@babel+core@7.18.10
@ -6116,16 +6110,14 @@ packages:
transitivePeerDependencies:
- supports-color
/metro-react-native-babel-transformer/0.70.3_@babel+core@7.18.10:
/metro-react-native-babel-transformer/0.70.3:
resolution: {integrity: sha512-WKBU6S/G50j9cfmFM4k4oRYprd8u3qjleD4so1E2zbTNILg+gYla7ZFGCAvi2G0ZcqS2XuGCR375c2hF6VVvwg==}
peerDependencies:
'@babel/core': '*'
dependencies:
'@babel/core': 7.18.10
babel-preset-fbjs: 3.4.0_@babel+core@7.18.10
hermes-parser: 0.6.0
metro-babel-transformer: 0.70.3
metro-react-native-babel-preset: 0.70.3_@babel+core@7.18.10
metro-react-native-babel-preset: 0.70.3
metro-source-map: 0.70.3
nullthrows: 1.1.1
transitivePeerDependencies:
@ -6238,7 +6230,7 @@ packages:
metro-hermes-compiler: 0.70.3
metro-inspector-proxy: 0.70.3
metro-minify-uglify: 0.70.3
metro-react-native-babel-preset: 0.70.3_@babel+core@7.18.10
metro-react-native-babel-preset: 0.70.3
metro-resolver: 0.70.3
metro-runtime: 0.70.3
metro-source-map: 0.70.3
@ -6861,7 +6853,7 @@ packages:
dependencies:
caniuse-lite: 1.0.30001374
react: 18.0.0
react-native: 0.69.4_k6xwmnqmgysg6weibx66ue6pyi
react-native: 0.69.4_react@18.0.0
react-native-svg: 13.0.0_jk6ntyzimkrv4hwdmdgaaf5yaa
dev: false
@ -7190,7 +7182,7 @@ packages:
lodash: 4.17.21
prop-types: 15.8.1
react: 18.0.0
react-native: 0.69.4_k6xwmnqmgysg6weibx66ue6pyi
react-native: 0.69.4_react@18.0.0
dev: false
/react-native-gradle-plugin/0.0.7:
@ -7220,7 +7212,7 @@ packages:
invariant: 2.2.4
lodash.isequal: 4.5.0
react: 18.0.0
react-native: 0.69.4_k6xwmnqmgysg6weibx66ue6pyi
react-native: 0.69.4_react@18.0.0
setimmediate: 1.0.5
string-hash-64: 1.0.3
transitivePeerDependencies:
@ -7239,7 +7231,7 @@ packages:
normalize-svg-path: 1.1.0
parse-svg-path: 0.1.2
react: 18.0.0
react-native: 0.69.4_k6xwmnqmgysg6weibx66ue6pyi
react-native: 0.69.4_react@18.0.0
react-native-gesture-handler: 2.5.0_jk6ntyzimkrv4hwdmdgaaf5yaa
react-native-reanimated: 2.10.0_s4gdcbt2zwshcgkhtvkmdoj3my
dev: false
@ -7251,7 +7243,7 @@ packages:
react-native: '*'
dependencies:
react: 18.0.0
react-native: 0.69.4_k6xwmnqmgysg6weibx66ue6pyi
react-native: 0.69.4_react@18.0.0
dev: false
/react-native-safe-modules/1.0.3_react-native@0.69.4:
@ -7260,7 +7252,7 @@ packages:
react-native: '*'
dependencies:
dedent: 0.6.0
react-native: 0.69.4_k6xwmnqmgysg6weibx66ue6pyi
react-native: 0.69.4_react@18.0.0
dev: false
/react-native-screens/3.15.0_jk6ntyzimkrv4hwdmdgaaf5yaa:
@ -7271,7 +7263,7 @@ packages:
dependencies:
react: 18.0.0
react-freeze: 1.0.3_react@18.0.0
react-native: 0.69.4_k6xwmnqmgysg6weibx66ue6pyi
react-native: 0.69.4_react@18.0.0
warn-once: 0.1.0
dev: false
@ -7284,7 +7276,7 @@ packages:
'@svgr/core': 6.3.1
'@svgr/plugin-svgo': 6.3.1_@svgr+core@6.3.1
path-dirname: 1.0.2
react-native: 0.69.4_k6xwmnqmgysg6weibx66ue6pyi
react-native: 0.69.4_react@18.0.0
react-native-svg: 13.0.0_jk6ntyzimkrv4hwdmdgaaf5yaa
transitivePeerDependencies:
- supports-color
@ -7299,9 +7291,9 @@ packages:
css-select: 5.1.0
css-tree: 1.1.3
react: 18.0.0
react-native: 0.69.4_k6xwmnqmgysg6weibx66ue6pyi
react-native: 0.69.4_react@18.0.0
/react-native/0.69.4_k6xwmnqmgysg6weibx66ue6pyi:
/react-native/0.69.4_react@18.0.0:
resolution: {integrity: sha512-rqNMialM/T4pHRKWqTIpOxA65B/9kUjtnepxwJqvsdCeMP9Q2YdSx4VASFR9RoEFYcPRU41yGf6EKrChNfns3g==}
engines: {node: '>=14'}
hasBin: true
@ -7309,7 +7301,7 @@ packages:
react: 18.0.0
dependencies:
'@jest/create-cache-key-function': 27.5.1
'@react-native-community/cli': 8.0.5_mqmjqcyqm4trh6m6pjidkcb5na
'@react-native-community/cli': 8.0.5_react-native@0.69.4
'@react-native-community/cli-platform-android': 8.0.5
'@react-native-community/cli-platform-ios': 8.0.4
'@react-native/assets': 1.0.0
@ -7323,7 +7315,7 @@ packages:
invariant: 2.2.4
jsc-android: 250230.2.1
memoize-one: 5.2.1
metro-react-native-babel-transformer: 0.70.3_@babel+core@7.18.10
metro-react-native-babel-transformer: 0.70.3
metro-runtime: 0.70.3
metro-source-map: 0.70.3
mkdirp: 0.5.6
@ -7343,7 +7335,6 @@ packages:
whatwg-fetch: 3.6.2
ws: 6.2.2
transitivePeerDependencies:
- '@babel/core'
- '@babel/preset-env'
- bufferutil
- encoding
@ -8337,7 +8328,7 @@ packages:
peerDependencies:
react-native: '>=0.63.0'
dependencies:
react-native: 0.69.4_k6xwmnqmgysg6weibx66ue6pyi
react-native: 0.69.4_react@18.0.0
tailwindcss: 3.1.7
transitivePeerDependencies:
- ts-node

View file

@ -9,18 +9,18 @@ name = "sdcore"
crate-type = ["staticlib", "cdylib"] # staticlib for IOS and cdylib for Android
[dependencies]
once_cell = "1.13.0"
once_cell = "1.15.0"
sdcore = { path = "../../../core", features = [
"mobile",
"p2p",
], default-features = false }
rspc = { version = "0.0.5", features = [] }
serde_json = "1.0.83"
tokio = "1.20.1"
openssl = { version = "0.10.41", features = [
rspc = { version = "0.1.2", features = [] }
serde_json = "1.0.85"
tokio = "1.21.2"
openssl = { version = "0.10.42", features = [
"vendored",
] } # Override features of transitive dependencies
openssl-sys = { version = "0.9.75", features = [
openssl-sys = { version = "0.9.76", features = [
"vendored",
] } # Override features of transitive dependencies to support IOS Simulator on M1

View file

@ -1,7 +1,7 @@
use crate::{CLIENT_CONTEXT, EVENT_SENDER, NODE, RUNTIME};
use crate::{EVENT_SENDER, NODE, RUNTIME, SUBSCRIPTIONS};
use jni::objects::{JClass, JObject, JString};
use jni::JNIEnv;
use rspc::Request;
use rspc::internal::jsonrpc::{handle_json_rpc, Request, Sender, SubscriptionMap};
use sdcore::Node;
use tokio::sync::mpsc::unbounded_channel;
@ -22,7 +22,7 @@ pub extern "system" fn Java_com_spacedrive_app_SDCore_registerCoreEventListener(
Err(err) => {
println!("Failed to serialize event: {}", err);
continue;
},
}
};
let env = jvm.attach_current_thread().unwrap();
@ -45,7 +45,7 @@ pub extern "system" fn Java_com_spacedrive_app_SDCore_handleCoreMsg(
env: JNIEnv,
class: JClass,
query: JString,
callback: JObject,
_callback: JObject,
) {
let jvm = env.get_java_vm().unwrap();
let query: String = env
@ -53,7 +53,6 @@ pub extern "system" fn Java_com_spacedrive_app_SDCore_handleCoreMsg(
.expect("Couldn't get java string!")
.into();
let class = env.new_global_ref(class).unwrap();
let callback = env.new_global_ref(callback).unwrap();
RUNTIME.spawn(async move {
let request: Request = serde_json::from_str(&query).unwrap();
@ -65,12 +64,7 @@ pub extern "system" fn Java_com_spacedrive_app_SDCore_handleCoreMsg(
let data_dir: String = {
let env = jvm.attach_current_thread().unwrap();
let data_dir = env
.call_method(
&class,
"getDataDirectory",
"()Ljava/lang/String;",
&[],
)
.call_method(&class, "getDataDirectory", "()Ljava/lang/String;", &[])
.unwrap()
.l()
.unwrap();
@ -78,34 +72,19 @@ pub extern "system" fn Java_com_spacedrive_app_SDCore_handleCoreMsg(
env.get_string(data_dir.into()).unwrap().into()
};
let new_node = Node::new(data_dir).await.expect("Unable to create node");
let new_node = Node::new(data_dir).await.unwrap();
node.replace(new_node.clone());
new_node
},
}
};
let resp = serde_json::to_string(
&request
.handle(
node.get_request_context(),
&router,
&CLIENT_CONTEXT,
EVENT_SENDER.get(),
)
.await,
handle_json_rpc(
node.get_request_context(),
request,
&router,
&mut Sender::ResponseChannel(&mut EVENT_SENDER.get().unwrap().clone()),
&mut SubscriptionMap::Mutex(&SUBSCRIPTIONS),
)
.unwrap();
let env = jvm.attach_current_thread().unwrap();
env.call_method(
&callback,
"resolve",
"(Ljava/lang/Object;)V",
&[env
.new_string(resp)
.expect("Couldn't create java string!")
.into()],
)
.unwrap();
.await;
});
}

View file

@ -1,24 +1,23 @@
use std::sync::Arc;
use std::{collections::HashMap, sync::Arc};
use once_cell::sync::{Lazy, OnceCell};
use rspc::{ClientContext, Response};
use rspc::internal::jsonrpc::{RequestId, Response};
use sdcore::{api::Router, Node};
use tokio::{
runtime::Runtime,
sync::{mpsc::UnboundedSender, Mutex},
sync::{mpsc::UnboundedSender, oneshot, Mutex},
};
#[allow(dead_code)]
pub(crate) static RUNTIME: Lazy<Runtime> = Lazy::new(|| Runtime::new().unwrap());
type LazyNode = Lazy<Mutex<Option<(Arc<Node>, Arc<Router>)>>>;
#[allow(dead_code)]
pub(crate) static NODE: LazyNode = Lazy::new(|| Mutex::new(None));
pub(crate) static NODE: Lazy<Mutex<Option<(Arc<Node>, Arc<Router>)>>> =
Lazy::new(|| Mutex::new(None));
#[allow(dead_code)]
pub(crate) static CLIENT_CONTEXT: Lazy<ClientContext> = Lazy::new(|| ClientContext {
subscriptions: Default::default(),
});
pub(crate) static SUBSCRIPTIONS: Lazy<Mutex<HashMap<RequestId, oneshot::Sender<()>>>> =
Lazy::new(Default::default);
#[allow(dead_code)]
pub(crate) static EVENT_SENDER: OnceCell<UnboundedSender<Response>> = OnceCell::new();

View file

@ -22,9 +22,9 @@ import RootNavigator from './navigation';
import OnboardingNavigator from './navigation/OnboardingNavigator';
import { libraryStore } from './stores/libraryStore';
import { onboardingStore } from './stores/onboardingStore';
import type { Operations } from './types/bindings';
import type { Procedures } from './types/bindings';
const client = createClient<Operations>({
const client = createClient<Procedures>({
transport: new ReactNativeTransport()
});

View file

@ -1,28 +1,19 @@
import { ClientTransformer, OperationKey, OperationType, RSPCError, Transport } from '@rspc/client';
import { OperationType, ProcedureDef, RSPCError, Transport } from '@rspc/client';
import { createReactQueryHooks } from '@rspc/react';
import {
QueryClient,
UseMutationOptions,
UseMutationResult,
UseQueryOptions,
UseQueryResult,
useMutation as _useMutation
} from '@tanstack/react-query';
import { QueryClient } from '@tanstack/react-query';
import { NativeEventEmitter, NativeModules } from 'react-native';
import { useSnapshot } from 'valtio';
import { libraryStore } from '../stores/libraryStore';
import type { LibraryArgs, Operations } from '../types/bindings';
import { getLibraryIdRaw } from '../stores/libraryStore';
import { LibraryArgs, Procedures } from '../types/bindings';
export const queryClient = new QueryClient();
export const rspc = createReactQueryHooks<Operations>();
export const rspc = createReactQueryHooks<Procedures>();
const { SDCore } = NativeModules;
const eventEmitter = new NativeEventEmitter(NativeModules.SDCore);
// TODO(@Oscar): Replace this with a better abstraction when it's released in rspc. This relies on internal details of rspc which will change without warning.
export class ReactNativeTransport implements Transport {
transformer?: ClientTransformer;
clientSubscriptionCallback?: (id: string, key: string, value: any) => void;
constructor() {
@ -41,12 +32,15 @@ export class ReactNativeTransport implements Transport {
});
}
async doRequest(operation: OperationType, key: OperationKey): Promise<any> {
async doRequest(operation: OperationType, key: string, input: any): Promise<any> {
const body = JSON.parse(
await SDCore.sd_core_msg(
JSON.stringify({
operation,
key: this.transformer?.serialize(operation, key) || key
method: operation,
params: {
path: key,
input
}
})
)
);
@ -54,91 +48,60 @@ export class ReactNativeTransport implements Transport {
const { status_code, message } = body;
throw new RSPCError(status_code, message);
} else if (body.type === 'response') {
return this.transformer?.deserialize(operation, key, body.result) || body.result;
return body.result;
} else if (body.type !== 'none') {
throw new Error(`RSPC ReactNative doRequest received invalid body type '${body?.type}'`);
}
}
}
type NonLibraryQueries = Exclude<Operations['queries'], { key: [any, LibraryArgs<any>] }> &
Extract<Operations['queries'], { key: [any] }>;
type NonLibraryQuery<K extends string> = Extract<NonLibraryQueries, { key: [K] | [K, any] }>;
type NonLibraryQueryKey = NonLibraryQueries['key'][0];
type NonLibraryQueryResult<K extends NonLibraryQueryKey> = NonLibraryQuery<K>['result'];
type NonLibraryProcedure<T extends keyof Procedures> =
| Exclude<Procedures[T], { input: LibraryArgs<any> }>
| Extract<Procedures[T], { input: never }>;
export function useBridgeQuery<K extends NonLibraryQueries['key']>(
key: K,
options?: UseQueryOptions<NonLibraryQueryResult<K[0]>, RSPCError>
): UseQueryResult<NonLibraryQueryResult<K[0]>, RSPCError> {
// @ts-ignore
return rspc.useQuery(key, options);
}
type LibraryQueries = Extract<Operations['queries'], { key: [string, LibraryArgs<any>] }>;
type LibraryQuery<K extends string> = Extract<LibraryQueries, { key: [K, any] }>;
type LibraryQueryKey = LibraryQueries['key'][0];
type LibraryQueryArgs<K extends string> = LibraryQuery<K>['key'][1] extends LibraryArgs<infer A>
? A
: never;
type LibraryQueryResult<K extends string> = LibraryQuery<K>['result'];
export function useLibraryQuery<K extends LibraryQueryKey>(
key: LibraryQueryArgs<K> extends null | undefined ? [K] : [K, LibraryQueryArgs<K>],
options?: UseQueryOptions<LibraryQueryResult<K>, RSPCError>
): UseQueryResult<LibraryQueryResult<K>, RSPCError> {
const store = useSnapshot(libraryStore);
const library_id = store.currentLibraryUuid;
if (!library_id) throw new Error(`Attempted to do library query with no library set!`);
// @ts-ignore
return rspc.useQuery([key[0], { library_id: library_id || '', arg: key[1] || null }], options);
}
type LibraryMutations = Extract<Operations['mutations'], { key: [string, LibraryArgs<any>] }>;
type LibraryMutation<K extends LibraryMutationKey> = Extract<LibraryMutations, { key: [K, any] }>;
type LibraryMutationKey = LibraryMutations['key'][0];
type LibraryMutationArgs<K extends LibraryMutationKey> =
LibraryMutation<K>['key'][1] extends LibraryArgs<infer A> ? A : never;
type LibraryMutationResult<K extends LibraryMutationKey> = LibraryMutation<K>['result'];
export function useLibraryMutation<K extends LibraryMutationKey>(
key: K,
options?: UseMutationOptions<LibraryMutationResult<K>, RSPCError>
) {
const ctx = rspc.useContext();
const store = useSnapshot(libraryStore);
const library_id = store.currentLibraryUuid;
if (!library_id) throw new Error(`Attempted to do library query with no library set!`);
// @ts-ignore
return _useMutation<LibraryMutationResult<K>, RSPCError, LibraryMutationArgs<K>>(
async (data) => ctx.client.mutation([key, { library_id: library_id || '', arg: data || null }]),
{
...options,
context: rspc.ReactQueryContext
}
);
}
type NonLibraryMutations = Exclude<Operations['mutations'], { key: [any, LibraryArgs<any>] }>;
type NonLibraryMutation<K extends NonLibraryMutationKey> = Extract<
NonLibraryMutations,
{ key: [K] | [K, any] }
type LibraryProcedures<T extends keyof Procedures> = Exclude<
Extract<Procedures[T], { input: LibraryArgs<any> }>,
{ input: never }
>;
type NonLibraryMutationKey = NonLibraryMutations['key'][0];
type NonLibraryMutationArgs<K extends NonLibraryMutationKey> = NonLibraryMutation<K>['key'][1];
type NonLibraryMutationResult<K extends NonLibraryMutationKey> = NonLibraryMutation<K>['result'];
export function useBridgeMutation<K extends NonLibraryMutationKey>(
key: K,
options?: UseMutationOptions<NonLibraryMutationResult<K>, RSPCError>
): UseMutationResult<NonLibraryMutationResult<K>, RSPCError, NonLibraryMutationArgs<K>> {
// @ts-ignore
return rspc.useMutation(key, options);
}
type MoreConstrainedQueries<T extends ProcedureDef> = T extends any
? T['input'] extends LibraryArgs<infer E>
? {
key: T['key'];
input: E;
result: T['result'];
}
: never
: never;
export const useBridgeQuery = rspc.customQuery<NonLibraryProcedure<'queries'>>(
(keyAndInput) => keyAndInput as any
);
export const useBridgeMutation = rspc.customMutation<NonLibraryProcedure<'mutations'>>(
(keyAndInput) => keyAndInput
);
export const useLibraryQuery = rspc.customQuery<
MoreConstrainedQueries<LibraryProcedures<'queries'>>
>((keyAndInput) => {
const library_id = getLibraryIdRaw();
if (library_id === null) throw new Error('Attempted to do library query with no library set!');
return [keyAndInput[0], { library_id, arg: keyAndInput[1] || null }];
});
export const useLibraryMutation = rspc.customMutation<
MoreConstrainedQueries<LibraryProcedures<'mutations'>>
>((keyAndInput) => {
const library_id = getLibraryIdRaw();
if (library_id === null) throw new Error('Attempted to do library query with no library set!');
return [keyAndInput[0], { library_id, arg: keyAndInput[1] || null }];
});
export function useInvalidateQuery() {
const context = rspc.useContext();
rspc.useSubscription(['invalidateQuery'], {
onNext: (invalidateOperation) => {
onData: (invalidateOperation) => {
const key = [invalidateOperation.key];
if (invalidateOperation.arg !== null) {
key.concat(invalidateOperation.arg);

View file

@ -27,6 +27,10 @@ export const libraryStore = proxyWithPersist({
getStorage: () => StorageEngine
});
export function getLibraryIdRaw(): string | null {
return libraryStore.currentLibraryUuid;
}
// this must be used at least once in the app to correct the initial state
// is memorized and can be used safely in any component
export const useCurrentLibrary = () => {

View file

@ -1,48 +1,48 @@
/* eslint-disable */
// This file was generated by [rspc](https://github.com/oscartbeaumont/rspc). Do not edit this file manually.
export type Operations = {
export type Procedures = {
queries:
{ key: ["files.readMetadata", LibraryArgs<number>], result: null } |
{ key: ["getNode"], result: NodeState } |
{ key: ["jobs.getHistory", LibraryArgs<null>], result: Array<JobReport> } |
{ key: ["jobs.getRunning", LibraryArgs<null>], result: Array<JobReport> } |
{ key: ["library.getStatistics", LibraryArgs<null>], result: Statistics } |
{ key: ["library.list"], result: Array<LibraryConfigWrapped> } |
{ key: ["locations.getById", LibraryArgs<number>], result: Location | null } |
{ key: ["locations.getExplorerData", LibraryArgs<LocationExplorerArgs>], result: ExplorerData } |
{ key: ["locations.indexer_rules.get", LibraryArgs<number>], result: IndexerRule } |
{ key: ["locations.indexer_rules.list", LibraryArgs<null>], result: Array<IndexerRule> } |
{ key: ["locations.list", LibraryArgs<null>], result: Array<{ id: number, pub_id: Array<number>, node_id: number, name: string | null, local_path: string | null, total_capacity: number | null, available_capacity: number | null, filesystem: string | null, disk_type: number | null, is_removable: boolean | null, is_online: boolean, is_archived: boolean, date_created: string, node: Node }> } |
{ key: ["tags.get", LibraryArgs<number>], result: Tag | null } |
{ key: ["tags.getExplorerData", LibraryArgs<number>], result: ExplorerData } |
{ key: ["tags.getForFile", LibraryArgs<number>], result: Array<Tag> } |
{ key: ["tags.list", LibraryArgs<null>], result: Array<Tag> } |
{ key: ["version"], result: string } |
{ key: ["volumes.list"], result: Array<Volume> },
{ key: "files.readMetadata", input: LibraryArgs<number>, result: null } |
{ key: "getNode", input: never, result: NodeState } |
{ key: "jobs.getHistory", input: LibraryArgs<null>, result: Array<JobReport> } |
{ key: "jobs.getRunning", input: LibraryArgs<null>, result: Array<JobReport> } |
{ key: "library.getStatistics", input: LibraryArgs<null>, result: Statistics } |
{ key: "library.list", input: never, result: Array<LibraryConfigWrapped> } |
{ key: "locations.getById", input: LibraryArgs<number>, result: Location | null } |
{ key: "locations.getExplorerData", input: LibraryArgs<LocationExplorerArgs>, result: ExplorerData } |
{ key: "locations.indexer_rules.get", input: LibraryArgs<number>, result: IndexerRule } |
{ key: "locations.indexer_rules.list", input: LibraryArgs<null>, result: Array<IndexerRule> } |
{ key: "locations.list", input: LibraryArgs<null>, result: Array<{ id: number, pub_id: Array<number>, node_id: number, name: string | null, local_path: string | null, total_capacity: number | null, available_capacity: number | null, filesystem: string | null, disk_type: number | null, is_removable: boolean | null, is_online: boolean, is_archived: boolean, date_created: string, node: Node }> } |
{ key: "tags.get", input: LibraryArgs<number>, result: Tag | null } |
{ key: "tags.getExplorerData", input: LibraryArgs<number>, result: ExplorerData } |
{ key: "tags.getForFile", input: LibraryArgs<number>, result: Array<Tag> } |
{ key: "tags.list", input: LibraryArgs<null>, result: Array<Tag> } |
{ key: "version", input: never, result: string } |
{ key: "volumes.list", input: never, result: Array<Volume> },
mutations:
{ key: ["files.delete", LibraryArgs<number>], result: null } |
{ key: ["files.setFavorite", LibraryArgs<SetFavoriteArgs>], result: null } |
{ key: ["files.setNote", LibraryArgs<SetNoteArgs>], result: null } |
{ key: ["jobs.generateThumbsForLocation", LibraryArgs<GenerateThumbsForLocationArgs>], result: null } |
{ key: ["jobs.identifyUniqueFiles", LibraryArgs<IdentifyUniqueFilesArgs>], result: null } |
{ key: ["library.create", string], result: LibraryConfigWrapped } |
{ key: ["library.delete", string], result: null } |
{ key: ["library.edit", EditLibraryArgs], result: null } |
{ key: ["locations.create", LibraryArgs<LocationCreateArgs>], result: null } |
{ key: ["locations.delete", LibraryArgs<number>], result: null } |
{ key: ["locations.fullRescan", LibraryArgs<number>], result: null } |
{ key: ["locations.indexer_rules.create", LibraryArgs<IndexerRuleCreateArgs>], result: IndexerRule } |
{ key: ["locations.indexer_rules.delete", LibraryArgs<number>], result: null } |
{ key: ["locations.quickRescan", LibraryArgs<null>], result: null } |
{ key: ["locations.update", LibraryArgs<LocationUpdateArgs>], result: null } |
{ key: ["tags.assign", LibraryArgs<TagAssignArgs>], result: null } |
{ key: ["tags.create", LibraryArgs<TagCreateArgs>], result: Tag } |
{ key: ["tags.delete", LibraryArgs<number>], result: null } |
{ key: ["tags.update", LibraryArgs<TagUpdateArgs>], result: null },
{ key: "files.delete", input: LibraryArgs<number>, result: null } |
{ key: "files.setFavorite", input: LibraryArgs<SetFavoriteArgs>, result: null } |
{ key: "files.setNote", input: LibraryArgs<SetNoteArgs>, result: null } |
{ key: "jobs.generateThumbsForLocation", input: LibraryArgs<GenerateThumbsForLocationArgs>, result: null } |
{ key: "jobs.identifyUniqueFiles", input: LibraryArgs<IdentifyUniqueFilesArgs>, result: null } |
{ key: "library.create", input: string, result: LibraryConfigWrapped } |
{ key: "library.delete", input: string, result: null } |
{ key: "library.edit", input: EditLibraryArgs, result: null } |
{ key: "locations.create", input: LibraryArgs<LocationCreateArgs>, result: null } |
{ key: "locations.delete", input: LibraryArgs<number>, result: null } |
{ key: "locations.fullRescan", input: LibraryArgs<number>, result: null } |
{ key: "locations.indexer_rules.create", input: LibraryArgs<IndexerRuleCreateArgs>, result: IndexerRule } |
{ key: "locations.indexer_rules.delete", input: LibraryArgs<number>, result: null } |
{ key: "locations.quickRescan", input: LibraryArgs<null>, result: null } |
{ key: "locations.update", input: LibraryArgs<LocationUpdateArgs>, result: null } |
{ key: "tags.assign", input: LibraryArgs<TagAssignArgs>, result: null } |
{ key: "tags.create", input: LibraryArgs<TagCreateArgs>, result: Tag } |
{ key: "tags.delete", input: LibraryArgs<number>, result: null } |
{ key: "tags.update", input: LibraryArgs<TagUpdateArgs>, result: null },
subscriptions:
{ key: ["invalidateQuery"], result: InvalidateOperationEvent } |
{ key: ["jobs.newThumbnail", LibraryArgs<null>], result: string }
{ key: "invalidateQuery", input: never, result: InvalidateOperationEvent } |
{ key: "jobs.newThumbnail", input: LibraryArgs<null>, result: string }
};
export interface ConfigMetadata { version: string | null }

View file

@ -5,8 +5,8 @@ edition = "2021"
[dependencies]
sdcore = { path = "../../core", features = [] }
rspc = { version = "0.0.5", features = ["axum"] }
axum = "0.5.13"
tokio = { version = "1.17.0", features = ["sync", "rt-multi-thread", "signal"] }
tracing = "0.1.35"
ctrlc = "3.2.2"
rspc = { version = "0.1.2", features = ["axum"] }
axum = "0.5.16"
tokio = { version = "1.21.2", features = ["sync", "rt-multi-thread", "signal"] }
tracing = "0.1.36"
ctrlc = "3.2.3"

View file

@ -22,11 +22,9 @@ async fn main() {
}
std::env::current_dir()
.expect(
"Unable to get your current directory. Maybe try setting $DATA_DIR?",
)
.expect("Unable to get your current directory. Maybe try setting $DATA_DIR?")
.join("sdserver_data")
},
}
};
let port = env::var("PORT")
@ -57,13 +55,10 @@ async fn main() {
})
})
.route(
"/rspcws",
router.axum_ws_handler(move || node.get_request_context()),
"/rspc/:id",
router.endpoint(move || node.get_request_context()).axum(),
)
.fallback(
(|| async { "404 Not Found: We're past the event horizon..." })
.into_service(),
);
.fallback((|| async { "404 Not Found: We're past the event horizon..." }).into_service());
let mut addr = "[::]:8080".parse::<SocketAddr>().unwrap(); // This listens on IPv6 and IPv4
addr.set_port(port);

View file

@ -8,25 +8,25 @@
"preview": "vite preview"
},
"dependencies": {
"@fontsource/inter": "^4.5.11",
"@rspc/client": "^0.0.6",
"@fontsource/inter": "^4.5.12",
"@rspc/client": "^0.1.2",
"@sd/client": "workspace:*",
"@sd/interface": "workspace:*",
"@sd/ui": "workspace:*",
"@tanstack/react-query": "^4.0.10",
"@tanstack/react-query": "^4.8.0",
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
"devDependencies": {
"@types/react": "^18.0.15",
"@types/react": "^18.0.21",
"@types/react-dom": "^18.0.6",
"@vitejs/plugin-react": "^2.0.0",
"autoprefixer": "^10.4.7",
"postcss": "^8.4.14",
"@vitejs/plugin-react": "^2.1.0",
"autoprefixer": "^10.4.12",
"postcss": "^8.4.17",
"tailwind": "^4.0.0",
"typescript": "^4.7.4",
"vite": "^3.0.3",
"typescript": "^4.8.4",
"vite": "^3.1.4",
"vite-plugin-svgr": "^2.2.1",
"vite-plugin-tsconfig-paths": "^1.1.0"
"vite-plugin-tsconfig-paths": "^1.2.0"
}
}

View file

@ -1,11 +1,11 @@
import { WebsocketTransport, createClient } from '@rspc/client';
import { Operations, PlatformProvider, queryClient, rspc } from '@sd/client';
import { PlatformProvider, Procedures, queryClient, rspc } from '@sd/client';
import SpacedriveInterface, { Platform } from '@sd/interface';
import { useEffect } from 'react';
const client = createClient<Operations>({
const client = createClient<Procedures>({
transport: new WebsocketTransport(
import.meta.env.VITE_SDSERVER_BASE_URL || 'ws://localhost:8080/rspcws'
import.meta.env.VITE_SDSERVER_BASE_URL || 'ws://localhost:8080/rspc/ws'
)
});

View file

@ -25,14 +25,14 @@ hostname = "0.3.1"
# Universal Dependencies
base64 = "0.13.0"
serde = { version = "1.0", features = ["derive"] }
chrono = { version = "0.4.19", features = ["serde"] }
chrono = { version = "0.4.22", features = ["serde"] }
serde_json = "1.0"
futures = "0.3"
data-encoding = "2.3.2"
ring = "0.17.0-alpha.10"
ring = "0.17.0-alpha.11"
int-enum = "0.4.0"
rmp = "^0.8.11"
rmp-serde = "^1.1.0"
rmp-serde = "^1.1.1"
# Project dependencies
prisma-client-rust = { git = "https://github.com/Brendonovich/prisma-client-rust.git", tag = "0.6.0", features = [
@ -41,30 +41,30 @@ prisma-client-rust = { git = "https://github.com/Brendonovich/prisma-client-rust
"migrations",
"sqlite",
], default-features = false }
rspc = { version = "0.0.5", features = ["uuid", "chrono", "tracing"] }
rspc = { version = "0.1.2", features = ["uuid", "chrono", "tracing"] }
uuid = { version = "1.1.2", features = ["v4", "serde"] }
sysinfo = "0.23.9"
thiserror = "1.0.30"
sysinfo = "0.26.4"
thiserror = "1.0.37"
tokio = { version = "1.17.0", features = [
tokio = { version = "1.21.2", features = [
"sync",
"rt-multi-thread",
"io-util",
] }
include_dir = { version = "0.7.2", features = ["glob"] }
async-trait = "^0.1.52"
image = "0.24.1"
async-trait = "^0.1.57"
image = "0.24.4"
webp = "0.2.2"
ffmpeg-next = { version = "5.0.3", optional = true, features = [] }
ffmpeg-next = { version = "5.1.1", optional = true, features = [] }
sd_ffmpeg = { path = "../crates/ffmpeg", optional = true }
fs_extra = "1.2.0"
tracing = "0.1.35"
tracing-subscriber = { version = "0.3.14", features = ["env-filter"] }
tracing = "0.1.36"
tracing-subscriber = { version = "0.3.15", features = ["env-filter"] }
async-stream = "0.3.3"
once_cell = "1.13.0"
ctor = "0.1.22"
once_cell = "1.15.0"
ctor = "0.1.23"
globset = { version = "^0.4.9", features = ["serde1"] }
itertools = "^0.10.3"
itertools = "^0.10.5"
enumflags2 = "0.7.5"
[dev-dependencies]

View file

@ -19,25 +19,28 @@ pub struct SetFavoriteArgs {
pub(crate) fn mount() -> RouterBuilder {
<RouterBuilder>::new()
.library_query("readMetadata", |_, _id: i32, _| async move {
#[allow(unreachable_code)]
Ok(todo!())
.library_query("readMetadata", |t| {
t(|_, _id: i32, _| async move {
#[allow(unreachable_code)]
Ok(todo!())
})
})
.library_mutation("setNote", |_, args: SetNoteArgs, library| async move {
library
.db
.file()
.update(file::id::equals(args.id), vec![file::note::set(args.note)])
.exec()
.await?;
.library_mutation("setNote", |t| {
t(|_, args: SetNoteArgs, library| async move {
library
.db
.file()
.update(file::id::equals(args.id), vec![file::note::set(args.note)])
.exec()
.await?;
invalidate_query!(library, "locations.getExplorerData");
invalidate_query!(library, "locations.getExplorerData");
Ok(())
Ok(())
})
})
.library_mutation(
"setFavorite",
|_, args: SetFavoriteArgs, library| async move {
.library_mutation("setFavorite", |t| {
t(|_, args: SetFavoriteArgs, library| async move {
library
.db
.file()
@ -51,17 +54,19 @@ pub(crate) fn mount() -> RouterBuilder {
invalidate_query!(library, "locations.getExplorerData");
Ok(())
},
)
.library_mutation("delete", |_, id: i32, library| async move {
library
.db
.file()
.delete(file::id::equals(id))
.exec()
.await?;
})
})
.library_mutation("delete", |t| {
t(|_, id: i32, library| async move {
library
.db
.file()
.delete(file::id::equals(id))
.exec()
.await?;
invalidate_query!(library, "locations.getExplorerData");
Ok(())
invalidate_query!(library, "locations.getExplorerData");
Ok(())
})
})
}

View file

@ -28,42 +28,42 @@ pub struct IdentifyUniqueFilesArgs {
pub(crate) fn mount() -> RouterBuilder {
<RouterBuilder>::new()
.library_query("getRunning", |ctx, _: (), _| async move {
Ok(ctx.jobs.get_running().await)
.library_query("getRunning", |t| {
t(|ctx, _: (), _| async move { Ok(ctx.jobs.get_running().await) })
})
.library_query("getHistory", |_, _: (), library| async move {
Ok(JobManager::get_history(&library).await?)
.library_query("getHistory", |t| {
t(|_, _: (), library| async move { Ok(JobManager::get_history(&library).await?) })
})
.library_mutation(
"generateThumbsForLocation",
|_, args: GenerateThumbsForLocationArgs, library| async move {
if library
.db
.location()
.count(vec![location::id::equals(args.id)])
.exec()
.await? == 0
{
return Err(LocationError::IdNotFound(args.id).into());
}
.library_mutation("generateThumbsForLocation", |t| {
t(
|_, args: GenerateThumbsForLocationArgs, library| async move {
if library
.db
.location()
.count(vec![location::id::equals(args.id)])
.exec()
.await? == 0
{
return Err(LocationError::IdNotFound(args.id).into());
}
library
.spawn_job(Job::new(
ThumbnailJobInit {
location_id: args.id,
path: args.path,
background: false, // fix
},
Box::new(ThumbnailJob {}),
))
.await;
library
.spawn_job(Job::new(
ThumbnailJobInit {
location_id: args.id,
path: args.path,
background: false, // fix
},
Box::new(ThumbnailJob {}),
))
.await;
Ok(())
},
)
.library_mutation(
"identifyUniqueFiles",
|_, args: IdentifyUniqueFilesArgs, library| async move {
Ok(())
},
)
})
.library_mutation("identifyUniqueFiles", |t| {
t(|_, args: IdentifyUniqueFilesArgs, library| async move {
if fetch_location(&library, args.id).exec().await?.is_none() {
return Err(rspc::Error::new(
ErrorCode::NotFound,
@ -82,19 +82,21 @@ pub(crate) fn mount() -> RouterBuilder {
.await;
Ok(())
},
)
.library_subscription("newThumbnail", |ctx, _: (), _| {
// TODO: Only return event for the library that was subscribed to
})
})
.library_subscription("newThumbnail", |t| {
t(|ctx, _: (), _| {
// TODO: Only return event for the library that was subscribed to
let mut event_bus_rx = ctx.event_bus.subscribe();
async_stream::stream! {
while let Ok(event) = event_bus_rx.recv().await {
match event {
CoreEvent::NewThumbnail { cas_id } => yield cas_id,
_ => {}
let mut event_bus_rx = ctx.event_bus.subscribe();
async_stream::stream! {
while let Ok(event) = event_bus_rx.recv().await {
match event {
CoreEvent::NewThumbnail { cas_id } => yield cas_id,
_ => {}
}
}
}
}
})
})
}

View file

@ -21,78 +21,84 @@ pub struct EditLibraryArgs {
pub(crate) fn mount() -> RouterBuilder {
<RouterBuilder>::new()
.query("list", |ctx, _: ()| async move {
ctx.library_manager.get_all_libraries_config().await
.query("list", |t| {
t(|ctx, _: ()| async move { ctx.library_manager.get_all_libraries_config().await })
})
.library_query("getStatistics", |_, _: (), library| async move {
let _statistics = library
.db
.statistics()
.find_unique(statistics::id::equals(library.node_local_id))
.exec()
.await?;
.library_query("getStatistics", |t| {
t(|_, _: (), library| async move {
let _statistics = library
.db
.statistics()
.find_unique(statistics::id::equals(library.node_local_id))
.exec()
.await?;
// TODO: get from database, not sys
let volumes = get_volumes();
save_volume(&library).await?;
// TODO: get from database, not sys
let volumes = get_volumes();
save_volume(&library).await?;
let mut available_capacity: u64 = 0;
let mut total_capacity: u64 = 0;
if volumes.is_ok() {
for volume in volumes? {
total_capacity += volume.total_capacity;
available_capacity += volume.available_capacity;
let mut available_capacity: u64 = 0;
let mut total_capacity: u64 = 0;
if volumes.is_ok() {
for volume in volumes? {
total_capacity += volume.total_capacity;
available_capacity += volume.available_capacity;
}
}
}
let library_db_size = match fs::metadata(library.config().data_directory()).await {
Ok(metadata) => metadata.len(),
Err(_) => 0,
};
let library_db_size = match fs::metadata(library.config().data_directory()).await {
Ok(metadata) => metadata.len(),
Err(_) => 0,
};
let thumbnail_folder_size =
get_size(library.config().data_directory().join("thumbnails"));
let thumbnail_folder_size =
get_size(library.config().data_directory().join("thumbnails"));
use statistics::*;
let params = vec![
id::set(1), // Each library is a database so only one of these ever exists
date_captured::set(Utc::now().into()),
total_file_count::set(0),
library_db_size::set(library_db_size.to_string()),
total_bytes_used::set(0.to_string()),
total_bytes_capacity::set(total_capacity.to_string()),
total_unique_bytes::set(0.to_string()),
total_bytes_free::set(available_capacity.to_string()),
preview_media_bytes::set(thumbnail_folder_size.unwrap_or(0).to_string()),
];
use statistics::*;
let params = vec![
id::set(1), // Each library is a database so only one of these ever exists
date_captured::set(Utc::now().into()),
total_file_count::set(0),
library_db_size::set(library_db_size.to_string()),
total_bytes_used::set(0.to_string()),
total_bytes_capacity::set(total_capacity.to_string()),
total_unique_bytes::set(0.to_string()),
total_bytes_free::set(available_capacity.to_string()),
preview_media_bytes::set(thumbnail_folder_size.unwrap_or(0).to_string()),
];
Ok(library
.db
.statistics()
.upsert(
statistics::id::equals(1), // Each library is a database so only one of these ever exists
params.clone(),
params,
)
.exec()
.await?)
Ok(library
.db
.statistics()
.upsert(
statistics::id::equals(1), // Each library is a database so only one of these ever exists
params.clone(),
params,
)
.exec()
.await?)
})
})
.mutation("create", |ctx, name: String| async move {
Ok(ctx
.library_manager
.create(LibraryConfig {
name: name.to_string(),
..Default::default()
})
.await?)
.mutation("create", |t| {
t(|ctx, name: String| async move {
Ok(ctx
.library_manager
.create(LibraryConfig {
name: name.to_string(),
..Default::default()
})
.await?)
})
})
.mutation("edit", |ctx, args: EditLibraryArgs| async move {
Ok(ctx
.library_manager
.edit(args.id, args.name, args.description)
.await?)
.mutation("edit", |t| {
t(|ctx, args: EditLibraryArgs| async move {
Ok(ctx
.library_manager
.edit(args.id, args.name, args.description)
.await?)
})
})
.mutation("delete", |ctx, id: Uuid| async move {
Ok(ctx.library_manager.delete_library(id).await?)
.mutation("delete", |t| {
t(|ctx, id: Uuid| async move { Ok(ctx.library_manager.delete_library(id).await?) })
})
}

View file

@ -9,11 +9,11 @@ use crate::{
prisma::{file, file_path, indexer_rule, indexer_rules_in_location, location, tag},
};
use rspc::{self, ErrorCode, Type};
use rspc::{self, internal::MiddlewareBuilderLike, ErrorCode, Type};
use serde::{Deserialize, Serialize};
use tracing::info;
use super::{utils::LibraryRequest, RouterBuilder};
use super::{utils::LibraryRequest, Ctx, RouterBuilder};
#[derive(Serialize, Deserialize, Type, Debug)]
pub struct ExplorerData {
@ -47,28 +47,36 @@ pub struct LocationExplorerArgs {
pub cursor: Option<String>,
}
pub(crate) fn mount() -> RouterBuilder {
// TODO(@Oscar): This return type sucks. Add an upstream rspc solution.
pub(crate) fn mount() -> rspc::RouterBuilder<
Ctx,
(),
impl MiddlewareBuilderLike<Ctx, LayerContext = Ctx> + Send + 'static,
> {
<RouterBuilder>::new()
.library_query("list", |_, _: (), library| async move {
Ok(library
.db
.location()
.find_many(vec![])
.include(location::include!({ node }))
.exec()
.await?)
.library_query("list", |t| {
t(|_, _: (), library| async move {
Ok(library
.db
.location()
.find_many(vec![])
.include(location::include!({ node }))
.exec()
.await?)
})
})
.library_query("getById", |_, location_id: i32, library| async move {
Ok(library
.db
.location()
.find_unique(location::id::equals(location_id))
.exec()
.await?)
.library_query("getById", |t| {
t(|_, location_id: i32, library| async move {
Ok(library
.db
.location()
.find_unique(location::id::equals(location_id))
.exec()
.await?)
})
})
.library_query(
"getExplorerData",
|_, args: LocationExplorerArgs, library| async move {
.library_query("getExplorerData", |t| {
t(|_, args: LocationExplorerArgs, library| async move {
let location = library
.db
.location()
@ -124,119 +132,128 @@ pub(crate) fn mount() -> RouterBuilder {
})
.collect(),
})
},
)
.library_mutation(
"create",
|_, args: LocationCreateArgs, library| async move {
})
})
.library_mutation("create", |t| {
t(|_, args: LocationCreateArgs, library| async move {
let location = args.create(&library).await?;
scan_location(&library, location).await?;
Ok(())
},
)
.library_mutation(
"update",
|_, args: LocationUpdateArgs, library| async move {
})
})
.library_mutation("update", |t| {
t(|_, args: LocationUpdateArgs, library| async move {
args.update(&library).await.map_err(Into::into)
},
)
.library_mutation("delete", |_, location_id: i32, library| async move {
library
.db
.file_path()
.delete_many(vec![file_path::location_id::equals(location_id)])
.exec()
.await?;
library
.db
.indexer_rules_in_location()
.delete_many(vec![indexer_rules_in_location::location_id::equals(
location_id,
)])
.exec()
.await?;
library
.db
.location()
.delete(location::id::equals(location_id))
.exec()
.await?;
invalidate_query!(library, "locations.list");
info!("Location {} deleted", location_id);
Ok(())
})
})
.library_mutation("fullRescan", |_, location_id: i32, library| async move {
scan_location(
&library,
fetch_location(&library, location_id)
.include(indexer_job_location::include())
.library_mutation("delete", |t| {
t(|_, location_id: i32, library| async move {
library
.db
.file_path()
.delete_many(vec![file_path::location_id::equals(location_id)])
.exec()
.await?
.ok_or(LocationError::IdNotFound(location_id))?,
)
.await
.map_err(Into::into)
.await?;
library
.db
.indexer_rules_in_location()
.delete_many(vec![indexer_rules_in_location::location_id::equals(
location_id,
)])
.exec()
.await?;
library
.db
.location()
.delete(location::id::equals(location_id))
.exec()
.await?;
invalidate_query!(library, "locations.list");
info!("Location {} deleted", location_id);
Ok(())
})
})
.library_mutation("quickRescan", |_, _: (), _| async move {
#[allow(unreachable_code)]
Ok(todo!())
.library_mutation("fullRescan", |t| {
t(|_, location_id: i32, library| async move {
scan_location(
&library,
fetch_location(&library, location_id)
.include(indexer_job_location::include())
.exec()
.await?
.ok_or(LocationError::IdNotFound(location_id))?,
)
.await
.map_err(Into::into)
})
})
.library_mutation("quickRescan", |t| {
t(|_, _: (), _| async move {
#[allow(unreachable_code)]
Ok(todo!())
})
})
.merge("indexer_rules.", mount_indexer_rule_routes())
}
fn mount_indexer_rule_routes() -> RouterBuilder {
<RouterBuilder>::new()
.library_mutation(
"create",
|_, args: IndexerRuleCreateArgs, library| async move {
.library_mutation("create", |t| {
t(|_, args: IndexerRuleCreateArgs, library| async move {
args.create(&library).await.map_err(Into::into)
},
)
.library_mutation("delete", |_, indexer_rule_id: i32, library| async move {
library
.db
.indexer_rules_in_location()
.delete_many(vec![indexer_rules_in_location::indexer_rule_id::equals(
indexer_rule_id,
)])
.exec()
.await?;
library
.db
.indexer_rule()
.delete(indexer_rule::id::equals(indexer_rule_id))
.exec()
.await?;
Ok(())
})
})
.library_query("get", |_, indexer_rule_id: i32, library| async move {
library
.db
.indexer_rule()
.find_unique(indexer_rule::id::equals(indexer_rule_id))
.exec()
.await?
.ok_or_else(|| {
rspc::Error::new(
ErrorCode::NotFound,
format!("Indexer rule <id={indexer_rule_id}> not found"),
)
})
.library_mutation("delete", |t| {
t(|_, indexer_rule_id: i32, library| async move {
library
.db
.indexer_rules_in_location()
.delete_many(vec![indexer_rules_in_location::indexer_rule_id::equals(
indexer_rule_id,
)])
.exec()
.await?;
library
.db
.indexer_rule()
.delete(indexer_rule::id::equals(indexer_rule_id))
.exec()
.await?;
Ok(())
})
})
.library_query("list", |_, _: (), library| async move {
library
.db
.indexer_rule()
.find_many(vec![])
.exec()
.await
.map_err(Into::into)
.library_query("get", |t| {
t(|_, indexer_rule_id: i32, library| async move {
library
.db
.indexer_rule()
.find_unique(indexer_rule::id::equals(indexer_rule_id))
.exec()
.await?
.ok_or_else(|| {
rspc::Error::new(
ErrorCode::NotFound,
format!("Indexer rule <id={indexer_rule_id}> not found"),
)
})
})
})
.library_query("list", |t| {
t(|_, _: (), library| async move {
library
.db
.indexer_rule()
.find_many(vec![])
.exec()
.await
.map_err(Into::into)
})
})
}

View file

@ -1,4 +1,5 @@
use std::{
path::PathBuf,
sync::Arc,
time::{Duration, Instant},
};
@ -62,12 +63,14 @@ pub(crate) fn mount() -> Arc<Router> {
// .export_ts_bindings(PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("./index.ts")),
.set_ts_bindings_header("/* eslint-disable */"),
)
.query("version", |_, _: ()| env!("CARGO_PKG_VERSION"))
.query("getNode", |ctx, _: ()| async move {
Ok(NodeState {
config: ctx.config.get().await,
// We are taking the assumption here that this value is only used on the frontend for display purposes
data_path: ctx.config.data_directory().to_string_lossy().into_owned(),
.query("version", |t| t(|_, _: ()| env!("CARGO_PKG_VERSION")))
.query("getNode", |t| {
t(|ctx, _: ()| async move {
Ok(NodeState {
config: ctx.config.get().await,
// We are taking the assumption here that this value is only used on the frontend for display purposes
data_path: ctx.config.data_directory().to_string_lossy().into_owned(),
})
})
})
.merge("library.", libraries::mount())
@ -77,46 +80,48 @@ pub(crate) fn mount() -> Arc<Router> {
.merge("files.", files::mount())
.merge("jobs.", jobs::mount())
// TODO: Scope the invalidate queries to a specific library (filtered server side)
.subscription("invalidateQuery", |ctx, _: ()| {
let mut event_bus_rx = ctx.event_bus.subscribe();
let mut last = Instant::now();
async_stream::stream! {
while let Ok(event) = event_bus_rx.recv().await {
match event {
CoreEvent::InvalidateOperation(op) => yield op,
CoreEvent::InvalidateOperationDebounced(op) => {
let current = Instant::now();
if current.duration_since(last) > Duration::from_millis(1000 / 60) {
last = current;
yield op;
}
},
_ => {}
.subscription("invalidateQuery", |t| {
t(|ctx, _: ()| {
let mut event_bus_rx = ctx.event_bus.subscribe();
let mut last = Instant::now();
async_stream::stream! {
while let Ok(event) = event_bus_rx.recv().await {
match event {
CoreEvent::InvalidateOperation(op) => yield op,
CoreEvent::InvalidateOperationDebounced(op) => {
let current = Instant::now();
if current.duration_since(last) > Duration::from_millis(1000 / 60) {
last = current;
yield op;
}
},
_ => {}
}
}
}
}
})
})
.build()
.arced();
InvalidRequests::validate(r.clone()); // This validates all invalidation calls.
export_ts_bindings(&r);
r
}
pub fn export_ts_bindings(r: &Router) {
r.export_ts(PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../packages/client/src/core.ts"))
.expect("Error exporting rspc Typescript bindings!");
r.export_ts(
PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../apps/mobile/src/types/bindings.ts"),
)
.expect("Error exporting rspc Typescript bindings!");
}
#[cfg(test)]
mod tests {
use std::path::PathBuf;
/// This test will ensure the rspc router and all calls to `invalidate_query` are valid and also export an updated version of the Typescript bindings.
#[test]
fn test_and_export_rspc_bindings() {
let r = super::mount();
r.export_ts(
PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../packages/client/src/core.ts"),
)
.expect("Error exporting rspc Typescript bindings!");
r.export_ts(
PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../apps/mobile/src/types/bindings.ts"),
)
.expect("Error exporting rspc Typescript bindings!");
super::export_ts_bindings(super::mount());
}
}

View file

@ -34,146 +34,165 @@ pub struct TagUpdateArgs {
pub(crate) fn mount() -> RouterBuilder {
RouterBuilder::new()
.library_query("list", |_, _: (), library| async move {
Ok(library.db.tag().find_many(vec![]).exec().await?)
.library_query("list", |t| {
t(
|_, _: (), library| async move { Ok(library.db.tag().find_many(vec![]).exec().await?) },
)
})
.library_query("getExplorerData", |_, tag_id: i32, library| async move {
info!("Getting files for tag {}", tag_id);
.library_query("getExplorerData", |t| {
t(|_, tag_id: i32, library| async move {
info!("Getting files for tag {}", tag_id);
let tag = library
.db
.tag()
.find_unique(tag::id::equals(tag_id))
.exec()
.await?
.ok_or_else(|| {
rspc::Error::new(ErrorCode::NotFound, format!("Tag <id={tag_id}> not found"))
})?;
let tag = library
.db
.tag()
.find_unique(tag::id::equals(tag_id))
.exec()
.await?
.ok_or_else(|| {
rspc::Error::new(
ErrorCode::NotFound,
format!("Tag <id={tag_id}> not found"),
)
})?;
let files: Vec<ExplorerItem> = library
.db
.file()
.find_many(vec![file::tags::some(vec![tag_on_file::tag_id::equals(
tag_id,
)])])
.include(file_with_paths::include())
.exec()
.await?
.into_iter()
.map(|mut file| {
// sorry brendan
// grab the first path and tac on the name
let oldest_path = &file.paths[0];
file.name = Some(oldest_path.name.clone());
file.extension = oldest_path.extension.clone();
// a long term fix for this would be to have the indexer give the Object a name and extension, sacrificing its own and only store newly found Path names that differ from the Object name
let files: Vec<ExplorerItem> = library
.db
.file()
.find_many(vec![file::tags::some(vec![tag_on_file::tag_id::equals(
tag_id,
)])])
.include(file_with_paths::include())
.exec()
.await?
.into_iter()
.map(|mut file| {
// sorry brendan
// grab the first path and tac on the name
let oldest_path = &file.paths[0];
file.name = Some(oldest_path.name.clone());
file.extension = oldest_path.extension.clone();
// a long term fix for this would be to have the indexer give the Object a name and extension, sacrificing its own and only store newly found Path names that differ from the Object name
let thumb_path = library
.config()
.data_directory()
.join(THUMBNAIL_CACHE_DIR_NAME)
.join(&file.cas_id)
.with_extension("webp");
let thumb_path = library
.config()
.data_directory()
.join(THUMBNAIL_CACHE_DIR_NAME)
.join(&file.cas_id)
.with_extension("webp");
file.has_thumbnail = thumb_path.exists();
file.has_thumbnail = thumb_path.exists();
ExplorerItem::Object(Box::new(file))
ExplorerItem::Object(Box::new(file))
})
.collect();
info!("Got files {}", files.len());
Ok(ExplorerData {
context: ExplorerContext::Tag(tag),
items: files,
})
.collect();
info!("Got files {}", files.len());
Ok(ExplorerData {
context: ExplorerContext::Tag(tag),
items: files,
})
})
.library_query("getForFile", |_, file_id: i32, library| async move {
Ok(library
.db
.tag()
.find_many(vec![tag::tag_files::some(vec![
tag_on_file::file_id::equals(file_id),
])])
.exec()
.await?)
})
.library_query("get", |_, tag_id: i32, library| async move {
Ok(library
.db
.tag()
.find_unique(tag::id::equals(tag_id))
.exec()
.await?)
})
.library_mutation("create", |_, args: TagCreateArgs, library| async move {
let created_tag = library
.db
.tag()
.create(
Uuid::new_v4().as_bytes().to_vec(),
vec![
tag::name::set(Some(args.name)),
tag::color::set(Some(args.color)),
],
)
.exec()
.await?;
invalidate_query!(library, "tags.list");
Ok(created_tag)
})
.library_mutation("assign", |_, args: TagAssignArgs, library| async move {
if args.unassign {
library
.library_query("getForFile", |t| {
t(|_, file_id: i32, library| async move {
Ok(library
.db
.tag_on_file()
.delete(tag_on_file::tag_id_file_id(args.tag_id, args.file_id))
.tag()
.find_many(vec![tag::tag_files::some(vec![
tag_on_file::file_id::equals(file_id),
])])
.exec()
.await?;
} else {
library
.await?)
})
})
.library_query("get", |t| {
t(|_, tag_id: i32, library| async move {
Ok(library
.db
.tag_on_file()
.tag()
.find_unique(tag::id::equals(tag_id))
.exec()
.await?)
})
})
.library_mutation("create", |t| {
t(|_, args: TagCreateArgs, library| async move {
let created_tag = library
.db
.tag()
.create(
tag::id::equals(args.tag_id),
file::id::equals(args.file_id),
vec![],
Uuid::new_v4().as_bytes().to_vec(),
vec![
tag::name::set(Some(args.name)),
tag::color::set(Some(args.color)),
],
)
.exec()
.await?;
}
invalidate_query!(library, "tags.getForFile");
invalidate_query!(library, "tags.list");
Ok(())
Ok(created_tag)
})
})
.library_mutation("update", |_, args: TagUpdateArgs, library| async move {
library
.db
.tag()
.update(
tag::id::equals(args.id),
vec![tag::name::set(args.name), tag::color::set(args.color)],
)
.exec()
.await?;
.library_mutation("assign", |t| {
t(|_, args: TagAssignArgs, library| async move {
if args.unassign {
library
.db
.tag_on_file()
.delete(tag_on_file::tag_id_file_id(args.tag_id, args.file_id))
.exec()
.await?;
} else {
library
.db
.tag_on_file()
.create(
tag::id::equals(args.tag_id),
file::id::equals(args.file_id),
vec![],
)
.exec()
.await?;
}
invalidate_query!(library, "tags.list");
invalidate_query!(library, "tags.getForFile");
Ok(())
Ok(())
})
})
.library_mutation("delete", |_, tag_id: i32, library| async move {
library
.db
.tag()
.delete(tag::id::equals(tag_id))
.exec()
.await?;
.library_mutation("update", |t| {
t(|_, args: TagUpdateArgs, library| async move {
library
.db
.tag()
.update(
tag::id::equals(args.id),
vec![tag::name::set(args.name), tag::color::set(args.color)],
)
.exec()
.await?;
invalidate_query!(library, "tags.list");
invalidate_query!(library, "tags.list");
Ok(())
Ok(())
})
})
.library_mutation("delete", |t| {
t(|_, tag_id: i32, library| async move {
library
.db
.tag()
.delete(tag::id::equals(tag_id))
.exec()
.await?;
invalidate_query!(library, "tags.list");
Ok(())
})
})
}

View file

@ -1,5 +1,8 @@
use futures::{Future, Stream};
use rspc::{internal::specta, ErrorCode, IntoLayerResult, Type};
use rspc::{
internal::{specta, BuiltProcedureBuilder, MiddlewareBuilderLike, UnbuiltProcedureBuilder},
ErrorCode, RequestLayer, SerializeMarker, Type,
};
use serde::{de::DeserializeOwned, Deserialize, Serialize};
use uuid::Uuid;
@ -12,116 +15,136 @@ pub(crate) struct LibraryArgs<T> {
pub arg: T,
}
// WARNING: This is system is using internal API's which means it will break between rspc release. I would avoid copying it unless you understand the cost of maintaining it!
pub trait LibraryRequest {
fn library_query<T, TArg, TResult, TResultMarker>(
fn library_query<T, TResolver, TArg, TResult>(
self,
key: &'static str,
resolver: fn(Ctx, TArg, LibraryContext) -> TResult,
builder: fn(UnbuiltProcedureBuilder<Ctx, TResolver>) -> BuiltProcedureBuilder<TResolver>,
) -> Self
where
TArg: DeserializeOwned + specta::Type + Send + 'static,
TResult: Future<Output = Result<T, rspc::Error>> + Send + 'static,
T: IntoLayerResult<TResultMarker> + Send + Serialize + specta::Type;
T: RequestLayer<SerializeMarker> + Serialize + specta::Type + Send,
TResolver: Fn(Ctx, TArg, LibraryContext) -> TResult + Send + Sync + 'static;
fn library_mutation<T, TArg, TResult, TResultMarker>(
fn library_mutation<T, TResolver, TArg, TResult>(
self,
key: &'static str,
resolver: fn(Ctx, TArg, LibraryContext) -> TResult,
builder: fn(UnbuiltProcedureBuilder<Ctx, TResolver>) -> BuiltProcedureBuilder<TResolver>,
) -> Self
where
TArg: DeserializeOwned + specta::Type + Send + 'static,
TResult: Future<Output = Result<T, rspc::Error>> + Send + 'static,
T: IntoLayerResult<TResultMarker> + Send + Serialize + specta::Type;
T: RequestLayer<SerializeMarker> + Serialize + specta::Type + Send,
TResolver: Fn(Ctx, TArg, LibraryContext) -> TResult + Send + Sync + 'static;
fn library_subscription<T, TArg, TResult>(
fn library_subscription<TResolver, TArg, TStream, TResult>(
self,
key: &'static str,
resolver: fn(Ctx, TArg, Uuid) -> T,
builder: fn(UnbuiltProcedureBuilder<Ctx, TResolver>) -> BuiltProcedureBuilder<TResolver>,
) -> Self
where
TArg: DeserializeOwned + specta::Type + Send + 'static,
T: Stream<Item = TResult> + Send + 'static,
TResult: Serialize + specta::Type;
TArg: DeserializeOwned + specta::Type + 'static,
TStream: Stream<Item = TResult> + Sync + Send + 'static,
TResult: Serialize + specta::Type,
// TODO: This should take the 'LibraryContext' not 'Uuid'
TResolver: Fn(Ctx, TArg, Uuid) -> TStream + Send + Sync + 'static;
}
// Note: This will break with middleware context switching but that's fine for now
impl LibraryRequest for rspc::RouterBuilder<Ctx, (), Ctx> {
fn library_query<T, TArg, TResult, TResultMarker>(
impl<TMiddleware> LibraryRequest for rspc::RouterBuilder<Ctx, (), TMiddleware>
where
TMiddleware: MiddlewareBuilderLike<Ctx, LayerContext = Ctx> + Send + 'static,
{
fn library_query<T, TResolver, TArg, TResult>(
self,
key: &'static str,
resolver: fn(Ctx, TArg, LibraryContext) -> TResult,
builder: fn(UnbuiltProcedureBuilder<Ctx, TResolver>) -> BuiltProcedureBuilder<TResolver>,
) -> Self
where
TArg: DeserializeOwned + specta::Type + Send + 'static,
TResult: Future<Output = Result<T, rspc::Error>> + Send + 'static,
T: IntoLayerResult<TResultMarker> + Send + Serialize + specta::Type,
T: RequestLayer<SerializeMarker> + Serialize + specta::Type + Send,
TResolver: Fn(Ctx, TArg, LibraryContext) -> TResult + Send + Sync + 'static,
{
self.query(key, move |ctx, arg: LibraryArgs<TArg>| async move {
let library = ctx
.library_manager
.get_ctx(arg.library_id)
.await
.ok_or_else(|| {
rspc::Error::new(
ErrorCode::BadRequest,
"You must specify a valid library to use this operation.".to_string(),
)
})?;
self.query(key, move |t| {
t(move |ctx, arg: LibraryArgs<TArg>| async move {
let library = ctx
.library_manager
.get_ctx(arg.library_id)
.await
.ok_or_else(|| {
rspc::Error::new(
ErrorCode::BadRequest,
"You must specify a valid library to use this operation.".to_string(),
)
})?;
resolver(ctx, arg.arg, library).await
let resolver = builder(UnbuiltProcedureBuilder::default()).resolver;
resolver(ctx, arg.arg, library).await
})
})
}
fn library_mutation<T, TArg, TResult, TResultMarker>(
fn library_mutation<T, TResolver, TArg, TResult>(
self,
key: &'static str,
resolver: fn(Ctx, TArg, LibraryContext) -> TResult,
builder: fn(UnbuiltProcedureBuilder<Ctx, TResolver>) -> BuiltProcedureBuilder<TResolver>,
) -> Self
where
TArg: DeserializeOwned + specta::Type + Send + 'static,
TResult: Future<Output = Result<T, rspc::Error>> + Send + 'static,
T: IntoLayerResult<TResultMarker> + Send + Serialize + specta::Type,
T: RequestLayer<SerializeMarker> + Serialize + specta::Type + Send,
TResolver: Fn(Ctx, TArg, LibraryContext) -> TResult + Send + Sync + 'static,
{
self.mutation(key, move |ctx, arg: LibraryArgs<TArg>| async move {
let library = ctx
.library_manager
.get_ctx(arg.library_id)
.await
.ok_or_else(|| {
rspc::Error::new(
ErrorCode::BadRequest,
"You must specify a valid library to use this operation.".to_string(),
)
})?;
self.mutation(key, move |t| {
t(move |ctx, arg: LibraryArgs<TArg>| async move {
let library = ctx
.library_manager
.get_ctx(arg.library_id)
.await
.ok_or_else(|| {
rspc::Error::new(
ErrorCode::BadRequest,
"You must specify a valid library to use this operation.".to_string(),
)
})?;
resolver(ctx, arg.arg, library).await
let resolver = builder(UnbuiltProcedureBuilder::default()).resolver;
resolver(ctx, arg.arg, library).await
})
})
}
fn library_subscription<T, TArg, TResult>(
fn library_subscription<TResolver, TArg, TStream, TResult>(
self,
key: &'static str,
resolver: fn(Ctx, TArg, Uuid) -> T,
builder: fn(UnbuiltProcedureBuilder<Ctx, TResolver>) -> BuiltProcedureBuilder<TResolver>,
) -> Self
where
TArg: DeserializeOwned + specta::Type + Send + 'static,
T: Stream<Item = TResult> + Send + 'static,
TArg: DeserializeOwned + specta::Type + 'static,
TStream: Stream<Item = TResult> + Sync + Send + 'static,
TResult: Serialize + specta::Type,
TResolver: Fn(Ctx, TArg, Uuid) -> TStream + Send + Sync + 'static,
{
self.subscription(key, move |ctx, arg: LibraryArgs<TArg>| {
// TODO: Make this fetch the library like the other functions. This needs upstream rspc work to be supported.
// let library = ctx
// .library_manager
// .get_ctx(arg.library_id)
// .await
// .ok_or_else(|| {
// rspc::Error::new(
// ErrorCode::BadRequest,
// "You must specify a valid library to use this operation.".to_string(),
// )
// })?;
self.subscription(key, |t| {
t(move |ctx, arg: LibraryArgs<TArg>| {
// TODO(@Oscar): Upstream rspc work to allow this to work
// let library = ctx
// .library_manager
// .get_ctx(arg.library_id)
// .await
// .ok_or_else(|| {
// rspc::Error::new(
// ErrorCode::BadRequest,
// "You must specify a valid library to use this operation.".to_string(),
// )
// })?;
resolver(ctx, arg.arg, arg.library_id)
let resolver = builder(UnbuiltProcedureBuilder::default()).resolver;
resolver(ctx, arg.arg, arg.library_id)
})
})
}
}

View file

@ -1,7 +1,7 @@
use crate::volume::get_volumes;
use super::{Router, RouterBuilder};
use super::RouterBuilder;
pub(crate) fn mount() -> RouterBuilder {
<Router>::new().query("list", |_, _: ()| Ok(get_volumes()?))
RouterBuilder::new().query("list", |t| t(|_, _: ()| Ok(get_volumes()?)))
}

View file

@ -66,7 +66,11 @@ impl Node {
"desktop=debug"
.parse()
.expect("Error invalid tracing directive!"),
),
), // .add_directive(
// "rspc=debug"
// .parse()
// .expect("Error invalid tracing directive!"),
// ),
)
.with(fmt::layer().with_filter(CONSOLE_LOG_FILTER))
.init();

View file

@ -13,10 +13,10 @@ resolver = "2"
[dependencies]
ffmpeg-sys-next = "5.1.1"
thiserror = "1.0.35"
thiserror = "1.0.37"
webp = "0.2.2"
tokio = { version = "1.21.1", features = ["fs", "rt"] }
tokio = { version = "1.21.2", features = ["fs", "rt"] }
[dev-dependencies]
tempfile = "3.3.0"
tokio = { version = "1.21.1", features = ["fs", "rt", "macros"] }
tokio = { version = "1.21.2", features = ["fs", "rt", "macros"] }

View file

@ -21,13 +21,13 @@
},
"devDependencies": {
"@cspell/dict-rust": "^2.0.1",
"@cspell/dict-typescript": "^2.0.1",
"@evilmartians/lefthook": "^1.0.5",
"@cspell/dict-typescript": "^2.0.2",
"@evilmartians/lefthook": "^1.1.1",
"@trivago/prettier-plugin-sort-imports": "^3.3.0",
"cspell": "^6.4.0",
"markdown-link-check": "^3.10.2",
"cspell": "^6.12.0",
"markdown-link-check": "^3.10.3",
"prettier": "^2.7.1",
"typescript": "^4.7.4"
"typescript": "^4.8.4"
},
"overrides": {
"vite-plugin-svgr": "https://github.com/spacedriveapp/vite-plugin-svgr#cb4195b69849429cdb18d1f12381676bf9196a84"

View file

@ -17,24 +17,24 @@
"preset": "scripts/jest/node"
},
"dependencies": {
"@rspc/client": "^0.0.6",
"@rspc/react": "^0.0.6",
"@rspc/client": "^0.1.2",
"@rspc/react": "^0.1.2",
"@sd/config": "workspace:*",
"@sd/interface": "workspace:*",
"@tanstack/react-query": "^4.0.10",
"@tanstack/react-query": "^4.8.0",
"eventemitter3": "^4.0.7",
"immer": "^9.0.15",
"lodash": "^4.17.21",
"valtio": "^1.7.0",
"valtio-persist": "^1.0.2",
"zustand": "4.0.0"
"zustand": "4.1.1"
},
"devDependencies": {
"@types/lodash": "^4.14.182",
"@types/react": "^18.0.15",
"@types/lodash": "^4.14.186",
"@types/react": "^18.0.21",
"scripts": "*",
"tsconfig": "*",
"typescript": "^4.7.4"
"typescript": "^4.8.4"
},
"peerDependencies": {
"react": "^18.2.0"

View file

@ -1,48 +1,48 @@
/* eslint-disable */
// This file was generated by [rspc](https://github.com/oscartbeaumont/rspc). Do not edit this file manually.
export type Operations = {
export type Procedures = {
queries:
{ key: ["files.readMetadata", LibraryArgs<number>], result: null } |
{ key: ["getNode"], result: NodeState } |
{ key: ["jobs.getHistory", LibraryArgs<null>], result: Array<JobReport> } |
{ key: ["jobs.getRunning", LibraryArgs<null>], result: Array<JobReport> } |
{ key: ["library.getStatistics", LibraryArgs<null>], result: Statistics } |
{ key: ["library.list"], result: Array<LibraryConfigWrapped> } |
{ key: ["locations.getById", LibraryArgs<number>], result: Location | null } |
{ key: ["locations.getExplorerData", LibraryArgs<LocationExplorerArgs>], result: ExplorerData } |
{ key: ["locations.indexer_rules.get", LibraryArgs<number>], result: IndexerRule } |
{ key: ["locations.indexer_rules.list", LibraryArgs<null>], result: Array<IndexerRule> } |
{ key: ["locations.list", LibraryArgs<null>], result: Array<{ id: number, pub_id: Array<number>, node_id: number, name: string | null, local_path: string | null, total_capacity: number | null, available_capacity: number | null, filesystem: string | null, disk_type: number | null, is_removable: boolean | null, is_online: boolean, is_archived: boolean, date_created: string, node: Node }> } |
{ key: ["tags.get", LibraryArgs<number>], result: Tag | null } |
{ key: ["tags.getExplorerData", LibraryArgs<number>], result: ExplorerData } |
{ key: ["tags.getForFile", LibraryArgs<number>], result: Array<Tag> } |
{ key: ["tags.list", LibraryArgs<null>], result: Array<Tag> } |
{ key: ["version"], result: string } |
{ key: ["volumes.list"], result: Array<Volume> },
{ key: "files.readMetadata", input: LibraryArgs<number>, result: null } |
{ key: "getNode", input: never, result: NodeState } |
{ key: "jobs.getHistory", input: LibraryArgs<null>, result: Array<JobReport> } |
{ key: "jobs.getRunning", input: LibraryArgs<null>, result: Array<JobReport> } |
{ key: "library.getStatistics", input: LibraryArgs<null>, result: Statistics } |
{ key: "library.list", input: never, result: Array<LibraryConfigWrapped> } |
{ key: "locations.getById", input: LibraryArgs<number>, result: Location | null } |
{ key: "locations.getExplorerData", input: LibraryArgs<LocationExplorerArgs>, result: ExplorerData } |
{ key: "locations.indexer_rules.get", input: LibraryArgs<number>, result: IndexerRule } |
{ key: "locations.indexer_rules.list", input: LibraryArgs<null>, result: Array<IndexerRule> } |
{ key: "locations.list", input: LibraryArgs<null>, result: Array<{ id: number, pub_id: Array<number>, node_id: number, name: string | null, local_path: string | null, total_capacity: number | null, available_capacity: number | null, filesystem: string | null, disk_type: number | null, is_removable: boolean | null, is_online: boolean, is_archived: boolean, date_created: string, node: Node }> } |
{ key: "tags.get", input: LibraryArgs<number>, result: Tag | null } |
{ key: "tags.getExplorerData", input: LibraryArgs<number>, result: ExplorerData } |
{ key: "tags.getForFile", input: LibraryArgs<number>, result: Array<Tag> } |
{ key: "tags.list", input: LibraryArgs<null>, result: Array<Tag> } |
{ key: "version", input: never, result: string } |
{ key: "volumes.list", input: never, result: Array<Volume> },
mutations:
{ key: ["files.delete", LibraryArgs<number>], result: null } |
{ key: ["files.setFavorite", LibraryArgs<SetFavoriteArgs>], result: null } |
{ key: ["files.setNote", LibraryArgs<SetNoteArgs>], result: null } |
{ key: ["jobs.generateThumbsForLocation", LibraryArgs<GenerateThumbsForLocationArgs>], result: null } |
{ key: ["jobs.identifyUniqueFiles", LibraryArgs<IdentifyUniqueFilesArgs>], result: null } |
{ key: ["library.create", string], result: LibraryConfigWrapped } |
{ key: ["library.delete", string], result: null } |
{ key: ["library.edit", EditLibraryArgs], result: null } |
{ key: ["locations.create", LibraryArgs<LocationCreateArgs>], result: null } |
{ key: ["locations.delete", LibraryArgs<number>], result: null } |
{ key: ["locations.fullRescan", LibraryArgs<number>], result: null } |
{ key: ["locations.indexer_rules.create", LibraryArgs<IndexerRuleCreateArgs>], result: IndexerRule } |
{ key: ["locations.indexer_rules.delete", LibraryArgs<number>], result: null } |
{ key: ["locations.quickRescan", LibraryArgs<null>], result: null } |
{ key: ["locations.update", LibraryArgs<LocationUpdateArgs>], result: null } |
{ key: ["tags.assign", LibraryArgs<TagAssignArgs>], result: null } |
{ key: ["tags.create", LibraryArgs<TagCreateArgs>], result: Tag } |
{ key: ["tags.delete", LibraryArgs<number>], result: null } |
{ key: ["tags.update", LibraryArgs<TagUpdateArgs>], result: null },
{ key: "files.delete", input: LibraryArgs<number>, result: null } |
{ key: "files.setFavorite", input: LibraryArgs<SetFavoriteArgs>, result: null } |
{ key: "files.setNote", input: LibraryArgs<SetNoteArgs>, result: null } |
{ key: "jobs.generateThumbsForLocation", input: LibraryArgs<GenerateThumbsForLocationArgs>, result: null } |
{ key: "jobs.identifyUniqueFiles", input: LibraryArgs<IdentifyUniqueFilesArgs>, result: null } |
{ key: "library.create", input: string, result: LibraryConfigWrapped } |
{ key: "library.delete", input: string, result: null } |
{ key: "library.edit", input: EditLibraryArgs, result: null } |
{ key: "locations.create", input: LibraryArgs<LocationCreateArgs>, result: null } |
{ key: "locations.delete", input: LibraryArgs<number>, result: null } |
{ key: "locations.fullRescan", input: LibraryArgs<number>, result: null } |
{ key: "locations.indexer_rules.create", input: LibraryArgs<IndexerRuleCreateArgs>, result: IndexerRule } |
{ key: "locations.indexer_rules.delete", input: LibraryArgs<number>, result: null } |
{ key: "locations.quickRescan", input: LibraryArgs<null>, result: null } |
{ key: "locations.update", input: LibraryArgs<LocationUpdateArgs>, result: null } |
{ key: "tags.assign", input: LibraryArgs<TagAssignArgs>, result: null } |
{ key: "tags.create", input: LibraryArgs<TagCreateArgs>, result: Tag } |
{ key: "tags.delete", input: LibraryArgs<number>, result: null } |
{ key: "tags.update", input: LibraryArgs<TagUpdateArgs>, result: null },
subscriptions:
{ key: ["invalidateQuery"], result: InvalidateOperationEvent } |
{ key: ["jobs.newThumbnail", LibraryArgs<null>], result: string }
{ key: "invalidateQuery", input: never, result: InvalidateOperationEvent } |
{ key: "jobs.newThumbnail", input: LibraryArgs<null>, result: string }
};
export interface ConfigMetadata { version: string | null }

View file

@ -22,6 +22,10 @@ export const LibraryContextProvider = ({
return <CringeContext.Provider value={{ onNoLibrary }}>{children}</CringeContext.Provider>;
};
export function getLibraryIdRaw(): string | null {
return currentLibraryUuidStore.id;
}
// this is a hook to get the current library loaded into the UI. It takes care of a bunch of invariants under the hood.
export const useCurrentLibrary = () => {
const currentLibraryUuid = useSnapshot(currentLibraryUuidStore).id;

View file

@ -1,120 +1,61 @@
import { RSPCError } from '@rspc/client';
import { ProcedureDef } from '@rspc/client';
import { createReactQueryHooks } from '@rspc/react';
import {
QueryClient,
UseInfiniteQueryOptions,
UseInfiniteQueryResult,
UseMutationOptions,
UseMutationResult,
UseQueryOptions,
UseQueryResult,
useMutation as _useMutation
} from '@tanstack/react-query';
import { QueryClient } from '@tanstack/react-query';
import { LibraryArgs, Operations } from './core';
import { useCurrentLibrary } from './index';
import { LibraryArgs, Procedures } from './core';
import { getLibraryIdRaw } from './index';
export const queryClient = new QueryClient();
export const rspc = createReactQueryHooks<Operations>();
export const rspc = createReactQueryHooks<Procedures>();
type NonLibraryQueries = Exclude<Operations['queries'], { key: [any, LibraryArgs<any>] }> &
Extract<Operations['queries'], { key: [any] }>;
type NonLibraryQuery<K extends string> = Extract<NonLibraryQueries, { key: [K] | [K, any] }>;
type NonLibraryQueryKey = NonLibraryQueries['key'][0];
type NonLibraryQueryResult<K extends NonLibraryQueryKey> = NonLibraryQuery<K>['result'];
type NonLibraryProcedure<T extends keyof Procedures> =
| Exclude<Procedures[T], { input: LibraryArgs<any> }>
| Extract<Procedures[T], { input: never }>;
export function useBridgeQuery<K extends NonLibraryQueries['key']>(
key: K,
options?: UseQueryOptions<NonLibraryQueryResult<K[0]>, RSPCError>
): UseQueryResult<NonLibraryQueryResult<K[0]>, RSPCError> {
// @ts-ignore
return rspc.useQuery(key, options);
}
type LibraryQueries = Extract<Operations['queries'], { key: [string, LibraryArgs<any>] }>;
type LibraryQuery<K extends string> = Extract<LibraryQueries, { key: [K, any] }>;
type LibraryQueryKey = LibraryQueries['key'][0];
type LibraryQueryArgs<K extends string> = LibraryQuery<K>['key'][1] extends LibraryArgs<infer A>
? A
: never;
type LibraryQueryResult<K extends string> = LibraryQuery<K>['result'];
export function useLibraryQuery<K extends LibraryQueryKey>(
key: LibraryQueryArgs<K> extends null | undefined ? [K] : [K, LibraryQueryArgs<K>],
options?: UseQueryOptions<LibraryQueryResult<K>, RSPCError>
): UseQueryResult<LibraryQueryResult<K>, RSPCError> {
const { library } = useCurrentLibrary();
if (!library?.uuid) throw new Error(`Attempted to do library query with no library set!`);
// @ts-ignore
return rspc.useQuery(
// @ts-ignore
[key[0], { library_id: library?.uuid || '', arg: key[1] || null }],
options
);
}
export function useInfiniteLibraryQuery<K extends LibraryQueryKey>(
key: LibraryQueryArgs<K> extends null | undefined ? [K] : [K, LibraryQueryArgs<K>],
options?: UseInfiniteQueryOptions<LibraryQueryResult<K>, RSPCError>
): UseInfiniteQueryResult<LibraryQueryResult<K>, RSPCError> {
const { library } = useCurrentLibrary();
if (!library?.uuid) throw new Error(`Attempted to do library query with no library set!`);
// @ts-ignore
return rspc.useInfiniteQuery(
// @ts-ignore
[key[0], { library_id: library?.uuid || '', arg: key[1] || null }],
options
);
}
type LibraryMutations = Extract<Operations['mutations'], { key: [string, LibraryArgs<any>] }>;
type LibraryMutation<K extends LibraryMutationKey> = Extract<LibraryMutations, { key: [K, any] }>;
type LibraryMutationKey = LibraryMutations['key'][0];
type LibraryMutationArgs<K extends LibraryMutationKey> =
LibraryMutation<K>['key'][1] extends LibraryArgs<infer A> ? A : never;
type LibraryMutationResult<K extends LibraryMutationKey> = LibraryMutation<K>['result'];
export function useLibraryMutation<K extends LibraryMutationKey>(
key: K,
options?: UseMutationOptions<LibraryMutationResult<K>, RSPCError>
) {
const ctx = rspc.useContext();
const { library } = useCurrentLibrary();
if (!library?.uuid) throw new Error(`Attempted to do library query with no library set!`);
// @ts-ignore
return _useMutation<LibraryMutationResult<K>, RSPCError, LibraryMutationArgs<K>>(
async (data) =>
ctx.client.mutation([key, { library_id: library?.uuid || '', arg: data || null }]),
{
...options,
context: rspc.ReactQueryContext
}
);
}
type NonLibraryMutations = Exclude<Operations['mutations'], { key: [any, LibraryArgs<any>] }>;
type NonLibraryMutation<K extends NonLibraryMutationKey> = Extract<
NonLibraryMutations,
{ key: [K] | [K, any] }
type LibraryProcedures<T extends keyof Procedures> = Exclude<
Extract<Procedures[T], { input: LibraryArgs<any> }>,
{ input: never }
>;
type NonLibraryMutationKey = NonLibraryMutations['key'][0];
type NonLibraryMutationArgs<K extends NonLibraryMutationKey> = NonLibraryMutation<K>['key'][1];
type NonLibraryMutationResult<K extends NonLibraryMutationKey> = NonLibraryMutation<K>['result'];
export function useBridgeMutation<K extends NonLibraryMutationKey>(
key: K,
options?: UseMutationOptions<NonLibraryMutationResult<K>, RSPCError>
): UseMutationResult<NonLibraryMutationResult<K>, RSPCError, NonLibraryMutationArgs<K>> {
// @ts-ignore
return rspc.useMutation(key, options);
}
type MoreConstrainedQueries<T extends ProcedureDef> = T extends any
? T['input'] extends LibraryArgs<infer E>
? {
key: T['key'];
input: E;
result: T['result'];
}
: never
: never;
export const useBridgeQuery = rspc.customQuery<NonLibraryProcedure<'queries'>>(
(keyAndInput) => keyAndInput as any
);
export const useBridgeMutation = rspc.customMutation<NonLibraryProcedure<'mutations'>>(
(keyAndInput) => keyAndInput
);
export const useLibraryQuery = rspc.customQuery<
MoreConstrainedQueries<LibraryProcedures<'queries'>>
>((keyAndInput) => {
const library_id = getLibraryIdRaw();
if (library_id === null) throw new Error('Attempted to do library query with no library set!');
return [keyAndInput[0], { library_id, arg: keyAndInput[1] || null }];
});
export const useLibraryMutation = rspc.customMutation<
MoreConstrainedQueries<LibraryProcedures<'mutations'>>
>((keyAndInput) => {
const library_id = getLibraryIdRaw();
if (library_id === null) throw new Error('Attempted to do library query with no library set!');
return [keyAndInput[0], { library_id, arg: keyAndInput[1] || null }];
});
export function useInvalidateQuery() {
const context = rspc.useContext();
rspc.useSubscription(['invalidateQuery'], {
onNext: (invalidateOperation) => {
let key = [invalidateOperation.key];
onData: (invalidateOperation) => {
const key = [invalidateOperation.key];
if (invalidateOperation.arg !== null) {
key.concat(invalidateOperation.arg);
}

View file

@ -15,7 +15,7 @@
"noUnusedLocals": false,
"noUnusedParameters": false,
"preserveWatchOutput": true,
"skipLibCheck": false,
"skipLibCheck": true,
"strict": true,
"allowSyntheticDefaultImports": true,
"resolveJsonModule": true,

View file

@ -7,11 +7,11 @@
"eslint-react.js"
],
"devDependencies": {
"eslint": "^8.21.0",
"@typescript-eslint/eslint-plugin": "^5.30.7",
"@typescript-eslint/parser": "^5.30.7",
"@typescript-eslint/eslint-plugin": "^5.38.1",
"@typescript-eslint/parser": "^5.38.1",
"eslint": "^8.24.0",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-react": "^7.30.1",
"eslint-plugin-react": "^7.31.8",
"eslint-plugin-react-hooks": "^4.6.0"
}
}

View file

@ -15,82 +15,82 @@
"lint": "eslint src/**/*.{ts,tsx} && tsc --noEmit"
},
"dependencies": {
"@fontsource/inter": "^4.5.11",
"@headlessui/react": "^1.6.6",
"@heroicons/react": "^2.0.10",
"@fontsource/inter": "^4.5.12",
"@headlessui/react": "^1.7.2",
"@heroicons/react": "^2.0.11",
"@radix-ui/react-dialog": "^1.0.0",
"@radix-ui/react-dropdown-menu": "^1.0.0",
"@radix-ui/react-icons": "^1.1.1",
"@radix-ui/react-progress": "^0.1.4",
"@radix-ui/react-slider": "^0.1.4",
"@radix-ui/react-progress": "^1.0.0",
"@radix-ui/react-slider": "^1.0.0",
"@radix-ui/react-tabs": "^1.0.0",
"@radix-ui/react-tooltip": "^1.0.0",
"@sd/assets": "workspace:*",
"@sd/client": "workspace:*",
"@sd/ui": "workspace:*",
"@tailwindcss/forms": "^0.5.2",
"@tanstack/react-query": "^4.2.3",
"@tanstack/react-query-devtools": "^4.0.10",
"@tailwindcss/forms": "^0.5.3",
"@tanstack/react-query": "^4.8.0",
"@tanstack/react-query-devtools": "^4.8.0",
"@tanstack/react-virtual": "3.0.0-beta.18",
"@types/styled-components": "^5.1.25",
"@vitejs/plugin-react": "^2.0.0",
"autoprefixer": "^10.4.7",
"@types/styled-components": "^5.1.26",
"@vitejs/plugin-react": "^2.1.0",
"autoprefixer": "^10.4.12",
"byte-size": "^8.1.0",
"clsx": "^1.2.1",
"date-fns": "^2.29.2",
"date-fns": "^2.29.3",
"immer": "^9.0.15",
"jotai": "^1.7.6",
"jotai": "^1.8.4",
"lodash": "^4.17.21",
"moment": "^2.29.4",
"phosphor-react": "^1.4.1",
"pretty-bytes": "^6.0.0",
"react": "^18.2.0",
"react-colorful": "^5.5.1",
"react-countup": "^6.3.0",
"react-colorful": "^5.6.1",
"react-countup": "^6.3.1",
"react-dom": "^18.2.0",
"react-dropzone": "^14.2.2",
"react-error-boundary": "^3.1.4",
"react-hook-form": "^7.33.1",
"react-hook-form": "^7.36.1",
"react-hotkeys-hook": "^3.4.7",
"react-json-view": "^1.21.3",
"react-loading-icons": "^1.1.0",
"react-loading-skeleton": "^3.1.0",
"react-portal": "^4.2.2",
"react-query": "^4.0.0",
"react-router": "6.3.0",
"react-router-dom": "6.3.0",
"react-scrollbars-custom": "^4.1.0",
"react-query": "^3.39.2",
"react-router": "6.4.1",
"react-router-dom": "6.4.1",
"react-scrollbars-custom": "^4.1.1",
"react-spline": "^1.2.1",
"react-transition-group": "^4.4.2",
"react-virtuoso": "^2.16.5",
"rooks": "^5.14.0",
"styled-components": "^5.3.5",
"tailwindcss": "^3.1.6",
"react-transition-group": "^4.4.5",
"react-virtuoso": "^2.19.0",
"rooks": "^7.4.0",
"styled-components": "^5.3.6",
"tailwindcss": "^3.1.8",
"use-count-up": "^3.0.1",
"use-debounce": "^8.0.3",
"use-debounce": "^8.0.4",
"valtio": "^1.7.0",
"valtio-persist": "^1.0.2",
"zod": "^3.18.0",
"zustand": "4.0.0"
"zod": "^3.19.1",
"zustand": "4.1.1"
},
"devDependencies": {
"@sd/config": "workspace:*",
"@types/babel-core": "^6.25.7",
"@types/byte-size": "^8.1.0",
"@types/lodash": "^4.14.182",
"@types/node": "^18.6.1",
"@types/lodash": "^4.14.186",
"@types/node": "^18.7.23",
"@types/pretty-bytes": "^5.2.0",
"@types/react": "^18.0.15",
"@types/react": "^18.0.21",
"@types/react-dom": "^18.0.6",
"@types/react-router-dom": "^5.3.3",
"@types/react-table": "^7.7.12",
"@types/react-window": "^1.8.5",
"@types/tailwindcss": "^3.1.0",
"@vitejs/plugin-react": "^1.3.1",
"concurrently": "^7.3.0",
"concurrently": "^7.4.0",
"prettier": "^2.7.1",
"typescript": "^4.7.4",
"vite": "^3.0.3",
"typescript": "^4.8.4",
"vite": "^3.1.4",
"vite-plugin-svgr": "^2.2.1"
}
}

View file

@ -14,7 +14,7 @@ export default function Explorer(props: Props) {
const { library } = useCurrentLibrary();
rspc.useSubscription(['jobs.newThumbnail', { library_id: library!.uuid, arg: null }], {
onNext: (cas_id) => {
onData: (cas_id) => {
expStore.addNewThumbnail(cas_id);
}
});

View file

@ -1,10 +1,9 @@
import { ExplorerLayoutMode, getExplorerStore, useExplorerStore } from '@sd/client';
import { ExplorerContext, ExplorerItem, FilePath } from '@sd/client';
import { useVirtualizer } from '@tanstack/react-virtual';
import { memo, useCallback, useLayoutEffect, useMemo, useRef, useState } from 'react';
import { useCallback, useLayoutEffect, useRef, useState } from 'react';
import { useSearchParams } from 'react-router-dom';
import { useKey, useOnWindowResize, useWindowSize } from 'rooks';
import { useSnapshot } from 'valtio';
import { useKey, useOnWindowResize } from 'rooks';
import FileItem from './FileItem';
import FileRow from './FileRow';

View file

@ -17,45 +17,45 @@
"storybook:build": "build-storybook"
},
"dependencies": {
"@headlessui/react": "^1.6.6",
"@heroicons/react": "^2.0.10",
"@headlessui/react": "^1.7.2",
"@heroicons/react": "^2.0.11",
"@radix-ui/react-context-menu": "^1.0.0",
"@radix-ui/react-dropdown-menu": "^1.0.0",
"@tailwindcss/forms": "^0.5.2",
"@tailwindcss/forms": "^0.5.3",
"class-variance-authority": "^0.2.3",
"clsx": "^1.2.1",
"phosphor-react": "^1.4.1",
"postcss": "^8.4.14",
"postcss": "^8.4.17",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"storybook": "^6.5.10",
"tailwindcss": "^3.1.6"
"storybook": "^6.5.12",
"tailwindcss": "^3.1.8"
},
"devDependencies": {
"@babel/core": "^7.18.9",
"@babel/core": "^7.19.3",
"@sd/config": "workspace:*",
"@storybook/addon-actions": "^6.5.9",
"@storybook/addon-essentials": "^6.5.9",
"@storybook/addon-interactions": "^6.5.9",
"@storybook/addon-links": "^6.5.9",
"@storybook/addon-postcss": "3.0.0-alpha.1",
"@storybook/builder-webpack5": "^6.5.9",
"@storybook/manager-webpack5": "^6.5.9",
"@storybook/addon-actions": "^6.5.12",
"@storybook/addon-essentials": "^6.5.12",
"@storybook/addon-interactions": "^6.5.12",
"@storybook/addon-links": "^6.5.12",
"@storybook/addon-postcss": "2.0.0",
"@storybook/builder-webpack5": "^6.5.12",
"@storybook/manager-webpack5": "^6.5.12",
"@storybook/preset-scss": "^1.0.3",
"@storybook/react": "^6.5.9",
"@storybook/react": "^6.5.12",
"@storybook/testing-library": "^0.0.13",
"@tailwindcss/line-clamp": "^0.4.0",
"@tailwindcss/typography": "^0.5.4",
"@types/react": "^18.0.15",
"@tailwindcss/line-clamp": "^0.4.2",
"@tailwindcss/typography": "^0.5.7",
"@types/react": "^18.0.21",
"@types/react-dom": "^18.0.6",
"autoprefixer": "^10.4.7",
"autoprefixer": "^10.4.12",
"babel-loader": "^8.2.5",
"css-loader": "^6.7.1",
"postcss-loader": "^7.0.1",
"sass": "^1.54.0",
"sass": "^1.55.0",
"sass-loader": "^13.0.2",
"storybook-tailwind-dark-mode": "^1.0.12",
"storybook-tailwind-dark-mode": "^1.0.15",
"style-loader": "^3.3.1",
"typescript": "^4.7.4"
"typescript": "^4.8.4"
}
}

File diff suppressed because it is too large Load diff