From fc1c6d09064471c416c363461b96fd3aed4ddb65 Mon Sep 17 00:00:00 2001 From: Oscar Beaumont Date: Sun, 2 Oct 2022 01:16:11 +0800 Subject: [PATCH 01/11] upgrade rspc --- .vscode/extensions.json | 7 + Cargo.lock | Bin 151042 -> 151720 bytes Cargo.toml | 4 +- apps/desktop/package.json | 22 +- apps/desktop/src-tauri/Cargo.toml | 14 +- apps/desktop/src/index.tsx | 4 +- apps/mobile/package.json | 4 +- apps/mobile/pnpm-lock.yaml | Bin 330329 -> 329592 bytes apps/mobile/rust/Cargo.toml | 12 +- apps/mobile/rust/src/android.rs | 49 +--- apps/mobile/rust/src/lib.rs | 15 +- apps/mobile/src/App.tsx | 4 +- apps/mobile/src/hooks/rspc.ts | 143 ++++------ apps/mobile/src/stores/libraryStore.ts | 4 + apps/mobile/src/types/bindings.ts | 78 +++--- apps/server/Cargo.toml | 10 +- apps/server/src/main.rs | 15 +- apps/web/package.json | 20 +- apps/web/src/App.tsx | 6 +- core/Cargo.toml | 30 +-- core/src/api/files.rs | 57 ++-- core/src/api/jobs.rs | 88 +++--- core/src/api/libraries.rs | 130 ++++----- core/src/api/locations.rs | 255 ++++++++++-------- core/src/api/mod.rs | 71 ++--- core/src/api/tags.rs | 253 +++++++++-------- core/src/api/utils/library.rs | 143 +++++----- core/src/api/volumes.rs | 4 +- core/src/lib.rs | 6 +- crates/ffmpeg/Cargo.toml | 6 +- package.json | 10 +- packages/client/package.json | 14 +- packages/client/src/core.ts | 78 +++--- .../client/src/hooks/useCurrentLibrary.tsx | 4 + packages/client/src/rspc.ts | 153 ++++------- packages/config/base.tsconfig.json | 2 +- packages/config/package.json | 8 +- packages/interface/package.json | 68 ++--- .../src/components/explorer/Explorer.tsx | 2 +- .../components/explorer/VirtualizedList.tsx | 5 +- packages/ui/package.json | 44 +-- pnpm-lock.yaml | Bin 672390 -> 671681 bytes 42 files changed, 907 insertions(+), 935 deletions(-) create mode 100644 .vscode/extensions.json diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 000000000..6ff490004 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,7 @@ +{ + "recommendations": [ + "tauri-apps.tauri-vscode", + "rust-lang.rust-analyzer", + "oscartbeaumont.rspc-vscode" + ] +} diff --git a/Cargo.lock b/Cargo.lock index 76ad097a8cd7f07fe9b3a2dc44b0ce7e399a530c..b81a8c2516259d55f0f3d03a5c0a562af3a0cc2f 100644 GIT binary patch delta 3093 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

m6)%iit7Z#g1=iyN|Lv zcRS7__=~34EG85b32XZzGgk%P79x;P%0S>MNnTSzRCprTA8(NKbM52zvzx{z53^sb zS+&3idcen+DNpyhpT3tH?WwP@4=+1gDQTpPl%0dTd{mfI8NRR{FmNNPGoc7lsGgkAupvna&mp-r zm$G9A`|k;lEIqJw$IQakx^#T$q4MzZ?<3*J(Zjj1U$ZT3%ZRNU|MIKs3Dwr3U7T*w)BCht^4svyH$3C325vpFFRsh!===Gvv_*!&8h)85?9 zZWyl}vF#fh?eE=jvk+VxftDh#+^C?6C4%9GK+I$w)EDPBnsC8Ci1Z;jcbBl%X1X5B7o2V+;5eWgi*+oOcEVt z5z$e%?%Vxt;r8|8i!ZV(Q`boS>mS)YE3Q4bKe5xR{`b(GePv5KbAhdCpZg08zVH(J z6ub7_7hh(2b$9L`i^HU4^%(ieAc_l;$YCTSm_wkFU4=Z11z#LVrVo6x_$apHe4=Q@rjWhXsAj0WF$?oLXj21>5`C|IvLH2E6Mr@Nff9I3xLU4 zR_i8GXp3(%H$L%qcD~o{eHVsj3NGL;Rmh3tGnIl^Pgxm@q;wWEBcTgcAuSPEV8Wz; zAce3Iwn|QhXLs

2~=hw$N_=C%e=xT!uYnFSF-a_t6L8V=ge=5XjuZtHxNU7g^4Q zcNire>lCO56$Q&c!YhdxBV$GG@zF_!dj_xfsvy2r5s}^#_)Nb#3 ZY(Osqilc+x=85FgK#spT=sot{{{l4eNl5?z diff --git a/Cargo.toml b/Cargo.toml index 96f10f8f7..b45727c65 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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" } diff --git a/apps/desktop/package.json b/apps/desktop/package.json index 818905ec2..e8fe551db 100644 --- a/apps/desktop/package.json +++ b/apps/desktop/package.json @@ -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" } diff --git a/apps/desktop/src-tauri/Cargo.toml b/apps/desktop/src-tauri/Cargo.toml index ec1592f58..2adf75975 100644 --- a/apps/desktop/src-tauri/Cargo.toml +++ b/apps/desktop/src-tauri/Cargo.toml @@ -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"] } diff --git a/apps/desktop/src/index.tsx b/apps/desktop/src/index.tsx index 815573030..a291067a7 100644 --- a/apps/desktop/src/index.tsx +++ b/apps/desktop/src/index.tsx @@ -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({ +const client = createClient({ transport: new TauriTransport() }); diff --git a/apps/mobile/package.json b/apps/mobile/package.json index f1c15ee93..49b065fb3 100644 --- a/apps/mobile/package.json +++ b/apps/mobile/package.json @@ -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", diff --git a/apps/mobile/pnpm-lock.yaml b/apps/mobile/pnpm-lock.yaml index 84ec59b3d8324321bc3a4418af7157cd3e7d0a15..c2a24bf98284818b212273f2ce5937ce8e1882d8 100644 GIT binary patch delta 1186 zcmaJ=T})eL7|z@C(XFLSumvK)+HEZ*W9c7lVMsz@bOm-g3SGO|kZRj;Xe|h*?Mlya z(?(5}Oo!9s_M#-fo#AR*cJXPPneNg=XR>U`qM6K_X>cYaUYIyDPg~ToM9s zJ|DZ{nT#cJ<{m@TW|1-JtZMY?`-`cLEuvb;p$mcRDsq`(un7$K#ku{!6E6Fn%Xxx4dpcO zapQLE4E=Hs6agcPu$#^q!D^`delrL^*5d6UFwvg_@DgD00#k?Vt4sqv`jFA!J%Q2T z(m3?sz7V`jLqWJn@QRsq)5LLj1h^IfBNoPB1TRNGkB=kpcxPFw$KH(%&7j5gFsP;C z=f+Zl3F+aEW_oV|+AB;@eqKZSqhKRdbc-D5q+d0YcryuZ>Q6wp3Z=5pKdOaqRhw|x zK%SzWG+f_OX_(hy)M@Fq*znqYGKl`u@HA73<)) zR8nhOC6D1*Y1La#dy7m@EvoY}cIoYZutuDDhgrf;1UY?w+Q~EMInOj&U9(G@e%R?bxJI04)H)F+^cPVXbv zU^@|%iL_yO9lVHonZm98Wc-P%eHK|d|FyzS(L(f4+B7X*N-;Ik_d6PJbqsc49}B(I kY9sG$?P_^LOD<5^1(O0#wGtg=o#c&$ZLH`|Hwf?h3p8Ml`Tzg` delta 1711 zcmai!T})eL7{~LR^A1;r4qP#7Ezov_inVJA^fbCe`6zH$i!E^41~SHa4waU2x*l3+ z*}(Y`zc6mW%^uj}N$c4N+7bhn< zzvuIP|NlSFo4T&;_UhyAo-Y;@-+Vfyl-v*4Px_A<|MXQ;^!kh3hc(T6 zf>jP*%YyUznkmUyb3&!8<~4O@sW>B)(^k&hCUvG8wd31FU|U6y{+`s7@PwA*O&#lQ7B@}O7>%91Ma|2&+>}~h^P0=fHIyOT%1V7 zf}WHooRs9A-2HvI-cc>tksn$JN+~rFEKQVhVnWTz<(Md?2l9oUaBMD|2#$$?#naP? zuBGvQNx_CNcer7ffPDX|!b-Xm*?2G%mlc09H=GP=fzD#Z?f<@N}jx)YT^`l4o>0UdhgDq9#a-Msc+i7L^fPa}hVLTm&c1 zbrLh4ScW@!L!_uJ!#G|RpdHr*FxA`bUVBy3-h8T*T}pJo7<~j+!bC*+_HN47yk467!)0`kqYYqVe~!D zLI1FmV=Uv@F|#uL;;Z#J%*d zc5;=8zU3hn%buo { 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; }); } diff --git a/apps/mobile/rust/src/lib.rs b/apps/mobile/rust/src/lib.rs index 1619101c2..4c9dc9510 100644 --- a/apps/mobile/rust/src/lib.rs +++ b/apps/mobile/rust/src/lib.rs @@ -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 = Lazy::new(|| Runtime::new().unwrap()); -type LazyNode = Lazy, Arc)>>>; #[allow(dead_code)] -pub(crate) static NODE: LazyNode = Lazy::new(|| Mutex::new(None)); +pub(crate) static NODE: Lazy, Arc)>>> = + Lazy::new(|| Mutex::new(None)); #[allow(dead_code)] -pub(crate) static CLIENT_CONTEXT: Lazy = Lazy::new(|| ClientContext { - subscriptions: Default::default(), -}); +pub(crate) static SUBSCRIPTIONS: Lazy>>> = + Lazy::new(Default::default); #[allow(dead_code)] pub(crate) static EVENT_SENDER: OnceCell> = OnceCell::new(); diff --git a/apps/mobile/src/App.tsx b/apps/mobile/src/App.tsx index 08ecaa158..7dfa19e47 100644 --- a/apps/mobile/src/App.tsx +++ b/apps/mobile/src/App.tsx @@ -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({ +const client = createClient({ transport: new ReactNativeTransport() }); diff --git a/apps/mobile/src/hooks/rspc.ts b/apps/mobile/src/hooks/rspc.ts index 0df3939c0..613ea1390 100644 --- a/apps/mobile/src/hooks/rspc.ts +++ b/apps/mobile/src/hooks/rspc.ts @@ -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(); +export const rspc = createReactQueryHooks(); 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 { + async doRequest(operation: OperationType, key: string, input: any): Promise { 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] }> & - Extract; -type NonLibraryQuery = Extract; -type NonLibraryQueryKey = NonLibraryQueries['key'][0]; -type NonLibraryQueryResult = NonLibraryQuery['result']; +type NonLibraryProcedure = + | Exclude }> + | Extract; -export function useBridgeQuery( - key: K, - options?: UseQueryOptions, RSPCError> -): UseQueryResult, RSPCError> { - // @ts-ignore - return rspc.useQuery(key, options); -} - -type LibraryQueries = Extract] }>; -type LibraryQuery = Extract; -type LibraryQueryKey = LibraryQueries['key'][0]; -type LibraryQueryArgs = LibraryQuery['key'][1] extends LibraryArgs - ? A - : never; -type LibraryQueryResult = LibraryQuery['result']; - -export function useLibraryQuery( - key: LibraryQueryArgs extends null | undefined ? [K] : [K, LibraryQueryArgs], - options?: UseQueryOptions, RSPCError> -): UseQueryResult, 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] }>; -type LibraryMutation = Extract; -type LibraryMutationKey = LibraryMutations['key'][0]; -type LibraryMutationArgs = - LibraryMutation['key'][1] extends LibraryArgs ? A : never; -type LibraryMutationResult = LibraryMutation['result']; -export function useLibraryMutation( - key: K, - options?: UseMutationOptions, 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, RSPCError, LibraryMutationArgs>( - async (data) => ctx.client.mutation([key, { library_id: library_id || '', arg: data || null }]), - { - ...options, - context: rspc.ReactQueryContext - } - ); -} - -type NonLibraryMutations = Exclude] }>; -type NonLibraryMutation = Extract< - NonLibraryMutations, - { key: [K] | [K, any] } +type LibraryProcedures = Exclude< + Extract }>, + { input: never } >; -type NonLibraryMutationKey = NonLibraryMutations['key'][0]; -type NonLibraryMutationArgs = NonLibraryMutation['key'][1]; -type NonLibraryMutationResult = NonLibraryMutation['result']; -export function useBridgeMutation( - key: K, - options?: UseMutationOptions, RSPCError> -): UseMutationResult, RSPCError, NonLibraryMutationArgs> { - // @ts-ignore - return rspc.useMutation(key, options); -} + +type MoreConstrainedQueries = T extends any + ? T['input'] extends LibraryArgs + ? { + key: T['key']; + input: E; + result: T['result']; + } + : never + : never; + +export const useBridgeQuery = rspc.customQuery>( + (keyAndInput) => keyAndInput as any +); + +export const useBridgeMutation = rspc.customMutation>( + (keyAndInput) => keyAndInput +); + +export const useLibraryQuery = rspc.customQuery< + MoreConstrainedQueries> +>((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> +>((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); diff --git a/apps/mobile/src/stores/libraryStore.ts b/apps/mobile/src/stores/libraryStore.ts index 73cf04544..20f6197c8 100644 --- a/apps/mobile/src/stores/libraryStore.ts +++ b/apps/mobile/src/stores/libraryStore.ts @@ -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 = () => { diff --git a/apps/mobile/src/types/bindings.ts b/apps/mobile/src/types/bindings.ts index c3d16c9aa..d82997047 100644 --- a/apps/mobile/src/types/bindings.ts +++ b/apps/mobile/src/types/bindings.ts @@ -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], result: null } | - { key: ["getNode"], result: NodeState } | - { key: ["jobs.getHistory", LibraryArgs], result: Array } | - { key: ["jobs.getRunning", LibraryArgs], result: Array } | - { key: ["library.getStatistics", LibraryArgs], result: Statistics } | - { key: ["library.list"], result: Array } | - { key: ["locations.getById", LibraryArgs], result: Location | null } | - { key: ["locations.getExplorerData", LibraryArgs], result: ExplorerData } | - { key: ["locations.indexer_rules.get", LibraryArgs], result: IndexerRule } | - { key: ["locations.indexer_rules.list", LibraryArgs], result: Array } | - { key: ["locations.list", LibraryArgs], result: Array<{ id: number, pub_id: Array, 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], result: Tag | null } | - { key: ["tags.getExplorerData", LibraryArgs], result: ExplorerData } | - { key: ["tags.getForFile", LibraryArgs], result: Array } | - { key: ["tags.list", LibraryArgs], result: Array } | - { key: ["version"], result: string } | - { key: ["volumes.list"], result: Array }, + { key: "files.readMetadata", input: LibraryArgs, result: null } | + { key: "getNode", input: never, result: NodeState } | + { key: "jobs.getHistory", input: LibraryArgs, result: Array } | + { key: "jobs.getRunning", input: LibraryArgs, result: Array } | + { key: "library.getStatistics", input: LibraryArgs, result: Statistics } | + { key: "library.list", input: never, result: Array } | + { key: "locations.getById", input: LibraryArgs, result: Location | null } | + { key: "locations.getExplorerData", input: LibraryArgs, result: ExplorerData } | + { key: "locations.indexer_rules.get", input: LibraryArgs, result: IndexerRule } | + { key: "locations.indexer_rules.list", input: LibraryArgs, result: Array } | + { key: "locations.list", input: LibraryArgs, result: Array<{ id: number, pub_id: Array, 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, result: Tag | null } | + { key: "tags.getExplorerData", input: LibraryArgs, result: ExplorerData } | + { key: "tags.getForFile", input: LibraryArgs, result: Array } | + { key: "tags.list", input: LibraryArgs, result: Array } | + { key: "version", input: never, result: string } | + { key: "volumes.list", input: never, result: Array }, mutations: - { key: ["files.delete", LibraryArgs], result: null } | - { key: ["files.setFavorite", LibraryArgs], result: null } | - { key: ["files.setNote", LibraryArgs], result: null } | - { key: ["jobs.generateThumbsForLocation", LibraryArgs], result: null } | - { key: ["jobs.identifyUniqueFiles", LibraryArgs], result: null } | - { key: ["library.create", string], result: LibraryConfigWrapped } | - { key: ["library.delete", string], result: null } | - { key: ["library.edit", EditLibraryArgs], result: null } | - { key: ["locations.create", LibraryArgs], result: null } | - { key: ["locations.delete", LibraryArgs], result: null } | - { key: ["locations.fullRescan", LibraryArgs], result: null } | - { key: ["locations.indexer_rules.create", LibraryArgs], result: IndexerRule } | - { key: ["locations.indexer_rules.delete", LibraryArgs], result: null } | - { key: ["locations.quickRescan", LibraryArgs], result: null } | - { key: ["locations.update", LibraryArgs], result: null } | - { key: ["tags.assign", LibraryArgs], result: null } | - { key: ["tags.create", LibraryArgs], result: Tag } | - { key: ["tags.delete", LibraryArgs], result: null } | - { key: ["tags.update", LibraryArgs], result: null }, + { key: "files.delete", input: LibraryArgs, result: null } | + { key: "files.setFavorite", input: LibraryArgs, result: null } | + { key: "files.setNote", input: LibraryArgs, result: null } | + { key: "jobs.generateThumbsForLocation", input: LibraryArgs, result: null } | + { key: "jobs.identifyUniqueFiles", input: LibraryArgs, 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, result: null } | + { key: "locations.delete", input: LibraryArgs, result: null } | + { key: "locations.fullRescan", input: LibraryArgs, result: null } | + { key: "locations.indexer_rules.create", input: LibraryArgs, result: IndexerRule } | + { key: "locations.indexer_rules.delete", input: LibraryArgs, result: null } | + { key: "locations.quickRescan", input: LibraryArgs, result: null } | + { key: "locations.update", input: LibraryArgs, result: null } | + { key: "tags.assign", input: LibraryArgs, result: null } | + { key: "tags.create", input: LibraryArgs, result: Tag } | + { key: "tags.delete", input: LibraryArgs, result: null } | + { key: "tags.update", input: LibraryArgs, result: null }, subscriptions: - { key: ["invalidateQuery"], result: InvalidateOperationEvent } | - { key: ["jobs.newThumbnail", LibraryArgs], result: string } + { key: "invalidateQuery", input: never, result: InvalidateOperationEvent } | + { key: "jobs.newThumbnail", input: LibraryArgs, result: string } }; export interface ConfigMetadata { version: string | null } diff --git a/apps/server/Cargo.toml b/apps/server/Cargo.toml index 99bd2e887..7ca7d8183 100644 --- a/apps/server/Cargo.toml +++ b/apps/server/Cargo.toml @@ -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" diff --git a/apps/server/src/main.rs b/apps/server/src/main.rs index 85892f76e..8566d052f 100644 --- a/apps/server/src/main.rs +++ b/apps/server/src/main.rs @@ -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::().unwrap(); // This listens on IPv6 and IPv4 addr.set_port(port); diff --git a/apps/web/package.json b/apps/web/package.json index 67d29d392..df365b134 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -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" } } diff --git a/apps/web/src/App.tsx b/apps/web/src/App.tsx index 52090595a..f944d8a85 100644 --- a/apps/web/src/App.tsx +++ b/apps/web/src/App.tsx @@ -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({ +const client = createClient({ 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' ) }); diff --git a/core/Cargo.toml b/core/Cargo.toml index 7551f8b1a..0e5301987 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -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] diff --git a/core/src/api/files.rs b/core/src/api/files.rs index 0250e2a88..cd07c0eb2 100644 --- a/core/src/api/files.rs +++ b/core/src/api/files.rs @@ -19,25 +19,28 @@ pub struct SetFavoriteArgs { pub(crate) fn mount() -> 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(()) + }) }) } diff --git a/core/src/api/jobs.rs b/core/src/api/jobs.rs index 7668d1ee8..847e72394 100644 --- a/core/src/api/jobs.rs +++ b/core/src/api/jobs.rs @@ -28,42 +28,42 @@ pub struct IdentifyUniqueFilesArgs { pub(crate) fn mount() -> 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, + _ => {} + } } } - } + }) }) } diff --git a/core/src/api/libraries.rs b/core/src/api/libraries.rs index c6c19c50a..fcfcee964 100644 --- a/core/src/api/libraries.rs +++ b/core/src/api/libraries.rs @@ -21,78 +21,84 @@ pub struct EditLibraryArgs { pub(crate) fn mount() -> 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?) }) }) } diff --git a/core/src/api/locations.rs b/core/src/api/locations.rs index aed2faa5f..a59be9956 100644 --- a/core/src/api/locations.rs +++ b/core/src/api/locations.rs @@ -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, } -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 + Send + 'static, +> { ::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 { ::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 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 not found"), + ) + }) + }) + }) + .library_query("list", |t| { + t(|_, _: (), library| async move { + library + .db + .indexer_rule() + .find_many(vec![]) + .exec() + .await + .map_err(Into::into) + }) }) } diff --git a/core/src/api/mod.rs b/core/src/api/mod.rs index 2266bf330..e04055e00 100644 --- a/core/src/api/mod.rs +++ b/core/src/api/mod.rs @@ -1,4 +1,5 @@ use std::{ + path::PathBuf, sync::Arc, time::{Duration, Instant}, }; @@ -62,12 +63,14 @@ pub(crate) fn mount() -> Arc { // .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 { .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()); } } diff --git a/core/src/api/tags.rs b/core/src/api/tags.rs index 111d5e242..c9a634667 100644 --- a/core/src/api/tags.rs +++ b/core/src/api/tags.rs @@ -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 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 not found"), + ) + })?; - let files: Vec = 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 = 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(()) + }) }) } diff --git a/core/src/api/utils/library.rs b/core/src/api/utils/library.rs index 4062b94d4..f776f4967 100644 --- a/core/src/api/utils/library.rs +++ b/core/src/api/utils/library.rs @@ -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 { 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( + fn library_query( self, key: &'static str, - resolver: fn(Ctx, TArg, LibraryContext) -> TResult, + builder: fn(UnbuiltProcedureBuilder) -> BuiltProcedureBuilder, ) -> Self where TArg: DeserializeOwned + specta::Type + Send + 'static, TResult: Future> + Send + 'static, - T: IntoLayerResult + Send + Serialize + specta::Type; + T: RequestLayer + Serialize + specta::Type + Send, + TResolver: Fn(Ctx, TArg, LibraryContext) -> TResult + Send + Sync + 'static; - fn library_mutation( + fn library_mutation( self, key: &'static str, - resolver: fn(Ctx, TArg, LibraryContext) -> TResult, + builder: fn(UnbuiltProcedureBuilder) -> BuiltProcedureBuilder, ) -> Self where TArg: DeserializeOwned + specta::Type + Send + 'static, TResult: Future> + Send + 'static, - T: IntoLayerResult + Send + Serialize + specta::Type; + T: RequestLayer + Serialize + specta::Type + Send, + TResolver: Fn(Ctx, TArg, LibraryContext) -> TResult + Send + Sync + 'static; - fn library_subscription( + fn library_subscription( self, key: &'static str, - resolver: fn(Ctx, TArg, Uuid) -> T, + builder: fn(UnbuiltProcedureBuilder) -> BuiltProcedureBuilder, ) -> Self where - TArg: DeserializeOwned + specta::Type + Send + 'static, - T: Stream + Send + 'static, - TResult: Serialize + specta::Type; + TArg: DeserializeOwned + specta::Type + 'static, + TStream: Stream + 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 { - fn library_query( +impl LibraryRequest for rspc::RouterBuilder +where + TMiddleware: MiddlewareBuilderLike + Send + 'static, +{ + fn library_query( self, key: &'static str, - resolver: fn(Ctx, TArg, LibraryContext) -> TResult, + builder: fn(UnbuiltProcedureBuilder) -> BuiltProcedureBuilder, ) -> Self where TArg: DeserializeOwned + specta::Type + Send + 'static, TResult: Future> + Send + 'static, - T: IntoLayerResult + Send + Serialize + specta::Type, + T: RequestLayer + Serialize + specta::Type + Send, + TResolver: Fn(Ctx, TArg, LibraryContext) -> TResult + Send + Sync + 'static, { - self.query(key, move |ctx, arg: LibraryArgs| 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| 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( + fn library_mutation( self, key: &'static str, - resolver: fn(Ctx, TArg, LibraryContext) -> TResult, + builder: fn(UnbuiltProcedureBuilder) -> BuiltProcedureBuilder, ) -> Self where TArg: DeserializeOwned + specta::Type + Send + 'static, TResult: Future> + Send + 'static, - T: IntoLayerResult + Send + Serialize + specta::Type, + T: RequestLayer + Serialize + specta::Type + Send, + TResolver: Fn(Ctx, TArg, LibraryContext) -> TResult + Send + Sync + 'static, { - self.mutation(key, move |ctx, arg: LibraryArgs| 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| 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( + fn library_subscription( self, key: &'static str, - resolver: fn(Ctx, TArg, Uuid) -> T, + builder: fn(UnbuiltProcedureBuilder) -> BuiltProcedureBuilder, ) -> Self where - TArg: DeserializeOwned + specta::Type + Send + 'static, - T: Stream + Send + 'static, + TArg: DeserializeOwned + specta::Type + 'static, + TStream: Stream + Sync + Send + 'static, TResult: Serialize + specta::Type, + TResolver: Fn(Ctx, TArg, Uuid) -> TStream + Send + Sync + 'static, { - self.subscription(key, move |ctx, arg: LibraryArgs| { - // 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| { + // 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) + }) }) } } diff --git a/core/src/api/volumes.rs b/core/src/api/volumes.rs index 6cd783056..f9a9724be 100644 --- a/core/src/api/volumes.rs +++ b/core/src/api/volumes.rs @@ -1,7 +1,7 @@ use crate::volume::get_volumes; -use super::{Router, RouterBuilder}; +use super::RouterBuilder; pub(crate) fn mount() -> RouterBuilder { - ::new().query("list", |_, _: ()| Ok(get_volumes()?)) + RouterBuilder::new().query("list", |t| t(|_, _: ()| Ok(get_volumes()?))) } diff --git a/core/src/lib.rs b/core/src/lib.rs index 3ab679658..11f4cf2f0 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -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(); diff --git a/crates/ffmpeg/Cargo.toml b/crates/ffmpeg/Cargo.toml index 216a7103b..b3b65d421 100644 --- a/crates/ffmpeg/Cargo.toml +++ b/crates/ffmpeg/Cargo.toml @@ -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"] } diff --git a/package.json b/package.json index ab0932e3d..0ba1d1873 100644 --- a/package.json +++ b/package.json @@ -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" diff --git a/packages/client/package.json b/packages/client/package.json index 4ed47610f..394c8eed2 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -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" diff --git a/packages/client/src/core.ts b/packages/client/src/core.ts index c3d16c9aa..d82997047 100644 --- a/packages/client/src/core.ts +++ b/packages/client/src/core.ts @@ -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], result: null } | - { key: ["getNode"], result: NodeState } | - { key: ["jobs.getHistory", LibraryArgs], result: Array } | - { key: ["jobs.getRunning", LibraryArgs], result: Array } | - { key: ["library.getStatistics", LibraryArgs], result: Statistics } | - { key: ["library.list"], result: Array } | - { key: ["locations.getById", LibraryArgs], result: Location | null } | - { key: ["locations.getExplorerData", LibraryArgs], result: ExplorerData } | - { key: ["locations.indexer_rules.get", LibraryArgs], result: IndexerRule } | - { key: ["locations.indexer_rules.list", LibraryArgs], result: Array } | - { key: ["locations.list", LibraryArgs], result: Array<{ id: number, pub_id: Array, 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], result: Tag | null } | - { key: ["tags.getExplorerData", LibraryArgs], result: ExplorerData } | - { key: ["tags.getForFile", LibraryArgs], result: Array } | - { key: ["tags.list", LibraryArgs], result: Array } | - { key: ["version"], result: string } | - { key: ["volumes.list"], result: Array }, + { key: "files.readMetadata", input: LibraryArgs, result: null } | + { key: "getNode", input: never, result: NodeState } | + { key: "jobs.getHistory", input: LibraryArgs, result: Array } | + { key: "jobs.getRunning", input: LibraryArgs, result: Array } | + { key: "library.getStatistics", input: LibraryArgs, result: Statistics } | + { key: "library.list", input: never, result: Array } | + { key: "locations.getById", input: LibraryArgs, result: Location | null } | + { key: "locations.getExplorerData", input: LibraryArgs, result: ExplorerData } | + { key: "locations.indexer_rules.get", input: LibraryArgs, result: IndexerRule } | + { key: "locations.indexer_rules.list", input: LibraryArgs, result: Array } | + { key: "locations.list", input: LibraryArgs, result: Array<{ id: number, pub_id: Array, 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, result: Tag | null } | + { key: "tags.getExplorerData", input: LibraryArgs, result: ExplorerData } | + { key: "tags.getForFile", input: LibraryArgs, result: Array } | + { key: "tags.list", input: LibraryArgs, result: Array } | + { key: "version", input: never, result: string } | + { key: "volumes.list", input: never, result: Array }, mutations: - { key: ["files.delete", LibraryArgs], result: null } | - { key: ["files.setFavorite", LibraryArgs], result: null } | - { key: ["files.setNote", LibraryArgs], result: null } | - { key: ["jobs.generateThumbsForLocation", LibraryArgs], result: null } | - { key: ["jobs.identifyUniqueFiles", LibraryArgs], result: null } | - { key: ["library.create", string], result: LibraryConfigWrapped } | - { key: ["library.delete", string], result: null } | - { key: ["library.edit", EditLibraryArgs], result: null } | - { key: ["locations.create", LibraryArgs], result: null } | - { key: ["locations.delete", LibraryArgs], result: null } | - { key: ["locations.fullRescan", LibraryArgs], result: null } | - { key: ["locations.indexer_rules.create", LibraryArgs], result: IndexerRule } | - { key: ["locations.indexer_rules.delete", LibraryArgs], result: null } | - { key: ["locations.quickRescan", LibraryArgs], result: null } | - { key: ["locations.update", LibraryArgs], result: null } | - { key: ["tags.assign", LibraryArgs], result: null } | - { key: ["tags.create", LibraryArgs], result: Tag } | - { key: ["tags.delete", LibraryArgs], result: null } | - { key: ["tags.update", LibraryArgs], result: null }, + { key: "files.delete", input: LibraryArgs, result: null } | + { key: "files.setFavorite", input: LibraryArgs, result: null } | + { key: "files.setNote", input: LibraryArgs, result: null } | + { key: "jobs.generateThumbsForLocation", input: LibraryArgs, result: null } | + { key: "jobs.identifyUniqueFiles", input: LibraryArgs, 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, result: null } | + { key: "locations.delete", input: LibraryArgs, result: null } | + { key: "locations.fullRescan", input: LibraryArgs, result: null } | + { key: "locations.indexer_rules.create", input: LibraryArgs, result: IndexerRule } | + { key: "locations.indexer_rules.delete", input: LibraryArgs, result: null } | + { key: "locations.quickRescan", input: LibraryArgs, result: null } | + { key: "locations.update", input: LibraryArgs, result: null } | + { key: "tags.assign", input: LibraryArgs, result: null } | + { key: "tags.create", input: LibraryArgs, result: Tag } | + { key: "tags.delete", input: LibraryArgs, result: null } | + { key: "tags.update", input: LibraryArgs, result: null }, subscriptions: - { key: ["invalidateQuery"], result: InvalidateOperationEvent } | - { key: ["jobs.newThumbnail", LibraryArgs], result: string } + { key: "invalidateQuery", input: never, result: InvalidateOperationEvent } | + { key: "jobs.newThumbnail", input: LibraryArgs, result: string } }; export interface ConfigMetadata { version: string | null } diff --git a/packages/client/src/hooks/useCurrentLibrary.tsx b/packages/client/src/hooks/useCurrentLibrary.tsx index 53cc877a3..d9d02e43f 100644 --- a/packages/client/src/hooks/useCurrentLibrary.tsx +++ b/packages/client/src/hooks/useCurrentLibrary.tsx @@ -22,6 +22,10 @@ export const LibraryContextProvider = ({ return {children}; }; +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; diff --git a/packages/client/src/rspc.ts b/packages/client/src/rspc.ts index fa2aff113..086363f16 100644 --- a/packages/client/src/rspc.ts +++ b/packages/client/src/rspc.ts @@ -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(); +export const rspc = createReactQueryHooks(); -type NonLibraryQueries = Exclude] }> & - Extract; -type NonLibraryQuery = Extract; -type NonLibraryQueryKey = NonLibraryQueries['key'][0]; -type NonLibraryQueryResult = NonLibraryQuery['result']; +type NonLibraryProcedure = + | Exclude }> + | Extract; -export function useBridgeQuery( - key: K, - options?: UseQueryOptions, RSPCError> -): UseQueryResult, RSPCError> { - // @ts-ignore - return rspc.useQuery(key, options); -} - -type LibraryQueries = Extract] }>; -type LibraryQuery = Extract; -type LibraryQueryKey = LibraryQueries['key'][0]; -type LibraryQueryArgs = LibraryQuery['key'][1] extends LibraryArgs - ? A - : never; -type LibraryQueryResult = LibraryQuery['result']; - -export function useLibraryQuery( - key: LibraryQueryArgs extends null | undefined ? [K] : [K, LibraryQueryArgs], - options?: UseQueryOptions, RSPCError> -): UseQueryResult, 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( - key: LibraryQueryArgs extends null | undefined ? [K] : [K, LibraryQueryArgs], - options?: UseInfiniteQueryOptions, RSPCError> -): UseInfiniteQueryResult, 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] }>; -type LibraryMutation = Extract; -type LibraryMutationKey = LibraryMutations['key'][0]; -type LibraryMutationArgs = - LibraryMutation['key'][1] extends LibraryArgs ? A : never; -type LibraryMutationResult = LibraryMutation['result']; -export function useLibraryMutation( - key: K, - options?: UseMutationOptions, 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, RSPCError, LibraryMutationArgs>( - async (data) => - ctx.client.mutation([key, { library_id: library?.uuid || '', arg: data || null }]), - { - ...options, - context: rspc.ReactQueryContext - } - ); -} - -type NonLibraryMutations = Exclude] }>; -type NonLibraryMutation = Extract< - NonLibraryMutations, - { key: [K] | [K, any] } +type LibraryProcedures = Exclude< + Extract }>, + { input: never } >; -type NonLibraryMutationKey = NonLibraryMutations['key'][0]; -type NonLibraryMutationArgs = NonLibraryMutation['key'][1]; -type NonLibraryMutationResult = NonLibraryMutation['result']; -export function useBridgeMutation( - key: K, - options?: UseMutationOptions, RSPCError> -): UseMutationResult, RSPCError, NonLibraryMutationArgs> { - // @ts-ignore - return rspc.useMutation(key, options); -} + +type MoreConstrainedQueries = T extends any + ? T['input'] extends LibraryArgs + ? { + key: T['key']; + input: E; + result: T['result']; + } + : never + : never; + +export const useBridgeQuery = rspc.customQuery>( + (keyAndInput) => keyAndInput as any +); + +export const useBridgeMutation = rspc.customMutation>( + (keyAndInput) => keyAndInput +); + +export const useLibraryQuery = rspc.customQuery< + MoreConstrainedQueries> +>((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> +>((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); } diff --git a/packages/config/base.tsconfig.json b/packages/config/base.tsconfig.json index 192c236c5..819f5cfbd 100644 --- a/packages/config/base.tsconfig.json +++ b/packages/config/base.tsconfig.json @@ -15,7 +15,7 @@ "noUnusedLocals": false, "noUnusedParameters": false, "preserveWatchOutput": true, - "skipLibCheck": false, + "skipLibCheck": true, "strict": true, "allowSyntheticDefaultImports": true, "resolveJsonModule": true, diff --git a/packages/config/package.json b/packages/config/package.json index 6d9f656ba..f997cf726 100644 --- a/packages/config/package.json +++ b/packages/config/package.json @@ -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" } } diff --git a/packages/interface/package.json b/packages/interface/package.json index d875a80df..370e734a2 100644 --- a/packages/interface/package.json +++ b/packages/interface/package.json @@ -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" } } diff --git a/packages/interface/src/components/explorer/Explorer.tsx b/packages/interface/src/components/explorer/Explorer.tsx index 7dcf6911f..df170d5df 100644 --- a/packages/interface/src/components/explorer/Explorer.tsx +++ b/packages/interface/src/components/explorer/Explorer.tsx @@ -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); } }); diff --git a/packages/interface/src/components/explorer/VirtualizedList.tsx b/packages/interface/src/components/explorer/VirtualizedList.tsx index d668bffb2..3e6b11fe6 100644 --- a/packages/interface/src/components/explorer/VirtualizedList.tsx +++ b/packages/interface/src/components/explorer/VirtualizedList.tsx @@ -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'; diff --git a/packages/ui/package.json b/packages/ui/package.json index 2241e948b..bed169404 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -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" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0c3ead9898d261d0f003b3b715f7082c53c6875f..4ceeb59e000e2d3b03cca273fae98ebc9d8ab632 100644 GIT binary patch delta 30578 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 Date: Sun, 2 Oct 2022 01:37:35 +0800 Subject: [PATCH 02/11] bundle splitting and performance optimisations --- .gitignore | 2 +- apps/mobile/package.json | 2 +- apps/mobile/pnpm-lock.yaml | Bin 329592 -> 329395 bytes apps/mobile/rust/src/lib.rs | 5 +- .../src/components/modals/FileModal.tsx | 6 +- apps/mobile/src/screens/Overview.tsx | 265 ++++++++++++++---- apps/web/package.json | 2 + apps/web/vite.config.ts | 15 +- packages/interface/package.json | 3 +- packages/interface/src/App.tsx | 8 + packages/interface/src/AppLayout.tsx | 5 +- packages/interface/src/AppRouter.tsx | 169 +++++------ packages/interface/src/NotFound.tsx | 2 +- .../src/components/explorer/FileThumb.tsx | 71 ++--- .../src/components/explorer/Inspector.tsx | 33 +-- .../components/explorer/inspector/Note.tsx | 2 +- .../src/components/jobs/JobManager.tsx | 6 +- packages/interface/src/screens/Content.tsx | 4 +- packages/interface/src/screens/Debug.tsx | 4 +- .../src/screens/LocationExplorer.tsx | 4 +- packages/interface/src/screens/Overview.tsx | 4 +- packages/interface/src/screens/Photos.tsx | 4 +- .../interface/src/screens/TagExplorer.tsx | 4 +- .../src/screens/settings/Settings.tsx | 4 +- pnpm-lock.yaml | Bin 671681 -> 674399 bytes 25 files changed, 405 insertions(+), 219 deletions(-) diff --git a/.gitignore b/.gitignore index 73aded57f..c9c309319 100644 --- a/.gitignore +++ b/.gitignore @@ -65,4 +65,4 @@ examples/*/*.lock /core/src/prisma.rs /sdserver_data -.spacedrive +.spacedrive \ No newline at end of file diff --git a/apps/mobile/package.json b/apps/mobile/package.json index 49b065fb3..97ae939b7 100644 --- a/apps/mobile/package.json +++ b/apps/mobile/package.json @@ -23,7 +23,7 @@ "@tanstack/react-query": "^4.2.3", "byte-size": "^8.1.0", "class-variance-authority": "^0.2.3", - "date-fns": "^2.29.2", + "dayjs": "^1.11.5", "expo": "~46.0.10", "expo-linking": "~3.2.2", "expo-splash-screen": "~0.16.2", diff --git a/apps/mobile/pnpm-lock.yaml b/apps/mobile/pnpm-lock.yaml index c2a24bf98284818b212273f2ce5937ce8e1882d8..fd4ed81a51eee68b033ab7ce1b5583d708c68d07 100644 GIT binary patch delta 185 zcmey-C$hO$WW#D^p31CZD}^{iJwro1)6Kh>r?GK^MIZvxFRo92suxo}5#eZyHumn4MmbWsw$~;uDx0R9cl5VV3J` z7LZYCkeB9Vkm?@kpBikQYm!@HRFLBm?&DbEXcAHwl9*kVl$7sL7Fv;(YLe;Lp6|o7 cJ>Q4 = Lazy::new(|| Runtime::new().unwrap()); +type NodeType = Lazy, Arc)>>>; + #[allow(dead_code)] -pub(crate) static NODE: Lazy, Arc)>>> = - Lazy::new(|| Mutex::new(None)); +pub(crate) static NODE: NodeType = Lazy::new(|| Mutex::new(None)); #[allow(dead_code)] pub(crate) static SUBSCRIPTIONS: Lazy>>> = diff --git a/apps/mobile/src/components/modals/FileModal.tsx b/apps/mobile/src/components/modals/FileModal.tsx index f46017c73..35d4434d0 100644 --- a/apps/mobile/src/components/modals/FileModal.tsx +++ b/apps/mobile/src/components/modals/FileModal.tsx @@ -1,5 +1,5 @@ import { BottomSheetModal, BottomSheetScrollView } from '@gorhom/bottom-sheet'; -import { format } from 'date-fns'; +import dayjs from 'dayjs'; import React, { useRef } from 'react'; import { Button, Pressable, Text, View } from 'react-native'; import { ChevronLeftIcon } from 'react-native-heroicons/outline'; @@ -98,12 +98,12 @@ export const FileModal = () => { diff --git a/apps/mobile/src/screens/Overview.tsx b/apps/mobile/src/screens/Overview.tsx index 05666fe54..fffec0059 100644 --- a/apps/mobile/src/screens/Overview.tsx +++ b/apps/mobile/src/screens/Overview.tsx @@ -1,65 +1,214 @@ -import React from 'react'; -import { FlatList, View } from 'react-native'; -import Device from '~/components/device/Device'; -import VirtualizedListWrapper from '~/components/layout/VirtualizedListWrapper'; -import OverviewStats from '~/containers/OverviewStats'; -import tw from '~/lib/tailwind'; -import { OverviewStackScreenProps } from '~/navigation/tabs/OverviewStack'; +import { ExclamationCircleIcon, PlusIcon } from '@heroicons/react/24/solid'; +import { useBridgeQuery, useLibraryQuery, usePlatform } from '@sd/client'; +import { Statistics } from '@sd/client'; +import { Button, Input } from '@sd/ui'; +import byteSize from 'byte-size'; +import clsx from 'clsx'; +import { useEffect } from 'react'; +import Skeleton from 'react-loading-skeleton'; +import 'react-loading-skeleton/dist/skeleton.css'; +import create from 'zustand'; -const placeholderOverviewStats = { - id: 1, - total_bytes_capacity: '8093333345230', - preview_media_bytes: '2304387532', - library_db_size: '83345230', - total_file_count: 20342345, - total_bytes_free: '89734502034', - total_bytes_used: '8093333345230', - total_unique_bytes: '9347397', - date_captured: '2020-01-01' +import { Device } from '../components/device/Device'; +import Dialog from '../components/layout/Dialog'; +import useCounter from '../hooks/useCounter'; + +interface StatItemProps { + title: string; + bytes: string; + isLoading: boolean; +} + +const StatItemNames: Partial> = { + total_bytes_capacity: 'Total capacity', + preview_media_bytes: 'Preview media', + library_db_size: 'Index size', + total_bytes_free: 'Free space' }; -const placeholderDevices: any = [ - { - name: "James' iPhone 12", - size: '47.9GB', - locations: [], - type: 'phone' - }, - { - name: "James' MacBook Pro", - size: '1TB', - locations: [], - type: 'laptop' - }, - { - name: "James' Toaster", - size: '1PB', - locations: [], - type: 'desktop' - }, - { - name: 'Spacedrive Server', - size: '5GB', - locations: [], - type: 'server' - } -]; +type OverviewStats = Partial>; +type OverviewState = { + overviewStats: OverviewStats; + setOverviewStat: (name: keyof OverviewStats, newValue: string) => void; + setOverviewStats: (stats: OverviewStats) => void; +}; + +export const useOverviewState = create((set) => ({ + overviewStats: {}, + setOverviewStat: (name, newValue) => + set((state) => ({ + ...state, + overviewStats: { + ...state.overviewStats, + [name]: newValue + } + })), + setOverviewStats: (stats) => + set((state) => ({ + ...state, + overviewStats: stats + })) +})); + +const StatItem: React.FC = (props) => { + const { title, bytes = '0', isLoading } = props; + + // const appProps = useContext(AppPropsContext); + + const size = byteSize(+bytes); + + const count = useCounter({ + name: title, + end: +size.value + }); -export default function OverviewScreen({ navigation }: OverviewStackScreenProps<'Overview'>) { return ( - - - {/* Stats */} - - {/* Devices */} - index.toString()} - renderItem={({ item }) => ( - - )} - /> - - +

+ {title} + + {isLoading && ( +
+ +
+ )} +
+ {count} + {size.unit} +
+
+
+ ); +}; + +export default function OverviewScreen() { + const platform = usePlatform(); + const { data: libraryStatistics, isLoading: isStatisticsLoading } = useLibraryQuery([ + 'library.getStatistics' + ]); + const { data: nodeState } = useBridgeQuery(['getNode']); + + const { overviewStats, setOverviewStats } = useOverviewState(); + + // get app props from context + useEffect(() => { + if (platform.demoMode === true) { + if (!Object.entries(overviewStats).length) + setOverviewStats({ + total_bytes_capacity: '8093333345230', + preview_media_bytes: '2304387532', + library_db_size: '83345230', + total_file_count: '20342345', + total_bytes_free: '89734502034', + total_bytes_used: '8093333345230', + total_unique_bytes: '9347397' + }); + } else { + const newStatistics: OverviewStats = { + total_bytes_capacity: '0', + preview_media_bytes: '0', + library_db_size: '0', + total_file_count: '0', + total_bytes_free: '0', + total_bytes_used: '0', + total_unique_bytes: '0' + }; + + Object.entries((libraryStatistics as Statistics) || {}).forEach(([key, value]) => { + newStatistics[key as keyof Statistics] = `${value}`; + }); + + setOverviewStats(newStatistics); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [platform, libraryStatistics]); + + // useEffect(() => { + // setTimeout(() => { + // setOverviewStat('total_bytes_capacity', '4093333345230'); + // }, 2000); + // }, [overviewStats]); + + const displayableStatItems = Object.keys(StatItemNames) as unknown as keyof typeof StatItemNames; + + return ( +
+
+ {/* PAGE */} +
+ {/* STAT HEADER */} +
+ {/* STAT CONTAINER */} +
+ {Object.entries(overviewStats).map(([key, value]) => { + if (!displayableStatItems.includes(key)) return null; + + return ( + + ); + })} +
+ +
+
+
+ {}} + ctaLabel="Connect" + trigger={ + + } + > +
+
+ + This Device + + +
+
+ + Enter a device code + + +
+
+
+
+
+
+
+ + + +
+
+ Note: This is a pre-alpha build of Spacedrive, many features are yet to be + functional. +
+
+
+
); } diff --git a/apps/web/package.json b/apps/web/package.json index df365b134..44d4e572a 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -23,9 +23,11 @@ "@vitejs/plugin-react": "^2.1.0", "autoprefixer": "^10.4.12", "postcss": "^8.4.17", + "rollup-plugin-visualizer": "^5.8.2", "tailwind": "^4.0.0", "typescript": "^4.8.4", "vite": "^3.1.4", + "vite-plugin-html": "^3.2.0", "vite-plugin-svgr": "^2.2.1", "vite-plugin-tsconfig-paths": "^1.2.0" } diff --git a/apps/web/vite.config.ts b/apps/web/vite.config.ts index b22575e2e..affc565fe 100644 --- a/apps/web/vite.config.ts +++ b/apps/web/vite.config.ts @@ -1,5 +1,7 @@ import react from '@vitejs/plugin-react'; +import { visualizer } from 'rollup-plugin-visualizer'; import { defineConfig } from 'vite'; +import { createHtmlPlugin } from 'vite-plugin-html'; import svg from 'vite-plugin-svgr'; import tsconfigPaths from 'vite-plugin-tsconfig-paths'; @@ -10,7 +12,18 @@ export default defineConfig({ server: { port: 8002 }, - plugins: [react(), svg({ svgrOptions: { icon: true } }), tsconfigPaths()], + plugins: [ + react(), + svg({ svgrOptions: { icon: true } }), + tsconfigPaths(), + createHtmlPlugin({ + minify: true + }), + visualizer({ + gzipSize: true, + brotliSize: true + }) + ], root: 'src', publicDir: '../../packages/interface/src/assets', define: { diff --git a/packages/interface/package.json b/packages/interface/package.json index 370e734a2..df37ad985 100644 --- a/packages/interface/package.json +++ b/packages/interface/package.json @@ -37,11 +37,10 @@ "autoprefixer": "^10.4.12", "byte-size": "^8.1.0", "clsx": "^1.2.1", - "date-fns": "^2.29.3", + "dayjs": "^1.11.5", "immer": "^9.0.15", "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", diff --git a/packages/interface/src/App.tsx b/packages/interface/src/App.tsx index 07a4dedff..84e3fd591 100644 --- a/packages/interface/src/App.tsx +++ b/packages/interface/src/App.tsx @@ -2,6 +2,10 @@ import '@fontsource/inter/variable.css'; import { LibraryContextProvider, queryClient } from '@sd/client'; import { QueryClientProvider, defaultContext } from '@tanstack/react-query'; import { ReactQueryDevtools } from '@tanstack/react-query-devtools'; +import dayjs from 'dayjs'; +import advancedFormat from 'dayjs/plugin/advancedFormat'; +import duration from 'dayjs/plugin/duration'; +import relativeTime from 'dayjs/plugin/relativeTime'; import { ErrorBoundary } from 'react-error-boundary'; import { MemoryRouter, useNavigate } from 'react-router-dom'; @@ -9,6 +13,10 @@ import { AppRouter } from './AppRouter'; import { ErrorFallback } from './ErrorFallback'; import './style.scss'; +dayjs.extend(advancedFormat); +dayjs.extend(relativeTime); +dayjs.extend(duration); + export default function SpacedriveInterface() { return ( diff --git a/packages/interface/src/AppLayout.tsx b/packages/interface/src/AppLayout.tsx index 14a9ab835..263173dae 100644 --- a/packages/interface/src/AppLayout.tsx +++ b/packages/interface/src/AppLayout.tsx @@ -1,5 +1,6 @@ import { useCurrentLibrary } from '@sd/client'; import clsx from 'clsx'; +import { Suspense } from 'react'; import { Outlet } from 'react-router-dom'; import { Sidebar } from './components/layout/Sidebar'; @@ -29,7 +30,9 @@ export function AppLayout() { >
- + Loading...

}> + +
); diff --git a/packages/interface/src/AppRouter.tsx b/packages/interface/src/AppRouter.tsx index 363be4cfb..0ec119793 100644 --- a/packages/interface/src/AppRouter.tsx +++ b/packages/interface/src/AppRouter.tsx @@ -1,38 +1,43 @@ import { useCurrentLibrary, useInvalidateQuery } from '@sd/client'; +import { Suspense, lazy } from 'react'; import { Route, Routes } from 'react-router-dom'; import { AppLayout } from './AppLayout'; -import { NotFound } from './NotFound'; -import OnboardingScreen from './components/onboarding/Onboarding'; import { useKeybindHandler } from './hooks/useKeyboardHandler'; -import { ContentScreen } from './screens/Content'; -import { DebugScreen } from './screens/Debug'; -import { LocationExplorer } from './screens/LocationExplorer'; -import { OverviewScreen } from './screens/Overview'; -import { PhotosScreen } from './screens/Photos'; import { RedirectPage } from './screens/Redirect'; -import { TagExplorer } from './screens/TagExplorer'; -import { SettingsScreen } from './screens/settings/Settings'; -import AppearanceSettings from './screens/settings/client/AppearanceSettings'; -import ExtensionSettings from './screens/settings/client/ExtensionsSettings'; -import GeneralSettings from './screens/settings/client/GeneralSettings'; -import KeybindingSettings from './screens/settings/client/KeybindingSettings'; -import PrivacySettings from './screens/settings/client/PrivacySettings'; -import AboutSpacedrive from './screens/settings/info/AboutSpacedrive'; -import Changelog from './screens/settings/info/Changelog'; -import Support from './screens/settings/info/Support'; -import ContactsSettings from './screens/settings/library/ContactsSettings'; -import KeysSettings from './screens/settings/library/KeysSetting'; -import LibraryGeneralSettings from './screens/settings/library/LibraryGeneralSettings'; -import LocationSettings from './screens/settings/library/LocationSettings'; -import NodesSettings from './screens/settings/library/NodesSettings'; -import SecuritySettings from './screens/settings/library/SecuritySettings'; -import SharingSettings from './screens/settings/library/SharingSettings'; -import SyncSettings from './screens/settings/library/SyncSettings'; -import TagsSettings from './screens/settings/library/TagsSettings'; -import ExperimentalSettings from './screens/settings/node/ExperimentalSettings'; -import LibrarySettings from './screens/settings/node/LibrariesSettings'; -import P2PSettings from './screens/settings/node/P2PSettings'; + +const DebugScreen = lazy(() => import('./screens/Debug')); +const SettingsScreen = lazy(() => import('./screens/settings/Settings')); +const TagExplorer = lazy(() => import('./screens/TagExplorer')); +const PhotosScreen = lazy(() => import('./screens/Photos')); +const OverviewScreen = lazy(() => import('./screens/Overview')); +const ContentScreen = lazy(() => import('./screens/Content')); +const LocationExplorer = lazy(() => import('./screens/LocationExplorer')); +const OnboardingScreen = lazy(() => import('./components/onboarding/Onboarding')); +const NotFound = lazy(() => import('./NotFound')); + +const AppearanceSettings = lazy(() => import('./screens/settings/client/AppearanceSettings')); +const ExtensionSettings = lazy(() => import('./screens/settings/client/ExtensionsSettings')); +const GeneralSettings = lazy(() => import('./screens/settings/client/GeneralSettings')); +const KeybindingSettings = lazy(() => import('./screens/settings/client/KeybindingSettings')); +const PrivacySettings = lazy(() => import('./screens/settings/client/PrivacySettings')); +const AboutSpacedrive = lazy(() => import('./screens/settings/info/AboutSpacedrive')); +const Changelog = lazy(() => import('./screens/settings/info/Changelog')); +const Support = lazy(() => import('./screens/settings/info/Support')); +const ContactsSettings = lazy(() => import('./screens/settings/library/ContactsSettings')); +const KeysSettings = lazy(() => import('./screens/settings/library/KeysSetting')); +const LibraryGeneralSettings = lazy( + () => import('./screens/settings/library/LibraryGeneralSettings') +); +const LocationSettings = lazy(() => import('./screens/settings/library/LocationSettings')); +const NodesSettings = lazy(() => import('./screens/settings/library/NodesSettings')); +const SecuritySettings = lazy(() => import('./screens/settings/library/SecuritySettings')); +const SharingSettings = lazy(() => import('./screens/settings/library/SharingSettings')); +const SyncSettings = lazy(() => import('./screens/settings/library/SyncSettings')); +const TagsSettings = lazy(() => import('./screens/settings/library/TagsSettings')); +const ExperimentalSettings = lazy(() => import('./screens/settings/node/ExperimentalSettings')); +const LibrarySettings = lazy(() => import('./screens/settings/node/LibrariesSettings')); +const P2PSettings = lazy(() => import('./screens/settings/node/P2PSettings')); export function AppRouter() { const { library } = useCurrentLibrary(); @@ -41,56 +46,60 @@ export function AppRouter() { useInvalidateQuery(); return ( - - } /> - }> - {/* As we are caching the libraries in localStore so this *shouldn't* result is visual problems unless something else is wrong */} - {library === undefined ? ( - Please select or create a library in the sidebar. - } - /> - ) : ( - <> - } /> - } /> - } /> - } /> - } /> - }> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - - } /> - } /> - } /> - - )} - - + Loading...

}> + + } /> + }> + {/* As we are caching the libraries in localStore so this *shouldn't* result is visual problems unless something else is wrong */} + {library === undefined ? ( + + Please select or create a library in the sidebar. + + } + /> + ) : ( + <> + } /> + } /> + } /> + } /> + } /> + }> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + + } /> + } /> + } /> + + )} + + +
); } diff --git a/packages/interface/src/NotFound.tsx b/packages/interface/src/NotFound.tsx index aeec54c35..ad732dac1 100644 --- a/packages/interface/src/NotFound.tsx +++ b/packages/interface/src/NotFound.tsx @@ -1,7 +1,7 @@ import { Button } from '@sd/ui'; import { useNavigate } from 'react-router'; -export function NotFound() { +export default function NotFound() { const navigate = useNavigate(); return (
; + const Icon = useMemo(() => { + const icon = icons[`../../../../assets/icons/${data.extension as any}.svg`]; + const Icon = icon + ? lazy(() => icon().then((v) => ({ default: (v as any).ReactComponent }))) + : undefined; + return Icon; + }, [data.extension]); + + if (isPath(data) && data.is_dir) return ; const cas_id = isObject(data) ? data.cas_id : data.file?.cas_id; - if (cas_id) { - // this won't work - const new_thumbnail = !!getExplorerStore().newThumbnails[cas_id]; + if (!cas_id) return
; - const has_thumbnail = isObject(data) - ? data.has_thumbnail - : isPath(data) - ? data.file?.has_thumbnail - : new_thumbnail; + const has_thumbnail = isObject(data) + ? data.has_thumbnail + : isPath(data) + ? data.file?.has_thumbnail + : !!store.newThumbnails[cas_id]; - const url = platform.getThumbnailUrlById(cas_id); - - if (has_thumbnail && url) - return ( - - ); - } - - const Icon = icons[data.extension as keyof typeof icons]; + if (has_thumbnail) + return ( + + ); return (
{Icon && (
- + }> + + {data.extension} diff --git a/packages/interface/src/components/explorer/Inspector.tsx b/packages/interface/src/components/explorer/Inspector.tsx index fec89f030..106ae6bd5 100644 --- a/packages/interface/src/components/explorer/Inspector.tsx +++ b/packages/interface/src/components/explorer/Inspector.tsx @@ -1,13 +1,14 @@ import { ShareIcon } from '@heroicons/react/24/solid'; import { useLibraryQuery } from '@sd/client'; -import { ExplorerContext, ExplorerItem, File, FilePath, Location } from '@sd/client'; -import { Button, TextArea } from '@sd/ui'; +import { ExplorerContext, ExplorerItem } from '@sd/client'; +import { Button } from '@sd/ui'; +import { useQuery } from '@tanstack/react-query'; import clsx from 'clsx'; -import moment from 'moment'; +import dayjs from 'dayjs'; import { Link } from 'phosphor-react'; import { useEffect, useState } from 'react'; -import types from '../../constants/file-types.json'; +// import types from '../../constants/file-types.json'; import { Tooltip } from '../tooltip/Tooltip'; import FileThumb from './FileThumb'; import { Divider } from './inspector/Divider'; @@ -22,6 +23,11 @@ interface Props { } export const Inspector = (props: Props) => { + const { data: types } = useQuery( + ['_file-types'], + () => import('../../constants/file-types.json') + ); + const is_dir = props.data?.type === 'Path' ? props.data.is_dir : false; const objectData = isObject(props.data) ? props.data : props.data.file; @@ -41,18 +47,13 @@ export const Inspector = (props: Props) => { }); return ( -
+
{!!props.data && ( <> -
- +
+
-
+

{props.data?.name} {props.data?.extension && `.${props.data.extension}`} @@ -111,12 +112,12 @@ export const Inspector = (props: Props) => { {!is_dir && ( <> @@ -128,7 +129,7 @@ export const Inspector = (props: Props) => { )}

- {props.data?.extension + {props.data?.extension && types !== undefined ? //@ts-ignore types[props.data.extension.toUpperCase()]?.descriptions.join(' / ') : 'Unknown'} diff --git a/packages/interface/src/components/explorer/inspector/Note.tsx b/packages/interface/src/components/explorer/inspector/Note.tsx index 500cafe79..5be79dc0c 100644 --- a/packages/interface/src/components/explorer/inspector/Note.tsx +++ b/packages/interface/src/components/explorer/inspector/Note.tsx @@ -2,7 +2,7 @@ import { useLibraryMutation } from '@sd/client'; import { File } from '@sd/client'; import { TextArea } from '@sd/ui'; -import { debounce } from 'lodash'; +import debounce from 'lodash/debounce'; import { useCallback, useState } from 'react'; import { Divider } from './Divider'; diff --git a/packages/interface/src/components/jobs/JobManager.tsx b/packages/interface/src/components/jobs/JobManager.tsx index 70d4a8349..8da2c5037 100644 --- a/packages/interface/src/components/jobs/JobManager.tsx +++ b/packages/interface/src/components/jobs/JobManager.tsx @@ -3,7 +3,7 @@ import { useLibraryQuery } from '@sd/client'; import { JobReport } from '@sd/client'; import { Button } from '@sd/ui'; import clsx from 'clsx'; -import { formatDistanceToNow, formatDuration } from 'date-fns'; +import dayjs from 'dayjs'; import { ArrowsClockwise } from 'phosphor-react'; import { Tooltip } from '../tooltip/Tooltip'; @@ -70,12 +70,12 @@ export function JobsManager() { {job.status === 'Failed' ? 'Failed after' : 'Took'}{' '} {job.seconds_elapsed - ? formatDuration({ seconds: job.seconds_elapsed }) + ? dayjs.duration({ seconds: job.seconds_elapsed }).humanize() : 'less than a second'} - {formatDistanceToNow(new Date(job.date_created))} ago + {dayjs(job.date_created).toNow(true)} ago

{job.data} diff --git a/packages/interface/src/screens/Content.tsx b/packages/interface/src/screens/Content.tsx index 47c83eb78..c1722ca4b 100644 --- a/packages/interface/src/screens/Content.tsx +++ b/packages/interface/src/screens/Content.tsx @@ -1,4 +1,4 @@ -export const ContentScreen: React.FC = (props) => { +export default function ContentScreen() { // const [address, setAddress] = React.useState(''); return
; -}; +} diff --git a/packages/interface/src/screens/Debug.tsx b/packages/interface/src/screens/Debug.tsx index 15a9aea69..cb1c33dea 100644 --- a/packages/interface/src/screens/Debug.tsx +++ b/packages/interface/src/screens/Debug.tsx @@ -3,7 +3,7 @@ import { useBridgeQuery, useLibraryMutation, useLibraryQuery, usePlatform } from import CodeBlock from '../components/primitive/Codeblock'; // TODO: Bring this back with a button in the sidebar near settings at the bottom -export const DebugScreen: React.FC = (props) => { +export default function DebugScreen() { const platform = usePlatform(); const { data: nodeState } = useBridgeQuery(['getNode']); const { data: libraryState } = useBridgeQuery(['library.list']); @@ -45,4 +45,4 @@ export const DebugScreen: React.FC = (props) => {
); -}; +} diff --git a/packages/interface/src/screens/LocationExplorer.tsx b/packages/interface/src/screens/LocationExplorer.tsx index a6751bfdc..78ff04ba2 100644 --- a/packages/interface/src/screens/LocationExplorer.tsx +++ b/packages/interface/src/screens/LocationExplorer.tsx @@ -16,7 +16,7 @@ export function useExplorerParams() { return { location_id, path, limit }; } -export const LocationExplorer: React.FC = () => { +export default function LocationExplorer() { const { location_id, path } = useExplorerParams(); const { library } = useCurrentLibrary(); @@ -39,4 +39,4 @@ export const LocationExplorer: React.FC = () => { {library!.uuid && explorerData.data && }
); -}; +} diff --git a/packages/interface/src/screens/Overview.tsx b/packages/interface/src/screens/Overview.tsx index 45d53ce23..2fa7bc601 100644 --- a/packages/interface/src/screens/Overview.tsx +++ b/packages/interface/src/screens/Overview.tsx @@ -89,7 +89,7 @@ const StatItem: React.FC = (props) => { ); }; -export const OverviewScreen = () => { +export default function OverviewScreen() { const platform = usePlatform(); const { data: libraryStatistics, isLoading: isStatisticsLoading } = useLibraryQuery([ 'library.getStatistics' @@ -211,4 +211,4 @@ export const OverviewScreen = () => {
); -}; +} diff --git a/packages/interface/src/screens/Photos.tsx b/packages/interface/src/screens/Photos.tsx index 17acd70b6..264677b64 100644 --- a/packages/interface/src/screens/Photos.tsx +++ b/packages/interface/src/screens/Photos.tsx @@ -1,4 +1,4 @@ -export const PhotosScreen: React.FC = (props) => { +export default function PhotosScreen() { return (
@@ -9,4 +9,4 @@ export const PhotosScreen: React.FC = (props) => {
); -}; +} diff --git a/packages/interface/src/screens/TagExplorer.tsx b/packages/interface/src/screens/TagExplorer.tsx index 134750d8d..0684dea8a 100644 --- a/packages/interface/src/screens/TagExplorer.tsx +++ b/packages/interface/src/screens/TagExplorer.tsx @@ -3,7 +3,7 @@ import { useParams } from 'react-router-dom'; import Explorer from '../components/explorer/Explorer'; -export const TagExplorer: React.FC = () => { +export default function TagExplorer() { const { id } = useParams(); const { library } = useCurrentLibrary(); @@ -16,4 +16,4 @@ export const TagExplorer: React.FC = () => { )}
); -}; +} diff --git a/packages/interface/src/screens/settings/Settings.tsx b/packages/interface/src/screens/settings/Settings.tsx index 34a095ffa..535338c30 100644 --- a/packages/interface/src/screens/settings/Settings.tsx +++ b/packages/interface/src/screens/settings/Settings.tsx @@ -17,7 +17,7 @@ import { SettingsScreenContainer } from '../../components/settings/SettingsScreenContainer'; -export const SettingsScreen: React.FC = () => { +export default function SettingsScreen() { return ( Client @@ -100,4 +100,4 @@ export const SettingsScreen: React.FC = () => { ); -}; +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4ceeb59e000e2d3b03cca273fae98ebc9d8ab632..ec41ecff1e6a81a924de5923c99a7b7ab537d30b 100644 GIT binary patch delta 1881 zcmZ`)Ta4pY8CGVJnPg{n+PyHd?XnfRW|KudF(#IbX8630nYP#s?rJGPTJ z8QWai3dE`}NJ}amgg}Mzf`HPkRuCkfS|K3;673r=6nI03RxCoiPywFZ6(A&z^uL_{ zJLfBePh!b zPJN4tI<>ES2iX0zV((*=e7e6w7qNfGtKt zYj{gkv*U^hd0tLXYp#glis$E>3CgqCzUuOQ-Oif|iP>m*)*xg)&%#Wa2e;YK&eHyB z_}dqDO<8mfwZYV}Cf=c74-OT zk7h&XW0DYX1P2rW_7|b+tz1UxkSyNi@uFyW7TLDPx@r$oN>eJcVq@kjox~`YsB0c# zDl{S&yEVC)91$Z2vyD7o&NvyOHEs#|yx+H|Ip-=e0iO9{^s(iy-Vf(e;Ir2vQ80Nv zdXsA&PimF9DkDA4<0UeSR67;c$m>-oHGwFt%}rgkR!f$wdcG#*8+nW#9=mom;o*!~ zXe1KDDP1{fny5W44dxn0PDFZ81@G{YtKe<;%vMaY9NC=1Xac-O9b5_DNRAba?LRPDI3~v7}2=?69 zBjLs0y{plopvy;lC<0y|hIf|xaHR24*a&(Uyz$p{h&w^W6?0l?qnX)R4*eUA* z;nlUP;E|Ws&w;&S_#$}wH<1W<L zpL}C=Ygv45{d@he;Ak>nACE%Zv^8*A^{#1RxI8U1@P;w&W_gnk36d|$WpT>*?0~a7 zbjDLeUbl?7(Y4#DLfJ~vgQ>=(iG;><>agj|uvlk~gYpEUee2#^>w!g=_uh)V zaWi_FG#tn^_`!QIjKkXHoSYv}qc)r!kECbYwrBh^wa?}%wf)i7evfyqz;gxELty=eJxL)*}K0)%lyB3drD#=j{FCCDvPJ*Q8JD{+oF|p}3bD4OiZ$>j6u;?3~}?ePYTK+FWh%-iD)SjscDm(OHbD7?LW9m@`@C&T{k6 zFY_#RG;sAZFi1`>vY4K5j$LBAeh~XVk?njL?8}nc15UF8F~|0R)0`W$wmbabln(*` D$E|ak From adc1f4f46e1bdee563a7bfa6ac81f73bd9bf07dc Mon Sep 17 00:00:00 2001 From: Brendan Allan Date: Wed, 5 Oct 2022 10:20:04 +0800 Subject: [PATCH 03/11] update lockfile --- Cargo.lock | Bin 152530 -> 152524 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9aaa961ef54a830bd140ddf97e7f35507e01d63c..f74ac67ee6c5788b0bd21a8a527ff7f2fe5b076e 100644 GIT binary patch delta 27 lcmV+$0ObGDrwPob34pW#pOBa3vjG;Dtabqlx5khG48yk&3`+n2 delta 24 gcmX@Job%Fh&W0_F^Cz$=80Z=3nQosyfl>D`0DUJ3Q2+n{ From f933bbe9fe69847bd2f3bda59b688b267da20486 Mon Sep 17 00:00:00 2001 From: Brendan Allan Date: Wed, 5 Oct 2022 11:32:25 +0800 Subject: [PATCH 04/11] update pcr --- Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index dca96c59c..04d5bbc69 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,13 +10,13 @@ members = [ resolver = "2" [workspace.dependencies] -prisma-client-rust = { git = "https://github.com/Brendonovich/prisma-client-rust.git", rev = "f5d4a952d8e8bc799a0006dc5f375a22fd64ac27", features = [ +prisma-client-rust = { git = "https://github.com/Brendonovich/prisma-client-rust.git", rev = "4ea7b785ec9539d80e29c9b90ebc2010ea3a390e", features = [ "rspc", "sqlite-create-many", "migrations", "sqlite", ], default-features = false } -prisma-client-rust-cli = { git = "https://github.com/Brendonovich/prisma-client-rust.git", rev = "f5d4a952d8e8bc799a0006dc5f375a22fd64ac27", features = [ +prisma-client-rust-cli = { git = "https://github.com/Brendonovich/prisma-client-rust.git", rev = "4ea7b785ec9539d80e29c9b90ebc2010ea3a390e", features = [ "rspc", "sqlite-create-many", "migrations", From 18e019fb8df6c6787d8b2a3c7b1ae4fff064f34e Mon Sep 17 00:00:00 2001 From: Brendan Allan Date: Wed, 5 Oct 2022 12:07:41 +0800 Subject: [PATCH 05/11] update pcr to 0.6.2 branch --- Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 04d5bbc69..7d179100b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,13 +10,13 @@ members = [ resolver = "2" [workspace.dependencies] -prisma-client-rust = { git = "https://github.com/Brendonovich/prisma-client-rust.git", rev = "4ea7b785ec9539d80e29c9b90ebc2010ea3a390e", features = [ +prisma-client-rust = { git = "https://github.com/Brendonovich/prisma-client-rust.git", rev = "078919e3724f35cc00c2402c66ba585b61c88d47", features = [ "rspc", "sqlite-create-many", "migrations", "sqlite", ], default-features = false } -prisma-client-rust-cli = { git = "https://github.com/Brendonovich/prisma-client-rust.git", rev = "4ea7b785ec9539d80e29c9b90ebc2010ea3a390e", features = [ +prisma-client-rust-cli = { git = "https://github.com/Brendonovich/prisma-client-rust.git", rev = "078919e3724f35cc00c2402c66ba585b61c88d47", features = [ "rspc", "sqlite-create-many", "migrations", From 136df626028f605133922961307fdfcb572c00e2 Mon Sep 17 00:00:00 2001 From: Brendan Allan Date: Wed, 5 Oct 2022 12:14:04 +0800 Subject: [PATCH 06/11] please formatter --- Cargo.lock | Bin 152524 -> 152524 bytes core/src/api/jobs.rs | 20 ++++++++++---------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5f8e266b264859340b97063241fd4ec7deeb9e1b..da23834566f7bb79456d11edcab4c6108cf0c534 100644 GIT binary patch delta 297 zcmX@Job$|b&W0_Fp{@Z2<`$NQmZ`?(MkZ;-rpd_$2FXSy21dzdW=V;r7N$vNhRGHd zDJJI1L@J!@C?qz0!wp8^?dMz>H!#x1eEn`l&gpO68GlpX_=UaV?f#yO+x zK%O#@3a39@%P2m*&w){J`&n1Ujf^z0Ky12xHzVitx9*I;X=8r7pC{vXKToDQE&wVq BS&IMw diff --git a/core/src/api/jobs.rs b/core/src/api/jobs.rs index f71ac4de2..cf6d6fa70 100644 --- a/core/src/api/jobs.rs +++ b/core/src/api/jobs.rs @@ -47,16 +47,16 @@ pub(crate) fn mount() -> RouterBuilder { return Err(LocationError::IdNotFound(args.id).into()); } - library - .spawn_job(Job::new( - ThumbnailJobInit { - location_id: args.id, - path: PathBuf::new(), - background: true, - }, - Box::new(ThumbnailJob {}), - )) - .await; + library + .spawn_job(Job::new( + ThumbnailJobInit { + location_id: args.id, + path: PathBuf::new(), + background: true, + }, + Box::new(ThumbnailJob {}), + )) + .await; Ok(()) }, From 008b0eb72bfc938f4735ba504a0d00ecf09cf309 Mon Sep 17 00:00:00 2001 From: Brendan Allan Date: Wed, 5 Oct 2022 17:20:28 +0800 Subject: [PATCH 07/11] separate fetch & check --- .github/workflows/ci.yml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 746198d4f..f0b0a304e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -155,8 +155,11 @@ jobs: - name: Generate Prisma client uses: ./.github/actions/generate-prisma-client - - name: Build everything - run: cargo build --release + - name: Cargo fetch + run: cargo fetch + + - name: Check core + run: cargo check -p sd-core --release - name: Bundle Desktop run: pnpm desktop tauri build From df1ff85815379d087b42ac91f269fd4b58bc7a2c Mon Sep 17 00:00:00 2001 From: Oscar Beaumont Date: Thu, 6 Oct 2022 13:30:57 +0800 Subject: [PATCH 08/11] move arg structs into the builder closure --- core/src/api/files.rs | 24 +++++++++++------------ core/src/api/jobs.rs | 24 +++++++++++------------ core/src/api/libraries.rs | 14 +++++++------- core/src/api/locations.rs | 30 ++++++++++++++--------------- core/src/api/tags.rs | 40 +++++++++++++++++++-------------------- 5 files changed, 66 insertions(+), 66 deletions(-) diff --git a/core/src/api/files.rs b/core/src/api/files.rs index 2c70c36a4..e973fb299 100644 --- a/core/src/api/files.rs +++ b/core/src/api/files.rs @@ -5,18 +5,6 @@ use serde::Deserialize; use super::{utils::LibraryRequest, RouterBuilder}; -#[derive(Type, Deserialize)] -pub struct SetNoteArgs { - pub id: i32, - pub note: Option, -} - -#[derive(Type, Deserialize)] -pub struct SetFavoriteArgs { - pub id: i32, - pub favorite: bool, -} - pub(crate) fn mount() -> RouterBuilder { ::new() .library_query("readMetadata", |t| { @@ -26,6 +14,12 @@ pub(crate) fn mount() -> RouterBuilder { }) }) .library_mutation("setNote", |t| { + #[derive(Type, Deserialize)] + pub struct SetNoteArgs { + pub id: i32, + pub note: Option, + } + t(|_, args: SetNoteArgs, library| async move { library .db @@ -43,6 +37,12 @@ pub(crate) fn mount() -> RouterBuilder { }) }) .library_mutation("setFavorite", |t| { + #[derive(Type, Deserialize)] + pub struct SetFavoriteArgs { + pub id: i32, + pub favorite: bool, + } + t(|_, args: SetFavoriteArgs, library| async move { library .db diff --git a/core/src/api/jobs.rs b/core/src/api/jobs.rs index cf6d6fa70..c27092f47 100644 --- a/core/src/api/jobs.rs +++ b/core/src/api/jobs.rs @@ -14,18 +14,6 @@ use std::path::PathBuf; use super::{utils::LibraryRequest, CoreEvent, RouterBuilder}; -#[derive(Type, Deserialize)] -pub struct GenerateThumbsForLocationArgs { - pub id: i32, - pub path: PathBuf, -} - -#[derive(Type, Deserialize)] -pub struct IdentifyUniqueFilesArgs { - pub id: i32, - pub path: PathBuf, -} - pub(crate) fn mount() -> RouterBuilder { ::new() .library_query("getRunning", |t| { @@ -35,6 +23,12 @@ pub(crate) fn mount() -> RouterBuilder { t(|_, _: (), library| async move { Ok(JobManager::get_history(&library).await?) }) }) .library_mutation("generateThumbsForLocation", |t| { + #[derive(Type, Deserialize)] + pub struct GenerateThumbsForLocationArgs { + pub id: i32, + pub path: PathBuf, + } + t( |_, args: GenerateThumbsForLocationArgs, library| async move { if library @@ -63,6 +57,12 @@ pub(crate) fn mount() -> RouterBuilder { ) }) .library_mutation("identifyUniqueFiles", |t| { + #[derive(Type, Deserialize)] + pub struct IdentifyUniqueFilesArgs { + pub id: i32, + pub path: PathBuf, + } + t(|_, args: IdentifyUniqueFilesArgs, library| async move { if fetch_location(&library, args.id).exec().await?.is_none() { return Err(rspc::Error::new( diff --git a/core/src/api/libraries.rs b/core/src/api/libraries.rs index 834aeb089..44d0180fc 100644 --- a/core/src/api/libraries.rs +++ b/core/src/api/libraries.rs @@ -12,13 +12,6 @@ use serde::Deserialize; use tokio::fs; use uuid::Uuid; -#[derive(Type, Deserialize)] -pub struct EditLibraryArgs { - pub id: Uuid, - pub name: Option, - pub description: Option, -} - pub(crate) fn mount() -> RouterBuilder { ::new() .query("list", |t| { @@ -91,6 +84,13 @@ pub(crate) fn mount() -> RouterBuilder { }) }) .mutation("edit", |t| { + #[derive(Type, Deserialize)] + pub struct EditLibraryArgs { + pub id: Uuid, + pub name: Option, + pub description: Option, + } + t(|ctx, args: EditLibraryArgs| async move { Ok(ctx .library_manager diff --git a/core/src/api/locations.rs b/core/src/api/locations.rs index 662943c2f..d5a0b617f 100644 --- a/core/src/api/locations.rs +++ b/core/src/api/locations.rs @@ -15,12 +15,6 @@ use tracing::info; use super::{utils::LibraryRequest, Ctx, RouterBuilder}; -#[derive(Serialize, Deserialize, Type, Debug)] -pub struct ExplorerData { - pub context: ExplorerContext, - pub items: Vec, -} - #[derive(Serialize, Deserialize, Type, Debug)] #[serde(tag = "type")] pub enum ExplorerContext { @@ -29,9 +23,6 @@ pub enum ExplorerContext { // Space(object_in_space::Data), } -file_path::include!(file_path_with_object { object }); -object::include!(object_with_file_paths { file_paths }); - #[derive(Serialize, Deserialize, Type, Debug)] #[serde(tag = "type")] pub enum ExplorerItem { @@ -39,14 +30,15 @@ pub enum ExplorerItem { Object(Box), } -#[derive(Clone, Serialize, Deserialize, Type, Debug)] -pub struct LocationExplorerArgs { - pub location_id: i32, - pub path: String, - pub limit: i32, - pub cursor: Option, +#[derive(Serialize, Deserialize, Type, Debug)] +pub struct ExplorerData { + pub context: ExplorerContext, + pub items: Vec, } +file_path::include!(file_path_with_object { object }); +object::include!(object_with_file_paths { file_paths }); + // TODO(@Oscar): This return type sucks. Add an upstream rspc solution. pub(crate) fn mount() -> rspc::RouterBuilder< Ctx, @@ -76,6 +68,14 @@ pub(crate) fn mount() -> rspc::RouterBuilder< }) }) .library_query("getExplorerData", |t| { + #[derive(Clone, Serialize, Deserialize, Type, Debug)] + pub struct LocationExplorerArgs { + pub location_id: i32, + pub path: String, + pub limit: i32, + pub cursor: Option, + } + t(|_, args: LocationExplorerArgs, library| async move { let location = library .db diff --git a/core/src/api/tags.rs b/core/src/api/tags.rs index e13d4ec21..b69238220 100644 --- a/core/src/api/tags.rs +++ b/core/src/api/tags.rs @@ -12,26 +12,6 @@ use crate::{ use super::{utils::LibraryRequest, RouterBuilder}; -#[derive(Type, Deserialize)] -pub struct TagCreateArgs { - pub name: String, - pub color: String, -} - -#[derive(Debug, Type, Deserialize)] -pub struct TagAssignArgs { - pub object_id: i32, - pub tag_id: i32, - pub unassign: bool, -} - -#[derive(Type, Deserialize)] -pub struct TagUpdateArgs { - pub id: i32, - pub name: Option, - pub color: Option, -} - pub(crate) fn mount() -> RouterBuilder { RouterBuilder::new() .library_query("list", |t| { @@ -118,6 +98,12 @@ pub(crate) fn mount() -> RouterBuilder { }) }) .library_mutation("create", |t| { + #[derive(Type, Deserialize)] + pub struct TagCreateArgs { + pub name: String, + pub color: String, + } + t(|_, args: TagCreateArgs, library| async move { let created_tag = library .db @@ -138,6 +124,13 @@ pub(crate) fn mount() -> RouterBuilder { }) }) .library_mutation("assign", |t| { + #[derive(Debug, Type, Deserialize)] + pub struct TagAssignArgs { + pub object_id: i32, + pub tag_id: i32, + pub unassign: bool, + } + t(|_, args: TagAssignArgs, library| async move { if args.unassign { library @@ -165,6 +158,13 @@ pub(crate) fn mount() -> RouterBuilder { }) }) .library_mutation("update", |t| { + #[derive(Type, Deserialize)] + pub struct TagUpdateArgs { + pub id: i32, + pub name: Option, + pub color: Option, + } + t(|_, args: TagUpdateArgs, library| async move { library .db From 6d7285b2ea7c01d14d9d7057817c144bfcc36835 Mon Sep 17 00:00:00 2001 From: Oscar Beaumont Date: Thu, 6 Oct 2022 14:03:58 +0800 Subject: [PATCH 09/11] upgrade workspace dependencies --- Cargo.lock | Bin 152524 -> 152525 bytes apps/desktop/package.json | 2 +- apps/web/package.json | 4 +- crates/sync/example/package.json | 16 ++++---- package.json | 10 ++--- packages/client/package.json | 2 +- packages/config/package.json | 4 +- packages/interface/package.json | 62 +++++++++++++++---------------- packages/ui/package.json | 4 +- pnpm-lock.yaml | Bin 682558 -> 681757 bytes 10 files changed, 52 insertions(+), 52 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index da23834566f7bb79456d11edcab4c6108cf0c534..54618df8e13f11af3e039bd68764f358e3488819 100644 GIT binary patch delta 279 zcmWN}tx7~e6aZjG6j=-^f(FZOw9U^sGj~9C?-PiyFW{V?F^bJ-(HGcolTBFT!iJm7 z78kJyViK#tM{wJhzSsF+H6JX76NAgqWb?86elo|)_UGcXd;T!fv9MB72o*C2RCNfA z1tibOXTX9b5JlD~vD(DKE(kX@5c_q!x0PwZ^DLfGxNhJvHPU5oJ%cDvHe*)b`g4b8xag?>^1f{%o{5AIthE uxj_a29~$M5xo}bOnu;R&N)i}Sq_x?J77o@sN|LnH+28$9zx8WgF8=}N3RuAa delta 281 zcmWO1JxT;Y5QbqIMA%Fd5kVL+G3>6c>h1z@#v6zSSnR(tR4-v*I>E+*u<6PM6Ki6k z7>kjZdIC-C{Nv$!-u_&9d|w=ozti~unL!{CiVmhYOWFJC z4d~#YU??e6HsS?Lt^zhDlTa$NHysKkIF_!VyAp sCS)63Vjz-IAd?C&jYpdY#>2zn>{82BL|ERE6rT_o{ diff --git a/apps/desktop/package.json b/apps/desktop/package.json index e8fe551db..a567d20a5 100644 --- a/apps/desktop/package.json +++ b/apps/desktop/package.json @@ -16,7 +16,7 @@ "@sd/client": "workspace:*", "@sd/interface": "workspace:*", "@sd/ui": "workspace:*", - "@tanstack/react-query": "^4.8.0", + "@tanstack/react-query": "^4.10.1", "@tauri-apps/api": "1.1.0", "react": "^18.2.0", "react-dom": "^18.2.0" diff --git a/apps/web/package.json b/apps/web/package.json index 44d4e572a..15588492d 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -8,12 +8,12 @@ "preview": "vite preview" }, "dependencies": { - "@fontsource/inter": "^4.5.12", + "@fontsource/inter": "^4.5.13", "@rspc/client": "^0.1.2", "@sd/client": "workspace:*", "@sd/interface": "workspace:*", "@sd/ui": "workspace:*", - "@tanstack/react-query": "^4.8.0", + "@tanstack/react-query": "^4.10.1", "react": "^18.2.0", "react-dom": "^18.2.0" }, diff --git a/crates/sync/example/package.json b/crates/sync/example/package.json index 1b3589ea6..2cd744da4 100644 --- a/crates/sync/example/package.json +++ b/crates/sync/example/package.json @@ -11,22 +11,22 @@ }, "license": "MIT", "devDependencies": { - "@tauri-apps/cli": "^1.1.0", + "@tauri-apps/cli": "^1.1.1", "@types/babel__core": "^7.1.19", - "@types/node": "^18.7.10", + "@types/node": "^18.8.2", "autoprefixer": "^10.4.12", - "postcss": "^8.4.16", + "postcss": "^8.4.17", "tailwindcss": "^3.1.8", - "typescript": "^4.7.4", - "vite": "^3.0.0", - "vite-plugin-solid": "^2.3.0" + "typescript": "^4.8.4", + "vite": "^3.1.4", + "vite-plugin-solid": "^2.3.9" }, "dependencies": { "@rspc/client": "~0.1.2", "@rspc/solid": "~0.1.2", "@rspc/tauri": "~0.1.2", - "@tanstack/solid-query": "4.7.1", + "@tanstack/solid-query": "4.10.1", "clsx": "^1.2.1", - "solid-js": "^1.4.7" + "solid-js": "^1.5.7" } } diff --git a/package.json b/package.json index 41fff5125..a000e359d 100644 --- a/package.json +++ b/package.json @@ -22,15 +22,15 @@ }, "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", "turbo": "^1.5.5", "turbo-ignore": "^0.3.0", - "typescript": "^4.7.4" + "typescript": "^4.8.4" }, "overrides": { "vite-plugin-svgr": "https://github.com/spacedriveapp/vite-plugin-svgr#cb4195b69849429cdb18d1f12381676bf9196a84", diff --git a/packages/client/package.json b/packages/client/package.json index 394c8eed2..9f8fd64dc 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -21,7 +21,7 @@ "@rspc/react": "^0.1.2", "@sd/config": "workspace:*", "@sd/interface": "workspace:*", - "@tanstack/react-query": "^4.8.0", + "@tanstack/react-query": "^4.10.1", "eventemitter3": "^4.0.7", "immer": "^9.0.15", "lodash": "^4.17.21", diff --git a/packages/config/package.json b/packages/config/package.json index f997cf726..ddc8bc105 100644 --- a/packages/config/package.json +++ b/packages/config/package.json @@ -7,8 +7,8 @@ "eslint-react.js" ], "devDependencies": { - "@typescript-eslint/eslint-plugin": "^5.38.1", - "@typescript-eslint/parser": "^5.38.1", + "@typescript-eslint/eslint-plugin": "^5.39.0", + "@typescript-eslint/parser": "^5.39.0", "eslint": "^8.24.0", "eslint-config-prettier": "^8.5.0", "eslint-plugin-react": "^7.31.8", diff --git a/packages/interface/package.json b/packages/interface/package.json index c765dfcbc..9563c9469 100644 --- a/packages/interface/package.json +++ b/packages/interface/package.json @@ -15,81 +15,81 @@ "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.13", + "@headlessui/react": "^1.7.3", + "@heroicons/react": "^2.0.12", "@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.10.1", + "@tanstack/react-query-devtools": "^4.10.1", "@tanstack/react-virtual": "3.0.0-beta.18", - "@vitejs/plugin-react": "^2.0.0", - "autoprefixer": "^10.4.7", + "@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", "dayjs": "^1.11.5", "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.2", + "react-router-dom": "6.4.2", + "react-scrollbars-custom": "^4.1.1", "react-spline": "^1.2.1", - "react-transition-group": "^4.4.2", - "react-virtuoso": "^2.16.5", + "react-transition-group": "^4.4.5", + "react-virtuoso": "^2.19.1", "rooks": "^5.14.0", - "tailwindcss": "^3.1.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.8.2", "@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" } } diff --git a/packages/ui/package.json b/packages/ui/package.json index bed169404..ff8a168ff 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -17,8 +17,8 @@ "storybook:build": "build-storybook" }, "dependencies": { - "@headlessui/react": "^1.7.2", - "@heroicons/react": "^2.0.11", + "@headlessui/react": "^1.7.3", + "@heroicons/react": "^2.0.12", "@radix-ui/react-context-menu": "^1.0.0", "@radix-ui/react-dropdown-menu": "^1.0.0", "@tailwindcss/forms": "^0.5.3", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5d7288fb54dfc1235c03212e2542cdf58a5b229d..d60c0a145670d396fae2960dad66d6ea7b705544 100644 GIT binary patch delta 17297 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 delta 17745 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 From 6462a18768f69e8de328a54f11804fd434a57ff5 Mon Sep 17 00:00:00 2001 From: Oscar Beaumont Date: Thu, 6 Oct 2022 21:07:46 +0800 Subject: [PATCH 10/11] Fix mobile + upgrade Expo + even newer rspc --- Cargo.lock | Bin 152525 -> 152331 bytes Cargo.toml | 4 +- apps/mobile/ios/Podfile.lock | 606 +++++++++--------- .../ios/Spacedrive.xcodeproj/project.pbxproj | 6 +- apps/mobile/package.json | 61 +- apps/mobile/pnpm-lock.yaml | Bin 329395 -> 327477 bytes apps/mobile/rust/src/android.rs | 165 +++-- apps/mobile/rust/src/ios.rs | 127 ++-- apps/mobile/src/hooks/rspc.ts | 26 +- apps/mobile/src/navigation/TabNavigator.tsx | 4 +- apps/mobile/src/screens/Overview.tsx | 265 ++------ core/Cargo.toml | 2 + core/src/api/utils/library.rs | 153 +++-- 13 files changed, 691 insertions(+), 728 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 54618df8e13f11af3e039bd68764f358e3488819..59debe61111d723014f3a3ecb2d32d3864f03885 100644 GIT binary patch delta 680 zcmchTJx|k79EEd8{rMiT<49q!VF z1s6?dc^b`fFJ>^2mmZkBv@vsOaFeLr)l{Z&0KsR{A|rKjO)0r zpR;;zwE3#xqo9OH2`W%el@vr6;%vkgxTn!dE~6mY1RJEt0|PWtaKd8+ktp69{ja9w zDq8QA`jzylIaS?QYlpp;nmXo#qf{6jG;ql0gk{(WqJr?88_GRqwl-NYeff(j>7an- zhto@F%iYno@2P2bcHNkb!4Vxr;2?Z-5;$=x|Dcouj0JE^ZB)do+Jwd4`jfH2#o=5R xJzhxNTdweztvET5pgm52RudQ?fTZ%`>cyFy>nhf7p?SbpweXs*$({w@A5&cXly delta 591 zcmWlWv1*k;5QW()+z2LBVq&EsA_OiwvpYMxjn@#hu?e<8WOrvrD^WD95Wzw$EdJte z0;bZ^1jSqU3QAtU!qz4}fy509Q!IxwXTJ09N_y!5Lp7HNF&@ZtK;7_b9X%3HaoWo zodtsCeYI){h?{ERo+b(bd&cM;AXH6w@mV6cl_tT5E-t+a^){0A?9#A(x-$Oz zYL13G$GfvkS*TwkEvL>tLI^;@h^2SPv0v@AN$k-Zg$kvL&Aqga+%rqOFq_Z5nIDHs zi+g*|^2_>Uy8m?lMU(M-&D=CJn8S_n{<>M;+EAYyM(I=nw!XHx>=0TLrmDUm*&;a> HzP|V$wnMLJ diff --git a/Cargo.toml b/Cargo.toml index 7d179100b..2bb63b954 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,4 +26,6 @@ rspc = { version = "0.1.2" } [patch.crates-io] # We use this patch so we can compile for the IOS simulator on M1 -openssl-sys = { git = "https://github.com/spacedriveapp/rust-openssl" } +openssl-sys = { git = "https://github.com/spacedriveapp/rust-openssl", rev = "92c3dec225a9e984884d5b30a517e5d44a24d03b" } + +rspc = { git = "https://github.com/oscartbeaumont/rspc", rev = "08c19f5e485dfc6841c7e9877c80058402bf71d7" } # TODO: Move back to crates.io when new jsonrpc executor is release \ No newline at end of file diff --git a/apps/mobile/ios/Podfile.lock b/apps/mobile/ios/Podfile.lock index 5825a73f1..d22ee0886 100644 --- a/apps/mobile/ios/Podfile.lock +++ b/apps/mobile/ios/Podfile.lock @@ -7,337 +7,337 @@ PODS: - ExpoModulesCore - EXFileSystem (14.1.0): - ExpoModulesCore - - EXFont (10.2.0): + - EXFont (10.2.1): - ExpoModulesCore - - Expo (46.0.10): + - Expo (46.0.15): - ExpoModulesCore - ExpoKeepAwake (10.2.0): - ExpoModulesCore - - ExpoModulesCore (0.11.5): + - ExpoModulesCore (0.11.7): - React-Core - ReactCommon/turbomodule/core - EXSplashScreen (0.16.2): - ExpoModulesCore - React-Core - - FBLazyVector (0.69.4) - - FBReactNativeSpec (0.69.4): - - RCT-Folly (= 2021.06.28.00-v2) - - RCTRequired (= 0.69.4) - - RCTTypeSafety (= 0.69.4) - - React-Core (= 0.69.4) - - React-jsi (= 0.69.4) - - ReactCommon/turbomodule/core (= 0.69.4) + - FBLazyVector (0.70.2) + - FBReactNativeSpec (0.70.2): + - RCT-Folly (= 2021.07.22.00) + - RCTRequired (= 0.70.2) + - RCTTypeSafety (= 0.70.2) + - React-Core (= 0.70.2) + - React-jsi (= 0.70.2) + - ReactCommon/turbomodule/core (= 0.70.2) - fmt (6.2.1) - glog (0.3.5) - - hermes-engine (0.69.4) + - hermes-engine (0.70.2) - libevent (2.1.12) - - lottie-ios (3.4.2) + - lottie-ios (3.4.3) - lottie-react-native (5.1.4): - lottie-ios (~> 3.4.0) - React-Core - - RCT-Folly (2021.06.28.00-v2): + - RCT-Folly (2021.07.22.00): - boost - DoubleConversion - fmt (~> 6.2.1) - glog - - RCT-Folly/Default (= 2021.06.28.00-v2) - - RCT-Folly/Default (2021.06.28.00-v2): + - RCT-Folly/Default (= 2021.07.22.00) + - RCT-Folly/Default (2021.07.22.00): - boost - DoubleConversion - fmt (~> 6.2.1) - glog - - RCT-Folly/Futures (2021.06.28.00-v2): + - RCT-Folly/Futures (2021.07.22.00): - boost - DoubleConversion - fmt (~> 6.2.1) - glog - libevent - - RCTRequired (0.69.4) - - RCTTypeSafety (0.69.4): - - FBLazyVector (= 0.69.4) - - RCTRequired (= 0.69.4) - - React-Core (= 0.69.4) - - React (0.69.4): - - React-Core (= 0.69.4) - - React-Core/DevSupport (= 0.69.4) - - React-Core/RCTWebSocket (= 0.69.4) - - React-RCTActionSheet (= 0.69.4) - - React-RCTAnimation (= 0.69.4) - - React-RCTBlob (= 0.69.4) - - React-RCTImage (= 0.69.4) - - React-RCTLinking (= 0.69.4) - - React-RCTNetwork (= 0.69.4) - - React-RCTSettings (= 0.69.4) - - React-RCTText (= 0.69.4) - - React-RCTVibration (= 0.69.4) - - React-bridging (0.69.4): - - RCT-Folly (= 2021.06.28.00-v2) - - React-jsi (= 0.69.4) - - React-callinvoker (0.69.4) - - React-Codegen (0.69.4): - - FBReactNativeSpec (= 0.69.4) - - RCT-Folly (= 2021.06.28.00-v2) - - RCTRequired (= 0.69.4) - - RCTTypeSafety (= 0.69.4) - - React-Core (= 0.69.4) - - React-jsi (= 0.69.4) - - React-jsiexecutor (= 0.69.4) - - ReactCommon/turbomodule/core (= 0.69.4) - - React-Core (0.69.4): + - RCTRequired (0.70.2) + - RCTTypeSafety (0.70.2): + - FBLazyVector (= 0.70.2) + - RCTRequired (= 0.70.2) + - React-Core (= 0.70.2) + - React (0.70.2): + - React-Core (= 0.70.2) + - React-Core/DevSupport (= 0.70.2) + - React-Core/RCTWebSocket (= 0.70.2) + - React-RCTActionSheet (= 0.70.2) + - React-RCTAnimation (= 0.70.2) + - React-RCTBlob (= 0.70.2) + - React-RCTImage (= 0.70.2) + - React-RCTLinking (= 0.70.2) + - React-RCTNetwork (= 0.70.2) + - React-RCTSettings (= 0.70.2) + - React-RCTText (= 0.70.2) + - React-RCTVibration (= 0.70.2) + - React-bridging (0.70.2): + - RCT-Folly (= 2021.07.22.00) + - React-jsi (= 0.70.2) + - React-callinvoker (0.70.2) + - React-Codegen (0.70.2): + - FBReactNativeSpec (= 0.70.2) + - RCT-Folly (= 2021.07.22.00) + - RCTRequired (= 0.70.2) + - RCTTypeSafety (= 0.70.2) + - React-Core (= 0.70.2) + - React-jsi (= 0.70.2) + - React-jsiexecutor (= 0.70.2) + - ReactCommon/turbomodule/core (= 0.70.2) + - React-Core (0.70.2): - glog - - RCT-Folly (= 2021.06.28.00-v2) - - React-Core/Default (= 0.69.4) - - React-cxxreact (= 0.69.4) - - React-jsi (= 0.69.4) - - React-jsiexecutor (= 0.69.4) - - React-perflogger (= 0.69.4) + - RCT-Folly (= 2021.07.22.00) + - React-Core/Default (= 0.70.2) + - React-cxxreact (= 0.70.2) + - React-jsi (= 0.70.2) + - React-jsiexecutor (= 0.70.2) + - React-perflogger (= 0.70.2) - Yoga - - React-Core/CoreModulesHeaders (0.69.4): + - React-Core/CoreModulesHeaders (0.70.2): - glog - - RCT-Folly (= 2021.06.28.00-v2) + - RCT-Folly (= 2021.07.22.00) - React-Core/Default - - React-cxxreact (= 0.69.4) - - React-jsi (= 0.69.4) - - React-jsiexecutor (= 0.69.4) - - React-perflogger (= 0.69.4) + - React-cxxreact (= 0.70.2) + - React-jsi (= 0.70.2) + - React-jsiexecutor (= 0.70.2) + - React-perflogger (= 0.70.2) - Yoga - - React-Core/Default (0.69.4): + - React-Core/Default (0.70.2): - glog - - RCT-Folly (= 2021.06.28.00-v2) - - React-cxxreact (= 0.69.4) - - React-jsi (= 0.69.4) - - React-jsiexecutor (= 0.69.4) - - React-perflogger (= 0.69.4) + - RCT-Folly (= 2021.07.22.00) + - React-cxxreact (= 0.70.2) + - React-jsi (= 0.70.2) + - React-jsiexecutor (= 0.70.2) + - React-perflogger (= 0.70.2) - Yoga - - React-Core/DevSupport (0.69.4): + - React-Core/DevSupport (0.70.2): - glog - - RCT-Folly (= 2021.06.28.00-v2) - - React-Core/Default (= 0.69.4) - - React-Core/RCTWebSocket (= 0.69.4) - - React-cxxreact (= 0.69.4) - - React-jsi (= 0.69.4) - - React-jsiexecutor (= 0.69.4) - - React-jsinspector (= 0.69.4) - - React-perflogger (= 0.69.4) + - RCT-Folly (= 2021.07.22.00) + - React-Core/Default (= 0.70.2) + - React-Core/RCTWebSocket (= 0.70.2) + - React-cxxreact (= 0.70.2) + - React-jsi (= 0.70.2) + - React-jsiexecutor (= 0.70.2) + - React-jsinspector (= 0.70.2) + - React-perflogger (= 0.70.2) - Yoga - - React-Core/RCTActionSheetHeaders (0.69.4): + - React-Core/RCTActionSheetHeaders (0.70.2): - glog - - RCT-Folly (= 2021.06.28.00-v2) + - RCT-Folly (= 2021.07.22.00) - React-Core/Default - - React-cxxreact (= 0.69.4) - - React-jsi (= 0.69.4) - - React-jsiexecutor (= 0.69.4) - - React-perflogger (= 0.69.4) + - React-cxxreact (= 0.70.2) + - React-jsi (= 0.70.2) + - React-jsiexecutor (= 0.70.2) + - React-perflogger (= 0.70.2) - Yoga - - React-Core/RCTAnimationHeaders (0.69.4): + - React-Core/RCTAnimationHeaders (0.70.2): - glog - - RCT-Folly (= 2021.06.28.00-v2) + - RCT-Folly (= 2021.07.22.00) - React-Core/Default - - React-cxxreact (= 0.69.4) - - React-jsi (= 0.69.4) - - React-jsiexecutor (= 0.69.4) - - React-perflogger (= 0.69.4) + - React-cxxreact (= 0.70.2) + - React-jsi (= 0.70.2) + - React-jsiexecutor (= 0.70.2) + - React-perflogger (= 0.70.2) - Yoga - - React-Core/RCTBlobHeaders (0.69.4): + - React-Core/RCTBlobHeaders (0.70.2): - glog - - RCT-Folly (= 2021.06.28.00-v2) + - RCT-Folly (= 2021.07.22.00) - React-Core/Default - - React-cxxreact (= 0.69.4) - - React-jsi (= 0.69.4) - - React-jsiexecutor (= 0.69.4) - - React-perflogger (= 0.69.4) + - React-cxxreact (= 0.70.2) + - React-jsi (= 0.70.2) + - React-jsiexecutor (= 0.70.2) + - React-perflogger (= 0.70.2) - Yoga - - React-Core/RCTImageHeaders (0.69.4): + - React-Core/RCTImageHeaders (0.70.2): - glog - - RCT-Folly (= 2021.06.28.00-v2) + - RCT-Folly (= 2021.07.22.00) - React-Core/Default - - React-cxxreact (= 0.69.4) - - React-jsi (= 0.69.4) - - React-jsiexecutor (= 0.69.4) - - React-perflogger (= 0.69.4) + - React-cxxreact (= 0.70.2) + - React-jsi (= 0.70.2) + - React-jsiexecutor (= 0.70.2) + - React-perflogger (= 0.70.2) - Yoga - - React-Core/RCTLinkingHeaders (0.69.4): + - React-Core/RCTLinkingHeaders (0.70.2): - glog - - RCT-Folly (= 2021.06.28.00-v2) + - RCT-Folly (= 2021.07.22.00) - React-Core/Default - - React-cxxreact (= 0.69.4) - - React-jsi (= 0.69.4) - - React-jsiexecutor (= 0.69.4) - - React-perflogger (= 0.69.4) + - React-cxxreact (= 0.70.2) + - React-jsi (= 0.70.2) + - React-jsiexecutor (= 0.70.2) + - React-perflogger (= 0.70.2) - Yoga - - React-Core/RCTNetworkHeaders (0.69.4): + - React-Core/RCTNetworkHeaders (0.70.2): - glog - - RCT-Folly (= 2021.06.28.00-v2) + - RCT-Folly (= 2021.07.22.00) - React-Core/Default - - React-cxxreact (= 0.69.4) - - React-jsi (= 0.69.4) - - React-jsiexecutor (= 0.69.4) - - React-perflogger (= 0.69.4) + - React-cxxreact (= 0.70.2) + - React-jsi (= 0.70.2) + - React-jsiexecutor (= 0.70.2) + - React-perflogger (= 0.70.2) - Yoga - - React-Core/RCTSettingsHeaders (0.69.4): + - React-Core/RCTSettingsHeaders (0.70.2): - glog - - RCT-Folly (= 2021.06.28.00-v2) + - RCT-Folly (= 2021.07.22.00) - React-Core/Default - - React-cxxreact (= 0.69.4) - - React-jsi (= 0.69.4) - - React-jsiexecutor (= 0.69.4) - - React-perflogger (= 0.69.4) + - React-cxxreact (= 0.70.2) + - React-jsi (= 0.70.2) + - React-jsiexecutor (= 0.70.2) + - React-perflogger (= 0.70.2) - Yoga - - React-Core/RCTTextHeaders (0.69.4): + - React-Core/RCTTextHeaders (0.70.2): - glog - - RCT-Folly (= 2021.06.28.00-v2) + - RCT-Folly (= 2021.07.22.00) - React-Core/Default - - React-cxxreact (= 0.69.4) - - React-jsi (= 0.69.4) - - React-jsiexecutor (= 0.69.4) - - React-perflogger (= 0.69.4) + - React-cxxreact (= 0.70.2) + - React-jsi (= 0.70.2) + - React-jsiexecutor (= 0.70.2) + - React-perflogger (= 0.70.2) - Yoga - - React-Core/RCTVibrationHeaders (0.69.4): + - React-Core/RCTVibrationHeaders (0.70.2): - glog - - RCT-Folly (= 2021.06.28.00-v2) + - RCT-Folly (= 2021.07.22.00) - React-Core/Default - - React-cxxreact (= 0.69.4) - - React-jsi (= 0.69.4) - - React-jsiexecutor (= 0.69.4) - - React-perflogger (= 0.69.4) + - React-cxxreact (= 0.70.2) + - React-jsi (= 0.70.2) + - React-jsiexecutor (= 0.70.2) + - React-perflogger (= 0.70.2) - Yoga - - React-Core/RCTWebSocket (0.69.4): + - React-Core/RCTWebSocket (0.70.2): - glog - - RCT-Folly (= 2021.06.28.00-v2) - - React-Core/Default (= 0.69.4) - - React-cxxreact (= 0.69.4) - - React-jsi (= 0.69.4) - - React-jsiexecutor (= 0.69.4) - - React-perflogger (= 0.69.4) + - RCT-Folly (= 2021.07.22.00) + - React-Core/Default (= 0.70.2) + - React-cxxreact (= 0.70.2) + - React-jsi (= 0.70.2) + - React-jsiexecutor (= 0.70.2) + - React-perflogger (= 0.70.2) - Yoga - - React-CoreModules (0.69.4): - - RCT-Folly (= 2021.06.28.00-v2) - - RCTTypeSafety (= 0.69.4) - - React-Codegen (= 0.69.4) - - React-Core/CoreModulesHeaders (= 0.69.4) - - React-jsi (= 0.69.4) - - React-RCTImage (= 0.69.4) - - ReactCommon/turbomodule/core (= 0.69.4) - - React-cxxreact (0.69.4): + - React-CoreModules (0.70.2): + - RCT-Folly (= 2021.07.22.00) + - RCTTypeSafety (= 0.70.2) + - React-Codegen (= 0.70.2) + - React-Core/CoreModulesHeaders (= 0.70.2) + - React-jsi (= 0.70.2) + - React-RCTImage (= 0.70.2) + - ReactCommon/turbomodule/core (= 0.70.2) + - React-cxxreact (0.70.2): - boost (= 1.76.0) - DoubleConversion - glog - - RCT-Folly (= 2021.06.28.00-v2) - - React-callinvoker (= 0.69.4) - - React-jsi (= 0.69.4) - - React-jsinspector (= 0.69.4) - - React-logger (= 0.69.4) - - React-perflogger (= 0.69.4) - - React-runtimeexecutor (= 0.69.4) - - React-hermes (0.69.4): + - RCT-Folly (= 2021.07.22.00) + - React-callinvoker (= 0.70.2) + - React-jsi (= 0.70.2) + - React-jsinspector (= 0.70.2) + - React-logger (= 0.70.2) + - React-perflogger (= 0.70.2) + - React-runtimeexecutor (= 0.70.2) + - React-hermes (0.70.2): - DoubleConversion - glog - hermes-engine - - RCT-Folly (= 2021.06.28.00-v2) - - RCT-Folly/Futures (= 2021.06.28.00-v2) - - React-cxxreact (= 0.69.4) - - React-jsi (= 0.69.4) - - React-jsiexecutor (= 0.69.4) - - React-jsinspector (= 0.69.4) - - React-perflogger (= 0.69.4) - - React-jsi (0.69.4): + - RCT-Folly (= 2021.07.22.00) + - RCT-Folly/Futures (= 2021.07.22.00) + - React-cxxreact (= 0.70.2) + - React-jsi (= 0.70.2) + - React-jsiexecutor (= 0.70.2) + - React-jsinspector (= 0.70.2) + - React-perflogger (= 0.70.2) + - React-jsi (0.70.2): - boost (= 1.76.0) - DoubleConversion - glog - - RCT-Folly (= 2021.06.28.00-v2) - - React-jsi/Default (= 0.69.4) - - React-jsi/Default (0.69.4): + - RCT-Folly (= 2021.07.22.00) + - React-jsi/Default (= 0.70.2) + - React-jsi/Default (0.70.2): - boost (= 1.76.0) - DoubleConversion - glog - - RCT-Folly (= 2021.06.28.00-v2) - - React-jsiexecutor (0.69.4): + - RCT-Folly (= 2021.07.22.00) + - React-jsiexecutor (0.70.2): - DoubleConversion - glog - - RCT-Folly (= 2021.06.28.00-v2) - - React-cxxreact (= 0.69.4) - - React-jsi (= 0.69.4) - - React-perflogger (= 0.69.4) - - React-jsinspector (0.69.4) - - React-logger (0.69.4): + - RCT-Folly (= 2021.07.22.00) + - React-cxxreact (= 0.70.2) + - React-jsi (= 0.70.2) + - React-perflogger (= 0.70.2) + - React-jsinspector (0.70.2) + - React-logger (0.70.2): - glog - - react-native-safe-area-context (4.3.1): + - react-native-safe-area-context (4.4.1): - RCT-Folly - RCTRequired - RCTTypeSafety - - React + - React-Core - ReactCommon/turbomodule/core - - React-perflogger (0.69.4) - - React-RCTActionSheet (0.69.4): - - React-Core/RCTActionSheetHeaders (= 0.69.4) - - React-RCTAnimation (0.69.4): - - RCT-Folly (= 2021.06.28.00-v2) - - RCTTypeSafety (= 0.69.4) - - React-Codegen (= 0.69.4) - - React-Core/RCTAnimationHeaders (= 0.69.4) - - React-jsi (= 0.69.4) - - ReactCommon/turbomodule/core (= 0.69.4) - - React-RCTBlob (0.69.4): - - RCT-Folly (= 2021.06.28.00-v2) - - React-Codegen (= 0.69.4) - - React-Core/RCTBlobHeaders (= 0.69.4) - - React-Core/RCTWebSocket (= 0.69.4) - - React-jsi (= 0.69.4) - - React-RCTNetwork (= 0.69.4) - - ReactCommon/turbomodule/core (= 0.69.4) - - React-RCTImage (0.69.4): - - RCT-Folly (= 2021.06.28.00-v2) - - RCTTypeSafety (= 0.69.4) - - React-Codegen (= 0.69.4) - - React-Core/RCTImageHeaders (= 0.69.4) - - React-jsi (= 0.69.4) - - React-RCTNetwork (= 0.69.4) - - ReactCommon/turbomodule/core (= 0.69.4) - - React-RCTLinking (0.69.4): - - React-Codegen (= 0.69.4) - - React-Core/RCTLinkingHeaders (= 0.69.4) - - React-jsi (= 0.69.4) - - ReactCommon/turbomodule/core (= 0.69.4) - - React-RCTNetwork (0.69.4): - - RCT-Folly (= 2021.06.28.00-v2) - - RCTTypeSafety (= 0.69.4) - - React-Codegen (= 0.69.4) - - React-Core/RCTNetworkHeaders (= 0.69.4) - - React-jsi (= 0.69.4) - - ReactCommon/turbomodule/core (= 0.69.4) - - React-RCTSettings (0.69.4): - - RCT-Folly (= 2021.06.28.00-v2) - - RCTTypeSafety (= 0.69.4) - - React-Codegen (= 0.69.4) - - React-Core/RCTSettingsHeaders (= 0.69.4) - - React-jsi (= 0.69.4) - - ReactCommon/turbomodule/core (= 0.69.4) - - React-RCTText (0.69.4): - - React-Core/RCTTextHeaders (= 0.69.4) - - React-RCTVibration (0.69.4): - - RCT-Folly (= 2021.06.28.00-v2) - - React-Codegen (= 0.69.4) - - React-Core/RCTVibrationHeaders (= 0.69.4) - - React-jsi (= 0.69.4) - - ReactCommon/turbomodule/core (= 0.69.4) - - React-runtimeexecutor (0.69.4): - - React-jsi (= 0.69.4) - - ReactCommon/turbomodule/core (0.69.4): + - React-perflogger (0.70.2) + - React-RCTActionSheet (0.70.2): + - React-Core/RCTActionSheetHeaders (= 0.70.2) + - React-RCTAnimation (0.70.2): + - RCT-Folly (= 2021.07.22.00) + - RCTTypeSafety (= 0.70.2) + - React-Codegen (= 0.70.2) + - React-Core/RCTAnimationHeaders (= 0.70.2) + - React-jsi (= 0.70.2) + - ReactCommon/turbomodule/core (= 0.70.2) + - React-RCTBlob (0.70.2): + - RCT-Folly (= 2021.07.22.00) + - React-Codegen (= 0.70.2) + - React-Core/RCTBlobHeaders (= 0.70.2) + - React-Core/RCTWebSocket (= 0.70.2) + - React-jsi (= 0.70.2) + - React-RCTNetwork (= 0.70.2) + - ReactCommon/turbomodule/core (= 0.70.2) + - React-RCTImage (0.70.2): + - RCT-Folly (= 2021.07.22.00) + - RCTTypeSafety (= 0.70.2) + - React-Codegen (= 0.70.2) + - React-Core/RCTImageHeaders (= 0.70.2) + - React-jsi (= 0.70.2) + - React-RCTNetwork (= 0.70.2) + - ReactCommon/turbomodule/core (= 0.70.2) + - React-RCTLinking (0.70.2): + - React-Codegen (= 0.70.2) + - React-Core/RCTLinkingHeaders (= 0.70.2) + - React-jsi (= 0.70.2) + - ReactCommon/turbomodule/core (= 0.70.2) + - React-RCTNetwork (0.70.2): + - RCT-Folly (= 2021.07.22.00) + - RCTTypeSafety (= 0.70.2) + - React-Codegen (= 0.70.2) + - React-Core/RCTNetworkHeaders (= 0.70.2) + - React-jsi (= 0.70.2) + - ReactCommon/turbomodule/core (= 0.70.2) + - React-RCTSettings (0.70.2): + - RCT-Folly (= 2021.07.22.00) + - RCTTypeSafety (= 0.70.2) + - React-Codegen (= 0.70.2) + - React-Core/RCTSettingsHeaders (= 0.70.2) + - React-jsi (= 0.70.2) + - ReactCommon/turbomodule/core (= 0.70.2) + - React-RCTText (0.70.2): + - React-Core/RCTTextHeaders (= 0.70.2) + - React-RCTVibration (0.70.2): + - RCT-Folly (= 2021.07.22.00) + - React-Codegen (= 0.70.2) + - React-Core/RCTVibrationHeaders (= 0.70.2) + - React-jsi (= 0.70.2) + - ReactCommon/turbomodule/core (= 0.70.2) + - React-runtimeexecutor (0.70.2): + - React-jsi (= 0.70.2) + - ReactCommon/turbomodule/core (0.70.2): - DoubleConversion - glog - - RCT-Folly (= 2021.06.28.00-v2) - - React-bridging (= 0.69.4) - - React-callinvoker (= 0.69.4) - - React-Core (= 0.69.4) - - React-cxxreact (= 0.69.4) - - React-jsi (= 0.69.4) - - React-logger (= 0.69.4) - - React-perflogger (= 0.69.4) - - RNCAsyncStorage (1.17.7): + - RCT-Folly (= 2021.07.22.00) + - React-bridging (= 0.70.2) + - React-callinvoker (= 0.70.2) + - React-Core (= 0.70.2) + - React-cxxreact (= 0.70.2) + - React-jsi (= 0.70.2) + - React-logger (= 0.70.2) + - React-perflogger (= 0.70.2) + - RNCAsyncStorage (1.17.10): - React-Core - - RNCMaskedView (0.2.7): + - RNCMaskedView (0.2.8): - React-Core - - RNGestureHandler (2.5.0): + - RNGestureHandler (2.7.0): - React-Core - RNReanimated (2.10.0): - DoubleConversion @@ -366,24 +366,24 @@ PODS: - React-RCTText - ReactCommon/turbomodule/core - Yoga - - RNScreens (3.15.0): + - RNScreens (3.18.0): - React-Core - React-RCTImage - - RNSVG (13.0.0): + - RNSVG (13.3.0): - React-Core - Yoga (1.14.0) DEPENDENCIES: - boost (from `../node_modules/react-native/third-party-podspecs/boost.podspec`) - DoubleConversion (from `../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec`) - - "EXApplication (from `../node_modules/.pnpm/expo-application@4.2.2_expo@46.0.10/node_modules/expo-application/ios`)" - - "EXConstants (from `../node_modules/.pnpm/expo-constants@13.2.4_expo@46.0.10/node_modules/expo-constants/ios`)" - - "EXFileSystem (from `../node_modules/.pnpm/expo-file-system@14.1.0_expo@46.0.10/node_modules/expo-file-system/ios`)" - - "EXFont (from `../node_modules/.pnpm/expo-font@10.2.0_expo@46.0.10/node_modules/expo-font/ios`)" - - "Expo (from `../node_modules/.pnpm/expo@46.0.10_@babel+core@7.18.10/node_modules/expo`)" - - "ExpoKeepAwake (from `../node_modules/.pnpm/expo-keep-awake@10.2.0_expo@46.0.10/node_modules/expo-keep-awake/ios`)" - - "ExpoModulesCore (from `../node_modules/.pnpm/expo-modules-core@0.11.5/node_modules/expo-modules-core/ios`)" - - "EXSplashScreen (from `../node_modules/.pnpm/expo-splash-screen@0.16.2_expo@46.0.10/node_modules/expo-splash-screen/ios`)" + - "EXApplication (from `../node_modules/.pnpm/expo-application@4.2.2_expo@46.0.15/node_modules/expo-application/ios`)" + - "EXConstants (from `../node_modules/.pnpm/expo-constants@13.2.4_expo@46.0.15/node_modules/expo-constants/ios`)" + - "EXFileSystem (from `../node_modules/.pnpm/expo-file-system@14.1.0_expo@46.0.15/node_modules/expo-file-system/ios`)" + - "EXFont (from `../node_modules/.pnpm/expo-font@10.2.1_expo@46.0.15/node_modules/expo-font/ios`)" + - "Expo (from `../node_modules/.pnpm/expo@46.0.15_@babel+core@7.19.3/node_modules/expo`)" + - "ExpoKeepAwake (from `../node_modules/.pnpm/expo-keep-awake@10.2.0_expo@46.0.15/node_modules/expo-keep-awake/ios`)" + - "ExpoModulesCore (from `../node_modules/.pnpm/expo-modules-core@0.11.7/node_modules/expo-modules-core/ios`)" + - "EXSplashScreen (from `../node_modules/.pnpm/expo-splash-screen@0.16.2_expo@46.0.15/node_modules/expo-splash-screen/ios`)" - FBLazyVector (from `../node_modules/react-native/Libraries/FBLazyVector`) - FBReactNativeSpec (from `../node_modules/react-native/React/FBReactNativeSpec`) - glog (from `../node_modules/react-native/third-party-podspecs/glog.podspec`) @@ -439,21 +439,21 @@ EXTERNAL SOURCES: DoubleConversion: :podspec: "../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec" EXApplication: - :path: "../node_modules/.pnpm/expo-application@4.2.2_expo@46.0.10/node_modules/expo-application/ios" + :path: "../node_modules/.pnpm/expo-application@4.2.2_expo@46.0.15/node_modules/expo-application/ios" EXConstants: - :path: "../node_modules/.pnpm/expo-constants@13.2.4_expo@46.0.10/node_modules/expo-constants/ios" + :path: "../node_modules/.pnpm/expo-constants@13.2.4_expo@46.0.15/node_modules/expo-constants/ios" EXFileSystem: - :path: "../node_modules/.pnpm/expo-file-system@14.1.0_expo@46.0.10/node_modules/expo-file-system/ios" + :path: "../node_modules/.pnpm/expo-file-system@14.1.0_expo@46.0.15/node_modules/expo-file-system/ios" EXFont: - :path: "../node_modules/.pnpm/expo-font@10.2.0_expo@46.0.10/node_modules/expo-font/ios" + :path: "../node_modules/.pnpm/expo-font@10.2.1_expo@46.0.15/node_modules/expo-font/ios" Expo: - :path: "../node_modules/.pnpm/expo@46.0.10_@babel+core@7.18.10/node_modules/expo" + :path: "../node_modules/.pnpm/expo@46.0.15_@babel+core@7.19.3/node_modules/expo" ExpoKeepAwake: - :path: "../node_modules/.pnpm/expo-keep-awake@10.2.0_expo@46.0.10/node_modules/expo-keep-awake/ios" + :path: "../node_modules/.pnpm/expo-keep-awake@10.2.0_expo@46.0.15/node_modules/expo-keep-awake/ios" ExpoModulesCore: - :path: "../node_modules/.pnpm/expo-modules-core@0.11.5/node_modules/expo-modules-core/ios" + :path: "../node_modules/.pnpm/expo-modules-core@0.11.7/node_modules/expo-modules-core/ios" EXSplashScreen: - :path: "../node_modules/.pnpm/expo-splash-screen@0.16.2_expo@46.0.10/node_modules/expo-splash-screen/ios" + :path: "../node_modules/.pnpm/expo-splash-screen@0.16.2_expo@46.0.15/node_modules/expo-splash-screen/ios" FBLazyVector: :path: "../node_modules/react-native/Libraries/FBLazyVector" FBReactNativeSpec: @@ -541,54 +541,54 @@ SPEC CHECKSUMS: EXApplication: e418d737a036e788510f2c4ad6c10a7d54d18586 EXConstants: 7c44785d41d8e959d527d23d29444277a4d1ee73 EXFileSystem: 927e0a8885aa9c49e50fc38eaba2c2389f2f1019 - EXFont: a5d80bd9b3452b2d5abbce2487da89b0150e6487 - Expo: fcdb32274e2ca9c7638d3b21b30fb665c6869219 + EXFont: 06df627203afcb8a3b3152ec06eb2f11f46f0cff + Expo: 7e821e708a35d2720ef6baa658e224dd91c4821e ExpoKeepAwake: 0e8f18142e71bbf2c7f6aa66ebed249ba1420320 - ExpoModulesCore: 5a973701f4400d70254bc836305228731c829010 + ExpoModulesCore: 2d60ec04c49641afb55fee3faac86fb108c68fe0 EXSplashScreen: 799bece80089219b2c989c1082d70f3b00995cda - FBLazyVector: c71b8c429a8af2aff1013934a7152e9d9d0c937d - FBReactNativeSpec: 3cc5cff7d792e74a875be91e56d6242335016f50 + FBLazyVector: 0507edc21c06f1650c591f0981c846445469373b + FBReactNativeSpec: 585ef61b9a394a9166de579a080a0df672054319 fmt: ff9d55029c625d3757ed641535fd4a75fedc7ce9 - glog: 3d02b25ca00c2d456734d0bcff864cbc62f6ae1a - hermes-engine: 761a544537e62df2a37189389b9d2654dc1f75af + glog: 04b94705f318337d7ead9e6d17c019bd9b1f6b1b + hermes-engine: f9312a2ea8036d03b63568ebf392314f4fa8b474 libevent: 4049cae6c81cdb3654a443be001fb9bdceff7913 - lottie-ios: 6bbc53eef6957e4744a50321507015fba72d8ca6 + lottie-ios: 9ae750cdc7820fecbd3c2f0cfc493038208fcdc4 lottie-react-native: b702fab740cdb952a8e2354713d3beda63ff97b0 - RCT-Folly: b9d9fe1fc70114b751c076104e52f3b1b5e5a95a - RCTRequired: bd9d2ab0fda10171fcbcf9ba61a7df4dc15a28f4 - RCTTypeSafety: e44e139bf6ec8042db396201834fc2372f6a21cd - React: 482cd1ba23c471be1aed3800180be2427418d7be - React-bridging: c2ea4fed6fe4ed27c12fd71e88b5d5d3da107fde - React-callinvoker: d4d1f98163fb5e35545e910415ef6c04796bb188 - React-Codegen: ff35fb9c7f6ec2ed34fb6de2e1099d88dfb25f2f - React-Core: 4d3443a45b67c71d74d7243ddde9569d1e4f4fad - React-CoreModules: 70be25399366b5632ab18ecf6fe444a8165a7bea - React-cxxreact: 822d3794fc0bf206f4691592f90e086dd4f92228 - React-hermes: 7f67b8363288258c3b0cd4aef5975cb7f0b9549a - React-jsi: ffa51cbc9a78cc156cf61f79ed52ecb76dc6013b - React-jsiexecutor: a27badbbdbc0ff781813370736a2d1c7261181d4 - React-jsinspector: 8a3d3f5dcd23a91e8c80b1bf0e96902cd1dca999 - React-logger: 1088859f145b8f6dd0d3ed051a647ef0e3e80fad - react-native-safe-area-context: 6c12e3859b6f27b25de4fee8201cfb858432d8de - React-perflogger: cb386fd44c97ec7f8199c04c12b22066b0f2e1e0 - React-RCTActionSheet: f803a85e46cf5b4066c2ac5e122447f918e9c6e5 - React-RCTAnimation: 19c80fa950ccce7f4db76a2a7f2cf79baae07fc7 - React-RCTBlob: f36ab97e2d515c36df14a1571e50056be80413d5 - React-RCTImage: 2c8f0a329a116248e82f8972ffe806e47c6d1cfa - React-RCTLinking: 670f0223075aff33be3b89714f1da4f5343fc4af - React-RCTNetwork: 09385b73f4ff1f46bd5d749540fb33f69a7e5908 - React-RCTSettings: 33b12d3ac7a1f2eba069ec7bd1b84345263b3bbe - React-RCTText: a1a3ea902403bd9ae4cf6f7960551dc1d25711b5 - React-RCTVibration: 9adb4a3cbb598d1bbd46a05256f445e4b8c70603 - React-runtimeexecutor: 61ee22a8cdf8b6bb2a7fb7b4ba2cc763e5285196 - ReactCommon: 8f67bd7e0a6afade0f20718f859dc8c2275f2e83 - RNCAsyncStorage: d81ee5c3db1060afd49ea7045ad460eff82d2b7d - RNCMaskedView: cb9670ea9239998340eaab21df13fa12a1f9de15 - RNGestureHandler: bad495418bcbd3ab47017a38d93d290ebd406f50 - RNReanimated: 7faa787e8d4493fbc95fab2ad331fa7625828cfa - RNScreens: 4a1af06327774490d97342c00aee0c2bafb497b7 - RNSVG: 42a0c731b11179ebbd27a3eeeafa7201ebb476ff - Yoga: ff994563b2fd98c982ca58e8cd9db2cdaf4dda74 + RCT-Folly: 0080d0a6ebf2577475bda044aa59e2ca1f909cda + RCTRequired: d4033a367d0bfd1f23f67b501f8cdabf9afe617e + RCTTypeSafety: b112b2ccc59309a65284280c0a53baf1ce4b5860 + React: 04474547a4729eef1fb378ca42f302f4b3219eb8 + React-bridging: 1c8695b292b4a9baaca3960f6166d9766e20492d + React-callinvoker: 4d91e2db7773ee3fcea2d3a5c6beb52a5bfd4d71 + React-Codegen: 33356335c6f3b0869cb4434055fdec219139f635 + React-Core: 634b8aa20e1dad445425ee9581f4719bcfd1b19b + React-CoreModules: 746825283de4b54dcb4fd88703ff516297a5f60d + React-cxxreact: f8d2686d98b5ffed1b1de3aa62e1f81db4903153 + React-hermes: 4e9f5f9cfff42a23e7d6d8083e6c8a3f6f4926ee + React-jsi: 198b9b3e0a85e68cb6898265400fd8bf34cacda4 + React-jsiexecutor: 53bd208e5c27939c6e6365528393445a596a9a2b + React-jsinspector: 26c42646ab0bb69e29e837e23754fe7121eeaf94 + React-logger: 1bfd109a0ffa4c0989bbfac0c2d8c4abe4637faa + react-native-safe-area-context: 99b24a0c5acd0d5dcac2b1a7f18c49ea317be99a + React-perflogger: 6009895616a455781293950bbd63d53cfc7ffbc5 + React-RCTActionSheet: 5e90aa5712af18bfc86c2c6d97d4dbe0e5451c1d + React-RCTAnimation: 50c44d6501f8bfb2fe885e544501f8798b4ff3d6 + React-RCTBlob: 3cc08e7112dd7b77faf3fa481ba22ca2bba5f20a + React-RCTImage: ca8335860b5f64c383ad27f52a28d85089d49b7a + React-RCTLinking: 297cd91bdbf427efc861fc7943e6d683e61860fa + React-RCTNetwork: 8a197bff6f1dc5353484507a4cdcd47e9356316f + React-RCTSettings: d3db1f1e61a5ad8deb50f44f5cb6c7c3ef32b3ac + React-RCTText: c2c05ab3dbfb1cf5855b14802f392148970e48da + React-RCTVibration: 89e2cbea456ac5ec623943661d00e4dc45fe74b9 + React-runtimeexecutor: 80065f60af4f4b05603661070c8622bb3740bf16 + ReactCommon: 1209130f460e4aa9d255ddc75fa0a827ebf93dfb + RNCAsyncStorage: 0c357f3156fcb16c8589ede67cc036330b6698ca + RNCMaskedView: bc0170f389056201c82a55e242e5d90070e18e5a + RNGestureHandler: 7673697e7c0e9391adefae4faa087442bc04af33 + RNReanimated: 60e291d42c77752a0f6d6f358387bdf225a87c6e + RNScreens: f3230dd008a7d0ce5c0a8bc78ff12cf2315bda24 + RNSVG: 1869ad9534459f24caaa0416a4764548c2aeedad + Yoga: 043f8eb97345d0171f27fead4d1849cacf0472a5 PODFILE CHECKSUM: b77befb1871220c1a94408eeae0857d78b685698 diff --git a/apps/mobile/ios/Spacedrive.xcodeproj/project.pbxproj b/apps/mobile/ios/Spacedrive.xcodeproj/project.pbxproj index 003b6e4b7..ecaea1a36 100644 --- a/apps/mobile/ios/Spacedrive.xcodeproj/project.pbxproj +++ b/apps/mobile/ios/Spacedrive.xcodeproj/project.pbxproj @@ -366,6 +366,7 @@ "@executable_path/Frameworks", ); LIBRARY_SEARCH_PATHS = ( + "$(SDKROOT)/usr/lib/swift", "$(inherited)", "\"${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/DoubleConversion\"", @@ -455,6 +456,7 @@ "@executable_path/Frameworks", ); LIBRARY_SEARCH_PATHS = ( + "$(SDKROOT)/usr/lib/swift", "$(inherited)", "\"${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/DoubleConversion\"", @@ -579,7 +581,7 @@ /usr/lib/swift, "$(inherited)", ); - LIBRARY_SEARCH_PATHS = "\"$(inherited)\""; + LIBRARY_SEARCH_PATHS = "$(SDKROOT)/usr/lib/swift\"$(inherited)\""; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native"; @@ -633,7 +635,7 @@ /usr/lib/swift, "$(inherited)", ); - LIBRARY_SEARCH_PATHS = "\"$(inherited)\""; + LIBRARY_SEARCH_PATHS = "$(SDKROOT)/usr/lib/swift\"$(inherited)\""; MTL_ENABLE_DEBUG_INFO = NO; REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native"; SDKROOT = iphoneos; diff --git a/apps/mobile/package.json b/apps/mobile/package.json index 97ae939b7..3f676c2f3 100644 --- a/apps/mobile/package.json +++ b/apps/mobile/package.json @@ -10,60 +10,63 @@ "lint": "eslint src/**/*.{ts,tsx} && tsc --noEmit" }, "dependencies": { - "@gorhom/bottom-sheet": "^4.4.3", - "@react-native-async-storage/async-storage": "~1.17.3", - "@react-native-masked-view/masked-view": "0.2.7", - "@react-navigation/bottom-tabs": "^6.3.3", - "@react-navigation/drawer": "^6.4.4", - "@react-navigation/native": "^6.0.12", - "@react-navigation/stack": "^6.2.3", + "@gorhom/bottom-sheet": "^4.4.5", + "@react-native-async-storage/async-storage": "~1.17.10", + "@react-native-masked-view/masked-view": "0.2.8", + "@react-navigation/bottom-tabs": "^6.4.0", + "@react-navigation/drawer": "^6.5.0", + "@react-navigation/native": "^6.0.13", + "@react-navigation/stack": "^6.3.2", "@rspc/client": "^0.1.2", "@rspc/react": "^0.1.2", "@sd/assets": "file:../../packages/assets", - "@tanstack/react-query": "^4.2.3", + "@tanstack/react-query": "^4.10.1", "byte-size": "^8.1.0", "class-variance-authority": "^0.2.3", + "clsx": "^1.2.1", "dayjs": "^1.11.5", - "expo": "~46.0.10", + "expo": "~46.0.15", "expo-linking": "~3.2.2", "expo-splash-screen": "~0.16.2", "expo-status-bar": "~1.4.0", "immer": "^9.0.15", "intl": "^1.2.5", "lottie-react-native": "^5.1.4", - "moti": "^0.18.0", + "moti": "^0.20.0", "phosphor-react-native": "^1.1.2", - "react": "18.0.0", - "react-native": "0.69.4", - "react-native-gesture-handler": "~2.5.0", - "react-native-heroicons": "^2.2.0", + "react": "18.2.0", + "react-loading-skeleton": "^3.1.0", + "react-native": "0.70.2", + "react-native-gesture-handler": "~2.7.0", + "react-native-heroicons": "^3.2.0", "react-native-reanimated": "~2.10.0", - "react-native-safe-area-context": "4.3.1", - "react-native-screens": "~3.15.0", - "react-native-svg": "13.0.0", + "react-native-safe-area-context": "4.4.1", + "react-native-screens": "~3.18.0", + "react-native-svg": "13.3.0", "twrnc": "^3.4.0", "use-count-up": "^3.0.1", "valtio": "^1.7.0", - "valtio-persist": "^1.0.2" + "valtio-persist": "^1.0.2", + "zustand": "^4.1.1" }, "devDependencies": { - "@babel/core": "^7.18.6", - "@babel/runtime": "^7.18.9", - "@rnx-kit/metro-config": "^1.2.37", + "@babel/core": "^7.19.3", + "@babel/runtime": "^7.19.0", + "@rnx-kit/metro-config": "^1.3.1", "@rnx-kit/metro-resolver-symlinks": "^0.1.21", - "@types/react": "~18.0.0", - "@types/react-native": "~0.69.1", - "@typescript-eslint/eslint-plugin": "^5.30.7", - "@typescript-eslint/parser": "^5.30.7", + "@types/react": "~18.0.21", + "@types/react-native": "~0.70.4", + "@typescript-eslint/eslint-plugin": "^5.39.0", + "@typescript-eslint/parser": "^5.39.0", "babel-plugin-module-resolver": "^4.1.0", - "eslint": "^8.21.0", + "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", "eslint-plugin-react-native": "^4.0.0", - "metro-minify-terser": "^0.72.1", + "metro-minify-terser": "^0.73.0", "react-native-svg-transformer": "^1.0.0", - "typescript": "^4.7.4" + "typescript": "^4.8.4" }, "private": true } diff --git a/apps/mobile/pnpm-lock.yaml b/apps/mobile/pnpm-lock.yaml index fd4ed81a51eee68b033ab7ce1b5583d708c68d07..9106e63e3b8791b945e03be64721ba081314e1f7 100644 GIT binary patch delta 35141 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 delta 35195 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 json, - Err(err) => { - println!("Failed to serialize event: {}", err); - continue; - } - }; + RUNTIME.spawn(async move { + while let Some(event) = rx.recv().await { + let data = match serde_json::to_string(&event) { + Ok(json) => json, + Err(err) => { + println!("Failed to serialize event: {}", err); + continue; + } + }; - let env = jvm.attach_current_thread().unwrap(); - env.call_method( - &class, - "sendCoreEvent", - "(Ljava/lang/String;)V", - &[env - .new_string(data) - .expect("Couldn't create java string!") - .into()], - ) - .unwrap(); - } + let env = jvm.attach_current_thread().unwrap(); + env.call_method( + &class, + "sendCoreEvent", + "(Ljava/lang/String;)V", + &[env + .new_string(data) + .expect("Couldn't create java string!") + .into()], + ) + .unwrap(); + } + }); }); + + if let Err(err) = result { + // TODO: Send rspc error or something here so we can show this in the UI. + // TODO: Maybe reinitialise the core cause it could be in an invalid state? + println!( + "Error in Java_com_spacedrive_app_SDCore_registerCoreEventListener: {:?}", + err + ); + } } #[no_mangle] @@ -45,46 +58,76 @@ 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 - .get_string(query) - .expect("Couldn't get java string!") - .into(); - let class = env.new_global_ref(class).unwrap(); + let result = panic::catch_unwind(|| { + let jvm = env.get_java_vm().unwrap(); + let query: String = env + .get_string(query) + .expect("Couldn't get java string!") + .into(); + let class = env.new_global_ref(class).unwrap(); - RUNTIME.spawn(async move { - let request: Request = serde_json::from_str(&query).unwrap(); + RUNTIME.spawn(async move { + let request: Request = serde_json::from_str(&query).unwrap(); - let node = &mut *NODE.lock().await; - let (node, router) = match node { - Some(node) => node.clone(), - None => { - let data_dir: String = { + let node = &mut *NODE.lock().await; + let (node, router) = match node { + Some(node) => node.clone(), + None => { + let data_dir: String = { + let env = jvm.attach_current_thread().unwrap(); + let data_dir = env + .call_method(&class, "getDataDirectory", "()Ljava/lang/String;", &[]) + .unwrap() + .l() + .unwrap(); + + env.get_string(data_dir.into()).unwrap().into() + }; + + let new_node = Node::new(data_dir).await.unwrap(); + node.replace(new_node.clone()); + new_node + } + }; + + let mut channel = EVENT_SENDER.get().unwrap().clone(); + let mut resp = Sender::ResponseAndChannel(None, &mut channel); + handle_json_rpc( + node.get_request_context(), + request, + &router, + &mut resp, + &mut SubscriptionMap::Mutex(&SUBSCRIPTIONS), + ) + .await; + + match resp { + Sender::Response(Some(resp)) => { let env = jvm.attach_current_thread().unwrap(); - let data_dir = env - .call_method(&class, "getDataDirectory", "()Ljava/lang/String;", &[]) - .unwrap() - .l() - .unwrap(); - - env.get_string(data_dir.into()).unwrap().into() - }; - - let new_node = Node::new(data_dir).await.unwrap(); - node.replace(new_node.clone()); - new_node + env.call_method( + &callback, + "resolve", + "(Ljava/lang/Object;)V", + &[env + .new_string(serde_json::to_vec(&resp).unwrap()) + .expect("Couldn't create java string!") + .into()], + ) + .unwrap(); + } + _ => unreachable!(), } - }; - - handle_json_rpc( - node.get_request_context(), - request, - &router, - &mut Sender::ResponseChannel(&mut EVENT_SENDER.get().unwrap().clone()), - &mut SubscriptionMap::Mutex(&SUBSCRIPTIONS), - ) - .await; + }); }); + + if let Err(err) = result { + // TODO: Send rspc error or something here so we can show this in the UI. + // TODO: Maybe reinitialise the core cause it could be in an invalid state? + println!( + "Error in Java_com_spacedrive_app_SDCore_registerCoreEventListener: {:?}", + err + ); + } } diff --git a/apps/mobile/rust/src/ios.rs b/apps/mobile/rust/src/ios.rs index 19d26d8eb..a21ead310 100644 --- a/apps/mobile/rust/src/ios.rs +++ b/apps/mobile/rust/src/ios.rs @@ -1,16 +1,16 @@ -use crate::{CLIENT_CONTEXT, EVENT_SENDER, NODE, RUNTIME}; +use crate::{EVENT_SENDER, NODE, RUNTIME, SUBSCRIPTIONS}; +use objc::{msg_send, runtime::Object, sel, sel_impl}; +use objc_foundation::{INSString, NSString}; +use objc_id::Id; +use rspc::internal::jsonrpc::{handle_json_rpc, Request, Sender, SubscriptionMap}; +use sd_core::Node; use std::{ ffi::{CStr, CString}, os::raw::{c_char, c_void}, + panic, }; use tokio::sync::mpsc::unbounded_channel; -use objc::{class, msg_send, runtime::Object, sel, sel_impl}; -use objc_foundation::{INSString, NSString}; -use objc_id::Id; -use rspc::Request; -use sd_core::Node; - extern "C" { fn get_data_directory() -> *const c_char; fn call_resolve(resolve: *const c_void, result: *const c_char); @@ -33,64 +33,81 @@ impl RNPromise { #[no_mangle] pub unsafe extern "C" fn register_core_event_listener(id: *mut Object) { - let id = Id::::from_ptr(id); + let result = panic::catch_unwind(|| { + let id = Id::::from_ptr(id); - let (tx, mut rx) = unbounded_channel(); - let _ = EVENT_SENDER.set(tx); + let (tx, mut rx) = unbounded_channel(); + let _ = EVENT_SENDER.set(tx); - RUNTIME.spawn(async move { - while let Some(event) = rx.recv().await { - let data = match serde_json::to_string(&event) { - Ok(json) => json, - Err(err) => { - println!("Failed to serialize event: {}", err); - continue; - } - }; - let data = NSString::from_str(&data); - let _: () = msg_send![id, sendCoreEvent: data]; - } + RUNTIME.spawn(async move { + while let Some(event) = rx.recv().await { + let data = match serde_json::to_string(&event) { + Ok(json) => json, + Err(err) => { + println!("Failed to serialize event: {}", err); + continue; + } + }; + let data = NSString::from_str(&data); + let _: () = msg_send![id, sendCoreEvent: data]; + } + }); }); + + if let Err(err) = result { + // TODO: Send rspc error or something here so we can show this in the UI. + // TODO: Maybe reinitialise the core cause it could be in an invalid state? + println!("Error in register_core_event_listener: {:?}", err); + } } #[no_mangle] pub unsafe extern "C" fn sd_core_msg(query: *const c_char, resolve: *const c_void) { - // This string is cloned to the Rust heap. This is important as Objective-C may remove the query once this function completions but prior to the async block finishing. - let query = CStr::from_ptr(query).to_str().unwrap().to_string(); + let result = panic::catch_unwind(|| { + // This string is cloned to the Rust heap. This is important as Objective-C may remove the query once this function completions but prior to the async block finishing. + let query = CStr::from_ptr(query).to_str().unwrap().to_string(); - let resolve = RNPromise(resolve); - RUNTIME.spawn(async move { - let request: Request = serde_json::from_str(&query).unwrap(); + let resolve = RNPromise(resolve); + RUNTIME.spawn(async move { + let request: Request = serde_json::from_str(&query).unwrap(); - let node = &mut *NODE.lock().await; - let (node, router) = match node { - Some(node) => node.clone(), - None => { - let doc_dir = CStr::from_ptr(get_data_directory()) - .to_str() - .unwrap() - .to_string(); - let new_node = Node::new(doc_dir).await.unwrap(); - node.replace(new_node.clone()); - new_node - } - }; + let node = &mut *NODE.lock().await; + let (node, router) = match node { + Some(node) => node.clone(), + None => { + let doc_dir = CStr::from_ptr(get_data_directory()) + .to_str() + .unwrap() + .to_string(); + let new_node = Node::new(doc_dir).await.unwrap(); + node.replace(new_node.clone()); + new_node + } + }; - resolve.resolve( - CString::new( - serde_json::to_vec( - &request - .handle( - node.get_request_context(), - &router, - &CLIENT_CONTEXT, - EVENT_SENDER.get(), - ) - .await, - ) - .unwrap(), + let mut channel = EVENT_SENDER.get().unwrap().clone(); + let mut resp = Sender::ResponseAndChannel(None, &mut channel); + handle_json_rpc( + node.get_request_context(), + request, + &router, + &mut resp, + &mut SubscriptionMap::Mutex(&SUBSCRIPTIONS), ) - .unwrap(), - ) + .await; + + match resp { + Sender::ResponseAndChannel(Some(resp), _) => { + resolve.resolve(CString::new(serde_json::to_vec(&resp).unwrap()).unwrap()); + } + _ => unreachable!(), + } + }); }); + + if let Err(err) = result { + // TODO: Send rspc error or something here so we can show this in the UI. + // TODO: Maybe reinitialise the core cause it could be in an invalid state? + println!("Error in sd_core_msg: {:?}", err); + } } diff --git a/apps/mobile/src/hooks/rspc.ts b/apps/mobile/src/hooks/rspc.ts index 613ea1390..774f03b7c 100644 --- a/apps/mobile/src/hooks/rspc.ts +++ b/apps/mobile/src/hooks/rspc.ts @@ -14,28 +14,28 @@ 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 { - clientSubscriptionCallback?: (id: string, key: string, value: any) => void; + clientSubscriptionCallback?: (id: string, value: any) => void; constructor() { const subscriptionEventListener = eventEmitter.addListener('SDCoreEvent', (event) => { - const body = JSON.parse(event); - if (body.type === 'event') { - const { id, key, result } = body; - this.clientSubscriptionCallback(id, key, result); - } else if (body.type === 'response' || body.type === 'error') { + const { id, result } = JSON.parse(event); + if (result.type === 'event') { + if (this.clientSubscriptionCallback) this.clientSubscriptionCallback(id, result.data); + } else if (result.type === 'response' || result.type === 'error') { throw new Error( - `Recieved event of type '${body.type}'. This should be impossible with the React Native transport!` + `Recieved event of type '${result.type}'. This should be impossible with the React Native transport!` ); } else { - console.error(`Received event of unknown method '${body.type}'`); + console.error(`Received event of unknown method '${result.type}'`); } }); } async doRequest(operation: OperationType, key: string, input: any): Promise { - const body = JSON.parse( + const resp = JSON.parse( await SDCore.sd_core_msg( JSON.stringify({ + id: null, method: operation, params: { path: key, @@ -44,11 +44,13 @@ export class ReactNativeTransport implements Transport { }) ) ); + + const body = resp.result; if (body.type === 'error') { - const { status_code, message } = body; - throw new RSPCError(status_code, message); + const { code, message } = body; + throw new RSPCError(code, message); } else if (body.type === 'response') { - return body.result; + return body.data; } else if (body.type !== 'none') { throw new Error(`RSPC ReactNative doRequest received invalid body type '${body?.type}'`); } diff --git a/apps/mobile/src/navigation/TabNavigator.tsx b/apps/mobile/src/navigation/TabNavigator.tsx index d8760a9ed..ecc2f6628 100644 --- a/apps/mobile/src/navigation/TabNavigator.tsx +++ b/apps/mobile/src/navigation/TabNavigator.tsx @@ -1,7 +1,7 @@ import { BottomTabScreenProps, createBottomTabNavigator } from '@react-navigation/bottom-tabs'; import { CompositeScreenProps, NavigatorScreenParams } from '@react-navigation/native'; import { CirclesFour, Folder, Planet } from 'phosphor-react-native'; -import { PhotographIcon } from 'react-native-heroicons/outline'; +import { PhotoIcon } from 'react-native-heroicons/outline'; import tw from '~/lib/tailwind'; import type { HomeDrawerScreenProps } from './DrawerNavigator'; @@ -65,7 +65,7 @@ export default function TabNavigator() { component={PhotosStack} options={{ tabBarIcon: ({ focused }) => ( - + ), tabBarLabel: 'Photos' }} diff --git a/apps/mobile/src/screens/Overview.tsx b/apps/mobile/src/screens/Overview.tsx index fffec0059..05666fe54 100644 --- a/apps/mobile/src/screens/Overview.tsx +++ b/apps/mobile/src/screens/Overview.tsx @@ -1,214 +1,65 @@ -import { ExclamationCircleIcon, PlusIcon } from '@heroicons/react/24/solid'; -import { useBridgeQuery, useLibraryQuery, usePlatform } from '@sd/client'; -import { Statistics } from '@sd/client'; -import { Button, Input } from '@sd/ui'; -import byteSize from 'byte-size'; -import clsx from 'clsx'; -import { useEffect } from 'react'; -import Skeleton from 'react-loading-skeleton'; -import 'react-loading-skeleton/dist/skeleton.css'; -import create from 'zustand'; +import React from 'react'; +import { FlatList, View } from 'react-native'; +import Device from '~/components/device/Device'; +import VirtualizedListWrapper from '~/components/layout/VirtualizedListWrapper'; +import OverviewStats from '~/containers/OverviewStats'; +import tw from '~/lib/tailwind'; +import { OverviewStackScreenProps } from '~/navigation/tabs/OverviewStack'; -import { Device } from '../components/device/Device'; -import Dialog from '../components/layout/Dialog'; -import useCounter from '../hooks/useCounter'; - -interface StatItemProps { - title: string; - bytes: string; - isLoading: boolean; -} - -const StatItemNames: Partial> = { - total_bytes_capacity: 'Total capacity', - preview_media_bytes: 'Preview media', - library_db_size: 'Index size', - total_bytes_free: 'Free space' +const placeholderOverviewStats = { + id: 1, + total_bytes_capacity: '8093333345230', + preview_media_bytes: '2304387532', + library_db_size: '83345230', + total_file_count: 20342345, + total_bytes_free: '89734502034', + total_bytes_used: '8093333345230', + total_unique_bytes: '9347397', + date_captured: '2020-01-01' }; -type OverviewStats = Partial>; -type OverviewState = { - overviewStats: OverviewStats; - setOverviewStat: (name: keyof OverviewStats, newValue: string) => void; - setOverviewStats: (stats: OverviewStats) => void; -}; - -export const useOverviewState = create((set) => ({ - overviewStats: {}, - setOverviewStat: (name, newValue) => - set((state) => ({ - ...state, - overviewStats: { - ...state.overviewStats, - [name]: newValue - } - })), - setOverviewStats: (stats) => - set((state) => ({ - ...state, - overviewStats: stats - })) -})); - -const StatItem: React.FC = (props) => { - const { title, bytes = '0', isLoading } = props; - - // const appProps = useContext(AppPropsContext); - - const size = byteSize(+bytes); - - const count = useCounter({ - name: title, - end: +size.value - }); +const placeholderDevices: any = [ + { + name: "James' iPhone 12", + size: '47.9GB', + locations: [], + type: 'phone' + }, + { + name: "James' MacBook Pro", + size: '1TB', + locations: [], + type: 'laptop' + }, + { + name: "James' Toaster", + size: '1PB', + locations: [], + type: 'desktop' + }, + { + name: 'Spacedrive Server', + size: '5GB', + locations: [], + type: 'server' + } +]; +export default function OverviewScreen({ navigation }: OverviewStackScreenProps<'Overview'>) { return ( -
- {title} - - {isLoading && ( -
- -
- )} -
- {count} - {size.unit} -
-
-
- ); -}; - -export default function OverviewScreen() { - const platform = usePlatform(); - const { data: libraryStatistics, isLoading: isStatisticsLoading } = useLibraryQuery([ - 'library.getStatistics' - ]); - const { data: nodeState } = useBridgeQuery(['getNode']); - - const { overviewStats, setOverviewStats } = useOverviewState(); - - // get app props from context - useEffect(() => { - if (platform.demoMode === true) { - if (!Object.entries(overviewStats).length) - setOverviewStats({ - total_bytes_capacity: '8093333345230', - preview_media_bytes: '2304387532', - library_db_size: '83345230', - total_file_count: '20342345', - total_bytes_free: '89734502034', - total_bytes_used: '8093333345230', - total_unique_bytes: '9347397' - }); - } else { - const newStatistics: OverviewStats = { - total_bytes_capacity: '0', - preview_media_bytes: '0', - library_db_size: '0', - total_file_count: '0', - total_bytes_free: '0', - total_bytes_used: '0', - total_unique_bytes: '0' - }; - - Object.entries((libraryStatistics as Statistics) || {}).forEach(([key, value]) => { - newStatistics[key as keyof Statistics] = `${value}`; - }); - - setOverviewStats(newStatistics); - } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [platform, libraryStatistics]); - - // useEffect(() => { - // setTimeout(() => { - // setOverviewStat('total_bytes_capacity', '4093333345230'); - // }, 2000); - // }, [overviewStats]); - - const displayableStatItems = Object.keys(StatItemNames) as unknown as keyof typeof StatItemNames; - - return ( -
-
- {/* PAGE */} -
- {/* STAT HEADER */} -
- {/* STAT CONTAINER */} -
- {Object.entries(overviewStats).map(([key, value]) => { - if (!displayableStatItems.includes(key)) return null; - - return ( - - ); - })} -
- -
-
-
- {}} - ctaLabel="Connect" - trigger={ - - } - > -
-
- - This Device - - -
-
- - Enter a device code - - -
-
-
-
-
-
-
- - - -
-
- Note: This is a pre-alpha build of Spacedrive, many features are yet to be - functional. -
-
-
-
+ + + {/* Stats */} + + {/* Devices */} + index.toString()} + renderItem={({ item }) => ( + + )} + /> + + ); } diff --git a/core/Cargo.toml b/core/Cargo.toml index 6a8e4db2b..32157f382 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -62,6 +62,8 @@ globset = { version = "^0.4.9", features = ["serde1"] } itertools = "^0.10.5" enumflags2 = "0.7.5" +openssl-sys = "0.9.76" # We don't use this in the core but it exists so that the workspace level patch doesn't complain that the dependency isn't used. + [dev-dependencies] tempfile = "^3.3.0" tracing-test = "^0.2.3" diff --git a/core/src/api/utils/library.rs b/core/src/api/utils/library.rs index f776f4967..aff888476 100644 --- a/core/src/api/utils/library.rs +++ b/core/src/api/utils/library.rs @@ -1,7 +1,12 @@ +use std::sync::Arc; + use futures::{Future, Stream}; use rspc::{ - internal::{specta, BuiltProcedureBuilder, MiddlewareBuilderLike, UnbuiltProcedureBuilder}, - ErrorCode, RequestLayer, SerializeMarker, Type, + internal::{ + specta, BuiltProcedureBuilder, MiddlewareBuilderLike, RequestResult, + UnbuiltProcedureBuilder, + }, + ErrorCode, Type, }; use serde::{de::DeserializeOwned, Deserialize, Serialize}; use uuid::Uuid; @@ -17,38 +22,47 @@ pub(crate) struct LibraryArgs { // 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( + fn library_query( self, key: &'static str, - builder: fn(UnbuiltProcedureBuilder) -> BuiltProcedureBuilder, + builder: impl FnOnce( + UnbuiltProcedureBuilder, + ) -> BuiltProcedureBuilder, ) -> Self where - TArg: DeserializeOwned + specta::Type + Send + 'static, - TResult: Future> + Send + 'static, - T: RequestLayer + Serialize + specta::Type + Send, - TResolver: Fn(Ctx, TArg, LibraryContext) -> TResult + Send + Sync + 'static; + TUnbuiltResolver: Fn(Ctx, TArg, LibraryContext) -> TUnbuiltResult + Send, + TBuiltResolver: Fn(Ctx, TArg, LibraryContext) -> TUnbuiltResult + Send + Sync + 'static, + TUnbuiltResult: RequestResult + Send, + TArg: DeserializeOwned + specta::Type + Send + 'static; - fn library_mutation( + fn library_mutation< + TUnbuiltResolver, + TUnbuiltResult, + TUnbuiltResultMarker, + TBuiltResolver, + TArg, + >( self, key: &'static str, - builder: fn(UnbuiltProcedureBuilder) -> BuiltProcedureBuilder, + builder: impl FnOnce( + UnbuiltProcedureBuilder, + ) -> BuiltProcedureBuilder, ) -> Self where - TArg: DeserializeOwned + specta::Type + Send + 'static, - TResult: Future> + Send + 'static, - T: RequestLayer + Serialize + specta::Type + Send, - TResolver: Fn(Ctx, TArg, LibraryContext) -> TResult + Send + Sync + 'static; + TUnbuiltResolver: Fn(Ctx, TArg, LibraryContext) -> TUnbuiltResult + Send, + TBuiltResolver: Fn(Ctx, TArg, LibraryContext) -> TUnbuiltResult + Send + Sync + 'static, + TUnbuiltResult: RequestResult + Send, + TArg: DeserializeOwned + specta::Type + Send + 'static; fn library_subscription( self, key: &'static str, - builder: fn(UnbuiltProcedureBuilder) -> BuiltProcedureBuilder, + builder: impl Fn(UnbuiltProcedureBuilder) -> BuiltProcedureBuilder, ) -> Self where TArg: DeserializeOwned + specta::Type + 'static, - TStream: Stream + Sync + Send + 'static, + TStream: Stream + Send + Sync + 'static, TResult: Serialize + specta::Type, - // TODO: This should take the 'LibraryContext' not 'Uuid' TResolver: Fn(Ctx, TArg, Uuid) -> TStream + Send + Sync + 'static; } @@ -57,62 +71,88 @@ impl LibraryRequest for rspc::RouterBuilder where TMiddleware: MiddlewareBuilderLike + Send + 'static, { - fn library_query( + fn library_query( self, key: &'static str, - builder: fn(UnbuiltProcedureBuilder) -> BuiltProcedureBuilder, + builder: impl FnOnce( + UnbuiltProcedureBuilder, + ) -> BuiltProcedureBuilder, ) -> Self where + TUnbuiltResolver: Fn(Ctx, TArg, LibraryContext) -> TUnbuiltResult + Send, + TBuiltResolver: Fn(Ctx, TArg, LibraryContext) -> TUnbuiltResult + Send + Sync + 'static, + TUnbuiltResult: RequestResult + Send, TArg: DeserializeOwned + specta::Type + Send + 'static, - TResult: Future> + Send + 'static, - T: RequestLayer + Serialize + specta::Type + Send, - TResolver: Fn(Ctx, TArg, LibraryContext) -> TResult + Send + Sync + 'static, { self.query(key, move |t| { - t(move |ctx, arg: LibraryArgs| 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(), - ) - })?; + let resolver = Arc::new(builder(UnbuiltProcedureBuilder::new(t.data())).resolver); - let resolver = builder(UnbuiltProcedureBuilder::default()).resolver; - resolver(ctx, arg.arg, library).await + t(move |ctx, arg: LibraryArgs| { + let resolver = resolver.clone(); + 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(), + ) + })?; + + Ok(resolver(ctx, arg.arg, library) + .into_request_future()? + .exec() + .await?) + } }) }) } - fn library_mutation( + fn library_mutation< + TUnbuiltResolver, + TUnbuiltResult, + TUnbuiltResultMarker, + TBuiltResolver, + TArg, + >( self, key: &'static str, - builder: fn(UnbuiltProcedureBuilder) -> BuiltProcedureBuilder, + builder: impl FnOnce( + UnbuiltProcedureBuilder, + ) -> BuiltProcedureBuilder, ) -> Self where + TUnbuiltResolver: Fn(Ctx, TArg, LibraryContext) -> TUnbuiltResult + Send, + TBuiltResolver: Fn(Ctx, TArg, LibraryContext) -> TUnbuiltResult + Send + Sync + 'static, + TUnbuiltResult: RequestResult + Send, TArg: DeserializeOwned + specta::Type + Send + 'static, - TResult: Future> + Send + 'static, - T: RequestLayer + Serialize + specta::Type + Send, - TResolver: Fn(Ctx, TArg, LibraryContext) -> TResult + Send + Sync + 'static, { self.mutation(key, move |t| { - t(move |ctx, arg: LibraryArgs| 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(), - ) - })?; + let resolver = Arc::new(builder(UnbuiltProcedureBuilder::new(t.data())).resolver); - let resolver = builder(UnbuiltProcedureBuilder::default()).resolver; - resolver(ctx, arg.arg, library).await + t(move |ctx, arg: LibraryArgs| { + let resolver = resolver.clone(); + 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(), + ) + })?; + + Ok(resolver(ctx, arg.arg, library) + .into_request_future()? + .exec() + .await?) + } }) }) } @@ -120,15 +160,17 @@ where fn library_subscription( self, key: &'static str, - builder: fn(UnbuiltProcedureBuilder) -> BuiltProcedureBuilder, + builder: impl Fn(UnbuiltProcedureBuilder) -> BuiltProcedureBuilder, ) -> Self where TArg: DeserializeOwned + specta::Type + 'static, - TStream: Stream + Sync + Send + 'static, + TStream: Stream + Send + Sync + 'static, TResult: Serialize + specta::Type, TResolver: Fn(Ctx, TArg, Uuid) -> TStream + Send + Sync + 'static, { self.subscription(key, |t| { + let resolver = Arc::new(builder(UnbuiltProcedureBuilder::new(t.data())).resolver); + t(move |ctx, arg: LibraryArgs| { // TODO(@Oscar): Upstream rspc work to allow this to work // let library = ctx @@ -142,7 +184,6 @@ where // ) // })?; - let resolver = builder(UnbuiltProcedureBuilder::default()).resolver; resolver(ctx, arg.arg, arg.library_id) }) }) From 90644be566bdb4c07bb681202085751ca06e3a60 Mon Sep 17 00:00:00 2001 From: Oscar Beaumont Date: Fri, 7 Oct 2022 04:56:59 +0800 Subject: [PATCH 11/11] Expo committed cringe --- apps/desktop/src-tauri/.env.example | 1 - apps/mobile/android/app/build.gradle | 2 +- .../main/java/com/spacedrive/app/SDCore.java | 7 +- apps/mobile/ios/Podfile.lock | 554 +++++++++--------- apps/mobile/package.json | 63 +- apps/mobile/pnpm-lock.yaml | Bin 327477 -> 324647 bytes apps/mobile/rust/src/android.rs | 23 +- apps/mobile/src/navigation/TabNavigator.tsx | 4 +- package.json | 1 + 9 files changed, 337 insertions(+), 318 deletions(-) delete mode 100644 apps/desktop/src-tauri/.env.example diff --git a/apps/desktop/src-tauri/.env.example b/apps/desktop/src-tauri/.env.example deleted file mode 100644 index dcb15beb5..000000000 --- a/apps/desktop/src-tauri/.env.example +++ /dev/null @@ -1 +0,0 @@ -RUST_LOG=spacedrive=debug,sdcore=debug \ No newline at end of file diff --git a/apps/mobile/android/app/build.gradle b/apps/mobile/android/app/build.gradle index d825f46f4..2b07ca96a 100644 --- a/apps/mobile/android/app/build.gradle +++ b/apps/mobile/android/app/build.gradle @@ -7,7 +7,7 @@ apply plugin: 'org.mozilla.rust-android-gradle.rust-android' cargo { module = "../../rust" - libname = "sdcore" + libname = "sd_core_mobile" // profile = 'release', pythonCommand = 'python3' targets = ["arm", "arm64", "x86", "x86_64"] diff --git a/apps/mobile/android/app/src/main/java/com/spacedrive/app/SDCore.java b/apps/mobile/android/app/src/main/java/com/spacedrive/app/SDCore.java index 782f44a1b..d6c9f011d 100644 --- a/apps/mobile/android/app/src/main/java/com/spacedrive/app/SDCore.java +++ b/apps/mobile/android/app/src/main/java/com/spacedrive/app/SDCore.java @@ -28,7 +28,7 @@ public class SDCore extends ReactContextBaseJavaModule { } static { - System.loadLibrary("sdcore"); + System.loadLibrary("sd_core_mobile"); } // is exposed by Rust and is used to register the subscription @@ -47,6 +47,11 @@ public class SDCore extends ReactContextBaseJavaModule { return getCurrentActivity().getFilesDir().toString(); } + public void print(String msg) + { + System.out.println(msg); + } + @ReactMethod public void addListener(String eventName) { diff --git a/apps/mobile/ios/Podfile.lock b/apps/mobile/ios/Podfile.lock index d22ee0886..9c1fd60da 100644 --- a/apps/mobile/ios/Podfile.lock +++ b/apps/mobile/ios/Podfile.lock @@ -19,325 +19,325 @@ PODS: - EXSplashScreen (0.16.2): - ExpoModulesCore - React-Core - - FBLazyVector (0.70.2) - - FBReactNativeSpec (0.70.2): - - RCT-Folly (= 2021.07.22.00) - - RCTRequired (= 0.70.2) - - RCTTypeSafety (= 0.70.2) - - React-Core (= 0.70.2) - - React-jsi (= 0.70.2) - - ReactCommon/turbomodule/core (= 0.70.2) + - FBLazyVector (0.69.4) + - FBReactNativeSpec (0.69.4): + - RCT-Folly (= 2021.06.28.00-v2) + - RCTRequired (= 0.69.4) + - RCTTypeSafety (= 0.69.4) + - React-Core (= 0.69.4) + - React-jsi (= 0.69.4) + - ReactCommon/turbomodule/core (= 0.69.4) - fmt (6.2.1) - glog (0.3.5) - - hermes-engine (0.70.2) + - hermes-engine (0.69.4) - libevent (2.1.12) - lottie-ios (3.4.3) - lottie-react-native (5.1.4): - lottie-ios (~> 3.4.0) - React-Core - - RCT-Folly (2021.07.22.00): + - RCT-Folly (2021.06.28.00-v2): - boost - DoubleConversion - fmt (~> 6.2.1) - glog - - RCT-Folly/Default (= 2021.07.22.00) - - RCT-Folly/Default (2021.07.22.00): + - RCT-Folly/Default (= 2021.06.28.00-v2) + - RCT-Folly/Default (2021.06.28.00-v2): - boost - DoubleConversion - fmt (~> 6.2.1) - glog - - RCT-Folly/Futures (2021.07.22.00): + - RCT-Folly/Futures (2021.06.28.00-v2): - boost - DoubleConversion - fmt (~> 6.2.1) - glog - libevent - - RCTRequired (0.70.2) - - RCTTypeSafety (0.70.2): - - FBLazyVector (= 0.70.2) - - RCTRequired (= 0.70.2) - - React-Core (= 0.70.2) - - React (0.70.2): - - React-Core (= 0.70.2) - - React-Core/DevSupport (= 0.70.2) - - React-Core/RCTWebSocket (= 0.70.2) - - React-RCTActionSheet (= 0.70.2) - - React-RCTAnimation (= 0.70.2) - - React-RCTBlob (= 0.70.2) - - React-RCTImage (= 0.70.2) - - React-RCTLinking (= 0.70.2) - - React-RCTNetwork (= 0.70.2) - - React-RCTSettings (= 0.70.2) - - React-RCTText (= 0.70.2) - - React-RCTVibration (= 0.70.2) - - React-bridging (0.70.2): - - RCT-Folly (= 2021.07.22.00) - - React-jsi (= 0.70.2) - - React-callinvoker (0.70.2) - - React-Codegen (0.70.2): - - FBReactNativeSpec (= 0.70.2) - - RCT-Folly (= 2021.07.22.00) - - RCTRequired (= 0.70.2) - - RCTTypeSafety (= 0.70.2) - - React-Core (= 0.70.2) - - React-jsi (= 0.70.2) - - React-jsiexecutor (= 0.70.2) - - ReactCommon/turbomodule/core (= 0.70.2) - - React-Core (0.70.2): + - RCTRequired (0.69.4) + - RCTTypeSafety (0.69.4): + - FBLazyVector (= 0.69.4) + - RCTRequired (= 0.69.4) + - React-Core (= 0.69.4) + - React (0.69.4): + - React-Core (= 0.69.4) + - React-Core/DevSupport (= 0.69.4) + - React-Core/RCTWebSocket (= 0.69.4) + - React-RCTActionSheet (= 0.69.4) + - React-RCTAnimation (= 0.69.4) + - React-RCTBlob (= 0.69.4) + - React-RCTImage (= 0.69.4) + - React-RCTLinking (= 0.69.4) + - React-RCTNetwork (= 0.69.4) + - React-RCTSettings (= 0.69.4) + - React-RCTText (= 0.69.4) + - React-RCTVibration (= 0.69.4) + - React-bridging (0.69.4): + - RCT-Folly (= 2021.06.28.00-v2) + - React-jsi (= 0.69.4) + - React-callinvoker (0.69.4) + - React-Codegen (0.69.4): + - FBReactNativeSpec (= 0.69.4) + - RCT-Folly (= 2021.06.28.00-v2) + - RCTRequired (= 0.69.4) + - RCTTypeSafety (= 0.69.4) + - React-Core (= 0.69.4) + - React-jsi (= 0.69.4) + - React-jsiexecutor (= 0.69.4) + - ReactCommon/turbomodule/core (= 0.69.4) + - React-Core (0.69.4): - glog - - RCT-Folly (= 2021.07.22.00) - - React-Core/Default (= 0.70.2) - - React-cxxreact (= 0.70.2) - - React-jsi (= 0.70.2) - - React-jsiexecutor (= 0.70.2) - - React-perflogger (= 0.70.2) + - RCT-Folly (= 2021.06.28.00-v2) + - React-Core/Default (= 0.69.4) + - React-cxxreact (= 0.69.4) + - React-jsi (= 0.69.4) + - React-jsiexecutor (= 0.69.4) + - React-perflogger (= 0.69.4) - Yoga - - React-Core/CoreModulesHeaders (0.70.2): + - React-Core/CoreModulesHeaders (0.69.4): - glog - - RCT-Folly (= 2021.07.22.00) + - RCT-Folly (= 2021.06.28.00-v2) - React-Core/Default - - React-cxxreact (= 0.70.2) - - React-jsi (= 0.70.2) - - React-jsiexecutor (= 0.70.2) - - React-perflogger (= 0.70.2) + - React-cxxreact (= 0.69.4) + - React-jsi (= 0.69.4) + - React-jsiexecutor (= 0.69.4) + - React-perflogger (= 0.69.4) - Yoga - - React-Core/Default (0.70.2): + - React-Core/Default (0.69.4): - glog - - RCT-Folly (= 2021.07.22.00) - - React-cxxreact (= 0.70.2) - - React-jsi (= 0.70.2) - - React-jsiexecutor (= 0.70.2) - - React-perflogger (= 0.70.2) + - RCT-Folly (= 2021.06.28.00-v2) + - React-cxxreact (= 0.69.4) + - React-jsi (= 0.69.4) + - React-jsiexecutor (= 0.69.4) + - React-perflogger (= 0.69.4) - Yoga - - React-Core/DevSupport (0.70.2): + - React-Core/DevSupport (0.69.4): - glog - - RCT-Folly (= 2021.07.22.00) - - React-Core/Default (= 0.70.2) - - React-Core/RCTWebSocket (= 0.70.2) - - React-cxxreact (= 0.70.2) - - React-jsi (= 0.70.2) - - React-jsiexecutor (= 0.70.2) - - React-jsinspector (= 0.70.2) - - React-perflogger (= 0.70.2) + - RCT-Folly (= 2021.06.28.00-v2) + - React-Core/Default (= 0.69.4) + - React-Core/RCTWebSocket (= 0.69.4) + - React-cxxreact (= 0.69.4) + - React-jsi (= 0.69.4) + - React-jsiexecutor (= 0.69.4) + - React-jsinspector (= 0.69.4) + - React-perflogger (= 0.69.4) - Yoga - - React-Core/RCTActionSheetHeaders (0.70.2): + - React-Core/RCTActionSheetHeaders (0.69.4): - glog - - RCT-Folly (= 2021.07.22.00) + - RCT-Folly (= 2021.06.28.00-v2) - React-Core/Default - - React-cxxreact (= 0.70.2) - - React-jsi (= 0.70.2) - - React-jsiexecutor (= 0.70.2) - - React-perflogger (= 0.70.2) + - React-cxxreact (= 0.69.4) + - React-jsi (= 0.69.4) + - React-jsiexecutor (= 0.69.4) + - React-perflogger (= 0.69.4) - Yoga - - React-Core/RCTAnimationHeaders (0.70.2): + - React-Core/RCTAnimationHeaders (0.69.4): - glog - - RCT-Folly (= 2021.07.22.00) + - RCT-Folly (= 2021.06.28.00-v2) - React-Core/Default - - React-cxxreact (= 0.70.2) - - React-jsi (= 0.70.2) - - React-jsiexecutor (= 0.70.2) - - React-perflogger (= 0.70.2) + - React-cxxreact (= 0.69.4) + - React-jsi (= 0.69.4) + - React-jsiexecutor (= 0.69.4) + - React-perflogger (= 0.69.4) - Yoga - - React-Core/RCTBlobHeaders (0.70.2): + - React-Core/RCTBlobHeaders (0.69.4): - glog - - RCT-Folly (= 2021.07.22.00) + - RCT-Folly (= 2021.06.28.00-v2) - React-Core/Default - - React-cxxreact (= 0.70.2) - - React-jsi (= 0.70.2) - - React-jsiexecutor (= 0.70.2) - - React-perflogger (= 0.70.2) + - React-cxxreact (= 0.69.4) + - React-jsi (= 0.69.4) + - React-jsiexecutor (= 0.69.4) + - React-perflogger (= 0.69.4) - Yoga - - React-Core/RCTImageHeaders (0.70.2): + - React-Core/RCTImageHeaders (0.69.4): - glog - - RCT-Folly (= 2021.07.22.00) + - RCT-Folly (= 2021.06.28.00-v2) - React-Core/Default - - React-cxxreact (= 0.70.2) - - React-jsi (= 0.70.2) - - React-jsiexecutor (= 0.70.2) - - React-perflogger (= 0.70.2) + - React-cxxreact (= 0.69.4) + - React-jsi (= 0.69.4) + - React-jsiexecutor (= 0.69.4) + - React-perflogger (= 0.69.4) - Yoga - - React-Core/RCTLinkingHeaders (0.70.2): + - React-Core/RCTLinkingHeaders (0.69.4): - glog - - RCT-Folly (= 2021.07.22.00) + - RCT-Folly (= 2021.06.28.00-v2) - React-Core/Default - - React-cxxreact (= 0.70.2) - - React-jsi (= 0.70.2) - - React-jsiexecutor (= 0.70.2) - - React-perflogger (= 0.70.2) + - React-cxxreact (= 0.69.4) + - React-jsi (= 0.69.4) + - React-jsiexecutor (= 0.69.4) + - React-perflogger (= 0.69.4) - Yoga - - React-Core/RCTNetworkHeaders (0.70.2): + - React-Core/RCTNetworkHeaders (0.69.4): - glog - - RCT-Folly (= 2021.07.22.00) + - RCT-Folly (= 2021.06.28.00-v2) - React-Core/Default - - React-cxxreact (= 0.70.2) - - React-jsi (= 0.70.2) - - React-jsiexecutor (= 0.70.2) - - React-perflogger (= 0.70.2) + - React-cxxreact (= 0.69.4) + - React-jsi (= 0.69.4) + - React-jsiexecutor (= 0.69.4) + - React-perflogger (= 0.69.4) - Yoga - - React-Core/RCTSettingsHeaders (0.70.2): + - React-Core/RCTSettingsHeaders (0.69.4): - glog - - RCT-Folly (= 2021.07.22.00) + - RCT-Folly (= 2021.06.28.00-v2) - React-Core/Default - - React-cxxreact (= 0.70.2) - - React-jsi (= 0.70.2) - - React-jsiexecutor (= 0.70.2) - - React-perflogger (= 0.70.2) + - React-cxxreact (= 0.69.4) + - React-jsi (= 0.69.4) + - React-jsiexecutor (= 0.69.4) + - React-perflogger (= 0.69.4) - Yoga - - React-Core/RCTTextHeaders (0.70.2): + - React-Core/RCTTextHeaders (0.69.4): - glog - - RCT-Folly (= 2021.07.22.00) + - RCT-Folly (= 2021.06.28.00-v2) - React-Core/Default - - React-cxxreact (= 0.70.2) - - React-jsi (= 0.70.2) - - React-jsiexecutor (= 0.70.2) - - React-perflogger (= 0.70.2) + - React-cxxreact (= 0.69.4) + - React-jsi (= 0.69.4) + - React-jsiexecutor (= 0.69.4) + - React-perflogger (= 0.69.4) - Yoga - - React-Core/RCTVibrationHeaders (0.70.2): + - React-Core/RCTVibrationHeaders (0.69.4): - glog - - RCT-Folly (= 2021.07.22.00) + - RCT-Folly (= 2021.06.28.00-v2) - React-Core/Default - - React-cxxreact (= 0.70.2) - - React-jsi (= 0.70.2) - - React-jsiexecutor (= 0.70.2) - - React-perflogger (= 0.70.2) + - React-cxxreact (= 0.69.4) + - React-jsi (= 0.69.4) + - React-jsiexecutor (= 0.69.4) + - React-perflogger (= 0.69.4) - Yoga - - React-Core/RCTWebSocket (0.70.2): + - React-Core/RCTWebSocket (0.69.4): - glog - - RCT-Folly (= 2021.07.22.00) - - React-Core/Default (= 0.70.2) - - React-cxxreact (= 0.70.2) - - React-jsi (= 0.70.2) - - React-jsiexecutor (= 0.70.2) - - React-perflogger (= 0.70.2) + - RCT-Folly (= 2021.06.28.00-v2) + - React-Core/Default (= 0.69.4) + - React-cxxreact (= 0.69.4) + - React-jsi (= 0.69.4) + - React-jsiexecutor (= 0.69.4) + - React-perflogger (= 0.69.4) - Yoga - - React-CoreModules (0.70.2): - - RCT-Folly (= 2021.07.22.00) - - RCTTypeSafety (= 0.70.2) - - React-Codegen (= 0.70.2) - - React-Core/CoreModulesHeaders (= 0.70.2) - - React-jsi (= 0.70.2) - - React-RCTImage (= 0.70.2) - - ReactCommon/turbomodule/core (= 0.70.2) - - React-cxxreact (0.70.2): + - React-CoreModules (0.69.4): + - RCT-Folly (= 2021.06.28.00-v2) + - RCTTypeSafety (= 0.69.4) + - React-Codegen (= 0.69.4) + - React-Core/CoreModulesHeaders (= 0.69.4) + - React-jsi (= 0.69.4) + - React-RCTImage (= 0.69.4) + - ReactCommon/turbomodule/core (= 0.69.4) + - React-cxxreact (0.69.4): - boost (= 1.76.0) - DoubleConversion - glog - - RCT-Folly (= 2021.07.22.00) - - React-callinvoker (= 0.70.2) - - React-jsi (= 0.70.2) - - React-jsinspector (= 0.70.2) - - React-logger (= 0.70.2) - - React-perflogger (= 0.70.2) - - React-runtimeexecutor (= 0.70.2) - - React-hermes (0.70.2): + - RCT-Folly (= 2021.06.28.00-v2) + - React-callinvoker (= 0.69.4) + - React-jsi (= 0.69.4) + - React-jsinspector (= 0.69.4) + - React-logger (= 0.69.4) + - React-perflogger (= 0.69.4) + - React-runtimeexecutor (= 0.69.4) + - React-hermes (0.69.4): - DoubleConversion - glog - hermes-engine - - RCT-Folly (= 2021.07.22.00) - - RCT-Folly/Futures (= 2021.07.22.00) - - React-cxxreact (= 0.70.2) - - React-jsi (= 0.70.2) - - React-jsiexecutor (= 0.70.2) - - React-jsinspector (= 0.70.2) - - React-perflogger (= 0.70.2) - - React-jsi (0.70.2): + - RCT-Folly (= 2021.06.28.00-v2) + - RCT-Folly/Futures (= 2021.06.28.00-v2) + - React-cxxreact (= 0.69.4) + - React-jsi (= 0.69.4) + - React-jsiexecutor (= 0.69.4) + - React-jsinspector (= 0.69.4) + - React-perflogger (= 0.69.4) + - React-jsi (0.69.4): - boost (= 1.76.0) - DoubleConversion - glog - - RCT-Folly (= 2021.07.22.00) - - React-jsi/Default (= 0.70.2) - - React-jsi/Default (0.70.2): + - RCT-Folly (= 2021.06.28.00-v2) + - React-jsi/Default (= 0.69.4) + - React-jsi/Default (0.69.4): - boost (= 1.76.0) - DoubleConversion - glog - - RCT-Folly (= 2021.07.22.00) - - React-jsiexecutor (0.70.2): + - RCT-Folly (= 2021.06.28.00-v2) + - React-jsiexecutor (0.69.4): - DoubleConversion - glog - - RCT-Folly (= 2021.07.22.00) - - React-cxxreact (= 0.70.2) - - React-jsi (= 0.70.2) - - React-perflogger (= 0.70.2) - - React-jsinspector (0.70.2) - - React-logger (0.70.2): + - RCT-Folly (= 2021.06.28.00-v2) + - React-cxxreact (= 0.69.4) + - React-jsi (= 0.69.4) + - React-perflogger (= 0.69.4) + - React-jsinspector (0.69.4) + - React-logger (0.69.4): - glog - - react-native-safe-area-context (4.4.1): + - react-native-safe-area-context (4.3.1): - RCT-Folly - RCTRequired - RCTTypeSafety - - React-Core + - React - ReactCommon/turbomodule/core - - React-perflogger (0.70.2) - - React-RCTActionSheet (0.70.2): - - React-Core/RCTActionSheetHeaders (= 0.70.2) - - React-RCTAnimation (0.70.2): - - RCT-Folly (= 2021.07.22.00) - - RCTTypeSafety (= 0.70.2) - - React-Codegen (= 0.70.2) - - React-Core/RCTAnimationHeaders (= 0.70.2) - - React-jsi (= 0.70.2) - - ReactCommon/turbomodule/core (= 0.70.2) - - React-RCTBlob (0.70.2): - - RCT-Folly (= 2021.07.22.00) - - React-Codegen (= 0.70.2) - - React-Core/RCTBlobHeaders (= 0.70.2) - - React-Core/RCTWebSocket (= 0.70.2) - - React-jsi (= 0.70.2) - - React-RCTNetwork (= 0.70.2) - - ReactCommon/turbomodule/core (= 0.70.2) - - React-RCTImage (0.70.2): - - RCT-Folly (= 2021.07.22.00) - - RCTTypeSafety (= 0.70.2) - - React-Codegen (= 0.70.2) - - React-Core/RCTImageHeaders (= 0.70.2) - - React-jsi (= 0.70.2) - - React-RCTNetwork (= 0.70.2) - - ReactCommon/turbomodule/core (= 0.70.2) - - React-RCTLinking (0.70.2): - - React-Codegen (= 0.70.2) - - React-Core/RCTLinkingHeaders (= 0.70.2) - - React-jsi (= 0.70.2) - - ReactCommon/turbomodule/core (= 0.70.2) - - React-RCTNetwork (0.70.2): - - RCT-Folly (= 2021.07.22.00) - - RCTTypeSafety (= 0.70.2) - - React-Codegen (= 0.70.2) - - React-Core/RCTNetworkHeaders (= 0.70.2) - - React-jsi (= 0.70.2) - - ReactCommon/turbomodule/core (= 0.70.2) - - React-RCTSettings (0.70.2): - - RCT-Folly (= 2021.07.22.00) - - RCTTypeSafety (= 0.70.2) - - React-Codegen (= 0.70.2) - - React-Core/RCTSettingsHeaders (= 0.70.2) - - React-jsi (= 0.70.2) - - ReactCommon/turbomodule/core (= 0.70.2) - - React-RCTText (0.70.2): - - React-Core/RCTTextHeaders (= 0.70.2) - - React-RCTVibration (0.70.2): - - RCT-Folly (= 2021.07.22.00) - - React-Codegen (= 0.70.2) - - React-Core/RCTVibrationHeaders (= 0.70.2) - - React-jsi (= 0.70.2) - - ReactCommon/turbomodule/core (= 0.70.2) - - React-runtimeexecutor (0.70.2): - - React-jsi (= 0.70.2) - - ReactCommon/turbomodule/core (0.70.2): + - React-perflogger (0.69.4) + - React-RCTActionSheet (0.69.4): + - React-Core/RCTActionSheetHeaders (= 0.69.4) + - React-RCTAnimation (0.69.4): + - RCT-Folly (= 2021.06.28.00-v2) + - RCTTypeSafety (= 0.69.4) + - React-Codegen (= 0.69.4) + - React-Core/RCTAnimationHeaders (= 0.69.4) + - React-jsi (= 0.69.4) + - ReactCommon/turbomodule/core (= 0.69.4) + - React-RCTBlob (0.69.4): + - RCT-Folly (= 2021.06.28.00-v2) + - React-Codegen (= 0.69.4) + - React-Core/RCTBlobHeaders (= 0.69.4) + - React-Core/RCTWebSocket (= 0.69.4) + - React-jsi (= 0.69.4) + - React-RCTNetwork (= 0.69.4) + - ReactCommon/turbomodule/core (= 0.69.4) + - React-RCTImage (0.69.4): + - RCT-Folly (= 2021.06.28.00-v2) + - RCTTypeSafety (= 0.69.4) + - React-Codegen (= 0.69.4) + - React-Core/RCTImageHeaders (= 0.69.4) + - React-jsi (= 0.69.4) + - React-RCTNetwork (= 0.69.4) + - ReactCommon/turbomodule/core (= 0.69.4) + - React-RCTLinking (0.69.4): + - React-Codegen (= 0.69.4) + - React-Core/RCTLinkingHeaders (= 0.69.4) + - React-jsi (= 0.69.4) + - ReactCommon/turbomodule/core (= 0.69.4) + - React-RCTNetwork (0.69.4): + - RCT-Folly (= 2021.06.28.00-v2) + - RCTTypeSafety (= 0.69.4) + - React-Codegen (= 0.69.4) + - React-Core/RCTNetworkHeaders (= 0.69.4) + - React-jsi (= 0.69.4) + - ReactCommon/turbomodule/core (= 0.69.4) + - React-RCTSettings (0.69.4): + - RCT-Folly (= 2021.06.28.00-v2) + - RCTTypeSafety (= 0.69.4) + - React-Codegen (= 0.69.4) + - React-Core/RCTSettingsHeaders (= 0.69.4) + - React-jsi (= 0.69.4) + - ReactCommon/turbomodule/core (= 0.69.4) + - React-RCTText (0.69.4): + - React-Core/RCTTextHeaders (= 0.69.4) + - React-RCTVibration (0.69.4): + - RCT-Folly (= 2021.06.28.00-v2) + - React-Codegen (= 0.69.4) + - React-Core/RCTVibrationHeaders (= 0.69.4) + - React-jsi (= 0.69.4) + - ReactCommon/turbomodule/core (= 0.69.4) + - React-runtimeexecutor (0.69.4): + - React-jsi (= 0.69.4) + - ReactCommon/turbomodule/core (0.69.4): - DoubleConversion - glog - - RCT-Folly (= 2021.07.22.00) - - React-bridging (= 0.70.2) - - React-callinvoker (= 0.70.2) - - React-Core (= 0.70.2) - - React-cxxreact (= 0.70.2) - - React-jsi (= 0.70.2) - - React-logger (= 0.70.2) - - React-perflogger (= 0.70.2) + - RCT-Folly (= 2021.06.28.00-v2) + - React-bridging (= 0.69.4) + - React-callinvoker (= 0.69.4) + - React-Core (= 0.69.4) + - React-cxxreact (= 0.69.4) + - React-jsi (= 0.69.4) + - React-logger (= 0.69.4) + - React-perflogger (= 0.69.4) - RNCAsyncStorage (1.17.10): - React-Core - - RNCMaskedView (0.2.8): + - RNCMaskedView (0.2.7): - React-Core - - RNGestureHandler (2.7.0): + - RNGestureHandler (2.5.0): - React-Core - RNReanimated (2.10.0): - DoubleConversion @@ -366,10 +366,10 @@ PODS: - React-RCTText - ReactCommon/turbomodule/core - Yoga - - RNScreens (3.18.0): + - RNScreens (3.15.0): - React-Core - React-RCTImage - - RNSVG (13.3.0): + - RNSVG (13.0.0): - React-Core - Yoga (1.14.0) @@ -546,49 +546,49 @@ SPEC CHECKSUMS: ExpoKeepAwake: 0e8f18142e71bbf2c7f6aa66ebed249ba1420320 ExpoModulesCore: 2d60ec04c49641afb55fee3faac86fb108c68fe0 EXSplashScreen: 799bece80089219b2c989c1082d70f3b00995cda - FBLazyVector: 0507edc21c06f1650c591f0981c846445469373b - FBReactNativeSpec: 585ef61b9a394a9166de579a080a0df672054319 + FBLazyVector: c71b8c429a8af2aff1013934a7152e9d9d0c937d + FBReactNativeSpec: 3cc5cff7d792e74a875be91e56d6242335016f50 fmt: ff9d55029c625d3757ed641535fd4a75fedc7ce9 - glog: 04b94705f318337d7ead9e6d17c019bd9b1f6b1b - hermes-engine: f9312a2ea8036d03b63568ebf392314f4fa8b474 + glog: 3d02b25ca00c2d456734d0bcff864cbc62f6ae1a + hermes-engine: 761a544537e62df2a37189389b9d2654dc1f75af libevent: 4049cae6c81cdb3654a443be001fb9bdceff7913 lottie-ios: 9ae750cdc7820fecbd3c2f0cfc493038208fcdc4 lottie-react-native: b702fab740cdb952a8e2354713d3beda63ff97b0 - RCT-Folly: 0080d0a6ebf2577475bda044aa59e2ca1f909cda - RCTRequired: d4033a367d0bfd1f23f67b501f8cdabf9afe617e - RCTTypeSafety: b112b2ccc59309a65284280c0a53baf1ce4b5860 - React: 04474547a4729eef1fb378ca42f302f4b3219eb8 - React-bridging: 1c8695b292b4a9baaca3960f6166d9766e20492d - React-callinvoker: 4d91e2db7773ee3fcea2d3a5c6beb52a5bfd4d71 - React-Codegen: 33356335c6f3b0869cb4434055fdec219139f635 - React-Core: 634b8aa20e1dad445425ee9581f4719bcfd1b19b - React-CoreModules: 746825283de4b54dcb4fd88703ff516297a5f60d - React-cxxreact: f8d2686d98b5ffed1b1de3aa62e1f81db4903153 - React-hermes: 4e9f5f9cfff42a23e7d6d8083e6c8a3f6f4926ee - React-jsi: 198b9b3e0a85e68cb6898265400fd8bf34cacda4 - React-jsiexecutor: 53bd208e5c27939c6e6365528393445a596a9a2b - React-jsinspector: 26c42646ab0bb69e29e837e23754fe7121eeaf94 - React-logger: 1bfd109a0ffa4c0989bbfac0c2d8c4abe4637faa - react-native-safe-area-context: 99b24a0c5acd0d5dcac2b1a7f18c49ea317be99a - React-perflogger: 6009895616a455781293950bbd63d53cfc7ffbc5 - React-RCTActionSheet: 5e90aa5712af18bfc86c2c6d97d4dbe0e5451c1d - React-RCTAnimation: 50c44d6501f8bfb2fe885e544501f8798b4ff3d6 - React-RCTBlob: 3cc08e7112dd7b77faf3fa481ba22ca2bba5f20a - React-RCTImage: ca8335860b5f64c383ad27f52a28d85089d49b7a - React-RCTLinking: 297cd91bdbf427efc861fc7943e6d683e61860fa - React-RCTNetwork: 8a197bff6f1dc5353484507a4cdcd47e9356316f - React-RCTSettings: d3db1f1e61a5ad8deb50f44f5cb6c7c3ef32b3ac - React-RCTText: c2c05ab3dbfb1cf5855b14802f392148970e48da - React-RCTVibration: 89e2cbea456ac5ec623943661d00e4dc45fe74b9 - React-runtimeexecutor: 80065f60af4f4b05603661070c8622bb3740bf16 - ReactCommon: 1209130f460e4aa9d255ddc75fa0a827ebf93dfb + RCT-Folly: b9d9fe1fc70114b751c076104e52f3b1b5e5a95a + RCTRequired: bd9d2ab0fda10171fcbcf9ba61a7df4dc15a28f4 + RCTTypeSafety: e44e139bf6ec8042db396201834fc2372f6a21cd + React: 482cd1ba23c471be1aed3800180be2427418d7be + React-bridging: c2ea4fed6fe4ed27c12fd71e88b5d5d3da107fde + React-callinvoker: d4d1f98163fb5e35545e910415ef6c04796bb188 + React-Codegen: ff35fb9c7f6ec2ed34fb6de2e1099d88dfb25f2f + React-Core: 4d3443a45b67c71d74d7243ddde9569d1e4f4fad + React-CoreModules: 70be25399366b5632ab18ecf6fe444a8165a7bea + React-cxxreact: 822d3794fc0bf206f4691592f90e086dd4f92228 + React-hermes: 7f67b8363288258c3b0cd4aef5975cb7f0b9549a + React-jsi: ffa51cbc9a78cc156cf61f79ed52ecb76dc6013b + React-jsiexecutor: a27badbbdbc0ff781813370736a2d1c7261181d4 + React-jsinspector: 8a3d3f5dcd23a91e8c80b1bf0e96902cd1dca999 + React-logger: 1088859f145b8f6dd0d3ed051a647ef0e3e80fad + react-native-safe-area-context: 6c12e3859b6f27b25de4fee8201cfb858432d8de + React-perflogger: cb386fd44c97ec7f8199c04c12b22066b0f2e1e0 + React-RCTActionSheet: f803a85e46cf5b4066c2ac5e122447f918e9c6e5 + React-RCTAnimation: 19c80fa950ccce7f4db76a2a7f2cf79baae07fc7 + React-RCTBlob: f36ab97e2d515c36df14a1571e50056be80413d5 + React-RCTImage: 2c8f0a329a116248e82f8972ffe806e47c6d1cfa + React-RCTLinking: 670f0223075aff33be3b89714f1da4f5343fc4af + React-RCTNetwork: 09385b73f4ff1f46bd5d749540fb33f69a7e5908 + React-RCTSettings: 33b12d3ac7a1f2eba069ec7bd1b84345263b3bbe + React-RCTText: a1a3ea902403bd9ae4cf6f7960551dc1d25711b5 + React-RCTVibration: 9adb4a3cbb598d1bbd46a05256f445e4b8c70603 + React-runtimeexecutor: 61ee22a8cdf8b6bb2a7fb7b4ba2cc763e5285196 + ReactCommon: 8f67bd7e0a6afade0f20718f859dc8c2275f2e83 RNCAsyncStorage: 0c357f3156fcb16c8589ede67cc036330b6698ca - RNCMaskedView: bc0170f389056201c82a55e242e5d90070e18e5a - RNGestureHandler: 7673697e7c0e9391adefae4faa087442bc04af33 - RNReanimated: 60e291d42c77752a0f6d6f358387bdf225a87c6e - RNScreens: f3230dd008a7d0ce5c0a8bc78ff12cf2315bda24 - RNSVG: 1869ad9534459f24caaa0416a4764548c2aeedad - Yoga: 043f8eb97345d0171f27fead4d1849cacf0472a5 + RNCMaskedView: cb9670ea9239998340eaab21df13fa12a1f9de15 + RNGestureHandler: bad495418bcbd3ab47017a38d93d290ebd406f50 + RNReanimated: 7faa787e8d4493fbc95fab2ad331fa7625828cfa + RNScreens: 4a1af06327774490d97342c00aee0c2bafb497b7 + RNSVG: 42a0c731b11179ebbd27a3eeeafa7201ebb476ff + Yoga: ff994563b2fd98c982ca58e8cd9db2cdaf4dda74 PODFILE CHECKSUM: b77befb1871220c1a94408eeae0857d78b685698 diff --git a/apps/mobile/package.json b/apps/mobile/package.json index 3f676c2f3..49b065fb3 100644 --- a/apps/mobile/package.json +++ b/apps/mobile/package.json @@ -10,63 +10,60 @@ "lint": "eslint src/**/*.{ts,tsx} && tsc --noEmit" }, "dependencies": { - "@gorhom/bottom-sheet": "^4.4.5", - "@react-native-async-storage/async-storage": "~1.17.10", - "@react-native-masked-view/masked-view": "0.2.8", - "@react-navigation/bottom-tabs": "^6.4.0", - "@react-navigation/drawer": "^6.5.0", - "@react-navigation/native": "^6.0.13", - "@react-navigation/stack": "^6.3.2", + "@gorhom/bottom-sheet": "^4.4.3", + "@react-native-async-storage/async-storage": "~1.17.3", + "@react-native-masked-view/masked-view": "0.2.7", + "@react-navigation/bottom-tabs": "^6.3.3", + "@react-navigation/drawer": "^6.4.4", + "@react-navigation/native": "^6.0.12", + "@react-navigation/stack": "^6.2.3", "@rspc/client": "^0.1.2", "@rspc/react": "^0.1.2", "@sd/assets": "file:../../packages/assets", - "@tanstack/react-query": "^4.10.1", + "@tanstack/react-query": "^4.2.3", "byte-size": "^8.1.0", "class-variance-authority": "^0.2.3", - "clsx": "^1.2.1", - "dayjs": "^1.11.5", - "expo": "~46.0.15", + "date-fns": "^2.29.2", + "expo": "~46.0.10", "expo-linking": "~3.2.2", "expo-splash-screen": "~0.16.2", "expo-status-bar": "~1.4.0", "immer": "^9.0.15", "intl": "^1.2.5", "lottie-react-native": "^5.1.4", - "moti": "^0.20.0", + "moti": "^0.18.0", "phosphor-react-native": "^1.1.2", - "react": "18.2.0", - "react-loading-skeleton": "^3.1.0", - "react-native": "0.70.2", - "react-native-gesture-handler": "~2.7.0", - "react-native-heroicons": "^3.2.0", + "react": "18.0.0", + "react-native": "0.69.4", + "react-native-gesture-handler": "~2.5.0", + "react-native-heroicons": "^2.2.0", "react-native-reanimated": "~2.10.0", - "react-native-safe-area-context": "4.4.1", - "react-native-screens": "~3.18.0", - "react-native-svg": "13.3.0", + "react-native-safe-area-context": "4.3.1", + "react-native-screens": "~3.15.0", + "react-native-svg": "13.0.0", "twrnc": "^3.4.0", "use-count-up": "^3.0.1", "valtio": "^1.7.0", - "valtio-persist": "^1.0.2", - "zustand": "^4.1.1" + "valtio-persist": "^1.0.2" }, "devDependencies": { - "@babel/core": "^7.19.3", - "@babel/runtime": "^7.19.0", - "@rnx-kit/metro-config": "^1.3.1", + "@babel/core": "^7.18.6", + "@babel/runtime": "^7.18.9", + "@rnx-kit/metro-config": "^1.2.37", "@rnx-kit/metro-resolver-symlinks": "^0.1.21", - "@types/react": "~18.0.21", - "@types/react-native": "~0.70.4", - "@typescript-eslint/eslint-plugin": "^5.39.0", - "@typescript-eslint/parser": "^5.39.0", + "@types/react": "~18.0.0", + "@types/react-native": "~0.69.1", + "@typescript-eslint/eslint-plugin": "^5.30.7", + "@typescript-eslint/parser": "^5.30.7", "babel-plugin-module-resolver": "^4.1.0", - "eslint": "^8.24.0", + "eslint": "^8.21.0", "eslint-config-prettier": "^8.5.0", - "eslint-plugin-react": "^7.31.8", + "eslint-plugin-react": "^7.30.1", "eslint-plugin-react-hooks": "^4.6.0", "eslint-plugin-react-native": "^4.0.0", - "metro-minify-terser": "^0.73.0", + "metro-minify-terser": "^0.72.1", "react-native-svg-transformer": "^1.0.0", - "typescript": "^4.8.4" + "typescript": "^4.7.4" }, "private": true } diff --git a/apps/mobile/pnpm-lock.yaml b/apps/mobile/pnpm-lock.yaml index 9106e63e3b8791b945e03be64721ba081314e1f7..f635ed63ae932954f37865dbfc12f87aa608d4b2 100644 GIT binary patch delta 11129 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 OzPI@R`0VTGFa2Nnj#W_r delta 11094 zcmc(Fd9>r^b>G1QW=6Bm=*_;q(K4D5HID#60Hoxxhx@*O3%E#@1_VKH0f>zxmdK72 zTU9JImPU;IIjJp6ZPF@@7pZN+x~(j!O??`U8(ZpVq$=k|e9OG; z&Xs%VRX;$EVarnu**YyEI}qy1zlRWV@y0H5#0!J9vE-_6`W$jIO0E*qr+0a#=+YA? zfv-+4?>aR7;?m~nE4vO%UtZdYG5D%~%I`ip#dq&P?ghk?$SLr^r;*LzJHLf&#z-hL zc;r7Iw@yEZW(h$yZ72w_>RTnYtt|f9ywf)q_XuK@TE8ipa&I_-cc**z?3;cYWl&-@ zFui~sosw7@%${7@Iei5C(mrw(Uw=VSM?E+khcesSPfhJj2T%LnerSliFghoze7iT4 z&Y1&I7Dwt34xcaW(&qis?{3Es2E2F>J1~85(|&}3HxEqnJGNtRgm3;2`00LR$MpDS z9QDIjke$ajeHgwQfR7GuzH@~jS4sG@h6JWh?mYO!mh*d8R@^aE<**GWfp5TfUV8u0 zX?e@BBLiEojaHA;jrN%DkeWSl{dTLzyZRM#(sPaa*8Y2a%gJMb`)GGyOC(9Pd6A|~ z*Xp&!PIv4d50!<{rr{g*9r0^an;Hx(P3%pKk=zzKqTlxWL|0rJQ$)6|(5uuce&5(N zpe9-(>2@WXk!g!=I}?Va_#QabLT*3u92EFFG5wp{{vdgM!LI=cR4xwHV9C0`^qA2|SA>COj0M3RIg^%bi_>4(e#-~t zzD1LL->}_whkn)R7%k1;R~fzUtbc3)Droxv#PSssUJqyxD{#ie(+l$#AXpZl+da4R zwf7HzT}@>91Ovxke?1U^`{wvuffj%R+Y^a2+NvO0v|m=nj>${Hu3%Yr)w>^;bBEAxm#Y&_-4iNJBp8%0Bt|A4X*8%VD0xbB61kn4=x-)_HQ86^tt$H@QDM+ z*EW#p^5Ed??;J$%y))8-#J0m&$o|(e;AtB9&p!iJI233fL~Z~VXk-(3fkE~mK|uTu z8biuzatW4Fq;9Ct)raL8*Ro0zE!u7c zQk6R2tEB4jM806xhlxzCZjSLtqXKjTISC#JBR6jf&ix6T`mLoS;3pT5W$={%B3+rA zP6XSOC5mm9j^$jEX*TLcJQ=C_q6yN`C+)21PpdvMKni7>mpy91Gms>{BI((1M$N@4 zuD2Y(GiFYVcx6vcE%gOLbFa>g!nr}{Bgg^pN)O!umhVKKfHNaHTs6~8;#AYB1}hrw zlxaI%!&|!0EOH~f5y>!;)n}w(X-xE^`Mhs1mbx7}E8z{(7c@eXQIp{cL@`4NM8V^l zj1wO^G8?S|eHA$lK9WEVgXUdG6VA2wo9NkUSmA|MZ{YBD$!}8rfle^l7~TrQX#y>w zFVIX-6iGU&59*$JukYiMNoSaKE7~}k4mfl#net5ta>9>ex&E;0@6&{DOufCzqd<8d zvURakm@gazkG~H&u~7QjwgieFKn`9t!l~)OxAxDDoJWet6(eLFe|spGnoTAy4C0+~ zZOBKdux+~Im>BfdgftyuOru6s)s{XSDlvB$oe-%8u7)c*AxT5UP3hxYu$^X`c(o-o zMYcas=c-r$;3#kx=?aq_hbC6MoocJz3h$QBtf=arLGhIF+-bHD|2>1=saNU5Y^xOtyr zm7-0r%@w+0m&)>;vcHj2jDCvmcL+jF0X~d`uPT4d1E$~p?>B%4Vi*RzA((l6>O8U= zeDfjn7VzBTAfU(9k4q2A~B}4p_yo8qhuo~ z=UJyDcgjpCmtgV{HXmpWeB)XzomOh02~GMk@oYpLTIqz4?GET>J~tQYPVi<7*|r%b zk8>AU;O1S1*{+BqL%nkaUuAsY*(h=Z@qzDt3_S$*0TMjdMpnSZUqQFSglaM1(j(|G zIN%G9phw}Q7(@Q>icRYsvRl=wLNM6nlv=@5I(faydQ7`J9tCr$q@2pTvdV;9TUMmt zBv|!MMpl|jms7f2gUb6Z+jt*?1FQ>brd`N z4ye!21akgugyT$;=sJ#HXpEeIzZet}x~JX=a4o#-#XB84%e6T+mQ%9*Dnpo&V53r< z5d1LRZaO2n6C78IlTgqjdK;;_MTN(>F&WoW;H3|tC&0Io$om12LcV%sy_u-fiU;e- z3E#=aQdzUr%UCXzQd@10WS97&GxWPsm{IWpRvUf9l0^s;3Sa_w;v7eldhzU;|{Tb8X5MnSF= zm{#5sZ%(RKGardasfN+BJ0;cA>*&$yB#@^^S(`5vaNXji_pwz=F2y$t3d;H4aL-+YT%2LJ3l zvJZSAk9>N=q(Sq8L0iu;S0AMCw| zoCaUG2ibg+m!4<)w5_$CCb=VW&RpiWUy9ATkt3JK!T9!K9 z^OtvkA8o^K03Y}kvTL@bheS4SK=HxTABT{7M1}0&{|r)dCi1F=6c23_eJ+0oeq8?; z@`-oI`);BFypJLT3=;gK$Y0EM{08#l&9K;WDT17-y3{DsY01fKg6@w@Ux*cYYSi+> zEzTEnJ8~g7^am*?@90jhQ5uv}TqRql{kddV)N>kTbqWniF}n_)FbmQ!UalMU3|n5? zSRa2JxncU&u1&LNeiQM16oqv!@K#~TQ;i8F+MxJAt50iV(h*GF8}kYoE-|i1&2+PE zI@Lz9FfbF|YBJT!zzxAI*^RX3aAB*#vtnT)b$L115d?p+*On!BEQMGQ`U`XgT$o~8 zLGci}ZT4q}mR`RBeB($m2Fw7T6X8Bj#bSd>-bv;Y@nY1M^a$Q| zz20G)4c==CkqmFzHKCs7Yr}jx7}SPrKFAFfU9~)#rzppZF`8s)rPAe_mPu4RNxP#- zqawKcS>(ia$go%LzklWZ=L!Gp^_!QD9G-pU{8IdZwP5Z4@=_I=Y4*qqOWxbInj=FL zz4&SXJh*A;Hnm2lqoG2!Nol!at{>~MiEN}^E^~~Q3df{UiEs?iPLYFQF} za;@5Hb}CYJQc5R1b*Wi1x~jfL*na)BrM*aC_S>&5-FRWP$%B4>)9i5qec>j+Ww7O0 zxq|*vbR$@wT7j_6*HK{uSi|sk5Zt$nZ3q9WfgXgAUZIhLGfxwZ?ts2~Dsx-4SSgfz zu4UnqbgL$cIa1FD@meO9wYBFWjYTrFyOH7Kg*GsRy${lnj$XLuXs1aM?qS%Hz7i zkGd_tWER@pnkg5?DYH=ylq7Jz3)j51Opix&nyxjdPkQ}Yi6bL}XlpF;^?E|)++;8j zqI_&kuSlVSR8BTDs$b)yR+bIunwf*rX;#@u#r@fACdj8qF~rn)g7mGK@rPY>H;f!V z?V=udxpWV9rV=wlDK0uNQe7zm30)wWsnl}eemX&y&z=0!y?po#^#-SL$?UD}ayv55)ze*&59zwDvs;Vi^M=)Nl)XwHt{t#uCc zpa{v_D+weIzS>83t*<^aZq&k%XN3KptX<9tO`@&T_!bwl^O1g2Br}dFsj&zY+G9B> z!DsmGP+ljfM7JFD+l@(`@RanXVOI%_$NMZ*$auUoc=gStlc4%B^wb$cG*x*b8f&a< zm0bAKg2m^D*myW`Su-1PN)V|$>*O_!)gqA9lAv+eL8oM6;cBoueD zPAnHqv|x$4L3{I}t#v!ub~;;;x&vNKm#9!Fp6jLTsub*`8eVP96!#v(R=^u)(S6{x z*I_EY>2{O^&pftt5Cm>V{|NlfnWejqtVy-*>w>CiP`(%o$vL6_y z*p{1eBke?ELKU@8-P`QN{a(3J(=(;oxGN8eetz8L8h%l4hcbQ2bc(j0k|eD^;9|HI z=!S~XW&_+Sqc^QXy;_V9c-=P$k|n;-^N6}WVyaa|cOa*a490dk%bP4kd2D`Csg^wz zw(N+NVMTEH#?aHqSe~Antz>06Ax!ikD>QqxMmJ%Brz6-o;8D?4cQrj zZ>K}1w-s;ZMsNWMHfchwdss(-yuBT4D^!tdB$Aq6Az4RHCcBYXwo{DZJ$Iz(LaF8m z6Avzkgtw&2+=QAF_~YQ=AsSeRRl8W%N4Zp>!U}y{Vwy&~8wu1&#U>Tf81+ZFaWa!g z^*Tj94X*vJ7e5XDy#GC<^snxmOQN;?Y(jmy$cS*om5%g(YVV75z`!!Hbuc zmH~boJN(ISA)7Z{wbD3k2OTewPw8r-qS4J7p_*x?N;QpoB9v|wSTF0!I2E4TEl-pg zR%yAtHf#nHaT1rOg=>BS%BH*2{F89L?ovUTCH!I!ids%&6?E zbu#8q8VVDNYlQ<1N=%m6A~`QCB-SS&bKOZa)3I}sZ_KonN?VH;I_(le+4=wqMU7TImT_~5!lY57y<)MUm2!*} zZO3@2TF^6vh}k2{qd-2LV$*IjV%kw(y6Mvzg`TQZ%YzEx%wc?T`qZHdv^+-L>U8}JDZPZN1>PD|{mov~FDC2YK^t}f4nK%C z-WCHqd=}dS{`Q0DgX6 z!{vOkA2*1^sD=~$yszVAO1`2{a&rA>MAPE!AZJB0!?hgriMwwB7e9)gn!a)%2=4j_ zDy`30Gsm@lFv;|2AvsQu9Zy(l)w-i#G(*J;Qrd>;aLB1=n{~>h86%~aRTimtZQ+!*u{0HrF+9{E>wsLXV)Q;3wCE!?k74d8mNTzW)e%@}0U``#o=Jmtg$?&Z zyJ7D4@kh}+_nv&O?&iEY)l{XX$Hx<_9iaI^dF;i#MzmP#P$@f36jL=%A&?l`?NHD0 zSNOiomWEy@D^!Y1zM~~OwPHCvQu(;z4^7&2s}NS5L2VGW=GCcN!Ly&owtye)gGIN0 zl!3LrFWrvJ`+Mt6^o<&k)2DxYcJ_nMpxnMSpmK#FH&T66xz8lJ8b09^UnL2HTiX@M z5vSwXf)vbFlV*sk=R`r%3q`yUaQRTB7RUvqm}L6od@LkHbPg|iyRuR!cDd3-n!WfB z(1Pd4^&7kk#tI7GM*n&t_w_ophi_i%{BPLr1h6l+Z}!4>(C0UUPYTHL?18^R$14jy z1deaPz5-{sJUB4>$rkK+CG<>nQr9IoZ>lD{W@KbV>26E0l!z=Q^67@+8T#!) zkjr&kSB{hRC@A$KjJH}Y=PDg;KkV#QslMDTiP>-{ z3v1$;R3ElDq&QiKQdAr=QtEs%tV+QIG zT+Dd$&Fo-I_*3qp;(P}<@(pYoczhRj=R!BX81moPft{LHI=7wl!qYzU-us3{CucYI zwGG%V(Dq`#^Bz@XaQRv6bTwG7^n2qdLpC)|7W+w~T1&;7f`@JrenBNNUX4h_bAyyp zWjy>ON(bYl=`=y`G8OZ#Ru_xmU32#lcwhlfyW>P{SGU)^>~pFYba)@!k;m z4>E3%zSK33DN*A-atnRIJBMsIK z6)H4k(_w$Borx!jL`E1?+bug|SgCv>H7b_M)m}*DQcR=a6xagq=NegmH%>B!VS7S- zsXr=#?-pPQ^&M*izqcPdeRYX@udV;h4{g9AqGuua^tC;^S72Frlzir|-h zrk6GBv~?9*=Q@4#AUK+D^m{jVE4YF>uw-lEXOn}x`>$T zi1>}e*qk<9=a>ih;bH8+&TDkIh~yOkubMKEg@u5P_Y1~$P+r1!y~n*-l}^?Ll2+HCnMo3tcGdbVMHIB3Gm><$ccHo?Jfi! z2YeWEx=ly1+%>JRYkTLgUG|RF{sHjcj$)VBc=i80hFyet#(M2xJrViDaZH0ZH=n>F z^Fub&{D9H^Yl7h-#lc}-@*@}4BtLNin^#U=I)Me@<;@cq3k!g`lh|jFwLS30Q`n!v z2e5y$54?2>TVC9)ddXBj*KYZ;LADic*LpQdB#S=pP_uGjz8X}Lk#eN!=H(&Yj5J^! zp<*Ulm9$ay4ici$PWn2tQ{yx;k$(OO)A)e;J;o{4%>M?J1foEQxKU>_y{}?vYnVLvW~crQ zcK4R`5!0{3R_mfecKPerpDw{~uGPTjuh0I=H?c472l3CL%d_8o9sB;KTfFOs6}=mr zx>`WC+V#iDT242if+l ( - + ), tabBarLabel: 'Photos' }} diff --git a/package.json b/package.json index a000e359d..eb0f93568 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ "client": "pnpm --filter @sd/client -- ", "server": "pnpm --filter @sd/server -- ", "prisma": "cd core && cargo prisma", + "codegen": "cargo test api::tests::test_and_export_rspc_bindings -- --exact", "typecheck": "pnpm -r exec tsc" }, "devDependencies": {