mirror of
https://github.com/hzrd149/nostrudel.git
synced 2025-03-17 13:21:44 +01:00
use timeline loader from applesauce packages
This commit is contained in:
parent
9257b06335
commit
1167dbae54
5
.changeset/five-flowers-roll.md
Normal file
5
.changeset/five-flowers-roll.md
Normal file
@ -0,0 +1,5 @@
|
||||
---
|
||||
"nostrudel": minor
|
||||
---
|
||||
|
||||
Use TimelineLoader from applesauce packages
|
@ -19,7 +19,7 @@
|
||||
"cap-sync-version": "pnpm dlx capacitor-set-version . -v $(jq -r .version package.json) -b 1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@cashu/cashu-ts": "^2.1.0",
|
||||
"@cashu/cashu-ts": "^2.2.0",
|
||||
"@chakra-ui/anatomy": "^2.3.4",
|
||||
"@chakra-ui/breakpoint-utils": "^2.0.8",
|
||||
"@chakra-ui/icons": "^2.2.4",
|
||||
@ -73,6 +73,7 @@
|
||||
"framer-motion": "^10.18.0",
|
||||
"gif-picker-react": "^1.4.0",
|
||||
"handlebars": "^4.7.8",
|
||||
"hash-sum": "^2.0.0",
|
||||
"hls.js": "^1.5.20",
|
||||
"i18n-iso-countries": "^7.13.0",
|
||||
"idb": "^8.0.2",
|
||||
@ -120,7 +121,6 @@
|
||||
"three": "^0.170.0",
|
||||
"three-spritetext": "^1.9.4",
|
||||
"three-stdlib": "^2.35.13",
|
||||
"tiny-lru": "^11.2.11",
|
||||
"unified": "^11.0.5",
|
||||
"uuid": "^11.0.5",
|
||||
"vite-plugin-funding": "^0.1.0",
|
||||
@ -146,6 +146,7 @@
|
||||
"@types/debug": "^4.1.12",
|
||||
"@types/dom-serial": "^1.0.6",
|
||||
"@types/file-saver": "^2.0.7",
|
||||
"@types/hash-sum": "^1.0.2",
|
||||
"@types/identicon.js": "^2.3.5",
|
||||
"@types/json-schema": "^7.0.15",
|
||||
"@types/leaflet": "^1.9.16",
|
||||
|
339
pnpm-lock.yaml
generated
339
pnpm-lock.yaml
generated
@ -13,8 +13,8 @@ importers:
|
||||
.:
|
||||
dependencies:
|
||||
'@cashu/cashu-ts':
|
||||
specifier: ^2.1.0
|
||||
version: 2.1.0
|
||||
specifier: ^2.2.0
|
||||
version: 2.2.0
|
||||
'@chakra-ui/anatomy':
|
||||
specifier: ^2.3.4
|
||||
version: 2.3.4
|
||||
@ -92,10 +92,10 @@ importers:
|
||||
version: 1.3.1
|
||||
'@uiw/codemirror-theme-github':
|
||||
specifier: ^4.23.7
|
||||
version: 4.23.7(@codemirror/language@6.10.8)(@codemirror/state@6.5.1)(@codemirror/view@6.36.2)
|
||||
version: 4.23.7(@codemirror/language@6.10.8)(@codemirror/state@6.5.2)(@codemirror/view@6.36.2)
|
||||
'@uiw/react-codemirror':
|
||||
specifier: ^4.23.7
|
||||
version: 4.23.7(@babel/runtime@7.26.7)(@codemirror/autocomplete@6.18.4)(@codemirror/language@6.10.8)(@codemirror/lint@6.8.4)(@codemirror/search@6.5.8)(@codemirror/state@6.5.1)(@codemirror/theme-one-dark@6.1.2)(@codemirror/view@6.36.2)(codemirror@6.0.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
|
||||
version: 4.23.7(@babel/runtime@7.26.7)(@codemirror/autocomplete@6.18.4)(@codemirror/language@6.10.8)(@codemirror/lint@6.8.4)(@codemirror/search@6.5.8)(@codemirror/state@6.5.2)(@codemirror/theme-one-dark@6.1.2)(@codemirror/view@6.36.2)(codemirror@6.0.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
|
||||
'@webscopeio/react-textarea-autocomplete':
|
||||
specifier: ^4.9.2
|
||||
version: 4.9.2(prop-types@15.8.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
|
||||
@ -104,28 +104,28 @@ importers:
|
||||
version: 0.7.2
|
||||
applesauce-accounts:
|
||||
specifier: next
|
||||
version: 0.0.0-next-20250131214402(typescript@5.7.3)
|
||||
version: 0.0.0-next-20250203180810(typescript@5.7.3)
|
||||
applesauce-content:
|
||||
specifier: next
|
||||
version: 0.0.0-next-20250131214402(typescript@5.7.3)
|
||||
version: 0.0.0-next-20250203180810(typescript@5.7.3)
|
||||
applesauce-core:
|
||||
specifier: next
|
||||
version: 0.0.0-next-20250131214402(typescript@5.7.3)
|
||||
version: 0.0.0-next-20250203180810(typescript@5.7.3)
|
||||
applesauce-factory:
|
||||
specifier: next
|
||||
version: 0.0.0-next-20250131214402(typescript@5.7.3)
|
||||
version: 0.0.0-next-20250203180810(typescript@5.7.3)
|
||||
applesauce-loaders:
|
||||
specifier: next
|
||||
version: 0.0.0-next-20250131214402(typescript@5.7.3)
|
||||
version: 0.0.0-next-20250203180810(typescript@5.7.3)
|
||||
applesauce-net:
|
||||
specifier: ^0.10.0
|
||||
version: 0.10.0(typescript@5.7.3)
|
||||
applesauce-react:
|
||||
specifier: next
|
||||
version: 0.0.0-next-20250131214402(typescript@5.7.3)
|
||||
version: 0.0.0-next-20250203180810(typescript@5.7.3)
|
||||
applesauce-signers:
|
||||
specifier: next
|
||||
version: 0.0.0-next-20250131214402(typescript@5.7.3)
|
||||
version: 0.0.0-next-20250203180810(typescript@5.7.3)
|
||||
bech32:
|
||||
specifier: ^2.0.0
|
||||
version: 2.0.0
|
||||
@ -149,7 +149,7 @@ importers:
|
||||
version: 6.0.1
|
||||
codemirror-json-schema:
|
||||
specifier: ^0.7.9
|
||||
version: 0.7.9(@codemirror/language@6.10.8)(@codemirror/lint@6.8.4)(@codemirror/state@6.5.1)(@codemirror/view@6.36.2)(@lezer/common@1.2.3)
|
||||
version: 0.7.9(@codemirror/language@6.10.8)(@codemirror/lint@6.8.4)(@codemirror/state@6.5.2)(@codemirror/view@6.36.2)(@lezer/common@1.2.3)
|
||||
dayjs:
|
||||
specifier: ^1.11.13
|
||||
version: 1.11.13
|
||||
@ -174,6 +174,9 @@ importers:
|
||||
handlebars:
|
||||
specifier: ^4.7.8
|
||||
version: 4.7.8
|
||||
hash-sum:
|
||||
specifier: ^2.0.0
|
||||
version: 2.0.0
|
||||
hls.js:
|
||||
specifier: ^1.5.20
|
||||
version: 1.5.20
|
||||
@ -315,9 +318,6 @@ importers:
|
||||
three-stdlib:
|
||||
specifier: ^2.35.13
|
||||
version: 2.35.13(three@0.170.0)
|
||||
tiny-lru:
|
||||
specifier: ^11.2.11
|
||||
version: 11.2.11
|
||||
unified:
|
||||
specifier: ^11.0.5
|
||||
version: 11.0.5
|
||||
@ -388,6 +388,9 @@ importers:
|
||||
'@types/file-saver':
|
||||
specifier: ^2.0.7
|
||||
version: 2.0.7
|
||||
'@types/hash-sum':
|
||||
specifier: ^1.0.2
|
||||
version: 1.0.2
|
||||
'@types/identicon.js':
|
||||
specifier: ^2.3.5
|
||||
version: 2.3.5
|
||||
@ -1032,8 +1035,8 @@ packages:
|
||||
'@cashu/cashu-ts@2.0.0-rc1':
|
||||
resolution: {integrity: sha512-39459l7x/fUMEgOsCdGLLl6rMekO4nbv+wEuavmyElh8hgN8t66wcb29AJvdFTb6K3lPACKF2rs/jAlPYrN7Ng==}
|
||||
|
||||
'@cashu/cashu-ts@2.1.0':
|
||||
resolution: {integrity: sha512-qFfFz1dx9keJxumjk5FyTvI1j0Yp/P5LXDy0cGO4Xlp3WYKOI1nykNOTPd+bTY9vSkvIM+xuXRer9BtQxqHtwA==}
|
||||
'@cashu/cashu-ts@2.2.0':
|
||||
resolution: {integrity: sha512-7b6pGyjjpm3uAJvmOL+ztpRxqp1qnmzGpydp+Pu30pOjxj93EhejPTJVrZMDJ0P35y6u5+5jIjHF4k0fpovvmg==}
|
||||
|
||||
'@cashu/crypto@0.2.7':
|
||||
resolution: {integrity: sha512-1aaDfUjiHNXoJqg8nW+341TLWV9W28DsVNXJUKcHL0yAmwLs5+56SSnb8LLDJzPamLVoYL0U0bda91klAzptig==}
|
||||
@ -1241,8 +1244,8 @@ packages:
|
||||
'@codemirror/search@6.5.8':
|
||||
resolution: {integrity: sha512-PoWtZvo7c1XFeZWmmyaOp2G0XVbOnm+fJzvghqGAktBW3cufwJUWvSCcNG0ppXiBEM05mZu6RhMtXPv2hpllig==}
|
||||
|
||||
'@codemirror/state@6.5.1':
|
||||
resolution: {integrity: sha512-3rA9lcwciEB47ZevqvD8qgbzhM9qMb8vCcQCNmDfVRPQG4JT9mSb0Jg8H7YjKGGQcFnLN323fj9jdnG59Kx6bg==}
|
||||
'@codemirror/state@6.5.2':
|
||||
resolution: {integrity: sha512-FVqsPqtPWKVVL3dPSxy8wEF/ymIEuVzF1PK3VbUgrxXpJUSHQWWZz4JMToquRxnkw+36LTamCZG2iua2Ptq0fA==}
|
||||
|
||||
'@codemirror/theme-one-dark@6.1.2':
|
||||
resolution: {integrity: sha512-F+sH0X16j/qFLMAfbciKTxVOwkdAS336b7AXTKOZhy8BR3eH/RelsnLgLFINrpST63mmN2OuwUt0W2ndUgYwUA==}
|
||||
@ -1717,98 +1720,98 @@ packages:
|
||||
rollup:
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-android-arm-eabi@4.32.1':
|
||||
resolution: {integrity: sha512-/pqA4DmqyCm8u5YIDzIdlLcEmuvxb0v8fZdFhVMszSpDTgbQKdw3/mB3eMUHIbubtJ6F9j+LtmyCnHTEqIHyzA==}
|
||||
'@rollup/rollup-android-arm-eabi@4.34.1':
|
||||
resolution: {integrity: sha512-kwctwVlswSEsr4ljpmxKrRKp1eG1v2NAhlzFzDf1x1OdYaMjBYjDCbHkzWm57ZXzTwqn8stMXgROrnMw8dJK3w==}
|
||||
cpu: [arm]
|
||||
os: [android]
|
||||
|
||||
'@rollup/rollup-android-arm64@4.32.1':
|
||||
resolution: {integrity: sha512-If3PDskT77q7zgqVqYuj7WG3WC08G1kwXGVFi9Jr8nY6eHucREHkfpX79c0ACAjLj3QIWKPJR7w4i+f5EdLH5Q==}
|
||||
'@rollup/rollup-android-arm64@4.34.1':
|
||||
resolution: {integrity: sha512-4H5ZtZitBPlbPsTv6HBB8zh1g5d0T8TzCmpndQdqq20Ugle/nroOyDMf9p7f88Gsu8vBLU78/cuh8FYHZqdXxw==}
|
||||
cpu: [arm64]
|
||||
os: [android]
|
||||
|
||||
'@rollup/rollup-darwin-arm64@4.32.1':
|
||||
resolution: {integrity: sha512-zCpKHioQ9KgZToFp5Wvz6zaWbMzYQ2LJHQ+QixDKq52KKrF65ueu6Af4hLlLWHjX1Wf/0G5kSJM9PySW9IrvHA==}
|
||||
'@rollup/rollup-darwin-arm64@4.34.1':
|
||||
resolution: {integrity: sha512-f2AJ7Qwx9z25hikXvg+asco8Sfuc5NCLg8rmqQBIOUoWys5sb/ZX9RkMZDPdnnDevXAMJA5AWLnRBmgdXGEUiA==}
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
|
||||
'@rollup/rollup-darwin-x64@4.32.1':
|
||||
resolution: {integrity: sha512-sFvF+t2+TyUo/ZQqUcifrJIgznx58oFZbdHS9TvHq3xhPVL9nOp+yZ6LKrO9GWTP+6DbFtoyLDbjTpR62Mbr3Q==}
|
||||
'@rollup/rollup-darwin-x64@4.34.1':
|
||||
resolution: {integrity: sha512-+/2JBrRfISCsWE4aEFXxd+7k9nWGXA8+wh7ZUHn/u8UDXOU9LN+QYKKhd57sIn6WRcorOnlqPMYFIwie/OHXWw==}
|
||||
cpu: [x64]
|
||||
os: [darwin]
|
||||
|
||||
'@rollup/rollup-freebsd-arm64@4.32.1':
|
||||
resolution: {integrity: sha512-NbOa+7InvMWRcY9RG+B6kKIMD/FsnQPH0MWUvDlQB1iXnF/UcKSudCXZtv4lW+C276g3w5AxPbfry5rSYvyeYA==}
|
||||
'@rollup/rollup-freebsd-arm64@4.34.1':
|
||||
resolution: {integrity: sha512-SUeB0pYjIXwT2vfAMQ7E4ERPq9VGRrPR7Z+S4AMssah5EHIilYqjWQoTn5dkDtuIJUSTs8H+C9dwoEcg3b0sCA==}
|
||||
cpu: [arm64]
|
||||
os: [freebsd]
|
||||
|
||||
'@rollup/rollup-freebsd-x64@4.32.1':
|
||||
resolution: {integrity: sha512-JRBRmwvHPXR881j2xjry8HZ86wIPK2CcDw0EXchE1UgU0ubWp9nvlT7cZYKc6bkypBt745b4bglf3+xJ7hXWWw==}
|
||||
'@rollup/rollup-freebsd-x64@4.34.1':
|
||||
resolution: {integrity: sha512-L3T66wAZiB/ooiPbxz0s6JEX6Sr2+HfgPSK+LMuZkaGZFAFCQAHiP3dbyqovYdNaiUXcl9TlgnIbcsIicAnOZg==}
|
||||
cpu: [x64]
|
||||
os: [freebsd]
|
||||
|
||||
'@rollup/rollup-linux-arm-gnueabihf@4.32.1':
|
||||
resolution: {integrity: sha512-PKvszb+9o/vVdUzCCjL0sKHukEQV39tD3fepXxYrHE3sTKrRdCydI7uldRLbjLmDA3TFDmh418XH19NOsDRH8g==}
|
||||
'@rollup/rollup-linux-arm-gnueabihf@4.34.1':
|
||||
resolution: {integrity: sha512-UBXdQ4+ATARuFgsFrQ+tAsKvBi/Hly99aSVdeCUiHV9dRTTpMU7OrM3WXGys1l40wKVNiOl0QYY6cZQJ2xhKlQ==}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
|
||||
'@rollup/rollup-linux-arm-musleabihf@4.32.1':
|
||||
resolution: {integrity: sha512-9WHEMV6Y89eL606ReYowXuGF1Yb2vwfKWKdD1A5h+OYnPZSJvxbEjxTRKPgi7tkP2DSnW0YLab1ooy+i/FQp/Q==}
|
||||
'@rollup/rollup-linux-arm-musleabihf@4.34.1':
|
||||
resolution: {integrity: sha512-m/yfZ25HGdcCSwmopEJm00GP7xAUyVcBPjttGLRAqZ60X/bB4Qn6gP7XTwCIU6bITeKmIhhwZ4AMh2XLro+4+w==}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
|
||||
'@rollup/rollup-linux-arm64-gnu@4.32.1':
|
||||
resolution: {integrity: sha512-tZWc9iEt5fGJ1CL2LRPw8OttkCBDs+D8D3oEM8mH8S1ICZCtFJhD7DZ3XMGM8kpqHvhGUTvNUYVDnmkj4BDXnw==}
|
||||
'@rollup/rollup-linux-arm64-gnu@4.34.1':
|
||||
resolution: {integrity: sha512-Wy+cUmFuvziNL9qWRRzboNprqSQ/n38orbjRvd6byYWridp5TJ3CD+0+HUsbcWVSNz9bxkDUkyASGP0zS7GAvg==}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
|
||||
'@rollup/rollup-linux-arm64-musl@4.32.1':
|
||||
resolution: {integrity: sha512-FTYc2YoTWUsBz5GTTgGkRYYJ5NGJIi/rCY4oK/I8aKowx1ToXeoVVbIE4LGAjsauvlhjfl0MYacxClLld1VrOw==}
|
||||
'@rollup/rollup-linux-arm64-musl@4.34.1':
|
||||
resolution: {integrity: sha512-CQ3MAGgiFmQW5XJX5W3wnxOBxKwFlUAgSXFA2SwgVRjrIiVt5LHfcQLeNSHKq5OEZwv+VCBwlD1+YKCjDG8cpg==}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
|
||||
'@rollup/rollup-linux-loongarch64-gnu@4.32.1':
|
||||
resolution: {integrity: sha512-F51qLdOtpS6P1zJVRzYM0v6MrBNypyPEN1GfMiz0gPu9jN8ScGaEFIZQwteSsGKg799oR5EaP7+B2jHgL+d+Kw==}
|
||||
'@rollup/rollup-linux-loongarch64-gnu@4.34.1':
|
||||
resolution: {integrity: sha512-rSzb1TsY4lSwH811cYC3OC2O2mzNMhM13vcnA7/0T6Mtreqr3/qs6WMDriMRs8yvHDI54qxHgOk8EV5YRAHFbw==}
|
||||
cpu: [loong64]
|
||||
os: [linux]
|
||||
|
||||
'@rollup/rollup-linux-powerpc64le-gnu@4.32.1':
|
||||
resolution: {integrity: sha512-wO0WkfSppfX4YFm5KhdCCpnpGbtgQNj/tgvYzrVYFKDpven8w2N6Gg5nB6w+wAMO3AIfSTWeTjfVe+uZ23zAlg==}
|
||||
'@rollup/rollup-linux-powerpc64le-gnu@4.34.1':
|
||||
resolution: {integrity: sha512-fwr0n6NS0pG3QxxlqVYpfiY64Fd1Dqd8Cecje4ILAV01ROMp4aEdCj5ssHjRY3UwU7RJmeWd5fi89DBqMaTawg==}
|
||||
cpu: [ppc64]
|
||||
os: [linux]
|
||||
|
||||
'@rollup/rollup-linux-riscv64-gnu@4.32.1':
|
||||
resolution: {integrity: sha512-iWswS9cIXfJO1MFYtI/4jjlrGb/V58oMu4dYJIKnR5UIwbkzR0PJ09O0PDZT0oJ3LYWXBSWahNf/Mjo6i1E5/g==}
|
||||
'@rollup/rollup-linux-riscv64-gnu@4.34.1':
|
||||
resolution: {integrity: sha512-4uJb9qz7+Z/yUp5RPxDGGGUcoh0PnKF33QyWgEZ3X/GocpWb6Mb+skDh59FEt5d8+Skxqs9mng6Swa6B2AmQZg==}
|
||||
cpu: [riscv64]
|
||||
os: [linux]
|
||||
|
||||
'@rollup/rollup-linux-s390x-gnu@4.32.1':
|
||||
resolution: {integrity: sha512-RKt8NI9tebzmEthMnfVgG3i/XeECkMPS+ibVZjZ6mNekpbbUmkNWuIN2yHsb/mBPyZke4nlI4YqIdFPgKuoyQQ==}
|
||||
'@rollup/rollup-linux-s390x-gnu@4.34.1':
|
||||
resolution: {integrity: sha512-QlIo8ndocWBEnfmkYqj8vVtIUpIqJjfqKggjy7IdUncnt8BGixte1wDON7NJEvLg3Kzvqxtbo8tk+U1acYEBlw==}
|
||||
cpu: [s390x]
|
||||
os: [linux]
|
||||
|
||||
'@rollup/rollup-linux-x64-gnu@4.32.1':
|
||||
resolution: {integrity: sha512-WQFLZ9c42ECqEjwg/GHHsouij3pzLXkFdz0UxHa/0OM12LzvX7DzedlY0SIEly2v18YZLRhCRoHZDxbBSWoGYg==}
|
||||
'@rollup/rollup-linux-x64-gnu@4.34.1':
|
||||
resolution: {integrity: sha512-hzpleiKtq14GWjz3ahWvJXgU1DQC9DteiwcsY4HgqUJUGxZThlL66MotdUEK9zEo0PK/2ADeZGM9LIondE302A==}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
|
||||
'@rollup/rollup-linux-x64-musl@4.32.1':
|
||||
resolution: {integrity: sha512-BLoiyHDOWoS3uccNSADMza6V6vCNiphi94tQlVIL5de+r6r/CCQuNnerf+1g2mnk2b6edp5dk0nhdZ7aEjOBsA==}
|
||||
'@rollup/rollup-linux-x64-musl@4.34.1':
|
||||
resolution: {integrity: sha512-jqtKrO715hDlvUcEsPn55tZt2TEiBvBtCMkUuU0R6fO/WPT7lO9AONjPbd8II7/asSiNVQHCMn4OLGigSuxVQA==}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
|
||||
'@rollup/rollup-win32-arm64-msvc@4.32.1':
|
||||
resolution: {integrity: sha512-w2l3UnlgYTNNU+Z6wOR8YdaioqfEnwPjIsJ66KxKAf0p+AuL2FHeTX6qvM+p/Ue3XPBVNyVSfCrfZiQh7vZHLQ==}
|
||||
'@rollup/rollup-win32-arm64-msvc@4.34.1':
|
||||
resolution: {integrity: sha512-RnHy7yFf2Wz8Jj1+h8klB93N0NHNHXFhNwAmiy9zJdpY7DE01VbEVtPdrK1kkILeIbHGRJjvfBDBhnxBr8kD4g==}
|
||||
cpu: [arm64]
|
||||
os: [win32]
|
||||
|
||||
'@rollup/rollup-win32-ia32-msvc@4.32.1':
|
||||
resolution: {integrity: sha512-Am9H+TGLomPGkBnaPWie4F3x+yQ2rr4Bk2jpwy+iV+Gel9jLAu/KqT8k3X4jxFPW6Zf8OMnehyutsd+eHoq1WQ==}
|
||||
'@rollup/rollup-win32-ia32-msvc@4.34.1':
|
||||
resolution: {integrity: sha512-i7aT5HdiZIcd7quhzvwQ2oAuX7zPYrYfkrd1QFfs28Po/i0q6kas/oRrzGlDhAEyug+1UfUtkWdmoVlLJj5x9Q==}
|
||||
cpu: [ia32]
|
||||
os: [win32]
|
||||
|
||||
'@rollup/rollup-win32-x64-msvc@4.32.1':
|
||||
resolution: {integrity: sha512-ar80GhdZb4DgmW3myIS9nRFYcpJRSME8iqWgzH2i44u+IdrzmiXVxeFnExQ5v4JYUSpg94bWjevMG8JHf1Da5Q==}
|
||||
'@rollup/rollup-win32-x64-msvc@4.34.1':
|
||||
resolution: {integrity: sha512-k3MVFD9Oq+laHkw2N2v7ILgoa9017ZMF/inTtHzyTVZjYs9cSH18sdyAf6spBAJIGwJ5UaC7et2ZH1WCdlhkMw==}
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
|
||||
@ -1951,6 +1954,9 @@ packages:
|
||||
'@types/geojson@7946.0.16':
|
||||
resolution: {integrity: sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==}
|
||||
|
||||
'@types/hash-sum@1.0.2':
|
||||
resolution: {integrity: sha512-UP28RddqY8xcU0SCEp9YKutQICXpaAq9N8U2klqF5hegGha7KzTOL8EdhIIV3bOSGBzjEpN9bU/d+nNZBdJYVw==}
|
||||
|
||||
'@types/hast@3.0.4':
|
||||
resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==}
|
||||
|
||||
@ -2186,32 +2192,32 @@ packages:
|
||||
engines: {node: '>=8.0.0'}
|
||||
hasBin: true
|
||||
|
||||
applesauce-accounts@0.0.0-next-20250131214402:
|
||||
resolution: {integrity: sha512-5BUtFswVFg82Oq9MG6VdkEa5VeOAuvoPMi7Fr/I4IxqJwpZDSFIU/rkuDOMtHcj+V6TCEYeTO670f2p7B4/yMg==}
|
||||
applesauce-accounts@0.0.0-next-20250203180810:
|
||||
resolution: {integrity: sha512-yymm0dQgBJGgf3nlv1DC+AyxK+cvHLZczmRLyYW4k4MCNM7mO7qwnFGbMJJftDmVw5l8f9xBu0T/8r3IWsOxJw==}
|
||||
|
||||
applesauce-content@0.0.0-next-20250131214402:
|
||||
resolution: {integrity: sha512-+cDqt4IRIjQ0Ncht0WLCcMueDaZRtsuAXBw3k4/ND37qUHsnt5Qj+VfnWr5Dfmhpk0HD3ghMqbMXZBwkybN6NA==}
|
||||
applesauce-content@0.0.0-next-20250203180810:
|
||||
resolution: {integrity: sha512-7TpIqocvhn5g4M/Biua7AP3pWo4YtDa1C21uci/ElkbuqMNhVT37ASwttGM8GPcfLTxQ7uBkpPjOBTXm74D8Rw==}
|
||||
|
||||
applesauce-core@0.0.0-next-20250131214402:
|
||||
resolution: {integrity: sha512-5+KRKnV2d+6z9QFzSHUGKHxbtoByRkx0MQpjOePNBcl/DCbVmC7Zf4Bo3VrouNeBG5deiCMIy5PGp0A4uuGXRg==}
|
||||
applesauce-core@0.0.0-next-20250203180810:
|
||||
resolution: {integrity: sha512-BNXzw8ydbp4KiPfn7X5iCMaeaNlAW5tr3o6dWz9UwV7ItWieQLd17ySh0KPLdVbE+e42msBN7ByE7iNC0ItJOQ==}
|
||||
|
||||
applesauce-core@0.10.0:
|
||||
resolution: {integrity: sha512-QMhUh4FIARcqY5soCB4Z8DIu+py0rYb28IgWT4gP9DLBGpDrY8lStXk7W1/46TLjEH97y0hbiXFK7kMCZ31oOQ==}
|
||||
|
||||
applesauce-factory@0.0.0-next-20250131214402:
|
||||
resolution: {integrity: sha512-94yTHDr+N+/IyDD88ruHzToG4craEyJ/u5nfU2TP85o6snR8Ngw5qmX5d8sD6RHJm9UjMpzfTcFjxU9ZCnbwjg==}
|
||||
applesauce-factory@0.0.0-next-20250203180810:
|
||||
resolution: {integrity: sha512-O4xMkwaOTX7t6JYaS78WTKzIRekCipCBnDeZpyYmLK+h4rQ+8aKd21VonV4hfh9A8dTeS28QNFsdDabbH+22Nw==}
|
||||
|
||||
applesauce-loaders@0.0.0-next-20250131214402:
|
||||
resolution: {integrity: sha512-ycKuHqqT951jwRpvMNjrhQq1YRhFHLYh57NIFJJTZFHOHzfi3OJjpagueJr5H7brFGOFdYtaOgJew3sxptucKw==}
|
||||
applesauce-loaders@0.0.0-next-20250203180810:
|
||||
resolution: {integrity: sha512-ZWU23UtUQPQdM26NFLUralB8M8IuxrJqYqCwA5j5pozi5EG49OxxdPaZuXn3u37VRX8mibQYRVQqR+rhPWEC6g==}
|
||||
|
||||
applesauce-net@0.10.0:
|
||||
resolution: {integrity: sha512-ZsAs/MkeGHiPZ2/a8lwP8lx/Eh+5Dot0qG4BLTAqjg4emP/RsiqW+hyc6v6QcVbdvuR0+hP1gka3+wWtiy/cTA==}
|
||||
|
||||
applesauce-react@0.0.0-next-20250131214402:
|
||||
resolution: {integrity: sha512-wqlVTecq3Aj+YY5gi71VOqKWNMwsK4nUFYuoY9ZFh1ueJG0anKqYLwZSrMvswsbt3JyhG4xtLrPc7FGdIsdmqQ==}
|
||||
applesauce-react@0.0.0-next-20250203180810:
|
||||
resolution: {integrity: sha512-/LloC27jD9BieXmoTZs59SVbHw/vzjh/mh1jt98TQT8NcSh9zoPD1quR4a4BNFXUmeDDAxOi4VcrTOCVXAvweA==}
|
||||
|
||||
applesauce-signers@0.0.0-next-20250131214402:
|
||||
resolution: {integrity: sha512-rWlDZrPPGmt2MWQ02WWRfUtApTDNJhu7Sze0hNZ4qaVSwIezq7l2f1N4vdB34A3gsagi9aXhhoipF72PtkbFHg==}
|
||||
applesauce-signers@0.0.0-next-20250203180810:
|
||||
resolution: {integrity: sha512-PJBPVmLW+lDYQ2TYflJGr/ddmvDu0v19l6I9XBhHfmlS1ypAej9kk4c4X56gRzROeq2zgIs/SSi1+Jm454AqRw==}
|
||||
|
||||
arg@4.1.3:
|
||||
resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==}
|
||||
@ -2312,8 +2318,8 @@ packages:
|
||||
bare-path@3.0.0:
|
||||
resolution: {integrity: sha512-tyfW2cQcB5NN8Saijrhqn0Zh7AnFNsnczRcuWODH0eYAXBsJ5gVxAUuNr7tsHSC6IZ77cA0SitzT+s47kot8Mw==}
|
||||
|
||||
bare-stream@2.6.4:
|
||||
resolution: {integrity: sha512-G6i3A74FjNq4nVrrSTUz5h3vgXzBJnjmWAVlBWaZETkgu+LgKd7AiyOml3EDJY1AHlIbBHKDXE+TUT53Ff8OaA==}
|
||||
bare-stream@2.6.5:
|
||||
resolution: {integrity: sha512-jSmxKJNJmHySi6hC42zlZnq00rga4jjxcgNZjY9N5WlOe/iOoGRtdwGsHzQv2RlH2KOYMwGUXhf2zXd32BA9RA==}
|
||||
peerDependencies:
|
||||
bare-buffer: '*'
|
||||
bare-events: '*'
|
||||
@ -3575,8 +3581,8 @@ packages:
|
||||
immutability-helper@3.1.1:
|
||||
resolution: {integrity: sha512-Q0QaXjPjwIju/28TsugCHNEASwoCcJSyJV3uO1sOIQGI0jKgm9f41Lvz0DZj3n46cNCyAZTsEYoY4C2bVRUzyQ==}
|
||||
|
||||
import-fresh@3.3.0:
|
||||
resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==}
|
||||
import-fresh@3.3.1:
|
||||
resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==}
|
||||
engines: {node: '>=6'}
|
||||
|
||||
indent-string@4.0.0:
|
||||
@ -5129,8 +5135,8 @@ packages:
|
||||
engines: {node: '>=10.0.0'}
|
||||
hasBin: true
|
||||
|
||||
rollup@4.32.1:
|
||||
resolution: {integrity: sha512-z+aeEsOeEa3mEbS1Tjl6sAZ8NE3+AalQz1RJGj81M+fizusbdDMoEJwdJNHfaB40Scr4qNu+welOfes7maKonA==}
|
||||
rollup@4.34.1:
|
||||
resolution: {integrity: sha512-iYZ/+PcdLYSGfH3S+dGahlW/RWmsqDhLgj1BT9DH/xXJ0ggZN7xkdP9wipPNjjNLczI+fmMLmTB9pye+d2r4GQ==}
|
||||
engines: {node: '>=18.0.0', npm: '>=8.0.0'}
|
||||
hasBin: true
|
||||
|
||||
@ -5557,10 +5563,6 @@ packages:
|
||||
tiny-invariant@1.3.3:
|
||||
resolution: {integrity: sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==}
|
||||
|
||||
tiny-lru@11.2.11:
|
||||
resolution: {integrity: sha512-27BIW0dIWTYYoWNnqSmoNMKe5WIbkXsc0xaCQHd3/3xT2XMuMJrzHdrO9QBFR14emBz1Bu0dOAs2sCBBrvgPQA==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
tinycolor2@1.6.0:
|
||||
resolution: {integrity: sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw==}
|
||||
|
||||
@ -6946,12 +6948,11 @@ snapshots:
|
||||
'@scure/bip32': 1.6.2
|
||||
buffer: 6.0.3
|
||||
|
||||
'@cashu/cashu-ts@2.1.0':
|
||||
'@cashu/cashu-ts@2.2.0':
|
||||
dependencies:
|
||||
'@cashu/crypto': 0.3.4
|
||||
'@noble/curves': 1.8.1
|
||||
'@noble/hashes': 1.7.1
|
||||
'@scure/bip32': 1.6.2
|
||||
buffer: 6.0.3
|
||||
|
||||
'@cashu/crypto@0.2.7':
|
||||
@ -7291,14 +7292,14 @@ snapshots:
|
||||
'@codemirror/autocomplete@6.18.4':
|
||||
dependencies:
|
||||
'@codemirror/language': 6.10.8
|
||||
'@codemirror/state': 6.5.1
|
||||
'@codemirror/state': 6.5.2
|
||||
'@codemirror/view': 6.36.2
|
||||
'@lezer/common': 1.2.3
|
||||
|
||||
'@codemirror/commands@6.8.0':
|
||||
dependencies:
|
||||
'@codemirror/language': 6.10.8
|
||||
'@codemirror/state': 6.5.1
|
||||
'@codemirror/state': 6.5.2
|
||||
'@codemirror/view': 6.36.2
|
||||
'@lezer/common': 1.2.3
|
||||
|
||||
@ -7311,7 +7312,7 @@ snapshots:
|
||||
dependencies:
|
||||
'@codemirror/autocomplete': 6.18.4
|
||||
'@codemirror/language': 6.10.8
|
||||
'@codemirror/state': 6.5.1
|
||||
'@codemirror/state': 6.5.2
|
||||
'@lezer/common': 1.2.3
|
||||
'@lezer/highlight': 1.2.1
|
||||
'@lezer/lr': 1.4.2
|
||||
@ -7320,7 +7321,7 @@ snapshots:
|
||||
|
||||
'@codemirror/language@6.10.8':
|
||||
dependencies:
|
||||
'@codemirror/state': 6.5.1
|
||||
'@codemirror/state': 6.5.2
|
||||
'@codemirror/view': 6.36.2
|
||||
'@lezer/common': 1.2.3
|
||||
'@lezer/highlight': 1.2.1
|
||||
@ -7329,30 +7330,30 @@ snapshots:
|
||||
|
||||
'@codemirror/lint@6.8.4':
|
||||
dependencies:
|
||||
'@codemirror/state': 6.5.1
|
||||
'@codemirror/state': 6.5.2
|
||||
'@codemirror/view': 6.36.2
|
||||
crelt: 1.0.6
|
||||
|
||||
'@codemirror/search@6.5.8':
|
||||
dependencies:
|
||||
'@codemirror/state': 6.5.1
|
||||
'@codemirror/state': 6.5.2
|
||||
'@codemirror/view': 6.36.2
|
||||
crelt: 1.0.6
|
||||
|
||||
'@codemirror/state@6.5.1':
|
||||
'@codemirror/state@6.5.2':
|
||||
dependencies:
|
||||
'@marijn/find-cluster-break': 1.0.2
|
||||
|
||||
'@codemirror/theme-one-dark@6.1.2':
|
||||
dependencies:
|
||||
'@codemirror/language': 6.10.8
|
||||
'@codemirror/state': 6.5.1
|
||||
'@codemirror/state': 6.5.2
|
||||
'@codemirror/view': 6.36.2
|
||||
'@lezer/highlight': 1.2.1
|
||||
|
||||
'@codemirror/view@6.36.2':
|
||||
dependencies:
|
||||
'@codemirror/state': 6.5.1
|
||||
'@codemirror/state': 6.5.2
|
||||
style-mod: 4.1.2
|
||||
w3c-keyname: 2.2.8
|
||||
|
||||
@ -7906,61 +7907,61 @@ snapshots:
|
||||
optionalDependencies:
|
||||
rollup: 2.79.2
|
||||
|
||||
'@rollup/rollup-android-arm-eabi@4.32.1':
|
||||
'@rollup/rollup-android-arm-eabi@4.34.1':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-android-arm64@4.32.1':
|
||||
'@rollup/rollup-android-arm64@4.34.1':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-darwin-arm64@4.32.1':
|
||||
'@rollup/rollup-darwin-arm64@4.34.1':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-darwin-x64@4.32.1':
|
||||
'@rollup/rollup-darwin-x64@4.34.1':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-freebsd-arm64@4.32.1':
|
||||
'@rollup/rollup-freebsd-arm64@4.34.1':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-freebsd-x64@4.32.1':
|
||||
'@rollup/rollup-freebsd-x64@4.34.1':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-arm-gnueabihf@4.32.1':
|
||||
'@rollup/rollup-linux-arm-gnueabihf@4.34.1':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-arm-musleabihf@4.32.1':
|
||||
'@rollup/rollup-linux-arm-musleabihf@4.34.1':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-arm64-gnu@4.32.1':
|
||||
'@rollup/rollup-linux-arm64-gnu@4.34.1':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-arm64-musl@4.32.1':
|
||||
'@rollup/rollup-linux-arm64-musl@4.34.1':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-loongarch64-gnu@4.32.1':
|
||||
'@rollup/rollup-linux-loongarch64-gnu@4.34.1':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-powerpc64le-gnu@4.32.1':
|
||||
'@rollup/rollup-linux-powerpc64le-gnu@4.34.1':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-riscv64-gnu@4.32.1':
|
||||
'@rollup/rollup-linux-riscv64-gnu@4.34.1':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-s390x-gnu@4.32.1':
|
||||
'@rollup/rollup-linux-s390x-gnu@4.34.1':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-x64-gnu@4.32.1':
|
||||
'@rollup/rollup-linux-x64-gnu@4.34.1':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-x64-musl@4.32.1':
|
||||
'@rollup/rollup-linux-x64-musl@4.34.1':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-win32-arm64-msvc@4.32.1':
|
||||
'@rollup/rollup-win32-arm64-msvc@4.34.1':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-win32-ia32-msvc@4.32.1':
|
||||
'@rollup/rollup-win32-ia32-msvc@4.34.1':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-win32-x64-msvc@4.32.1':
|
||||
'@rollup/rollup-win32-x64-msvc@4.34.1':
|
||||
optional: true
|
||||
|
||||
'@sagold/json-pointer@5.1.2': {}
|
||||
@ -8183,6 +8184,8 @@ snapshots:
|
||||
|
||||
'@types/geojson@7946.0.16': {}
|
||||
|
||||
'@types/hash-sum@1.0.2': {}
|
||||
|
||||
'@types/hast@3.0.4':
|
||||
dependencies:
|
||||
'@types/unist': 3.0.3
|
||||
@ -8283,38 +8286,38 @@ snapshots:
|
||||
|
||||
'@types/webxr@0.5.21': {}
|
||||
|
||||
'@uiw/codemirror-extensions-basic-setup@4.23.7(@codemirror/autocomplete@6.18.4)(@codemirror/commands@6.8.0)(@codemirror/language@6.10.8)(@codemirror/lint@6.8.4)(@codemirror/search@6.5.8)(@codemirror/state@6.5.1)(@codemirror/view@6.36.2)':
|
||||
'@uiw/codemirror-extensions-basic-setup@4.23.7(@codemirror/autocomplete@6.18.4)(@codemirror/commands@6.8.0)(@codemirror/language@6.10.8)(@codemirror/lint@6.8.4)(@codemirror/search@6.5.8)(@codemirror/state@6.5.2)(@codemirror/view@6.36.2)':
|
||||
dependencies:
|
||||
'@codemirror/autocomplete': 6.18.4
|
||||
'@codemirror/commands': 6.8.0
|
||||
'@codemirror/language': 6.10.8
|
||||
'@codemirror/lint': 6.8.4
|
||||
'@codemirror/search': 6.5.8
|
||||
'@codemirror/state': 6.5.1
|
||||
'@codemirror/state': 6.5.2
|
||||
'@codemirror/view': 6.36.2
|
||||
|
||||
'@uiw/codemirror-theme-github@4.23.7(@codemirror/language@6.10.8)(@codemirror/state@6.5.1)(@codemirror/view@6.36.2)':
|
||||
'@uiw/codemirror-theme-github@4.23.7(@codemirror/language@6.10.8)(@codemirror/state@6.5.2)(@codemirror/view@6.36.2)':
|
||||
dependencies:
|
||||
'@uiw/codemirror-themes': 4.23.7(@codemirror/language@6.10.8)(@codemirror/state@6.5.1)(@codemirror/view@6.36.2)
|
||||
'@uiw/codemirror-themes': 4.23.7(@codemirror/language@6.10.8)(@codemirror/state@6.5.2)(@codemirror/view@6.36.2)
|
||||
transitivePeerDependencies:
|
||||
- '@codemirror/language'
|
||||
- '@codemirror/state'
|
||||
- '@codemirror/view'
|
||||
|
||||
'@uiw/codemirror-themes@4.23.7(@codemirror/language@6.10.8)(@codemirror/state@6.5.1)(@codemirror/view@6.36.2)':
|
||||
'@uiw/codemirror-themes@4.23.7(@codemirror/language@6.10.8)(@codemirror/state@6.5.2)(@codemirror/view@6.36.2)':
|
||||
dependencies:
|
||||
'@codemirror/language': 6.10.8
|
||||
'@codemirror/state': 6.5.1
|
||||
'@codemirror/state': 6.5.2
|
||||
'@codemirror/view': 6.36.2
|
||||
|
||||
'@uiw/react-codemirror@4.23.7(@babel/runtime@7.26.7)(@codemirror/autocomplete@6.18.4)(@codemirror/language@6.10.8)(@codemirror/lint@6.8.4)(@codemirror/search@6.5.8)(@codemirror/state@6.5.1)(@codemirror/theme-one-dark@6.1.2)(@codemirror/view@6.36.2)(codemirror@6.0.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)':
|
||||
'@uiw/react-codemirror@4.23.7(@babel/runtime@7.26.7)(@codemirror/autocomplete@6.18.4)(@codemirror/language@6.10.8)(@codemirror/lint@6.8.4)(@codemirror/search@6.5.8)(@codemirror/state@6.5.2)(@codemirror/theme-one-dark@6.1.2)(@codemirror/view@6.36.2)(codemirror@6.0.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)':
|
||||
dependencies:
|
||||
'@babel/runtime': 7.26.7
|
||||
'@codemirror/commands': 6.8.0
|
||||
'@codemirror/state': 6.5.1
|
||||
'@codemirror/state': 6.5.2
|
||||
'@codemirror/theme-one-dark': 6.1.2
|
||||
'@codemirror/view': 6.36.2
|
||||
'@uiw/codemirror-extensions-basic-setup': 4.23.7(@codemirror/autocomplete@6.18.4)(@codemirror/commands@6.8.0)(@codemirror/language@6.10.8)(@codemirror/lint@6.8.4)(@codemirror/search@6.5.8)(@codemirror/state@6.5.1)(@codemirror/view@6.36.2)
|
||||
'@uiw/codemirror-extensions-basic-setup': 4.23.7(@codemirror/autocomplete@6.18.4)(@codemirror/commands@6.8.0)(@codemirror/language@6.10.8)(@codemirror/lint@6.8.4)(@codemirror/search@6.5.8)(@codemirror/state@6.5.2)(@codemirror/view@6.36.2)
|
||||
codemirror: 6.0.1
|
||||
react: 19.0.0
|
||||
react-dom: 19.0.0(react@19.0.0)
|
||||
@ -8420,10 +8423,10 @@ snapshots:
|
||||
dependencies:
|
||||
entities: 2.2.0
|
||||
|
||||
applesauce-accounts@0.0.0-next-20250131214402(typescript@5.7.3):
|
||||
applesauce-accounts@0.0.0-next-20250203180810(typescript@5.7.3):
|
||||
dependencies:
|
||||
'@noble/hashes': 1.7.1
|
||||
applesauce-signers: 0.0.0-next-20250131214402(typescript@5.7.3)
|
||||
applesauce-signers: 0.0.0-next-20250203180810(typescript@5.7.3)
|
||||
nanoid: 5.0.9
|
||||
nostr-tools: 2.10.4(typescript@5.7.3)
|
||||
rxjs: 7.8.1
|
||||
@ -8431,13 +8434,13 @@ snapshots:
|
||||
- supports-color
|
||||
- typescript
|
||||
|
||||
applesauce-content@0.0.0-next-20250131214402(typescript@5.7.3):
|
||||
applesauce-content@0.0.0-next-20250203180810(typescript@5.7.3):
|
||||
dependencies:
|
||||
'@cashu/cashu-ts': 2.0.0-rc1
|
||||
'@types/hast': 3.0.4
|
||||
'@types/mdast': 4.0.4
|
||||
'@types/unist': 3.0.3
|
||||
applesauce-core: 0.0.0-next-20250131214402(typescript@5.7.3)
|
||||
applesauce-core: 0.0.0-next-20250203180810(typescript@5.7.3)
|
||||
mdast-util-find-and-replace: 3.0.2
|
||||
nostr-tools: 2.10.4(typescript@5.7.3)
|
||||
remark: 15.0.1
|
||||
@ -8448,7 +8451,7 @@ snapshots:
|
||||
- supports-color
|
||||
- typescript
|
||||
|
||||
applesauce-core@0.0.0-next-20250131214402(typescript@5.7.3):
|
||||
applesauce-core@0.0.0-next-20250203180810(typescript@5.7.3):
|
||||
dependencies:
|
||||
'@scure/base': 1.2.4
|
||||
debug: 4.4.0
|
||||
@ -8476,19 +8479,19 @@ snapshots:
|
||||
- supports-color
|
||||
- typescript
|
||||
|
||||
applesauce-factory@0.0.0-next-20250131214402(typescript@5.7.3):
|
||||
applesauce-factory@0.0.0-next-20250203180810(typescript@5.7.3):
|
||||
dependencies:
|
||||
applesauce-content: 0.0.0-next-20250131214402(typescript@5.7.3)
|
||||
applesauce-core: 0.0.0-next-20250131214402(typescript@5.7.3)
|
||||
applesauce-content: 0.0.0-next-20250203180810(typescript@5.7.3)
|
||||
applesauce-core: 0.0.0-next-20250203180810(typescript@5.7.3)
|
||||
nanoid: 5.0.9
|
||||
nostr-tools: 2.10.4(typescript@5.7.3)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
- typescript
|
||||
|
||||
applesauce-loaders@0.0.0-next-20250131214402(typescript@5.7.3):
|
||||
applesauce-loaders@0.0.0-next-20250203180810(typescript@5.7.3):
|
||||
dependencies:
|
||||
applesauce-core: 0.0.0-next-20250131214402(typescript@5.7.3)
|
||||
applesauce-core: 0.0.0-next-20250203180810(typescript@5.7.3)
|
||||
nanoid: 5.0.9
|
||||
nostr-tools: 2.10.4(typescript@5.7.3)
|
||||
rx-nostr: 3.5.0
|
||||
@ -8507,12 +8510,12 @@ snapshots:
|
||||
- supports-color
|
||||
- typescript
|
||||
|
||||
applesauce-react@0.0.0-next-20250131214402(typescript@5.7.3):
|
||||
applesauce-react@0.0.0-next-20250203180810(typescript@5.7.3):
|
||||
dependencies:
|
||||
applesauce-accounts: 0.0.0-next-20250131214402(typescript@5.7.3)
|
||||
applesauce-content: 0.0.0-next-20250131214402(typescript@5.7.3)
|
||||
applesauce-core: 0.0.0-next-20250131214402(typescript@5.7.3)
|
||||
applesauce-factory: 0.0.0-next-20250131214402(typescript@5.7.3)
|
||||
applesauce-accounts: 0.0.0-next-20250203180810(typescript@5.7.3)
|
||||
applesauce-content: 0.0.0-next-20250203180810(typescript@5.7.3)
|
||||
applesauce-core: 0.0.0-next-20250203180810(typescript@5.7.3)
|
||||
applesauce-factory: 0.0.0-next-20250203180810(typescript@5.7.3)
|
||||
nostr-tools: 2.10.4(typescript@5.7.3)
|
||||
react: 18.3.1
|
||||
rxjs: 7.8.1
|
||||
@ -8520,12 +8523,12 @@ snapshots:
|
||||
- supports-color
|
||||
- typescript
|
||||
|
||||
applesauce-signers@0.0.0-next-20250131214402(typescript@5.7.3):
|
||||
applesauce-signers@0.0.0-next-20250203180810(typescript@5.7.3):
|
||||
dependencies:
|
||||
'@noble/hashes': 1.7.1
|
||||
'@noble/secp256k1': 1.7.1
|
||||
'@scure/base': 1.2.4
|
||||
applesauce-core: 0.0.0-next-20250131214402(typescript@5.7.3)
|
||||
applesauce-core: 0.0.0-next-20250203180810(typescript@5.7.3)
|
||||
debug: 4.4.0
|
||||
nanoid: 5.0.9
|
||||
nostr-tools: 2.10.4(typescript@5.7.3)
|
||||
@ -8625,7 +8628,7 @@ snapshots:
|
||||
dependencies:
|
||||
bare-events: 2.5.4
|
||||
bare-path: 3.0.0
|
||||
bare-stream: 2.6.4(bare-events@2.5.4)
|
||||
bare-stream: 2.6.5(bare-events@2.5.4)
|
||||
transitivePeerDependencies:
|
||||
- bare-buffer
|
||||
optional: true
|
||||
@ -8638,7 +8641,7 @@ snapshots:
|
||||
bare-os: 3.4.0
|
||||
optional: true
|
||||
|
||||
bare-stream@2.6.4(bare-events@2.5.4):
|
||||
bare-stream@2.6.5(bare-events@2.5.4):
|
||||
dependencies:
|
||||
streamx: 2.22.0
|
||||
optionalDependencies:
|
||||
@ -8680,7 +8683,7 @@ snapshots:
|
||||
|
||||
blossom-client-sdk@0.0.0-next-20250124155258:
|
||||
dependencies:
|
||||
'@cashu/cashu-ts': 2.1.0
|
||||
'@cashu/cashu-ts': 2.2.0
|
||||
'@noble/hashes': 1.7.1
|
||||
|
||||
blossom-client-sdk@0.9.1:
|
||||
@ -8897,11 +8900,11 @@ snapshots:
|
||||
strip-ansi: 6.0.1
|
||||
wrap-ansi: 7.0.0
|
||||
|
||||
codemirror-json-schema@0.7.9(@codemirror/language@6.10.8)(@codemirror/lint@6.8.4)(@codemirror/state@6.5.1)(@codemirror/view@6.36.2)(@lezer/common@1.2.3):
|
||||
codemirror-json-schema@0.7.9(@codemirror/language@6.10.8)(@codemirror/lint@6.8.4)(@codemirror/state@6.5.2)(@codemirror/view@6.36.2)(@lezer/common@1.2.3):
|
||||
dependencies:
|
||||
'@codemirror/language': 6.10.8
|
||||
'@codemirror/lint': 6.8.4
|
||||
'@codemirror/state': 6.5.1
|
||||
'@codemirror/state': 6.5.2
|
||||
'@codemirror/view': 6.36.2
|
||||
'@lezer/common': 1.2.3
|
||||
'@sagold/json-pointer': 5.1.2
|
||||
@ -8923,7 +8926,7 @@ snapshots:
|
||||
codemirror-json5@1.0.3:
|
||||
dependencies:
|
||||
'@codemirror/language': 6.10.8
|
||||
'@codemirror/state': 6.5.1
|
||||
'@codemirror/state': 6.5.2
|
||||
'@codemirror/view': 6.36.2
|
||||
'@lezer/common': 1.2.3
|
||||
'@lezer/highlight': 1.2.1
|
||||
@ -8944,7 +8947,7 @@ snapshots:
|
||||
'@codemirror/language': 6.10.8
|
||||
'@codemirror/lint': 6.8.4
|
||||
'@codemirror/search': 6.5.8
|
||||
'@codemirror/state': 6.5.1
|
||||
'@codemirror/state': 6.5.2
|
||||
'@codemirror/view': 6.36.2
|
||||
|
||||
color-convert@1.9.3:
|
||||
@ -9119,7 +9122,7 @@ snapshots:
|
||||
cosmiconfig@7.1.0:
|
||||
dependencies:
|
||||
'@types/parse-json': 4.0.2
|
||||
import-fresh: 3.3.0
|
||||
import-fresh: 3.3.1
|
||||
parse-json: 5.2.0
|
||||
path-type: 4.0.0
|
||||
yaml: 1.10.2
|
||||
@ -10110,7 +10113,7 @@ snapshots:
|
||||
|
||||
immutability-helper@3.1.1: {}
|
||||
|
||||
import-fresh@3.3.0:
|
||||
import-fresh@3.3.1:
|
||||
dependencies:
|
||||
parent-module: 1.0.1
|
||||
resolve-from: 4.0.0
|
||||
@ -11908,29 +11911,29 @@ snapshots:
|
||||
optionalDependencies:
|
||||
fsevents: 2.3.3
|
||||
|
||||
rollup@4.32.1:
|
||||
rollup@4.34.1:
|
||||
dependencies:
|
||||
'@types/estree': 1.0.6
|
||||
optionalDependencies:
|
||||
'@rollup/rollup-android-arm-eabi': 4.32.1
|
||||
'@rollup/rollup-android-arm64': 4.32.1
|
||||
'@rollup/rollup-darwin-arm64': 4.32.1
|
||||
'@rollup/rollup-darwin-x64': 4.32.1
|
||||
'@rollup/rollup-freebsd-arm64': 4.32.1
|
||||
'@rollup/rollup-freebsd-x64': 4.32.1
|
||||
'@rollup/rollup-linux-arm-gnueabihf': 4.32.1
|
||||
'@rollup/rollup-linux-arm-musleabihf': 4.32.1
|
||||
'@rollup/rollup-linux-arm64-gnu': 4.32.1
|
||||
'@rollup/rollup-linux-arm64-musl': 4.32.1
|
||||
'@rollup/rollup-linux-loongarch64-gnu': 4.32.1
|
||||
'@rollup/rollup-linux-powerpc64le-gnu': 4.32.1
|
||||
'@rollup/rollup-linux-riscv64-gnu': 4.32.1
|
||||
'@rollup/rollup-linux-s390x-gnu': 4.32.1
|
||||
'@rollup/rollup-linux-x64-gnu': 4.32.1
|
||||
'@rollup/rollup-linux-x64-musl': 4.32.1
|
||||
'@rollup/rollup-win32-arm64-msvc': 4.32.1
|
||||
'@rollup/rollup-win32-ia32-msvc': 4.32.1
|
||||
'@rollup/rollup-win32-x64-msvc': 4.32.1
|
||||
'@rollup/rollup-android-arm-eabi': 4.34.1
|
||||
'@rollup/rollup-android-arm64': 4.34.1
|
||||
'@rollup/rollup-darwin-arm64': 4.34.1
|
||||
'@rollup/rollup-darwin-x64': 4.34.1
|
||||
'@rollup/rollup-freebsd-arm64': 4.34.1
|
||||
'@rollup/rollup-freebsd-x64': 4.34.1
|
||||
'@rollup/rollup-linux-arm-gnueabihf': 4.34.1
|
||||
'@rollup/rollup-linux-arm-musleabihf': 4.34.1
|
||||
'@rollup/rollup-linux-arm64-gnu': 4.34.1
|
||||
'@rollup/rollup-linux-arm64-musl': 4.34.1
|
||||
'@rollup/rollup-linux-loongarch64-gnu': 4.34.1
|
||||
'@rollup/rollup-linux-powerpc64le-gnu': 4.34.1
|
||||
'@rollup/rollup-linux-riscv64-gnu': 4.34.1
|
||||
'@rollup/rollup-linux-s390x-gnu': 4.34.1
|
||||
'@rollup/rollup-linux-x64-gnu': 4.34.1
|
||||
'@rollup/rollup-linux-x64-musl': 4.34.1
|
||||
'@rollup/rollup-win32-arm64-msvc': 4.34.1
|
||||
'@rollup/rollup-win32-ia32-msvc': 4.34.1
|
||||
'@rollup/rollup-win32-x64-msvc': 4.34.1
|
||||
fsevents: 2.3.3
|
||||
|
||||
rtl-css-js@1.16.1:
|
||||
@ -12458,8 +12461,6 @@ snapshots:
|
||||
|
||||
tiny-invariant@1.3.3: {}
|
||||
|
||||
tiny-lru@11.2.11: {}
|
||||
|
||||
tinycolor2@1.6.0: {}
|
||||
|
||||
tinyglobby@0.2.10:
|
||||
@ -12747,7 +12748,7 @@ snapshots:
|
||||
dependencies:
|
||||
esbuild: 0.21.5
|
||||
postcss: 8.5.1
|
||||
rollup: 4.32.1
|
||||
rollup: 4.34.1
|
||||
optionalDependencies:
|
||||
'@types/node': 22.13.0
|
||||
fsevents: 2.3.3
|
||||
|
@ -1,128 +0,0 @@
|
||||
import { Debugger } from "debug";
|
||||
import { Filter, NostrEvent, matchFilters } from "nostr-tools";
|
||||
import { AbstractRelay } from "nostr-tools/abstract-relay";
|
||||
import { SimpleRelay } from "nostr-idb";
|
||||
import _throttle from "lodash.throttle";
|
||||
import { nanoid } from "nanoid";
|
||||
import { Subject, Subscription } from "rxjs";
|
||||
|
||||
import { logger } from "../helpers/debug";
|
||||
import EventStore from "./event-store";
|
||||
import { mergeFilter } from "../helpers/nostr/filter";
|
||||
import relayPoolService from "../services/relay-pool";
|
||||
import Process from "./process";
|
||||
import processManager from "../services/process-manager";
|
||||
import LayersThree01 from "../components/icons/layers-three-01";
|
||||
import { eventStore } from "../services/event-store";
|
||||
|
||||
const DEFAULT_CHUNK_SIZE = 100;
|
||||
|
||||
export type EventFilter = (event: NostrEvent) => boolean;
|
||||
|
||||
/** @deprecated this should be replaced with a rx-nostr based timeline loader */
|
||||
export default class ChunkedRequest {
|
||||
id: string;
|
||||
process: Process;
|
||||
relay: AbstractRelay;
|
||||
filters: Filter[];
|
||||
chunkSize = DEFAULT_CHUNK_SIZE;
|
||||
private log: Debugger;
|
||||
private subs: Subscription[] = [];
|
||||
|
||||
loading = false;
|
||||
events: EventStore;
|
||||
/** set to true when the next chunk produces 0 events */
|
||||
complete = false;
|
||||
|
||||
private lastChunkIdx = 0;
|
||||
onChunkFinish = new Subject<number>();
|
||||
|
||||
constructor(relay: SimpleRelay | AbstractRelay, filters: Filter[], log?: Debugger) {
|
||||
this.id = nanoid(8);
|
||||
this.process = new Process("ChunkedRequest", this, [relay]);
|
||||
this.process.icon = LayersThree01;
|
||||
this.relay = relay as AbstractRelay;
|
||||
this.filters = filters;
|
||||
|
||||
this.log = log || logger.extend(relay.url);
|
||||
this.events = new EventStore(relay.url);
|
||||
|
||||
processManager.registerProcess(this.process);
|
||||
}
|
||||
|
||||
async loadNextChunk() {
|
||||
if (this.loading) return;
|
||||
|
||||
// check if its possible to subscribe to this relay
|
||||
if (!relayPoolService.canSubscribe(this.relay)) {
|
||||
this.log("Cant subscribe to relay, aborting");
|
||||
return;
|
||||
}
|
||||
|
||||
this.loading = true;
|
||||
|
||||
if (!this.relay.connected) {
|
||||
this.log("requesting relay connection");
|
||||
relayPoolService.requestConnect(this.relay);
|
||||
this.loading = false;
|
||||
return;
|
||||
}
|
||||
|
||||
let filters: Filter[] = mergeFilter(this.filters, { limit: this.chunkSize });
|
||||
const oldestEvent = this.getLastEvent();
|
||||
if (oldestEvent) {
|
||||
filters = mergeFilter(filters, { until: oldestEvent.created_at - 1 });
|
||||
}
|
||||
|
||||
let gotEvents = 0;
|
||||
|
||||
this.process.active = true;
|
||||
await new Promise<number>((res) => {
|
||||
const sub = this.relay.subscribe(filters, {
|
||||
id: this.id + "-" + this.lastChunkIdx++,
|
||||
onevent: (event) => {
|
||||
this.handleEvent(event);
|
||||
gotEvents++;
|
||||
},
|
||||
oneose: () => {
|
||||
this.loading = false;
|
||||
if (gotEvents === 0) {
|
||||
this.complete = true;
|
||||
this.log("Complete");
|
||||
} else {
|
||||
this.log(`Got ${gotEvents} events`);
|
||||
}
|
||||
|
||||
this.onChunkFinish.next(gotEvents);
|
||||
sub.close();
|
||||
this.process.active = false;
|
||||
res(gotEvents);
|
||||
},
|
||||
onclose: (reason) => {
|
||||
relayPoolService.handleRelayNotice(this.relay, reason);
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private handleEvent(event: NostrEvent) {
|
||||
if (!matchFilters(this.filters, event)) return;
|
||||
|
||||
event = eventStore.add(event, this.relay.url);
|
||||
|
||||
return this.events.addEvent(event);
|
||||
}
|
||||
|
||||
getFirstEvent(nth = 0, eventFilter?: EventFilter) {
|
||||
return this.events.getFirstEvent(nth, eventFilter);
|
||||
}
|
||||
getLastEvent(nth = 0, eventFilter?: EventFilter) {
|
||||
return this.events.getLastEvent(nth, eventFilter);
|
||||
}
|
||||
|
||||
destroy() {
|
||||
for (const sub of this.subs) sub.unsubscribe();
|
||||
this.subs = [];
|
||||
processManager.unregisterProcess(this.process);
|
||||
}
|
||||
}
|
@ -1,111 +0,0 @@
|
||||
import { NostrEvent } from "nostr-tools";
|
||||
import { Subject, Subscription } from "rxjs";
|
||||
import { nanoid } from "nanoid";
|
||||
|
||||
import { getEventUID, sortByDate } from "../helpers/nostr/event";
|
||||
import SuperMap from "./super-map";
|
||||
|
||||
export type EventFilter = (event: NostrEvent) => boolean;
|
||||
|
||||
/**
|
||||
* a class used to store and sort events
|
||||
* @deprecated there shouldn't be a need for one-off event stores now that EventStore from applesauce is used
|
||||
*/
|
||||
export default class EventStore {
|
||||
id = nanoid(8);
|
||||
name?: string;
|
||||
events = new Map<string, NostrEvent>();
|
||||
|
||||
customSort?: typeof sortByDate;
|
||||
|
||||
constructor(name?: string, customSort?: typeof sortByDate) {
|
||||
this.name = name;
|
||||
this.customSort = customSort;
|
||||
}
|
||||
|
||||
getSortedEvents() {
|
||||
return Array.from(this.events.values()).sort(this.customSort || sortByDate);
|
||||
}
|
||||
|
||||
onEvent = new Subject<NostrEvent>();
|
||||
onDelete = new Subject<string>();
|
||||
onClear = new Subject();
|
||||
|
||||
private handleEvent(event: NostrEvent) {
|
||||
const uid = getEventUID(event);
|
||||
const existing = this.events.get(uid);
|
||||
if (!existing || event.created_at > existing.created_at) {
|
||||
this.events.set(uid, event);
|
||||
this.onEvent.next(event);
|
||||
}
|
||||
}
|
||||
|
||||
addEvent(event: NostrEvent) {
|
||||
this.handleEvent(event);
|
||||
}
|
||||
getEvent(id: string) {
|
||||
return this.events.get(id);
|
||||
}
|
||||
deleteEvent(id: string) {
|
||||
if (this.events.has(id)) {
|
||||
this.events.delete(id);
|
||||
this.onDelete.next(id);
|
||||
}
|
||||
}
|
||||
|
||||
clear() {
|
||||
this.events.clear();
|
||||
this.onClear.next(undefined);
|
||||
}
|
||||
|
||||
private storeSubs = new SuperMap<EventStore, Subscription[]>(() => []);
|
||||
connect(other: EventStore, fullSync = true) {
|
||||
const subs = this.storeSubs.get(other);
|
||||
subs.push(
|
||||
other.onEvent.subscribe((e) => {
|
||||
if (fullSync || this.events.has(getEventUID(e))) this.addEvent(e);
|
||||
}),
|
||||
);
|
||||
subs.push(other.onDelete.subscribe(this.deleteEvent.bind(this)));
|
||||
}
|
||||
disconnect(other: EventStore) {
|
||||
const subs = this.storeSubs.get(other);
|
||||
for (const sub of subs) sub.unsubscribe();
|
||||
this.storeSubs.delete(other);
|
||||
}
|
||||
|
||||
cleanup() {
|
||||
this.clear();
|
||||
for (const [_, subs] of this.storeSubs) {
|
||||
for (const sub of subs) sub.unsubscribe();
|
||||
}
|
||||
this.storeSubs.clear();
|
||||
}
|
||||
|
||||
getFirstEvent(nth = 0, filter?: EventFilter) {
|
||||
const events = this.getSortedEvents();
|
||||
|
||||
let i = 0;
|
||||
while (true) {
|
||||
const event = events.shift();
|
||||
if (!event) return;
|
||||
if (filter && !filter(event)) continue;
|
||||
if (i === nth) return event;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
getLastEvent(nth = 0, filter?: EventFilter) {
|
||||
const events = this.getSortedEvents();
|
||||
|
||||
let i = 0;
|
||||
while (true) {
|
||||
const event = events.pop();
|
||||
if (!event) return;
|
||||
try {
|
||||
if (filter && !filter(event)) continue;
|
||||
} catch (error) {}
|
||||
if (i === nth) return event;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,284 +0,0 @@
|
||||
import dayjs from "dayjs";
|
||||
import { Debugger } from "debug";
|
||||
import { Filter, NostrEvent } from "nostr-tools";
|
||||
import { AbstractRelay } from "nostr-tools/abstract-relay";
|
||||
import _throttle from "lodash.throttle";
|
||||
import { BehaviorSubject, Observable, Subscription, map } from "rxjs";
|
||||
import { isFilterEqual } from "applesauce-core/helpers";
|
||||
import { shareLatestValue } from "applesauce-core/observable";
|
||||
import { MultiSubscription } from "applesauce-net/subscription";
|
||||
|
||||
import { logger } from "../helpers/debug";
|
||||
import { mergeFilter } from "../helpers/nostr/filter";
|
||||
import SuperMap from "./super-map";
|
||||
import ChunkedRequest from "./chunked-request";
|
||||
import relayPoolService from "../services/relay-pool";
|
||||
import Process from "./process";
|
||||
import AlignHorizontalCentre02 from "../components/icons/align-horizontal-centre-02";
|
||||
import processManager from "../services/process-manager";
|
||||
import { eventStore, queryStore } from "../services/event-store";
|
||||
import { getCacheRelay } from "../services/cache-relay";
|
||||
|
||||
const BLOCK_SIZE = 100;
|
||||
|
||||
export type EventFilter = (event: NostrEvent) => boolean;
|
||||
|
||||
export default class TimelineLoader {
|
||||
cursor = dayjs().unix();
|
||||
filters: Filter[] = [];
|
||||
relays: AbstractRelay[] = [];
|
||||
|
||||
loading = new BehaviorSubject(false);
|
||||
complete = new BehaviorSubject(false);
|
||||
|
||||
loadNextBlockBuffer = 2;
|
||||
eventFilter?: EventFilter;
|
||||
useCache = true;
|
||||
|
||||
name: string;
|
||||
/** @deprecated */
|
||||
timeline?: Observable<NostrEvent[]>;
|
||||
process: Process;
|
||||
private log: Debugger;
|
||||
private subscription: MultiSubscription;
|
||||
|
||||
private cacheLoader: ChunkedRequest | null = null;
|
||||
private loaders = new Map<string, ChunkedRequest>();
|
||||
|
||||
constructor(name: string) {
|
||||
this.name = name;
|
||||
this.process = new Process("TimelineLoader", this);
|
||||
this.process.name = name;
|
||||
this.process.icon = AlignHorizontalCentre02;
|
||||
|
||||
this.log = logger.extend("TimelineLoader:" + name);
|
||||
|
||||
this.subscription = new MultiSubscription(relayPoolService);
|
||||
this.subscription.onEvent.subscribe(this.handleEvent.bind(this));
|
||||
|
||||
processManager.registerProcess(this.process);
|
||||
}
|
||||
|
||||
private updateTimeline() {
|
||||
const timeline = queryStore.timeline(this.filters);
|
||||
|
||||
if (this.eventFilter) {
|
||||
// add filter
|
||||
this.timeline = timeline.pipe(
|
||||
map((events) =>
|
||||
events.filter((e) => {
|
||||
try {
|
||||
return this.eventFilter!(e);
|
||||
} catch (error) {}
|
||||
return false;
|
||||
}),
|
||||
),
|
||||
shareLatestValue(),
|
||||
);
|
||||
} else {
|
||||
this.timeline = timeline.pipe(shareLatestValue());
|
||||
}
|
||||
}
|
||||
|
||||
private seenInCache = new Set<string>();
|
||||
private handleEvent(event: NostrEvent, fromCache = false) {
|
||||
event = eventStore.add(event);
|
||||
|
||||
if (fromCache) this.seenInCache.add(event.id);
|
||||
}
|
||||
private handleChunkFinished() {
|
||||
this.updateLoading();
|
||||
this.updateComplete();
|
||||
}
|
||||
|
||||
private chunkLoaderSubs = new SuperMap<ChunkedRequest, Subscription[]>(() => []);
|
||||
private connectToChunkLoader(loader: ChunkedRequest) {
|
||||
this.process.addChild(loader.process);
|
||||
|
||||
const subs = this.chunkLoaderSubs.get(loader);
|
||||
subs.push(loader.onChunkFinish.subscribe(this.handleChunkFinished.bind(this)));
|
||||
}
|
||||
private disconnectFromChunkLoader(loader: ChunkedRequest) {
|
||||
loader.destroy();
|
||||
|
||||
const subs = this.chunkLoaderSubs.get(loader);
|
||||
for (const sub of subs) sub.unsubscribe();
|
||||
this.chunkLoaderSubs.delete(loader);
|
||||
}
|
||||
|
||||
setFilters(filters: Filter[]) {
|
||||
if (isFilterEqual(this.filters, filters)) return;
|
||||
|
||||
this.log("Set filters", filters);
|
||||
|
||||
// recreate all chunk loaders
|
||||
for (const relay of this.relays) {
|
||||
const loader = this.loaders.get(relay.url);
|
||||
if (loader) {
|
||||
this.disconnectFromChunkLoader(loader);
|
||||
this.loaders.delete(relay.url);
|
||||
}
|
||||
|
||||
const chunkLoader = new ChunkedRequest(
|
||||
relayPoolService.requestRelay(relay.url),
|
||||
filters,
|
||||
this.log.extend(relay.url),
|
||||
);
|
||||
this.loaders.set(relay.url, chunkLoader);
|
||||
this.connectToChunkLoader(chunkLoader);
|
||||
}
|
||||
|
||||
// set filters
|
||||
this.filters = filters;
|
||||
|
||||
// recreate cache chunk loader
|
||||
if (this.cacheLoader) this.disconnectFromChunkLoader(this.cacheLoader);
|
||||
const cacheRelay = getCacheRelay();
|
||||
if (cacheRelay && this.useCache) {
|
||||
this.cacheLoader = new ChunkedRequest(cacheRelay, this.filters, this.log.extend("cache-relay"));
|
||||
this.connectToChunkLoader(this.cacheLoader);
|
||||
}
|
||||
|
||||
// update the live subscription query map and add limit
|
||||
this.subscription.setFilters(mergeFilter(filters, { limit: BLOCK_SIZE / 2 }));
|
||||
|
||||
// update timeline
|
||||
this.updateTimeline();
|
||||
}
|
||||
|
||||
setRelays(relays: Iterable<string | URL | AbstractRelay>) {
|
||||
const newRelays = relayPoolService.getRelays(relays);
|
||||
|
||||
// remove chunk loaders
|
||||
for (const relay of newRelays) {
|
||||
const loader = this.loaders.get(relay.url);
|
||||
if (!loader) continue;
|
||||
if (!this.relays.includes(relay)) {
|
||||
this.disconnectFromChunkLoader(loader);
|
||||
this.loaders.delete(relay.url);
|
||||
}
|
||||
}
|
||||
|
||||
// create chunk loaders only if filters are set
|
||||
if (this.filters.length > 0) {
|
||||
for (const relay of newRelays) {
|
||||
if (!this.loaders.has(relay.url)) {
|
||||
const loader = new ChunkedRequest(relay, this.filters, this.log.extend(relay.url));
|
||||
this.loaders.set(relay.url, loader);
|
||||
this.connectToChunkLoader(loader);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.relays = relayPoolService.getRelays(relays);
|
||||
this.process.relays = new Set(this.relays);
|
||||
|
||||
// update live subscription
|
||||
this.subscription.setRelays(this.relays);
|
||||
}
|
||||
|
||||
setEventFilter(filter?: EventFilter) {
|
||||
this.eventFilter = filter;
|
||||
this.updateTimeline();
|
||||
}
|
||||
setCursor(cursor: number) {
|
||||
this.cursor = cursor;
|
||||
this.triggerChunkLoad();
|
||||
}
|
||||
|
||||
private getAllLoaders() {
|
||||
return this.cacheLoader ? [...this.loaders.values(), this.cacheLoader] : Array.from(this.loaders.values());
|
||||
}
|
||||
|
||||
triggerChunkLoad() {
|
||||
let triggeredLoad = false;
|
||||
const loaders = this.getAllLoaders();
|
||||
|
||||
for (const loader of loaders) {
|
||||
// skip loader if its already loading or complete
|
||||
if (loader.complete || loader.loading) continue;
|
||||
|
||||
const event = loader.getLastEvent(this.loadNextBlockBuffer, this.eventFilter);
|
||||
if (!event || event.created_at >= this.cursor) {
|
||||
loader.loadNextChunk();
|
||||
triggeredLoad = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (triggeredLoad) this.updateLoading();
|
||||
}
|
||||
loadAllNextChunks() {
|
||||
let triggeredLoad = false;
|
||||
const loaders = this.getAllLoaders();
|
||||
|
||||
for (const loader of loaders) {
|
||||
// skip loader if its already loading or complete
|
||||
if (loader.complete || loader.loading) continue;
|
||||
|
||||
loader.loadNextChunk();
|
||||
triggeredLoad = true;
|
||||
}
|
||||
|
||||
if (triggeredLoad) this.updateLoading();
|
||||
}
|
||||
|
||||
private updateLoading() {
|
||||
const loaders = this.getAllLoaders();
|
||||
|
||||
for (const loader of loaders) {
|
||||
if (loader.loading) {
|
||||
if (!this.loading.value) {
|
||||
this.loading.next(true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (this.loading.value) this.loading.next(false);
|
||||
}
|
||||
private updateComplete() {
|
||||
const loaders = this.getAllLoaders();
|
||||
|
||||
for (const loader of loaders) {
|
||||
if (!loader.complete) {
|
||||
this.complete.next(false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
return this.complete.next(true);
|
||||
}
|
||||
open() {
|
||||
this.process.active = true;
|
||||
this.subscription.open();
|
||||
}
|
||||
close() {
|
||||
this.process.active = false;
|
||||
this.subscription.close();
|
||||
}
|
||||
|
||||
forgetEvents() {
|
||||
this.timeline = undefined;
|
||||
}
|
||||
reset() {
|
||||
this.cursor = dayjs().unix();
|
||||
const loaders = this.getAllLoaders();
|
||||
for (const loader of loaders) this.disconnectFromChunkLoader(loader);
|
||||
this.loaders.clear();
|
||||
this.cacheLoader = null;
|
||||
this.forgetEvents();
|
||||
}
|
||||
|
||||
/** close the subscription and remove any event listeners for this timeline */
|
||||
destroy() {
|
||||
this.close();
|
||||
|
||||
const loaders = this.getAllLoaders();
|
||||
for (const loader of loaders) this.disconnectFromChunkLoader(loader);
|
||||
this.loaders.clear();
|
||||
this.cacheLoader = null;
|
||||
|
||||
this.subscription.close();
|
||||
|
||||
this.process.remove();
|
||||
processManager.unregisterProcess(this.process);
|
||||
}
|
||||
}
|
@ -22,7 +22,7 @@ import useTimelineLoader from "../../hooks/use-timeline-loader";
|
||||
import { useReadRelays } from "../../hooks/use-client-relays";
|
||||
import { useTimelineCurserIntersectionCallback } from "../../hooks/use-timeline-cursor-intersection-callback";
|
||||
import IntersectionObserverProvider from "../../providers/local/intersection-observer";
|
||||
import SearchRelayPicker, { useSearchRelay } from "../../views/search/components/search-relay-picker";
|
||||
import SearchRelayPicker from "../../views/search/components/search-relay-picker";
|
||||
import useEventIntersectionRef from "../../hooks/use-event-intersection-ref";
|
||||
import { ListId, usePeopleListSelect } from "../../providers/local/people-list-provider";
|
||||
|
||||
@ -57,7 +57,7 @@ export default function GifPickerModal({ onClose, isOpen, onSelect, ...props }:
|
||||
const [list, setList] = useState<ListId>("global");
|
||||
const { selected, setSelected, filter, listId } = usePeopleListSelect(list, setList);
|
||||
|
||||
const searchRelay = useSearchRelay(searchRelayUrl);
|
||||
// const searchRelay = useSearchRelay(searchRelayUrl);
|
||||
|
||||
const [debounceSearch, setDebounceSearch] = useState<string>();
|
||||
useEffect(() => {
|
||||
@ -75,8 +75,8 @@ export default function GifPickerModal({ onClose, isOpen, onSelect, ...props }:
|
||||
|
||||
const readRelays = useReadRelays();
|
||||
const { loader, timeline } = useTimelineLoader(
|
||||
[listId, "gifs", searchRelay?.url ?? "all", debounceSearch ?? "all"].join("-"),
|
||||
searchRelay !== undefined ? [searchRelay] : readRelays,
|
||||
[listId, "gifs", searchRelayUrl ?? "all", debounceSearch ?? "all"].join("-"),
|
||||
searchRelayUrl !== undefined ? [searchRelayUrl] : readRelays,
|
||||
debounceSearch !== undefined ? { ...baseFilter, search: debounceSearch } : baseFilter,
|
||||
);
|
||||
|
||||
|
@ -2,18 +2,17 @@ import { useCallback } from "react";
|
||||
import { FlexProps } from "@chakra-ui/react";
|
||||
import { useSearchParams } from "react-router-dom";
|
||||
import { Expressions } from "applesauce-content/helpers";
|
||||
import { TimelineLoader } from "applesauce-loaders";
|
||||
|
||||
import IntersectionObserverProvider from "../../providers/local/intersection-observer";
|
||||
import GenericNoteTimeline from "./generic-note-timeline";
|
||||
import MediaTimeline from "./media-timeline";
|
||||
import TimelineLoader from "../../classes/timeline-loader";
|
||||
import { useTimelineCurserIntersectionCallback } from "../../hooks/use-timeline-cursor-intersection-callback";
|
||||
import TimelineActionAndStatus from "../timeline/timeline-action-and-status";
|
||||
import { NostrEvent } from "../../types/nostr-event";
|
||||
import TimelineHealth from "./timeline-health";
|
||||
import useRouteSearchValue from "../../hooks/use-route-search-value";
|
||||
import VerticalPageLayout from "../vertical-page-layout";
|
||||
import useAppSettings from "../../hooks/use-user-app-settings";
|
||||
import useMaxPageWidth from "../../hooks/use-max-page-width";
|
||||
|
||||
export function useTimelinePageEventFilter() {
|
||||
@ -36,13 +35,12 @@ export default function TimelinePage({
|
||||
timeline,
|
||||
header,
|
||||
...props
|
||||
}: { loader: TimelineLoader; timeline: NostrEvent[]; header?: React.ReactNode } & Omit<
|
||||
}: { loader?: TimelineLoader; timeline: NostrEvent[]; header?: React.ReactNode } & Omit<
|
||||
FlexProps,
|
||||
"children" | "direction" | "gap"
|
||||
>) {
|
||||
const callback = useTimelineCurserIntersectionCallback(loader);
|
||||
|
||||
const { maxPageWidth } = useAppSettings();
|
||||
const viewParam = useRouteSearchValue("view", "timeline");
|
||||
const mode = (viewParam.value as TimelineViewType) ?? "timeline";
|
||||
|
||||
@ -67,7 +65,7 @@ export default function TimelinePage({
|
||||
<VerticalPageLayout maxW={maxWidth} mx="auto" {...props}>
|
||||
{header}
|
||||
{renderTimeline()}
|
||||
<TimelineActionAndStatus timeline={loader} />
|
||||
<TimelineActionAndStatus loader={loader} />
|
||||
</VerticalPageLayout>
|
||||
</IntersectionObserverProvider>
|
||||
);
|
||||
|
@ -15,8 +15,8 @@ import {
|
||||
useColorMode,
|
||||
} from "@chakra-ui/react";
|
||||
import { getSeenRelays } from "applesauce-core/helpers";
|
||||
import { TimelineLoader } from "applesauce-loaders";
|
||||
|
||||
import TimelineLoader from "../../../classes/timeline-loader";
|
||||
import { NostrEvent } from "../../../types/nostr-event";
|
||||
import RelayFavicon from "../../relay-favicon";
|
||||
import { NoteLink } from "../../note/note-link";
|
||||
@ -70,8 +70,8 @@ function EventRow({
|
||||
);
|
||||
}
|
||||
|
||||
export default function TimelineHealth({ timeline, loader }: { loader: TimelineLoader; timeline: NostrEvent[] }) {
|
||||
const relays = loader.relays.map((r) => r.url);
|
||||
export default function TimelineHealth({ timeline, loader }: { loader?: TimelineLoader; timeline: NostrEvent[] }) {
|
||||
const relays = loader && loader.requests ? Object.keys(loader.requests) : [];
|
||||
|
||||
return (
|
||||
<>
|
||||
|
@ -1,11 +1,10 @@
|
||||
import { Alert, AlertIcon, Button, Spinner } from "@chakra-ui/react";
|
||||
import { TimelineLoader } from "applesauce-loaders";
|
||||
import { useObservable } from "applesauce-react/hooks";
|
||||
|
||||
import TimelineLoader from "../../classes/timeline-loader";
|
||||
|
||||
export default function TimelineActionAndStatus({ timeline }: { timeline: TimelineLoader }) {
|
||||
const loading = useObservable(timeline.loading);
|
||||
const complete = useObservable(timeline.complete);
|
||||
export default function TimelineActionAndStatus({ loader }: { loader?: TimelineLoader }) {
|
||||
const loading = useObservable(loader?.loading$);
|
||||
const complete = false;
|
||||
|
||||
if (complete) {
|
||||
return (
|
||||
@ -20,15 +19,10 @@ export default function TimelineActionAndStatus({ timeline }: { timeline: Timeli
|
||||
return <Spinner ml="auto" mr="auto" mt="8" mb="8" flexShrink={0} />;
|
||||
}
|
||||
|
||||
if (!loader) return null;
|
||||
|
||||
return (
|
||||
<Button
|
||||
onClick={() => timeline.loadAllNextChunks()}
|
||||
flexShrink={0}
|
||||
size="lg"
|
||||
mx="auto"
|
||||
colorScheme="primary"
|
||||
my="4"
|
||||
>
|
||||
<Button onClick={() => loader?.next(-Infinity)} flexShrink={0} size="lg" mx="auto" colorScheme="primary" my="4">
|
||||
Load More
|
||||
</Button>
|
||||
);
|
||||
|
@ -1,8 +1,8 @@
|
||||
import { kinds } from "nostr-tools";
|
||||
import { RelayMode } from "../../classes/relay";
|
||||
import { DraftNostrEvent, NostrEvent, RTag, Tag, isRTag } from "../../types/nostr-event";
|
||||
import { safeRelayUrl } from "../relay";
|
||||
import { cloneEvent } from "./event";
|
||||
import { RelayMode } from "../../services/app-relays";
|
||||
|
||||
/** fixes or removes any bad r tags */
|
||||
export function cleanRTags(tags: Tag[]) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { useCallback } from "react";
|
||||
import { LRU } from "tiny-lru";
|
||||
import { LRU } from "applesauce-core/helpers";
|
||||
|
||||
const cache = new LRU<Map<string, number>>(10);
|
||||
|
||||
|
46
src/hooks/use-forward-subscription.ts
Normal file
46
src/hooks/use-forward-subscription.ts
Normal file
@ -0,0 +1,46 @@
|
||||
import { nanoid } from "nanoid";
|
||||
import { Filter } from "nostr-tools";
|
||||
import { useEffect, useMemo } from "react";
|
||||
import { createRxForwardReq } from "rx-nostr";
|
||||
import hash from "hash-sum";
|
||||
|
||||
import rxNostr from "../services/rx-nostr";
|
||||
import { useEventStore } from "applesauce-react/hooks/use-event-store";
|
||||
|
||||
export default function useForwardSubscription(relays: string[], filters?: Filter | Filter[]) {
|
||||
const eventStore = useEventStore();
|
||||
const id = useMemo(() => nanoid(10), []);
|
||||
const rxReq = useMemo(() => createRxForwardReq(id), [id]);
|
||||
|
||||
// load from cache
|
||||
// useEffect(() => {
|
||||
// const sub = cacheRequest(Array.isArray(filters) ? filters : [filters]).subscribe({
|
||||
// next: (e) => eventStore.add(e),
|
||||
// complete: () => sub.unsubscribe(),
|
||||
// });
|
||||
// }, [hash(filters)]);
|
||||
|
||||
// attach to rxNostr
|
||||
const observable = useMemo(() => rxNostr.use(rxReq, { on: { relays } }), [rxReq, relays.join(",")]);
|
||||
|
||||
// subscribe
|
||||
// NOTE: have to subscribe before emitting filter
|
||||
useEffect(() => {
|
||||
const sub = observable.subscribe((packet) => {
|
||||
eventStore.add(packet.event, packet.from);
|
||||
});
|
||||
|
||||
return () => sub.unsubscribe();
|
||||
}, [observable, eventStore]);
|
||||
|
||||
// update filters
|
||||
useEffect(() => {
|
||||
if (filters) {
|
||||
if (Array.isArray(filters)) {
|
||||
if (filters.length > 0) rxReq.emit(filters);
|
||||
} else rxReq.emit([filters]);
|
||||
}
|
||||
}, [rxReq, hash(filters)]);
|
||||
|
||||
return observable;
|
||||
}
|
@ -1,15 +0,0 @@
|
||||
import { useEffect, useRef } from "react";
|
||||
import { usePrevious } from "react-use";
|
||||
|
||||
export default function useRelaysChanged(relays: string[], cb: (relays: string[]) => void) {
|
||||
const callback = useRef(cb);
|
||||
callback.current = cb;
|
||||
|
||||
const prev = usePrevious(relays);
|
||||
useEffect(() => {
|
||||
if (!!prev && prev?.join(",") !== relays.join(",")) {
|
||||
// always call the latest callback
|
||||
callback.current(relays);
|
||||
}
|
||||
}, [relays.join(",")]);
|
||||
}
|
@ -1,35 +1,43 @@
|
||||
import { useEffect, useRef } from "react";
|
||||
import { useInterval } from "react-use";
|
||||
import { NostrEvent } from "nostr-tools";
|
||||
import { TimelineLoader } from "applesauce-loaders";
|
||||
|
||||
import TimelineLoader from "../classes/timeline-loader";
|
||||
import { useCachedIntersectionMapCallback } from "../providers/local/intersection-observer";
|
||||
import { eventStore } from "../services/event-store";
|
||||
|
||||
export function useTimelineCurserIntersectionCallback(timeline: TimelineLoader) {
|
||||
export function useTimelineCurserIntersectionCallback(loader?: TimelineLoader) {
|
||||
const oldest = useRef<NostrEvent | undefined>(undefined);
|
||||
|
||||
// Request next batch when components mounts
|
||||
useEffect(() => {
|
||||
if (loader)
|
||||
setTimeout(() => {
|
||||
loader?.next(-Infinity);
|
||||
}, 100);
|
||||
}, [loader]);
|
||||
|
||||
// if the cursor is set too far ahead and the last block did not overlap with the cursor
|
||||
// we need to keep loading blocks until the timeline is complete or the blocks pass the cursor
|
||||
useInterval(() => {
|
||||
timeline.triggerChunkLoad();
|
||||
if (oldest.current) loader?.next(oldest.current.created_at - 1);
|
||||
else loader?.next(-Infinity);
|
||||
}, 1000);
|
||||
|
||||
return useCachedIntersectionMapCallback(
|
||||
(map) => {
|
||||
// find oldest event that is visible
|
||||
let oldestEvent: NostrEvent | undefined = undefined;
|
||||
for (const [id, entry] of map) {
|
||||
if (!entry.isIntersecting) continue;
|
||||
const event = eventStore.getEvent(id);
|
||||
if (!event) continue;
|
||||
if (!oldestEvent || event.created_at < oldestEvent.created_at) {
|
||||
oldestEvent = event;
|
||||
if (!oldest.current || event.created_at < oldest.current.created_at - 1) {
|
||||
oldest.current = event;
|
||||
}
|
||||
}
|
||||
|
||||
if (oldestEvent) {
|
||||
timeline.setCursor(oldestEvent.created_at);
|
||||
timeline.triggerChunkLoad();
|
||||
}
|
||||
if (oldest.current) loader?.next(oldest.current.created_at);
|
||||
},
|
||||
[timeline],
|
||||
[loader],
|
||||
);
|
||||
}
|
||||
|
@ -1,67 +1,43 @@
|
||||
import { useEffect, useMemo } from "react";
|
||||
import { usePrevious, useUnmount } from "react-use";
|
||||
import { AbstractRelay } from "nostr-tools/abstract-relay";
|
||||
import { useStoreQuery } from "applesauce-react/hooks";
|
||||
import { useEventStore } from "applesauce-react/hooks/use-event-store";
|
||||
import { Queries } from "applesauce-core";
|
||||
import { Filter } from "nostr-tools";
|
||||
import { Filter, NostrEvent } from "nostr-tools";
|
||||
import sum from "hash-sum";
|
||||
|
||||
import timelineCacheService from "../services/timeline-cache";
|
||||
import { EventFilter } from "../classes/timeline-loader";
|
||||
import useForwardSubscription from "./use-forward-subscription";
|
||||
|
||||
type Options = {
|
||||
eventFilter?: EventFilter;
|
||||
useCache?: boolean;
|
||||
eventFilter?: (event: NostrEvent) => boolean;
|
||||
};
|
||||
|
||||
export default function useTimelineLoader(
|
||||
key: string,
|
||||
relays: Iterable<string | AbstractRelay>,
|
||||
relays: string[],
|
||||
filters: Filter | Filter[] | undefined,
|
||||
opts?: Options,
|
||||
) {
|
||||
const loader = useMemo(() => timelineCacheService.createTimeline(key), [key]);
|
||||
// start a forward subscription while component is mounted
|
||||
useForwardSubscription(relays, filters);
|
||||
|
||||
// set use cache
|
||||
if (opts?.useCache !== undefined) loader.useCache = opts?.useCache;
|
||||
const eventStore = useEventStore();
|
||||
const loader = useMemo(() => {
|
||||
if (filters) return timelineCacheService.createTimeline(key, relays, Array.isArray(filters) ? filters : [filters]);
|
||||
}, [key, sum(filters), relays.join(",")]);
|
||||
|
||||
// update relays
|
||||
// start and stop loader
|
||||
useEffect(() => {
|
||||
loader.setRelays(relays);
|
||||
loader.triggerChunkLoad();
|
||||
}, [
|
||||
Array.from(relays)
|
||||
.map((t) => (typeof t === "string" ? t : t.url))
|
||||
.join("|"),
|
||||
]);
|
||||
const sub = loader?.subscribe((packet) => {
|
||||
eventStore.add(packet.event, packet.from);
|
||||
});
|
||||
|
||||
// update filters
|
||||
useEffect(() => {
|
||||
if (filters) {
|
||||
loader.setFilters(Array.isArray(filters) ? filters : [filters]);
|
||||
loader.open();
|
||||
loader.triggerChunkLoad();
|
||||
} else loader.close();
|
||||
}, [loader, JSON.stringify(filters)]);
|
||||
|
||||
// update event filter
|
||||
useEffect(() => {
|
||||
loader.setEventFilter(opts?.eventFilter);
|
||||
}, [loader, opts?.eventFilter]);
|
||||
|
||||
// close the old timeline when the key changes
|
||||
const oldTimeline = usePrevious(loader);
|
||||
useEffect(() => {
|
||||
if (oldTimeline && oldTimeline !== loader) {
|
||||
oldTimeline.close();
|
||||
}
|
||||
}, [loader, oldTimeline]);
|
||||
|
||||
// stop the loader when unmount
|
||||
useUnmount(() => {
|
||||
loader.close();
|
||||
});
|
||||
return () => sub?.unsubscribe();
|
||||
}, [eventStore, loader]);
|
||||
|
||||
let timeline = useStoreQuery(Queries.TimelineQuery, filters && [filters]) ?? [];
|
||||
|
||||
// set event filter
|
||||
if (opts?.eventFilter)
|
||||
timeline = timeline.filter((e) => {
|
||||
try {
|
||||
|
@ -1,53 +0,0 @@
|
||||
import { PropsWithChildren, createContext, useCallback, useContext, useMemo } from "react";
|
||||
import { kinds } from "nostr-tools";
|
||||
import { useActiveAccount } from "applesauce-react/hooks";
|
||||
|
||||
import TimelineLoader from "../../classes/timeline-loader";
|
||||
import { NostrEvent } from "../../types/nostr-event";
|
||||
import useClientSideMuteFilter from "../../hooks/use-client-side-mute-filter";
|
||||
import useTimelineLoader from "../../hooks/use-timeline-loader";
|
||||
import { useUserInbox } from "../../hooks/use-user-mailboxes";
|
||||
import { truncateId } from "../../helpers/string";
|
||||
|
||||
type DMTimelineContextType = {
|
||||
timeline?: TimelineLoader;
|
||||
};
|
||||
const DMTimelineContext = createContext<DMTimelineContextType>({});
|
||||
|
||||
export function useDMTimeline() {
|
||||
const context = useContext(DMTimelineContext);
|
||||
|
||||
if (!context?.timeline) throw new Error("No dm timeline");
|
||||
|
||||
return context.timeline;
|
||||
}
|
||||
|
||||
export default function DMTimelineProvider({ children }: PropsWithChildren) {
|
||||
const account = useActiveAccount();
|
||||
const inbox = useUserInbox(account?.pubkey);
|
||||
|
||||
const userMuteFilter = useClientSideMuteFilter();
|
||||
const eventFilter = useCallback(
|
||||
(event: NostrEvent) => {
|
||||
if (userMuteFilter(event)) return false;
|
||||
return true;
|
||||
},
|
||||
[userMuteFilter],
|
||||
);
|
||||
|
||||
const { loader } = useTimelineLoader(
|
||||
`${truncateId(account?.pubkey ?? "anon")}-dms`,
|
||||
inbox ?? [],
|
||||
account?.pubkey
|
||||
? [
|
||||
{ authors: [account.pubkey], kinds: [kinds.EncryptedDirectMessage] },
|
||||
{ "#p": [account.pubkey], kinds: [kinds.EncryptedDirectMessage] },
|
||||
]
|
||||
: undefined,
|
||||
{ eventFilter },
|
||||
);
|
||||
|
||||
const context = useMemo(() => ({ timeline: loader }), [loader]);
|
||||
|
||||
return <DMTimelineContext.Provider value={context}>{children}</DMTimelineContext.Provider>;
|
||||
}
|
@ -8,7 +8,6 @@ import useAppSettings from "../../hooks/use-user-app-settings";
|
||||
import NotificationsProvider from "./notifications-provider";
|
||||
import { UserEmojiProvider } from "./emoji-provider";
|
||||
import BreakpointProvider from "./breakpoint-provider";
|
||||
import DMTimelineProvider from "./dms-provider";
|
||||
import PublishProvider from "./publish-provider";
|
||||
import WebOfTrustProvider from "./web-of-trust-provider";
|
||||
import { queryStore } from "../../services/event-store";
|
||||
@ -35,13 +34,11 @@ export const GlobalProviders = ({ children }: { children: React.ReactNode }) =>
|
||||
<SigningProvider>
|
||||
<PublishProvider>
|
||||
<NotificationsProvider>
|
||||
<DMTimelineProvider>
|
||||
<UserEmojiProvider>
|
||||
<EventFactoryProvider>
|
||||
<WebOfTrustProvider>{children}</WebOfTrustProvider>
|
||||
</EventFactoryProvider>
|
||||
</UserEmojiProvider>
|
||||
</DMTimelineProvider>
|
||||
<UserEmojiProvider>
|
||||
<EventFactoryProvider>
|
||||
<WebOfTrustProvider>{children}</WebOfTrustProvider>
|
||||
</EventFactoryProvider>
|
||||
</UserEmojiProvider>
|
||||
</NotificationsProvider>
|
||||
</PublishProvider>
|
||||
</SigningProvider>
|
||||
|
@ -1,9 +1,9 @@
|
||||
import { PropsWithChildren, createContext, useCallback, useContext, useEffect, useMemo, useState } from "react";
|
||||
import { kinds } from "nostr-tools";
|
||||
import { useActiveAccount } from "applesauce-react/hooks";
|
||||
import { TimelineLoader } from "applesauce-loaders";
|
||||
|
||||
import { useReadRelays } from "../../hooks/use-client-relays";
|
||||
import TimelineLoader from "../../classes/timeline-loader";
|
||||
import { NostrEvent } from "../../types/nostr-event";
|
||||
import useClientSideMuteFilter from "../../hooks/use-client-side-mute-filter";
|
||||
import useTimelineLoader from "../../hooks/use-timeline-loader";
|
||||
@ -13,7 +13,7 @@ import AccountNotifications from "../../classes/notifications";
|
||||
import { truncateId } from "../../helpers/string";
|
||||
|
||||
type NotificationTimelineContextType = {
|
||||
timeline: TimelineLoader;
|
||||
timeline?: TimelineLoader;
|
||||
notifications?: AccountNotifications;
|
||||
};
|
||||
const NotificationTimelineContext = createContext<NotificationTimelineContextType | null>(null);
|
||||
|
@ -1,8 +1,6 @@
|
||||
import { PropsWithChildren, createContext, useCallback, useContext, useMemo } from "react";
|
||||
import { NostrEvent } from "nostr-tools";
|
||||
import { useObservable } from "applesauce-react/hooks";
|
||||
|
||||
import TimelineLoader from "../../classes/timeline-loader";
|
||||
import { eventStore } from "../../services/event-store";
|
||||
|
||||
export type Thread = {
|
||||
@ -25,9 +23,7 @@ export function useThreadsContext() {
|
||||
return useContext(ThreadsContext);
|
||||
}
|
||||
|
||||
export default function ThreadsProvider({ timeline, children }: { timeline: TimelineLoader } & PropsWithChildren) {
|
||||
const messages = useObservable(timeline.timeline) ?? [];
|
||||
|
||||
export default function ThreadsProvider({ messages, children }: { messages: NostrEvent[] } & PropsWithChildren) {
|
||||
const threads = useMemo(() => {
|
||||
const grouped: Record<string, Thread> = {};
|
||||
for (const message of messages) {
|
||||
|
@ -1,36 +1,25 @@
|
||||
import TimelineLoader from "../classes/timeline-loader";
|
||||
import { LRU } from "applesauce-core/helpers";
|
||||
import { TimelessFilter, TimelineLoader } from "applesauce-loaders";
|
||||
|
||||
import rxNostr from "./rx-nostr";
|
||||
import { logger } from "../helpers/debug";
|
||||
|
||||
const MAX_CACHE = 30;
|
||||
const BATCH_LIMIT = 100;
|
||||
|
||||
class TimelineCacheService {
|
||||
private timelines = new Map<string, TimelineLoader>();
|
||||
private cacheQueue: string[] = [];
|
||||
private log = logger.extend("TimelineCacheService");
|
||||
protected timelines = new LRU<TimelineLoader>(MAX_CACHE);
|
||||
protected log = logger.extend("TimelineCacheService");
|
||||
|
||||
createTimeline(key: string) {
|
||||
createTimeline(key: string, relays: string[], filters: TimelessFilter[]) {
|
||||
let timeline = this.timelines.get(key);
|
||||
if (!timeline) {
|
||||
|
||||
if (!timeline && relays.length > 0 && filters.length > 0) {
|
||||
this.log(`Creating ${key}`);
|
||||
timeline = new TimelineLoader(key);
|
||||
timeline = new TimelineLoader(rxNostr, TimelineLoader.simpleFilterMap(relays, filters), { limit: BATCH_LIMIT });
|
||||
this.timelines.set(key, timeline);
|
||||
}
|
||||
|
||||
// add or move the timelines key to the top of the queue
|
||||
this.cacheQueue = this.cacheQueue.filter((p) => p !== key).concat(key);
|
||||
|
||||
// remove any timelines at the end of the queue
|
||||
while (this.cacheQueue.length > MAX_CACHE) {
|
||||
const deleteKey = this.cacheQueue.shift();
|
||||
if (!deleteKey) break;
|
||||
const deadTimeline = this.timelines.get(deleteKey);
|
||||
if (deadTimeline) {
|
||||
this.log(`Destroying ${deadTimeline.name}`);
|
||||
this.timelines.delete(deleteKey);
|
||||
deadTimeline.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
return timeline;
|
||||
}
|
||||
}
|
||||
|
@ -61,7 +61,7 @@ function ArticlesHomePage() {
|
||||
<ArticleCard article={article} />
|
||||
</ErrorBoundary>
|
||||
))}
|
||||
<TimelineActionAndStatus timeline={loader} />
|
||||
<TimelineActionAndStatus loader={loader} />
|
||||
</IntersectionObserverProvider>
|
||||
</VerticalPageLayout>
|
||||
);
|
||||
|
@ -1,6 +1,5 @@
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { kinds } from "nostr-tools";
|
||||
import { useObservable } from "applesauce-react/hooks";
|
||||
import {
|
||||
Button,
|
||||
Flex,
|
||||
@ -32,31 +31,22 @@ import UserLink from "../../components/user/user-link";
|
||||
import Timestamp from "../../components/timestamp";
|
||||
import VerticalPageLayout from "../../components/vertical-page-layout";
|
||||
import BadgeAwardCard from "./components/badge-award-card";
|
||||
import TimelineLoader from "../../classes/timeline-loader";
|
||||
import { ErrorBoundary } from "../../components/error-boundary";
|
||||
import useParamsAddressPointer from "../../hooks/use-params-address-pointer";
|
||||
|
||||
function BadgeActivityTab({ timeline }: { timeline: TimelineLoader }) {
|
||||
const awards = useObservable(timeline.timeline);
|
||||
const callback = useTimelineCurserIntersectionCallback(timeline);
|
||||
|
||||
function BadgeActivityTab({ awards }: { awards: NostrEvent[] }) {
|
||||
return (
|
||||
<Flex direction="column" gap="4">
|
||||
<IntersectionObserverProvider callback={callback}>
|
||||
{awards?.map((award) => (
|
||||
<ErrorBoundary key={award.id}>
|
||||
<BadgeAwardCard award={award} showImage={false} />
|
||||
</ErrorBoundary>
|
||||
))}
|
||||
</IntersectionObserverProvider>
|
||||
{awards?.map((award) => (
|
||||
<ErrorBoundary key={award.id}>
|
||||
<BadgeAwardCard award={award} showImage={false} />
|
||||
</ErrorBoundary>
|
||||
))}
|
||||
</Flex>
|
||||
);
|
||||
}
|
||||
|
||||
function BadgeUsersTab({ timeline }: { timeline: TimelineLoader }) {
|
||||
const awards = useObservable(timeline.timeline);
|
||||
const callback = useTimelineCurserIntersectionCallback(timeline);
|
||||
|
||||
function BadgeUsersTab({ awards }: { awards: NostrEvent[] }) {
|
||||
const pubkeys = new Set<string>();
|
||||
if (awards) {
|
||||
for (const award of awards) {
|
||||
@ -68,14 +58,12 @@ function BadgeUsersTab({ timeline }: { timeline: TimelineLoader }) {
|
||||
|
||||
return (
|
||||
<SimpleGrid spacing={4} columns={[1, 2, 2, 3, 4, 5, 6]}>
|
||||
<IntersectionObserverProvider callback={callback}>
|
||||
{Array.from(pubkeys).map((pubkey) => (
|
||||
<Flex key={pubkey} gap="2" alignItems="center">
|
||||
<UserAvatarLink pubkey={pubkey} size="md" />
|
||||
<UserLink pubkey={pubkey} fontWeight="bold" isTruncated />
|
||||
</Flex>
|
||||
))}
|
||||
</IntersectionObserverProvider>
|
||||
{Array.from(pubkeys).map((pubkey) => (
|
||||
<Flex key={pubkey} gap="2" alignItems="center">
|
||||
<UserAvatarLink pubkey={pubkey} size="md" />
|
||||
<UserLink pubkey={pubkey} fontWeight="bold" isTruncated />
|
||||
</Flex>
|
||||
))}
|
||||
</SimpleGrid>
|
||||
);
|
||||
}
|
||||
@ -88,68 +76,72 @@ function BadgeDetailsPage({ badge }: { badge: NostrEvent }) {
|
||||
|
||||
const readRelays = useReadRelays();
|
||||
const coordinate = getEventCoordinate(badge);
|
||||
const { loader } = useTimelineLoader(`${coordinate}-awards`, readRelays, {
|
||||
const { loader, timeline } = useTimelineLoader(`${coordinate}-awards`, readRelays, {
|
||||
"#a": [coordinate],
|
||||
kinds: [kinds.BadgeAward],
|
||||
});
|
||||
|
||||
const callback = useTimelineCurserIntersectionCallback(loader);
|
||||
|
||||
if (!badge) return <Spinner />;
|
||||
|
||||
return (
|
||||
<VerticalPageLayout>
|
||||
<Flex gap="2" alignItems="center" wrap="wrap">
|
||||
<Button onClick={() => navigate(-1)} leftIcon={<ChevronLeftIcon />}>
|
||||
Back
|
||||
</Button>
|
||||
<IntersectionObserverProvider callback={callback}>
|
||||
<Flex gap="2" alignItems="center" wrap="wrap">
|
||||
<Button onClick={() => navigate(-1)} leftIcon={<ChevronLeftIcon />}>
|
||||
Back
|
||||
</Button>
|
||||
|
||||
<UserAvatarLink pubkey={badge.pubkey} size="sm" />
|
||||
<UserLink fontWeight="bold" pubkey={badge.pubkey} />
|
||||
<Text>|</Text>
|
||||
<Heading size="md">{getBadgeName(badge)}</Heading>
|
||||
|
||||
<Spacer />
|
||||
|
||||
<BadgeMenu aria-label="More options" badge={badge} />
|
||||
</Flex>
|
||||
|
||||
<Flex direction={{ base: "column", lg: "row" }} gap="4">
|
||||
{image && (
|
||||
<Image src={image.src} maxW="3in" mr="2" mb="2" mx={{ base: "auto", lg: "initial" }} borderRadius="lg" />
|
||||
)}
|
||||
<Flex direction="column">
|
||||
<UserAvatarLink pubkey={badge.pubkey} size="sm" />
|
||||
<UserLink fontWeight="bold" pubkey={badge.pubkey} />
|
||||
<Text>|</Text>
|
||||
<Heading size="md">{getBadgeName(badge)}</Heading>
|
||||
<Text>
|
||||
Created by: <UserAvatarLink pubkey={badge.pubkey} size="xs" />{" "}
|
||||
<UserLink fontWeight="bold" pubkey={badge.pubkey} />
|
||||
</Text>
|
||||
<Text>
|
||||
Created: <Timestamp timestamp={badge.created_at} />
|
||||
</Text>
|
||||
{description && (
|
||||
<>
|
||||
<Heading size="md" mt="2">
|
||||
Description
|
||||
</Heading>
|
||||
<Text pb="2">{description}</Text>
|
||||
</>
|
||||
)}
|
||||
</Flex>
|
||||
</Flex>
|
||||
|
||||
<Tabs colorScheme="primary" isLazy>
|
||||
<TabList>
|
||||
<Tab>Activity</Tab>
|
||||
<Tab>Users</Tab>
|
||||
</TabList>
|
||||
<TabPanels>
|
||||
<TabPanel px="0">
|
||||
<BadgeActivityTab timeline={loader} />
|
||||
</TabPanel>
|
||||
<TabPanel>
|
||||
<BadgeUsersTab timeline={loader} />
|
||||
</TabPanel>
|
||||
</TabPanels>
|
||||
</Tabs>
|
||||
<Spacer />
|
||||
|
||||
<BadgeMenu aria-label="More options" badge={badge} />
|
||||
</Flex>
|
||||
|
||||
<Flex direction={{ base: "column", lg: "row" }} gap="4">
|
||||
{image && (
|
||||
<Image src={image.src} maxW="3in" mr="2" mb="2" mx={{ base: "auto", lg: "initial" }} borderRadius="lg" />
|
||||
)}
|
||||
<Flex direction="column">
|
||||
<Heading size="md">{getBadgeName(badge)}</Heading>
|
||||
<Text>
|
||||
Created by: <UserAvatarLink pubkey={badge.pubkey} size="xs" />{" "}
|
||||
<UserLink fontWeight="bold" pubkey={badge.pubkey} />
|
||||
</Text>
|
||||
<Text>
|
||||
Created: <Timestamp timestamp={badge.created_at} />
|
||||
</Text>
|
||||
{description && (
|
||||
<>
|
||||
<Heading size="md" mt="2">
|
||||
Description
|
||||
</Heading>
|
||||
<Text pb="2">{description}</Text>
|
||||
</>
|
||||
)}
|
||||
</Flex>
|
||||
</Flex>
|
||||
|
||||
<Tabs colorScheme="primary" isLazy>
|
||||
<TabList>
|
||||
<Tab>Activity</Tab>
|
||||
<Tab>Users</Tab>
|
||||
</TabList>
|
||||
<TabPanels>
|
||||
<TabPanel px="0">
|
||||
<BadgeActivityTab awards={timeline} />
|
||||
</TabPanel>
|
||||
<TabPanel>
|
||||
<BadgeUsersTab awards={timeline} />
|
||||
</TabPanel>
|
||||
</TabPanels>
|
||||
</Tabs>
|
||||
</IntersectionObserverProvider>
|
||||
</VerticalPageLayout>
|
||||
);
|
||||
}
|
||||
|
@ -1,5 +1,4 @@
|
||||
import { memo, useCallback, useMemo } from "react";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { Button, ButtonGroup, Flex, Spinner, useDisclosure } from "@chakra-ui/react";
|
||||
import { kinds } from "nostr-tools";
|
||||
import { useStoreQuery } from "applesauce-react/hooks";
|
||||
@ -17,7 +16,6 @@ import useTimelineLoader from "../../hooks/use-timeline-loader";
|
||||
import { useTimelineCurserIntersectionCallback } from "../../hooks/use-timeline-cursor-intersection-callback";
|
||||
import IntersectionObserverProvider from "../../providers/local/intersection-observer";
|
||||
import ThreadsProvider from "../../providers/local/thread-provider";
|
||||
import TimelineLoader from "../../classes/timeline-loader";
|
||||
import { groupMessages } from "../../helpers/nostr/dms";
|
||||
import ChannelMessageBlock from "./components/channel-message-block";
|
||||
import TimelineActionAndStatus from "../../components/timeline/timeline-action-and-status";
|
||||
@ -28,7 +26,7 @@ import { truncateId } from "../../helpers/string";
|
||||
import ContainedSimpleView from "../../components/layout/presets/contained-simple-view";
|
||||
import ChannelImage from "./components/channel-image";
|
||||
|
||||
const ChannelChatLog = memo(({ timeline, channel }: { timeline: TimelineLoader; channel: NostrEvent }) => {
|
||||
const ChannelChatLog = memo(({ channel }: { channel: NostrEvent }) => {
|
||||
const messages = useStoreQuery(ChannelMessagesQuery, [channel]) ?? [];
|
||||
const mutes = useStoreQuery(ChannelMutedQuery, [channel]);
|
||||
const hidden = useStoreQuery(ChannelHiddenQuery, [channel]);
|
||||
@ -55,7 +53,6 @@ const ChannelChatLog = memo(({ timeline, channel }: { timeline: TimelineLoader;
|
||||
});
|
||||
|
||||
function ChannelPage({ channel }: { channel: NostrEvent }) {
|
||||
const navigate = useNavigate();
|
||||
const relays = useReadRelays();
|
||||
const drawer = useDisclosure();
|
||||
|
||||
@ -81,7 +78,7 @@ function ChannelPage({ channel }: { channel: NostrEvent }) {
|
||||
const callback = useTimelineCurserIntersectionCallback(loader);
|
||||
|
||||
return (
|
||||
<ThreadsProvider timeline={loader}>
|
||||
<ThreadsProvider messages={timeline}>
|
||||
<IntersectionObserverProvider callback={callback}>
|
||||
<ContainedSimpleView
|
||||
reverse
|
||||
@ -100,8 +97,8 @@ function ChannelPage({ channel }: { channel: NostrEvent }) {
|
||||
}
|
||||
bottom={<ChannelMessageForm channel={channel} p="2" />}
|
||||
>
|
||||
<ChannelChatLog timeline={loader} channel={channel} />
|
||||
<TimelineActionAndStatus timeline={loader} />
|
||||
<ChannelChatLog channel={channel} />
|
||||
<TimelineActionAndStatus loader={loader} />
|
||||
</ContainedSimpleView>
|
||||
{drawer.isOpen && <ChannelMetadataDrawer isOpen onClose={drawer.onClose} channel={channel} size="lg" />}
|
||||
</IntersectionObserverProvider>
|
||||
|
@ -41,7 +41,7 @@ function UserCard({ pubkey }: { pubkey: string }) {
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
function ChannelMembers({ channel, relays }: { channel: NostrEvent; relays: Iterable<string> }) {
|
||||
function ChannelMembers({ channel, relays }: { channel: NostrEvent; relays: string[] }) {
|
||||
const { loader, timeline: userLists } = useTimelineLoader(`${channel.id}-members`, relays, {
|
||||
kinds: [kinds.PublicChatsList],
|
||||
"#e": [channel.id],
|
||||
|
@ -113,7 +113,7 @@ function FilesHomePage() {
|
||||
</Table>
|
||||
</TableContainer>
|
||||
</IntersectionObserverProvider>
|
||||
<TimelineActionAndStatus timeline={loader} />
|
||||
<TimelineActionAndStatus loader={loader} />
|
||||
</VerticalPageLayout>
|
||||
);
|
||||
}
|
||||
|
@ -18,7 +18,6 @@ import useTimelineLoader from "../../hooks/use-timeline-loader";
|
||||
import { isReply, isRepost } from "../../helpers/nostr/event";
|
||||
import { CheckIcon, EditIcon } from "../../components/icons";
|
||||
import { NostrEvent } from "../../types/nostr-event";
|
||||
import useRelaysChanged from "../../hooks/use-relays-changed";
|
||||
import TimelinePage, { useTimelinePageEventFilter } from "../../components/timeline-page";
|
||||
import TimelineViewTypeButtons from "../../components/timeline-page/timeline-view-type";
|
||||
import useClientSideMuteFilter from "../../hooks/use-client-side-mute-filter";
|
||||
@ -74,8 +73,6 @@ function HashTagPage() {
|
||||
{ eventFilter },
|
||||
);
|
||||
|
||||
useRelaysChanged(readRelays, () => loader.reset());
|
||||
|
||||
const header = (
|
||||
<Flex gap="2" alignItems="center" wrap="wrap">
|
||||
<Editable
|
||||
|
@ -1,12 +1,10 @@
|
||||
import { useMemo, useState } from "react";
|
||||
import { Button, Card, CardBody, CardHeader, CardProps, Flex, Heading, Link, LinkBox, Text } from "@chakra-ui/react";
|
||||
import { Link as RouterLink, useNavigate } from "react-router-dom";
|
||||
import { useObservable } from "applesauce-react/hooks";
|
||||
import { nip19 } from "nostr-tools";
|
||||
|
||||
import KeyboardShortcut from "../../../components/keyboard-shortcut";
|
||||
import { useActiveAccount } from "applesauce-react/hooks";
|
||||
import { useDMTimeline } from "../../../providers/global/dms-provider";
|
||||
import {
|
||||
KnownConversation,
|
||||
groupIntoConversations,
|
||||
@ -22,6 +20,7 @@ import UserDnsIdentity from "../../../components/user/user-dns-identity";
|
||||
import Timestamp from "../../../components/timestamp";
|
||||
import { useKind4Decrypt } from "../../../hooks/use-kind4-decryption";
|
||||
import decryptionCacheService from "../../../services/decryption-cache";
|
||||
import { useDirectMessagesTimeline } from "../../messages";
|
||||
|
||||
function MessagePreview({ message, pubkey }: { message: NostrEvent; pubkey: string }) {
|
||||
const { plaintext } = useKind4Decrypt(message);
|
||||
@ -52,9 +51,8 @@ export default function DMsCard({ ...props }: Omit<CardProps, "children">) {
|
||||
const navigate = useNavigate();
|
||||
const account = useActiveAccount()!;
|
||||
|
||||
const timeline = useDMTimeline();
|
||||
const { timeline: messages } = useDirectMessagesTimeline(account.pubkey);
|
||||
|
||||
const messages = useObservable(timeline.timeline) ?? [];
|
||||
const conversations = useMemo(() => {
|
||||
const grouped = groupIntoConversations(messages)
|
||||
.map((c) => identifyConversation(c, account.pubkey))
|
||||
|
@ -82,8 +82,7 @@ export default function MapView() {
|
||||
setFocused(event.id);
|
||||
}, []);
|
||||
|
||||
const events = useObservable(loader.timeline) ?? [];
|
||||
useEventMarkers(events, map, handleMarkerClick);
|
||||
useEventMarkers(timeline, map, handleMarkerClick);
|
||||
|
||||
return (
|
||||
<Flex overflow={{ lg: "hidden" }} h={{ lg: "full" }} direction={{ base: "column-reverse", lg: "row" }}>
|
||||
@ -98,8 +97,8 @@ export default function MapView() {
|
||||
</Flex>
|
||||
|
||||
<Flex overflowY="auto" overflowX="hidden" gap="2" direction="column" h="full">
|
||||
<MapTimeline timeline={loader} focused={focused} />
|
||||
{cells.length > 0 && <TimelineActionAndStatus timeline={loader} />}
|
||||
<MapTimeline timeline={timeline} focused={focused} />
|
||||
{cells.length > 0 && <TimelineActionAndStatus loader={loader} />}
|
||||
</Flex>
|
||||
</Flex>
|
||||
|
||||
|
@ -1,10 +1,8 @@
|
||||
import React from "react";
|
||||
import { kinds } from "nostr-tools";
|
||||
import { useObservable } from "applesauce-react/hooks";
|
||||
|
||||
import { ErrorBoundary } from "../../components/error-boundary";
|
||||
import StreamNote from "../../components/timeline-page/generic-note-timeline/stream-note";
|
||||
import TimelineLoader from "../../classes/timeline-loader";
|
||||
import { NostrEvent } from "../../types/nostr-event";
|
||||
import TimelineNote from "../../components/note/timeline-note";
|
||||
|
||||
@ -19,12 +17,10 @@ const RenderEvent = React.memo(({ event, focused }: { event: NostrEvent; focused
|
||||
}
|
||||
});
|
||||
|
||||
const MapTimeline = React.memo(({ timeline, focused }: { timeline: TimelineLoader; focused?: string }) => {
|
||||
const events = useObservable(timeline.timeline);
|
||||
|
||||
const MapTimeline = React.memo(({ timeline, focused }: { timeline: NostrEvent[]; focused?: string }) => {
|
||||
return (
|
||||
<>
|
||||
{events?.map((event) => (
|
||||
{timeline?.map((event) => (
|
||||
<ErrorBoundary key={event.id} event={event}>
|
||||
<RenderEvent event={event} focused={focused === event.id} />
|
||||
</ErrorBoundary>
|
||||
|
@ -112,7 +112,7 @@ function DirectMessageChatPage({ pubkey }: { pubkey: string }) {
|
||||
const callback = useTimelineCurserIntersectionCallback(loader);
|
||||
|
||||
return (
|
||||
<ThreadsProvider timeline={loader}>
|
||||
<ThreadsProvider messages={messages}>
|
||||
<IntersectionObserverProvider callback={callback}>
|
||||
<ContainedSimpleView
|
||||
reverse
|
||||
@ -141,7 +141,7 @@ function DirectMessageChatPage({ pubkey }: { pubkey: string }) {
|
||||
bottom={<SendMessageForm flexShrink={0} pubkey={pubkey} p="2" />}
|
||||
>
|
||||
<ChatLog messages={messages} />
|
||||
<TimelineActionAndStatus timeline={loader} />
|
||||
<TimelineActionAndStatus loader={loader} />
|
||||
{location.state?.thread && (
|
||||
<ThreadDrawer isOpen onClose={closeDrawer} threadId={location.state.thread} pubkey={pubkey} />
|
||||
)}
|
||||
|
@ -1,8 +1,7 @@
|
||||
import { useMemo } from "react";
|
||||
import { useCallback, useMemo } from "react";
|
||||
import { Card, CardBody, Flex, LinkBox, LinkOverlay, Text } from "@chakra-ui/react";
|
||||
import { Link as RouterLink, useLocation } from "react-router-dom";
|
||||
import { useObservable } from "applesauce-react/hooks";
|
||||
import { nip19 } from "nostr-tools";
|
||||
import { kinds, nip19 } from "nostr-tools";
|
||||
|
||||
import UserAvatar from "../../components/user/user-avatar";
|
||||
import RequireActiveAccount from "../../components/router/require-active-account";
|
||||
@ -14,7 +13,6 @@ import { KnownConversation, groupIntoConversations, hasResponded, identifyConver
|
||||
import IntersectionObserverProvider from "../../providers/local/intersection-observer";
|
||||
import { useTimelineCurserIntersectionCallback } from "../../hooks/use-timeline-cursor-intersection-callback";
|
||||
import TimelineActionAndStatus from "../../components/timeline/timeline-action-and-status";
|
||||
import { useDMTimeline } from "../../providers/global/dms-provider";
|
||||
import UserName from "../../components/user/user-name";
|
||||
import { NostrEvent } from "../../types/nostr-event";
|
||||
import { CheckIcon } from "../../components/icons";
|
||||
@ -22,6 +20,34 @@ import UserDnsIdentity from "../../components/user/user-dns-identity";
|
||||
import useEventIntersectionRef from "../../hooks/use-event-intersection-ref";
|
||||
import { useKind4Decrypt } from "../../hooks/use-kind4-decryption";
|
||||
import ContainedParentView from "../../components/layout/presets/contained-parent-view";
|
||||
import { truncateId } from "../../helpers/string";
|
||||
import useTimelineLoader from "../../hooks/use-timeline-loader";
|
||||
import useUserMailboxes from "../../hooks/use-user-mailboxes";
|
||||
import useClientSideMuteFilter from "../../hooks/use-client-side-mute-filter";
|
||||
|
||||
export function useDirectMessagesTimeline(pubkey?: string) {
|
||||
const userMuteFilter = useClientSideMuteFilter();
|
||||
const eventFilter = useCallback(
|
||||
(event: NostrEvent) => {
|
||||
if (userMuteFilter(event)) return false;
|
||||
return true;
|
||||
},
|
||||
[userMuteFilter],
|
||||
);
|
||||
const mailboxes = useUserMailboxes(pubkey);
|
||||
|
||||
return useTimelineLoader(
|
||||
`${truncateId(pubkey ?? "anon")}-dms`,
|
||||
mailboxes?.inboxes ?? [],
|
||||
pubkey
|
||||
? [
|
||||
{ authors: [pubkey], kinds: [kinds.EncryptedDirectMessage] },
|
||||
{ "#p": [pubkey], kinds: [kinds.EncryptedDirectMessage] },
|
||||
]
|
||||
: undefined,
|
||||
{ eventFilter },
|
||||
);
|
||||
}
|
||||
|
||||
function MessagePreview({ message, pubkey }: { message: NostrEvent; pubkey: string }) {
|
||||
const ref = useEventIntersectionRef(message);
|
||||
@ -64,9 +90,8 @@ function MessagesHomePage() {
|
||||
const { people } = usePeopleListContext();
|
||||
|
||||
const account = useActiveAccount()!;
|
||||
const timeline = useDMTimeline();
|
||||
const { timeline: messages, loader } = useDirectMessagesTimeline(account.pubkey);
|
||||
|
||||
const messages = useObservable(timeline.timeline) ?? [];
|
||||
const conversations = useMemo(() => {
|
||||
const conversations = groupIntoConversations(messages).map((c) => identifyConversation(c, account.pubkey));
|
||||
const filtered = conversations.filter((conversation) =>
|
||||
@ -76,7 +101,7 @@ function MessagesHomePage() {
|
||||
return filtered.sort((a, b) => b.messages[0].created_at - a.messages[0].created_at);
|
||||
}, [messages, people, account.pubkey]);
|
||||
|
||||
const callback = useTimelineCurserIntersectionCallback(timeline);
|
||||
const callback = useTimelineCurserIntersectionCallback(loader);
|
||||
|
||||
return (
|
||||
<ContainedParentView path="/messages" width="md">
|
||||
@ -88,7 +113,7 @@ function MessagesHomePage() {
|
||||
<ConversationCard key={conversation.pubkeys.join("-")} conversation={conversation} />
|
||||
))}
|
||||
</IntersectionObserverProvider>
|
||||
<TimelineActionAndStatus timeline={timeline} />
|
||||
<TimelineActionAndStatus loader={loader} />
|
||||
</ContainedParentView>
|
||||
);
|
||||
}
|
||||
|
@ -201,7 +201,7 @@ function NotificationsPage() {
|
||||
</FocusedContext.Provider>
|
||||
</IntersectionObserverProvider>
|
||||
|
||||
<TimelineActionAndStatus timeline={timeline} />
|
||||
<TimelineActionAndStatus loader={timeline} />
|
||||
</VerticalPageLayout>
|
||||
);
|
||||
}
|
||||
|
@ -53,7 +53,7 @@ function BrowseRelaySetsPage() {
|
||||
<IntersectionObserverProvider callback={callback}>
|
||||
{relaySets?.map((set) => <RelaySetCard key={getEventUID(set)} set={set} />)}
|
||||
</IntersectionObserverProvider>
|
||||
<TimelineActionAndStatus timeline={loader} />
|
||||
<TimelineActionAndStatus loader={loader} />
|
||||
</VerticalPageLayout>
|
||||
);
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { useCallback } from "react";
|
||||
import { Flex, Spacer, useDisclosure } from "@chakra-ui/react";
|
||||
import { kinds } from "nostr-tools";
|
||||
import { getSeenRelays } from "applesauce-core/helpers";
|
||||
|
||||
import { isReply, isRepost } from "../../../helpers/nostr/event";
|
||||
import { useAppTitle } from "../../../hooks/use-app-title";
|
||||
@ -12,7 +13,6 @@ import PeopleListSelection from "../../../components/people-list-selection/peopl
|
||||
import { usePeopleListContext } from "../../../providers/local/people-list-provider";
|
||||
import useClientSideMuteFilter from "../../../hooks/use-client-side-mute-filter";
|
||||
import NoteFilterTypeButtons from "../../../components/note-filter-type-buttons";
|
||||
import { getSeenRelays } from "applesauce-core/helpers";
|
||||
|
||||
export default function RelayNotes({ relay }: { relay: string }) {
|
||||
useAppTitle(`${relay} - Notes`);
|
||||
@ -38,10 +38,7 @@ export default function RelayNotes({ relay }: { relay: string }) {
|
||||
`${relay}-notes`,
|
||||
[relay],
|
||||
filter ? { ...filter, kinds: k } : undefined,
|
||||
{
|
||||
eventFilter,
|
||||
useCache: false,
|
||||
},
|
||||
{ eventFilter },
|
||||
);
|
||||
|
||||
const header = (
|
||||
@ -53,5 +50,7 @@ export default function RelayNotes({ relay }: { relay: string }) {
|
||||
</Flex>
|
||||
);
|
||||
|
||||
if (!loader) return null;
|
||||
|
||||
return <TimelinePage loader={loader} timeline={timeline} header={header} />;
|
||||
}
|
||||
|
@ -55,7 +55,7 @@ export default function RelayUsersTab({ relay }: { relay: string }) {
|
||||
{lists?.map((list) => <UserCard key={getEventUID(list)} pubkey={list.pubkey} list={list} />)}
|
||||
</SimpleGrid>
|
||||
</IntersectionObserverProvider>
|
||||
<TimelineActionAndStatus timeline={loader} />
|
||||
<TimelineActionAndStatus loader={loader} />
|
||||
</Flex>
|
||||
);
|
||||
}
|
||||
|
@ -2,7 +2,7 @@ import { useEffect, useMemo, useState } from "react";
|
||||
import { Filter, kinds, NostrEvent } from "nostr-tools";
|
||||
import { AbstractRelay, Subscription, SubscriptionParams } from "nostr-tools/abstract-relay";
|
||||
import { Alert, AlertDescription, AlertIcon, AlertTitle, Heading, Spinner, Text } from "@chakra-ui/react";
|
||||
import { LRU } from "tiny-lru";
|
||||
import { LRU } from "applesauce-core/helpers";
|
||||
|
||||
import relayPoolService from "../../../services/relay-pool";
|
||||
import ProfileSearchResults from "./profile-results";
|
||||
|
@ -7,7 +7,6 @@ import useTimelineLoader from "../../hooks/use-timeline-loader";
|
||||
import IntersectionObserverProvider from "../../providers/local/intersection-observer";
|
||||
import { useTimelineCurserIntersectionCallback } from "../../hooks/use-timeline-cursor-intersection-callback";
|
||||
import StreamCard from "./components/stream-card";
|
||||
import useRelaysChanged from "../../hooks/use-relays-changed";
|
||||
import PeopleListSelection from "../../components/people-list-selection/people-list-selection";
|
||||
import PeopleListProvider, { usePeopleListContext } from "../../providers/local/people-list-provider";
|
||||
import TimelineActionAndStatus from "../../components/timeline/timeline-action-and-status";
|
||||
@ -54,8 +53,6 @@ function StreamsPage() {
|
||||
});
|
||||
const callback = useTimelineCurserIntersectionCallback(loader);
|
||||
|
||||
useRelaysChanged(relays, () => loader.reset());
|
||||
|
||||
const { streams: favorites } = useFavoriteStreams();
|
||||
|
||||
const liveStreams = streams.filter((stream) => getStreamStatus(stream) === "live");
|
||||
@ -104,7 +101,7 @@ function StreamsPage() {
|
||||
</SimpleGrid>
|
||||
</>
|
||||
)}
|
||||
<TimelineActionAndStatus timeline={loader} />
|
||||
<TimelineActionAndStatus loader={loader} />
|
||||
</IntersectionObserverProvider>
|
||||
</VerticalPageLayout>
|
||||
);
|
||||
|
@ -31,7 +31,7 @@ export default function UserArticlesTab() {
|
||||
<ArticleCard article={article} />
|
||||
</ErrorBoundary>
|
||||
))}
|
||||
<TimelineActionAndStatus timeline={loader} />
|
||||
<TimelineActionAndStatus loader={loader} />
|
||||
</IntersectionObserverProvider>
|
||||
</SimpleView>
|
||||
);
|
||||
|
@ -71,7 +71,7 @@ export default function UserFilesTab() {
|
||||
</Tbody>
|
||||
</Table>
|
||||
</TableContainer>
|
||||
<TimelineActionAndStatus timeline={loader} />
|
||||
<TimelineActionAndStatus loader={loader} />
|
||||
</IntersectionObserverProvider>
|
||||
</SimpleView>
|
||||
);
|
||||
|
@ -49,7 +49,7 @@ export default function UserFollowersTab() {
|
||||
<FollowerItem key={event.pubkey} event={event} />
|
||||
))}
|
||||
</SimpleGrid>
|
||||
<TimelineActionAndStatus timeline={loader} />
|
||||
<TimelineActionAndStatus loader={loader} />
|
||||
</IntersectionObserverProvider>
|
||||
);
|
||||
}
|
||||
|
@ -81,7 +81,7 @@ export default function UserMessagesTab() {
|
||||
</Tbody>
|
||||
</Table>
|
||||
</TableContainer>
|
||||
<TimelineActionAndStatus timeline={loader} />
|
||||
<TimelineActionAndStatus loader={loader} />
|
||||
</VerticalPageLayout>
|
||||
</IntersectionObserverProvider>
|
||||
);
|
||||
|
@ -58,7 +58,7 @@ export default function UserReactionsTab() {
|
||||
<VerticalPageLayout>
|
||||
{reactions?.map((event) => <Reaction key={event.id} reaction={event} />)}
|
||||
|
||||
<TimelineActionAndStatus timeline={loader} />
|
||||
<TimelineActionAndStatus loader={loader} />
|
||||
</VerticalPageLayout>
|
||||
</TrustProvider>
|
||||
</IntersectionObserverProvider>
|
||||
|
@ -65,7 +65,7 @@ export default function UserReportsTab() {
|
||||
<VerticalPageLayout>
|
||||
{events?.map((report) => <ReportEvent key={report.id} report={report} />)}
|
||||
|
||||
<TimelineActionAndStatus timeline={loader} />
|
||||
<TimelineActionAndStatus loader={loader} />
|
||||
</VerticalPageLayout>
|
||||
</IntersectionObserverProvider>
|
||||
);
|
||||
|
@ -34,7 +34,7 @@ export default function UserStreamsTab() {
|
||||
<StreamCard key={getEventUID(stream)} stream={stream} />
|
||||
))}
|
||||
</SimpleGrid>
|
||||
<TimelineActionAndStatus timeline={loader} />
|
||||
<TimelineActionAndStatus loader={loader} />
|
||||
</IntersectionObserverProvider>
|
||||
</SimpleView>
|
||||
);
|
||||
|
@ -48,7 +48,7 @@ export default function UserTorrentsTab() {
|
||||
</Table>
|
||||
</TableContainer>
|
||||
|
||||
<TimelineActionAndStatus timeline={loader} />
|
||||
<TimelineActionAndStatus loader={loader} />
|
||||
</IntersectionObserverProvider>
|
||||
</SimpleView>
|
||||
);
|
||||
|
@ -132,7 +132,7 @@ const UserZapsTab = () => {
|
||||
</ErrorBoundary>
|
||||
))}
|
||||
|
||||
<TimelineActionAndStatus timeline={loader} />
|
||||
<TimelineActionAndStatus loader={loader} />
|
||||
</VerticalPageLayout>
|
||||
</IntersectionObserverProvider>
|
||||
);
|
||||
|
@ -39,7 +39,7 @@ function VideosPage() {
|
||||
))}
|
||||
</SimpleGrid>
|
||||
</IntersectionObserverProvider>
|
||||
<TimelineActionAndStatus timeline={loader} />
|
||||
<TimelineActionAndStatus loader={loader} />
|
||||
</VerticalPageLayout>
|
||||
);
|
||||
}
|
||||
|
@ -78,7 +78,7 @@ export default function WikiHomeView() {
|
||||
</LinkBox>
|
||||
))}
|
||||
</SimpleGrid>
|
||||
<TimelineActionAndStatus timeline={loader} />
|
||||
<TimelineActionAndStatus loader={loader} />
|
||||
</VerticalPageLayout>
|
||||
);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user