fix: app hang when loading

This commit is contained in:
reya
2024-07-31 10:13:48 +07:00
parent 48eb2f5339
commit db4a7c1037
14 changed files with 181 additions and 219 deletions

View File

@@ -14,10 +14,8 @@
"@radix-ui/react-avatar": "^1.1.0",
"@radix-ui/react-dialog": "^1.1.1",
"@radix-ui/react-scroll-area": "^1.1.0",
"@tanstack/query-sync-storage-persister": "^5.51.15",
"@tanstack/react-query": "^5.51.15",
"@tanstack/react-query-persist-client": "^5.51.15",
"@tanstack/react-router": "^1.45.11",
"@tanstack/react-router": "^1.45.15",
"@tauri-apps/api": "2.0.0-beta.15",
"@tauri-apps/plugin-clipboard-manager": "2.1.0-beta.5",
"@tauri-apps/plugin-dialog": "2.0.0-beta.7",
@@ -36,7 +34,7 @@
},
"devDependencies": {
"@biomejs/biome": "1.8.3",
"@tanstack/router-plugin": "^1.45.8",
"@tanstack/router-plugin": "^1.45.13",
"@tauri-apps/cli": "2.0.0-beta.22",
"@types/react": "npm:types-react@rc",
"@types/react-dom": "npm:types-react-dom@rc",

189
pnpm-lock.yaml generated
View File

@@ -20,18 +20,12 @@ importers:
'@radix-ui/react-scroll-area':
specifier: ^1.1.0
version: 1.1.0(react-dom@19.0.0-rc-d025ddd3-20240722(react@19.0.0-rc-d025ddd3-20240722))(react@19.0.0-rc-d025ddd3-20240722)(types-react-dom@19.0.0-rc.1)(types-react@19.0.0-rc.1)
'@tanstack/query-sync-storage-persister':
specifier: ^5.51.15
version: 5.51.15
'@tanstack/react-query':
specifier: ^5.51.15
version: 5.51.15(react@19.0.0-rc-d025ddd3-20240722)
'@tanstack/react-query-persist-client':
specifier: ^5.51.15
version: 5.51.15(@tanstack/react-query@5.51.15(react@19.0.0-rc-d025ddd3-20240722))(react@19.0.0-rc-d025ddd3-20240722)
'@tanstack/react-router':
specifier: ^1.45.11
version: 1.45.11(react-dom@19.0.0-rc-d025ddd3-20240722(react@19.0.0-rc-d025ddd3-20240722))(react@19.0.0-rc-d025ddd3-20240722)
specifier: ^1.45.15
version: 1.45.15(react-dom@19.0.0-rc-d025ddd3-20240722(react@19.0.0-rc-d025ddd3-20240722))(react@19.0.0-rc-d025ddd3-20240722)
'@tauri-apps/api':
specifier: 2.0.0-beta.15
version: 2.0.0-beta.15
@@ -82,8 +76,8 @@ importers:
specifier: 1.8.3
version: 1.8.3
'@tanstack/router-plugin':
specifier: ^1.45.8
version: 1.45.8(vite@5.3.5)
specifier: ^1.45.13
version: 1.45.13(vite@5.3.5)
'@tauri-apps/cli':
specifier: 2.0.0-beta.22
version: 2.0.0-beta.22
@@ -138,12 +132,12 @@ packages:
resolution: {integrity: sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==}
engines: {node: '>=6.9.0'}
'@babel/compat-data@7.25.0':
resolution: {integrity: sha512-P4fwKI2mjEb3ZU5cnMJzvRsRKGBUcs8jvxIoRmr6ufAY9Xk2Bz7JubRTTivkw55c7WQJfTECeqYVa+HZ0FzREg==}
'@babel/compat-data@7.25.2':
resolution: {integrity: sha512-bYcppcpKBvX4znYaPEeFau03bp89ShqNMLs+rmdptMw+heSZh9+z84d2YG+K7cYLbWwzdjtDoW/uqZmPjulClQ==}
engines: {node: '>=6.9.0'}
'@babel/core@7.24.9':
resolution: {integrity: sha512-5e3FI4Q3M3Pbr21+5xJwCv6ZT6KmGkI0vw3Tozy5ODAQFTIWe37iT8Cr7Ice2Ntb+M3iSKCEWMB1MBgKrW3whg==}
'@babel/core@7.25.2':
resolution: {integrity: sha512-BBt3opiCOxUr9euZ5/ro/Xv8/V7yJ5bjYMqG/C1YAo8MIKAnumZalCN+msbci3Pigy4lIQfPUpfMM27HMGaYEA==}
engines: {node: '>=6.9.0'}
'@babel/generator@7.2.0':
@@ -153,16 +147,16 @@ packages:
resolution: {integrity: sha512-3LEEcj3PVW8pW2R1SR1M89g/qrYk/m/mB/tLqn7dn4sbBUQyTqnlod+II2U4dqiGtUmkcnAmkMDralTFZttRiw==}
engines: {node: '>=6.9.0'}
'@babel/helper-compilation-targets@7.24.8':
resolution: {integrity: sha512-oU+UoqCHdp+nWVDkpldqIQL/i/bvAv53tRqLG/s+cOXxe66zOYLU7ar/Xs3LdmBihrUMEUhwu6dMZwbNOYDwvw==}
'@babel/helper-compilation-targets@7.25.2':
resolution: {integrity: sha512-U2U5LsSaZ7TAt3cfaymQ8WHh0pxvdHoEk6HVpaexxixjyEquMh0L0YNJNM6CTGKMXV1iksi0iZkGw4AcFkPaaw==}
engines: {node: '>=6.9.0'}
'@babel/helper-module-imports@7.24.7':
resolution: {integrity: sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA==}
engines: {node: '>=6.9.0'}
'@babel/helper-module-transforms@7.25.0':
resolution: {integrity: sha512-bIkOa2ZJYn7FHnepzr5iX9Kmz8FjIz4UKzJ9zhX3dnYuVW0xul9RuR3skBfoLu+FPTQw90EHW9rJsSZhyLQ3fQ==}
'@babel/helper-module-transforms@7.25.2':
resolution: {integrity: sha512-BjyRAbix6j/wv83ftcVJmBt72QtHI56C7JXZoG2xATiLpmoC7dpd8WnkikExHDVPpi/3qCmO6WY1EaXOluiecQ==}
engines: {node: '>=6.9.0'}
peerDependencies:
'@babel/core': ^7.0.0
@@ -228,12 +222,12 @@ packages:
resolution: {integrity: sha512-aOOgh1/5XzKvg1jvVz7AVrx2piJ2XBi227DHmbY6y+bM9H2FlN+IfecYu4Xl0cNiiVejlsCri89LUsbj8vJD9Q==}
engines: {node: '>=6.9.0'}
'@babel/traverse@7.25.1':
resolution: {integrity: sha512-LrHHoWq08ZpmmFqBAzN+hUdWwy5zt7FGa/hVwMcOqW6OVtwqaoD5utfuGYU87JYxdZgLUvktAsn37j/sYR9siA==}
'@babel/traverse@7.25.2':
resolution: {integrity: sha512-s4/r+a7xTnny2O6FcZzqgT6nE4/GHEdcqj4qAeglbUOh0TeglEfmNJFAd/OLoVtGd6ZhAO8GCVvCNUO5t/VJVQ==}
engines: {node: '>=6.9.0'}
'@babel/types@7.25.0':
resolution: {integrity: sha512-LcnxQSsd9aXOIgmmSpvZ/1yo46ra2ESYyqLcryaBZOghxy5qqOBjvCWP5JfkI8yl9rlxRgdLTTMCQQRcN2hdCg==}
'@babel/types@7.25.2':
resolution: {integrity: sha512-YTnYtra7W9e6/oAZEHj0bJehPRUlLH9/fbpT5LfB0NhQXyALCRkRs3zH9v07IYhkgpqX6Z78FnuccZr/l4Fs4Q==}
engines: {node: '>=6.9.0'}
'@biomejs/biome@1.8.3':
@@ -789,25 +783,13 @@ packages:
'@tanstack/query-core@5.51.15':
resolution: {integrity: sha512-xyobHDJ0yhPE3+UkSQ2/4X1fLSg7ICJI5J1JyU9yf7F3deQfEwSImCDrB1WSRrauJkMtXW7YIEcC0oA6ZZWt5A==}
'@tanstack/query-persist-client-core@5.51.15':
resolution: {integrity: sha512-y/gsUFINiVkxV06Jz5TqFNrXbKs81lIfj7PDamheEk+vWTmlBKTh0rMXthoDdUIVm4JO0+No9CXYahRSm683pg==}
'@tanstack/query-sync-storage-persister@5.51.15':
resolution: {integrity: sha512-Jrqqv4zBQQmfkuArsx++JQfKi1nobFGry9T702c4h80jA01MGnAd2Eev6uG7mRYor4vnUzjP1CrGS+xzRq5oMQ==}
'@tanstack/react-query-persist-client@5.51.15':
resolution: {integrity: sha512-SxSfGc9JggTUzv/dwIirKdMOe47OAdT0LBaVrkowI9QdVxJByjo+uaPCXZLoTlkaclvzFxd4G3YmmjsHXV/33A==}
peerDependencies:
'@tanstack/react-query': ^5.51.15
react: ^18 || ^19
'@tanstack/react-query@5.51.15':
resolution: {integrity: sha512-UgFg23SrdIYrmfTSxAUn9g+J64VQy11pb9/EefoY/u2+zWuNMeqEOnvpJhf52XQy0yztQoyM9p6x8PFyTNaxXg==}
peerDependencies:
react: ^18.0.0
'@tanstack/react-router@1.45.11':
resolution: {integrity: sha512-unVxPYsOwwMnyAW/ZeOCymWpstEV0tiUexUPqiCuYwb2rCwsrmjsgB4tIpVONHabPlFKrxoMbkUh5UCSpL0h+w==}
'@tanstack/react-router@1.45.15':
resolution: {integrity: sha512-QVftG8QlD8u3QB38ZkpyWUHEuuaq12fsxm7Nr52pkxueKM099j8pqouoqLb6nDDyLC54/PhLZxavrIeH7aaqaA==}
engines: {node: '>=12'}
peerDependencies:
react: '>=18'
@@ -823,8 +805,8 @@ packages:
resolution: {integrity: sha512-5B756YXpZO0/yr7ahsxXoBOCpqroLx/D3l6X9qPlZaP0FVHVmTR6ZKGRX6zzuAxns/VO+sxnQso4AYLdDyZ9GA==}
engines: {node: '>=12'}
'@tanstack/router-plugin@1.45.8':
resolution: {integrity: sha512-mncDu49pBEivRHWVOdCl9fHwtyUT3QLZ0X+gYIsm7o6LhT6i7BzC++BZqOOSrjDcyXy3dx2Nf/FMrB06qlXx9Q==}
'@tanstack/router-plugin@1.45.13':
resolution: {integrity: sha512-7IWdtIDC5jjhD6IZ5c/s11xNwvKDom/p6ZOO78FxeeA0FIaSx+3AQD7/iVhzfiRfepqGmecLn9a1KfNTFGQI/A==}
engines: {node: '>=12'}
peerDependencies:
'@rsbuild/core': '>=0.7.9'
@@ -1049,8 +1031,8 @@ packages:
resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==}
engines: {node: '>= 6'}
caniuse-lite@1.0.30001643:
resolution: {integrity: sha512-ERgWGNleEilSrHM6iUz/zJNSQTP8Mr21wDWpdgvRwcTXGAq6jMtOUPP4dqFPTdKqZ2wKTdtB+uucZ3MRpAUSmg==}
caniuse-lite@1.0.30001644:
resolution: {integrity: sha512-YGvlOZB4QhZuiis+ETS0VXR+MExbFf4fZYYeMTEE0aTQd/RdIjkTyZjLrbYVKnHzppDvnOhritRVv+i7Go6mHw==}
chalk@2.4.2:
resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==}
@@ -1124,8 +1106,8 @@ packages:
eastasianwidth@0.2.0:
resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==}
electron-to-chromium@1.5.2:
resolution: {integrity: sha512-kc4r3U3V3WLaaZqThjYz/Y6z8tJe+7K0bbjUVo3i+LWIypVdMx5nXCkwRe6SWbY6ILqLdc1rKcKmr3HoH7wjSQ==}
electron-to-chromium@1.5.4:
resolution: {integrity: sha512-orzA81VqLyIGUEA77YkVA1D+N+nNfl2isJVjjmOyrlxuooZ19ynb+dOlaDTqd/idKRS9lDCSBmtzM+kyCsMnkA==}
emoji-regex@8.0.0:
resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
@@ -1770,20 +1752,20 @@ snapshots:
'@babel/highlight': 7.24.7
picocolors: 1.0.1
'@babel/compat-data@7.25.0': {}
'@babel/compat-data@7.25.2': {}
'@babel/core@7.24.9':
'@babel/core@7.25.2':
dependencies:
'@ampproject/remapping': 2.3.0
'@babel/code-frame': 7.24.7
'@babel/generator': 7.25.0
'@babel/helper-compilation-targets': 7.24.8
'@babel/helper-module-transforms': 7.25.0(@babel/core@7.24.9)
'@babel/helper-compilation-targets': 7.25.2
'@babel/helper-module-transforms': 7.25.2(@babel/core@7.25.2)
'@babel/helpers': 7.25.0
'@babel/parser': 7.25.0
'@babel/template': 7.25.0
'@babel/traverse': 7.25.1
'@babel/types': 7.25.0
'@babel/traverse': 7.25.2
'@babel/types': 7.25.2
convert-source-map: 2.0.0
debug: 4.3.6
gensync: 1.0.0-beta.2
@@ -1794,7 +1776,7 @@ snapshots:
'@babel/generator@7.2.0':
dependencies:
'@babel/types': 7.25.0
'@babel/types': 7.25.2
jsesc: 2.5.2
lodash: 4.17.21
source-map: 0.5.7
@@ -1802,14 +1784,14 @@ snapshots:
'@babel/generator@7.25.0':
dependencies:
'@babel/types': 7.25.0
'@babel/types': 7.25.2
'@jridgewell/gen-mapping': 0.3.5
'@jridgewell/trace-mapping': 0.3.25
jsesc: 2.5.2
'@babel/helper-compilation-targets@7.24.8':
'@babel/helper-compilation-targets@7.25.2':
dependencies:
'@babel/compat-data': 7.25.0
'@babel/compat-data': 7.25.2
'@babel/helper-validator-option': 7.24.8
browserslist: 4.23.2
lru-cache: 5.1.1
@@ -1817,18 +1799,18 @@ snapshots:
'@babel/helper-module-imports@7.24.7':
dependencies:
'@babel/traverse': 7.25.1
'@babel/types': 7.25.0
'@babel/traverse': 7.25.2
'@babel/types': 7.25.2
transitivePeerDependencies:
- supports-color
'@babel/helper-module-transforms@7.25.0(@babel/core@7.24.9)':
'@babel/helper-module-transforms@7.25.2(@babel/core@7.25.2)':
dependencies:
'@babel/core': 7.24.9
'@babel/core': 7.25.2
'@babel/helper-module-imports': 7.24.7
'@babel/helper-simple-access': 7.24.7
'@babel/helper-validator-identifier': 7.24.7
'@babel/traverse': 7.25.1
'@babel/traverse': 7.25.2
transitivePeerDependencies:
- supports-color
@@ -1836,8 +1818,8 @@ snapshots:
'@babel/helper-simple-access@7.24.7':
dependencies:
'@babel/traverse': 7.25.1
'@babel/types': 7.25.0
'@babel/traverse': 7.25.2
'@babel/types': 7.25.2
transitivePeerDependencies:
- supports-color
@@ -1850,7 +1832,7 @@ snapshots:
'@babel/helpers@7.25.0':
dependencies:
'@babel/template': 7.25.0
'@babel/types': 7.25.0
'@babel/types': 7.25.2
'@babel/highlight@7.24.7':
dependencies:
@@ -1861,47 +1843,47 @@ snapshots:
'@babel/parser@7.25.0':
dependencies:
'@babel/types': 7.25.0
'@babel/types': 7.25.2
'@babel/plugin-syntax-jsx@7.24.7(@babel/core@7.24.9)':
'@babel/plugin-syntax-jsx@7.24.7(@babel/core@7.25.2)':
dependencies:
'@babel/core': 7.24.9
'@babel/core': 7.25.2
'@babel/helper-plugin-utils': 7.24.8
'@babel/plugin-syntax-typescript@7.24.7(@babel/core@7.24.9)':
'@babel/plugin-syntax-typescript@7.24.7(@babel/core@7.25.2)':
dependencies:
'@babel/core': 7.24.9
'@babel/core': 7.25.2
'@babel/helper-plugin-utils': 7.24.8
'@babel/plugin-transform-react-jsx-self@7.24.7(@babel/core@7.24.9)':
'@babel/plugin-transform-react-jsx-self@7.24.7(@babel/core@7.25.2)':
dependencies:
'@babel/core': 7.24.9
'@babel/core': 7.25.2
'@babel/helper-plugin-utils': 7.24.8
'@babel/plugin-transform-react-jsx-source@7.24.7(@babel/core@7.24.9)':
'@babel/plugin-transform-react-jsx-source@7.24.7(@babel/core@7.25.2)':
dependencies:
'@babel/core': 7.24.9
'@babel/core': 7.25.2
'@babel/helper-plugin-utils': 7.24.8
'@babel/template@7.25.0':
dependencies:
'@babel/code-frame': 7.24.7
'@babel/parser': 7.25.0
'@babel/types': 7.25.0
'@babel/types': 7.25.2
'@babel/traverse@7.25.1':
'@babel/traverse@7.25.2':
dependencies:
'@babel/code-frame': 7.24.7
'@babel/generator': 7.25.0
'@babel/parser': 7.25.0
'@babel/template': 7.25.0
'@babel/types': 7.25.0
'@babel/types': 7.25.2
debug: 4.3.6
globals: 11.12.0
transitivePeerDependencies:
- supports-color
'@babel/types@7.25.0':
'@babel/types@7.25.2':
dependencies:
'@babel/helper-string-parser': 7.24.8
'@babel/helper-validator-identifier': 7.24.7
@@ -2314,27 +2296,12 @@ snapshots:
'@tanstack/query-core@5.51.15': {}
'@tanstack/query-persist-client-core@5.51.15':
dependencies:
'@tanstack/query-core': 5.51.15
'@tanstack/query-sync-storage-persister@5.51.15':
dependencies:
'@tanstack/query-core': 5.51.15
'@tanstack/query-persist-client-core': 5.51.15
'@tanstack/react-query-persist-client@5.51.15(@tanstack/react-query@5.51.15(react@19.0.0-rc-d025ddd3-20240722))(react@19.0.0-rc-d025ddd3-20240722)':
dependencies:
'@tanstack/query-persist-client-core': 5.51.15
'@tanstack/react-query': 5.51.15(react@19.0.0-rc-d025ddd3-20240722)
react: 19.0.0-rc-d025ddd3-20240722
'@tanstack/react-query@5.51.15(react@19.0.0-rc-d025ddd3-20240722)':
dependencies:
'@tanstack/query-core': 5.51.15
react: 19.0.0-rc-d025ddd3-20240722
'@tanstack/react-router@1.45.11(react-dom@19.0.0-rc-d025ddd3-20240722(react@19.0.0-rc-d025ddd3-20240722))(react@19.0.0-rc-d025ddd3-20240722)':
'@tanstack/react-router@1.45.15(react-dom@19.0.0-rc-d025ddd3-20240722(react@19.0.0-rc-d025ddd3-20240722))(react@19.0.0-rc-d025ddd3-20240722)':
dependencies:
'@tanstack/history': 1.45.3
'@tanstack/react-store': 0.5.5(react-dom@19.0.0-rc-d025ddd3-20240722(react@19.0.0-rc-d025ddd3-20240722))(react@19.0.0-rc-d025ddd3-20240722)
@@ -2355,16 +2322,16 @@ snapshots:
prettier: 3.3.3
zod: 3.23.8
'@tanstack/router-plugin@1.45.8(vite@5.3.5)':
'@tanstack/router-plugin@1.45.13(vite@5.3.5)':
dependencies:
'@babel/core': 7.24.9
'@babel/core': 7.25.2
'@babel/generator': 7.25.0
'@babel/parser': 7.25.0
'@babel/plugin-syntax-jsx': 7.24.7(@babel/core@7.24.9)
'@babel/plugin-syntax-typescript': 7.24.7(@babel/core@7.24.9)
'@babel/plugin-syntax-jsx': 7.24.7(@babel/core@7.25.2)
'@babel/plugin-syntax-typescript': 7.24.7(@babel/core@7.25.2)
'@babel/template': 7.25.0
'@babel/traverse': 7.25.1
'@babel/types': 7.25.0
'@babel/traverse': 7.25.2
'@babel/types': 7.25.2
'@tanstack/router-generator': 1.45.7
'@types/babel__core': 7.20.5
'@types/babel__generator': 7.6.8
@@ -2453,23 +2420,23 @@ snapshots:
'@types/babel__core@7.20.5':
dependencies:
'@babel/parser': 7.25.0
'@babel/types': 7.25.0
'@babel/types': 7.25.2
'@types/babel__generator': 7.6.8
'@types/babel__template': 7.4.4
'@types/babel__traverse': 7.20.6
'@types/babel__generator@7.6.8':
dependencies:
'@babel/types': 7.25.0
'@babel/types': 7.25.2
'@types/babel__template@7.4.4':
dependencies:
'@babel/parser': 7.25.0
'@babel/types': 7.25.0
'@babel/types': 7.25.2
'@types/babel__traverse@7.20.6':
dependencies:
'@babel/types': 7.25.0
'@babel/types': 7.25.2
'@types/estree@1.0.5': {}
@@ -2499,9 +2466,9 @@ snapshots:
'@vitejs/plugin-react@4.3.1(vite@5.3.5)':
dependencies:
'@babel/core': 7.24.9
'@babel/plugin-transform-react-jsx-self': 7.24.7(@babel/core@7.24.9)
'@babel/plugin-transform-react-jsx-source': 7.24.7(@babel/core@7.24.9)
'@babel/core': 7.25.2
'@babel/plugin-transform-react-jsx-self': 7.24.7(@babel/core@7.25.2)
'@babel/plugin-transform-react-jsx-source': 7.24.7(@babel/core@7.25.2)
'@types/babel__core': 7.20.5
react-refresh: 0.14.2
vite: 5.3.5
@@ -2542,7 +2509,7 @@ snapshots:
autoprefixer@10.4.19(postcss@8.4.40):
dependencies:
browserslist: 4.23.2
caniuse-lite: 1.0.30001643
caniuse-lite: 1.0.30001644
fraction.js: 4.3.7
normalize-range: 0.1.2
picocolors: 1.0.1
@@ -2551,17 +2518,17 @@ snapshots:
babel-dead-code-elimination@1.0.6:
dependencies:
'@babel/core': 7.24.9
'@babel/core': 7.25.2
'@babel/parser': 7.25.0
'@babel/traverse': 7.25.1
'@babel/types': 7.25.0
'@babel/traverse': 7.25.2
'@babel/types': 7.25.2
transitivePeerDependencies:
- supports-color
babel-plugin-react-compiler@0.0.0-experimental-696af53-20240625:
dependencies:
'@babel/generator': 7.2.0
'@babel/types': 7.25.0
'@babel/types': 7.25.2
chalk: 4.1.2
invariant: 2.2.4
pretty-format: 24.9.0
@@ -2582,14 +2549,14 @@ snapshots:
browserslist@4.23.2:
dependencies:
caniuse-lite: 1.0.30001643
electron-to-chromium: 1.5.2
caniuse-lite: 1.0.30001644
electron-to-chromium: 1.5.4
node-releases: 2.0.18
update-browserslist-db: 1.1.0(browserslist@4.23.2)
camelcase-css@2.0.1: {}
caniuse-lite@1.0.30001643: {}
caniuse-lite@1.0.30001644: {}
chalk@2.4.2:
dependencies:
@@ -2656,7 +2623,7 @@ snapshots:
eastasianwidth@0.2.0: {}
electron-to-chromium@1.5.2: {}
electron-to-chromium@1.5.4: {}
emoji-regex@8.0.0: {}

View File

@@ -5,10 +5,10 @@ use serde::Serialize;
use std::{collections::HashSet, time::Duration};
use tauri::{Emitter, Manager, State};
use crate::Nostr;
use crate::{Nostr, BOOTSTRAP_RELAYS};
#[derive(Clone, Serialize)]
struct Payload {
struct EventPayload {
event: String,
sender: String,
}
@@ -32,7 +32,8 @@ pub async fn get_metadata(id: String, state: State<'_, Nostr>) -> Result<String,
let public_key = PublicKey::parse(&id).map_err(|e| e.to_string())?;
let filter = Filter::new().author(public_key).kind(Kind::Metadata).limit(1);
match client.get_events_of(vec![filter], Some(Duration::from_secs(2))).await {
match client.get_events_from(BOOTSTRAP_RELAYS, vec![filter], Some(Duration::from_secs(3))).await
{
Ok(events) => {
if let Some(event) = events.first() {
Ok(Metadata::from_json(&event.content).unwrap_or(Metadata::new()).as_json())
@@ -150,11 +151,16 @@ pub async fn connect_account(uri: &str, state: State<'_, Nostr>) -> Result<Strin
#[tauri::command]
#[specta::specta]
pub async fn get_contact_list(state: State<'_, Nostr>) -> Result<Vec<String>, ()> {
let contact_list = state.contact_list.lock().await;
let list = contact_list.clone().into_iter().map(|c| c.public_key.to_hex()).collect::<Vec<_>>();
pub async fn get_contact_list(state: State<'_, Nostr>) -> Result<Vec<String>, String> {
let client = &state.client;
Ok(list)
match client.get_contact_list(Some(Duration::from_secs(10))).await {
Ok(contacts) => {
let list = contacts.into_iter().map(|c| c.public_key.to_hex()).collect::<Vec<_>>();
Ok(list)
}
Err(e) => Err(e.to_string()),
}
}
#[tauri::command]
@@ -164,7 +170,7 @@ pub async fn get_inbox(id: String, state: State<'_, Nostr>) -> Result<Vec<String
let public_key = PublicKey::parse(id).map_err(|e| e.to_string())?;
let inbox = Filter::new().kind(Kind::Custom(10050)).author(public_key).limit(1);
match client.get_events_of(vec![inbox], None).await {
match client.get_events_from(BOOTSTRAP_RELAYS, vec![inbox], None).await {
Ok(events) => {
if let Some(event) = events.into_iter().next() {
let urls = event
@@ -246,14 +252,9 @@ pub async fn login(
}
}
if let Ok(contacts) = client.get_contact_list(Some(Duration::from_secs(10))).await {
let mut contact_list = state.contact_list.lock().await;
*contact_list = contacts;
};
let inbox = Filter::new().kind(Kind::Custom(10050)).author(public_key).limit(1);
if let Ok(events) = client.get_events_of(vec![inbox], None).await {
if let Ok(events) = client.get_events_of(vec![inbox], Some(Duration::from_secs(5))).await {
if let Some(event) = events.into_iter().next() {
let urls = event
.tags()
@@ -279,36 +280,18 @@ pub async fn login(
}
}
let subscription_id = SubscriptionId::new("personal_inbox");
let new_message = Filter::new().kind(Kind::GiftWrap).pubkey(public_key);
let sub_id = SubscriptionId::new("personal_inbox");
let new_message = Filter::new().kind(Kind::GiftWrap).pubkey(public_key).limit(0);
if client.subscription(&subscription_id).await.is_some() {
if client.subscription(&sub_id).await.is_some() {
// Remove old subscriotion
client.unsubscribe(subscription_id.clone()).await;
client.unsubscribe(sub_id.clone()).await;
// Resubscribe new message for current user
let _ = client.subscribe_with_id(subscription_id, vec![new_message], None).await;
let _ = client.subscribe_with_id(sub_id.clone(), vec![new_message], None).await;
} else {
let _ = client.subscribe_with_id(subscription_id, vec![new_message], None).await;
let _ = client.subscribe_with_id(sub_id, vec![new_message], None).await;
}
let handle_clone = handle.app_handle().clone();
tauri::async_runtime::spawn(async move {
let window = handle_clone.get_webview_window("main").expect("Window is terminated.");
let state = window.state::<Nostr>();
let client = &state.client;
let sync = Filter::new().kind(Kind::GiftWrap).pubkey(public_key);
if client.reconcile(sync.clone(), NegentropyOptions::default()).await.is_ok() {
handle_clone.emit("synchronized", ()).unwrap();
};
if client.get_events_of(vec![sync], Some(Duration::from_secs(20))).await.is_ok() {
handle_clone.emit("synchronized", ()).unwrap();
};
});
tauri::async_runtime::spawn(async move {
let window = handle.get_webview_window("main").expect("Window is terminated.");
let state = window.state::<Nostr>();
@@ -323,7 +306,7 @@ pub async fn login(
{
if let Err(e) = window.emit(
"event",
Payload { event: rumor.as_json(), sender: sender.to_hex() },
EventPayload { event: rumor.as_json(), sender: sender.to_hex() },
) {
println!("emit failed: {}", e)
}

View File

@@ -15,24 +15,27 @@ pub async fn get_chats(state: State<'_, Nostr>) -> Result<Vec<String>, String> {
let filter = Filter::new().kind(Kind::GiftWrap).pubkey(public_key);
let events = match client.database().query(vec![filter], Order::Desc).await {
let rumors = match client.get_events_of(vec![filter], Some(Duration::from_secs(20))).await {
Ok(events) => {
stream::iter(events)
.filter_map(|ev| async move {
if let Ok(UnwrappedGift { rumor, .. }) = client.unwrap_gift_wrap(&ev).await {
if rumor.kind == Kind::PrivateDirectMessage {
return Some(rumor);
Some(rumor)
} else {
None
}
} else {
None
}
None
})
.collect::<Vec<_>>()
.await
}
Err(err) => return Err(err.to_string()),
Err(e) => return Err(e.to_string()),
};
let uniqs = events
let uniqs = rumors
.into_iter()
.sorted_by_key(|ev| Reverse(ev.created_at))
.filter(|ev| ev.pubkey != public_key)
@@ -47,14 +50,14 @@ pub async fn get_chats(state: State<'_, Nostr>) -> Result<Vec<String>, String> {
#[specta::specta]
pub async fn get_chat_messages(id: String, state: State<'_, Nostr>) -> Result<Vec<String>, String> {
let client = &state.client;
let signer = client.signer().await.map_err(|e| e.to_string())?;
let signer = client.signer().await.map_err(|e| e.to_string())?;
let receiver_pk = signer.public_key().await.map_err(|e| e.to_string())?;
let sender_pk = PublicKey::parse(id).map_err(|e| e.to_string())?;
let filter = Filter::new().kind(Kind::GiftWrap).pubkeys(vec![receiver_pk, sender_pk]);
let rumors = match client.database().query(vec![filter], Order::Desc).await {
let rumors = match client.get_events_of(vec![filter], None).await {
Ok(events) => {
stream::iter(events)
.filter_map(|ev| async move {

View File

@@ -16,10 +16,17 @@ mod common;
pub struct Nostr {
client: Client,
contact_list: Mutex<Vec<Contact>>,
inbox_relays: Mutex<HashMap<PublicKey, Vec<String>>>,
}
// TODO: Allow user config bootstrap relays.
pub const BOOTSTRAP_RELAYS: [&str; 4] = [
"wss://relay.damus.io/",
"wss://relay.nostr.net/",
"wss://relay.0xchat.com/",
"wss://nostr.wine/",
];
fn main() {
let invoke_handler = {
let builder = tauri_specta::ts::builder().commands(tauri_specta::collect_commands![
@@ -67,6 +74,19 @@ fn main() {
#[cfg(target_os = "macos")]
main_window.set_traffic_lights_inset(12.0, 18.0).unwrap();
// Workaround for reset traffic light when window resized
#[cfg(target_os = "macos")]
let win_ = main_window.clone();
#[cfg(target_os = "macos")]
main_window.on_window_event(move |event| {
if let tauri::WindowEvent::Resized(_) = event {
win_.set_traffic_lights_inset(12.0, 18.0).unwrap();
}
if let tauri::WindowEvent::ThemeChanged(_) = event {
win_.set_traffic_lights_inset(12.0, 18.0).unwrap();
}
});
// Restore native border
#[cfg(target_os = "macos")]
main_window.add_border(None);
@@ -81,16 +101,14 @@ fn main() {
// Setup nostr client
let opts = Options::new()
.timeout(Duration::from_secs(30))
.send_timeout(Some(Duration::from_secs(5)))
.connection_timeout(Some(Duration::from_secs(5)));
.timeout(Duration::from_secs(40))
.send_timeout(Some(Duration::from_secs(10)))
.connection_timeout(Some(Duration::from_secs(10)));
let client = ClientBuilder::default().opts(opts).database(database).build();
// Add bootstrap relay
let _ = client
.add_relays(["wss://relay.poster.place/", "wss://bostr.nokotaro.com/"])
.await;
let _ = client.add_relays(BOOTSTRAP_RELAYS).await;
// Connect
client.connect().await;
@@ -99,11 +117,7 @@ fn main() {
});
// Create global state
app.manage(Nostr {
client,
contact_list: Mutex::new(Vec::new()),
inbox_relays: Mutex::new(HashMap::new()),
});
app.manage(Nostr { client, inbox_relays: Mutex::new(HashMap::new()) });
Ok(())
})

View File

@@ -47,7 +47,7 @@ try {
else return { status: "error", error: e as any };
}
},
async getContactList() : Promise<Result<string[], null>> {
async getContactList() : Promise<Result<string[], string>> {
try {
return { status: "ok", data: await TAURI_INVOKE("get_contact_list") };
} catch (e) {

View File

@@ -1,6 +1,4 @@
import { createSyncStoragePersister } from "@tanstack/query-sync-storage-persister";
import { QueryClient } from "@tanstack/react-query";
import { PersistQueryClientProvider } from "@tanstack/react-query-persist-client";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { RouterProvider, createRouter } from "@tanstack/react-router";
import { type } from "@tauri-apps/plugin-os";
import { StrictMode } from "react";
@@ -9,18 +7,7 @@ import "./global.css";
// Import the generated route tree
import { routeTree } from "./routes.gen";
const queryClient = new QueryClient({
defaultOptions: {
queries: {
gcTime: 1000 * 60 * 60 * 24,
},
},
});
const persister = createSyncStoragePersister({
storage: window.localStorage,
});
const queryClient = new QueryClient();
const platform = type();
const router = createRouter({
@@ -44,12 +31,9 @@ if (!rootElement.innerHTML) {
const root = ReactDOM.createRoot(rootElement);
root.render(
<StrictMode>
<PersistQueryClientProvider
client={queryClient}
persistOptions={{ persister }}
>
<QueryClientProvider client={queryClient}>
<RouterProvider router={router} />
</PersistQueryClientProvider>
</QueryClientProvider>
</StrictMode>,
);
}

View File

@@ -2,7 +2,7 @@ import { commands } from "@/commands";
import { cn, getReceivers, groupEventByDate, time } from "@/commons";
import { Spinner } from "@/components/spinner";
import { User } from "@/components/user";
import { ArrowUp, Paperclip } from "@phosphor-icons/react";
import { ArrowUp } from "@phosphor-icons/react";
import * as ScrollArea from "@radix-ui/react-scroll-area";
import { useQuery, useQueryClient } from "@tanstack/react-query";
import { createLazyFileRoute } from "@tanstack/react-router";

View File

@@ -19,7 +19,7 @@ import { message } from "@tauri-apps/plugin-dialog";
import type { NostrEvent } from "nostr-tools";
import { useCallback, useEffect, useState, useTransition } from "react";
type Payload = {
type EventPayload = {
event: string;
sender: string;
};
@@ -90,6 +90,8 @@ function ChatList() {
}
},
select: (data) => data.sort((a, b) => b.created_at - a.created_at),
refetchOnMount: false,
refetchOnWindowFocus: false,
});
useEffect(() => {
@@ -103,14 +105,14 @@ function ChatList() {
}, []);
useEffect(() => {
const unlisten = listen<Payload>("event", async (data) => {
const unlisten = listen<EventPayload>("event", async (data) => {
const event: NostrEvent = JSON.parse(data.payload.event);
const chats: NostrEvent[] = await queryClient.getQueryData(["chats"]);
if (chats) {
const exist = chats.find((ev) => ev.pubkey === event.pubkey);
const index = chats.findIndex((item) => item.pubkey === event.pubkey);
if (!exist) {
if (index === -1) {
await queryClient.setQueryData(
["chats"],
(prevEvents: NostrEvent[]) => {
@@ -121,16 +123,12 @@ function ChatList() {
},
);
} else {
const index = chats.findIndex((item) => item.pubkey === event.pubkey);
const newEvents = [...chats];
newEvents[index] = {
...event,
};
if (index !== -1) {
newEvents[index] = {
...event,
};
await queryClient.setQueryData(["chats"], newEvents);
}
await queryClient.setQueryData(["chats"], newEvents);
}
}
});
@@ -147,7 +145,7 @@ function ChatList() {
className="overflow-hidden flex-1 w-full"
>
<ScrollArea.Viewport className="relative h-full px-1.5">
{isLoading ? (
{isLoading || !data.length ? (
<div>
{[...Array(5).keys()].map((i) => (
<div

View File

@@ -38,7 +38,10 @@ function Screen() {
};
return (
<div className="size-full flex items-center justify-center">
<div
data-tauri-drag-region
className="size-full flex items-center justify-center"
>
<div className="w-[320px] flex flex-col gap-8">
<div className="flex flex-col gap-1 text-center">
<h1 className="leading-tight text-xl font-semibold">New Identity</h1>
@@ -61,7 +64,7 @@ function Screen() {
placeholder="https://"
value={picture}
onChange={(e) => setPicture(e.target.value)}
className="px-3 rounded-lg h-10 bg-transparent border border-neutral-200 dark:border-neutral-800 focus:border-blue-500 focus:outline-none"
className="px-3 rounded-lg h-10 bg-transparent border border-neutral-200 dark:border-neutral-500 focus:border-blue-500 focus:outline-none"
/>
</div>
<div className="flex flex-col gap-1">
@@ -76,7 +79,7 @@ function Screen() {
type="text"
value={name}
onChange={(e) => setName(e.target.value)}
className="px-3 rounded-lg h-10 bg-transparent border border-neutral-200 dark:border-neutral-800 focus:border-blue-500 focus:outline-none"
className="px-3 rounded-lg h-10 bg-transparent border border-neutral-200 dark:border-neutral-500 focus:border-blue-500 focus:outline-none"
/>
</div>
</Frame>

View File

@@ -48,7 +48,10 @@ function Screen() {
};
return (
<div className="size-full flex items-center justify-center">
<div
data-tauri-drag-region
className="size-full flex items-center justify-center"
>
<div className="w-[320px] flex flex-col gap-8">
<div className="flex flex-col gap-1 text-center">
<h1 className="leading-tight text-xl font-semibold">
@@ -75,7 +78,7 @@ function Screen() {
placeholder="nsec or ncryptsec..."
value={key}
onChange={(e) => setKey(e.target.value)}
className="pl-3 pr-12 rounded-lg w-full h-10 bg-transparent border border-neutral-200 dark:border-neutral-800 focus:border-blue-500 focus:outline-none"
className="pl-3 pr-12 rounded-lg w-full h-10 bg-transparent border border-neutral-200 dark:border-neutral-500 focus:border-blue-500 focus:outline-none"
/>
<button
type="button"
@@ -98,7 +101,7 @@ function Screen() {
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
className="px-3 rounded-lg h-10 bg-transparent border border-neutral-200 dark:border-neutral-800 focus:border-blue-500 focus:outline-none"
className="px-3 rounded-lg h-10 bg-transparent border border-neutral-200 dark:border-neutral-500 focus:border-blue-500 focus:outline-none"
/>
</div>
</Frame>

View File

@@ -54,7 +54,10 @@ function Screen() {
};
return (
<div className="size-full flex items-center justify-center">
<div
data-tauri-drag-region
className="size-full flex items-center justify-center"
>
<div className="w-[320px] flex flex-col gap-8">
<div className="flex flex-col gap-1 text-center">
<h3 className="leading-tight text-neutral-700 dark:text-neutral-300">

View File

@@ -6,7 +6,10 @@ export const Route = createLazyFileRoute("/new")({
function Screen() {
return (
<div className="size-full flex items-center justify-center">
<div
data-tauri-drag-region
className="size-full flex items-center justify-center"
>
<div className="w-[320px] flex flex-col gap-8">
<div className="flex flex-col gap-1 text-center">
<h1 className="leading-tight text-xl font-semibold">
@@ -22,7 +25,7 @@ function Screen() {
</Link>
<Link
to="/nostr-connect"
className="w-full h-10 bg-white hover:bg-neutral-100 dark:hover:bg-neutral-950 dark:bg-neutral-900 rounded-lg inline-flex items-center justify-center"
className="w-full h-10 bg-white hover:bg-neutral-100 dark:hover:bg-neutral-100 dark:bg-white dark:text-black rounded-lg inline-flex items-center justify-center"
>
Login with Nostr Connect
</Link>

View File

@@ -51,7 +51,10 @@ function Screen() {
};
return (
<div className="size-full flex items-center justify-center">
<div
data-tauri-drag-region
className="size-full flex items-center justify-center"
>
<div className="w-[320px] flex flex-col gap-8">
<div className="flex flex-col gap-1 text-center">
<h1 className="leading-tight text-xl font-semibold">Nostr Connect</h1>
@@ -74,7 +77,7 @@ function Screen() {
placeholder="bunker://..."
value={uri}
onChange={(e) => setUri(e.target.value)}
className="pl-3 pr-12 rounded-lg w-full h-10 bg-transparent border border-neutral-200 dark:border-neutral-800 focus:border-blue-500 focus:outline-none"
className="pl-3 pr-12 rounded-lg w-full h-10 bg-transparent border border-neutral-200 dark:border-neutral-500 focus:border-blue-500 focus:outline-none"
/>
<button
type="button"