diff --git a/.changeset/eleven-planets-hear.md b/.changeset/eleven-planets-hear.md new file mode 100644 index 000000000..a626d049d --- /dev/null +++ b/.changeset/eleven-planets-hear.md @@ -0,0 +1,5 @@ +--- +"nostrudel": minor +--- + +Remove legacy relay connection pool diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c41fc921b..d796ea636 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -104,28 +104,28 @@ importers: version: 0.7.2 applesauce-accounts: specifier: next - version: 0.0.0-next-20250204170704(typescript@5.7.3) + version: 0.0.0-next-20250204175150(typescript@5.7.3) applesauce-content: specifier: next - version: 0.0.0-next-20250204170704(typescript@5.7.3) + version: 0.0.0-next-20250204175150(typescript@5.7.3) applesauce-core: specifier: next - version: 0.0.0-next-20250204170704(typescript@5.7.3) + version: 0.0.0-next-20250204175150(typescript@5.7.3) applesauce-factory: specifier: next - version: 0.0.0-next-20250204170704(typescript@5.7.3) + version: 0.0.0-next-20250204175150(typescript@5.7.3) applesauce-loaders: specifier: next - version: 0.0.0-next-20250204170704(typescript@5.7.3) + version: 0.0.0-next-20250204175150(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-20250204170704(typescript@5.7.3) + version: 0.0.0-next-20250204175150(typescript@5.7.3) applesauce-signers: specifier: next - version: 0.0.0-next-20250204170704(typescript@5.7.3) + version: 0.0.0-next-20250204175150(typescript@5.7.3) bech32: specifier: ^2.0.0 version: 2.0.0 @@ -426,7 +426,7 @@ importers: version: 4.7.5 '@vitejs/plugin-react': specifier: ^4.3.4 - version: 4.3.4(vite@5.4.14(@types/node@22.13.1)(terser@5.37.0)) + version: 4.3.4(vite@5.4.14(@types/node@22.13.1)(terser@5.38.0)) camelcase: specifier: ^8.0.0 version: 8.0.0 @@ -441,13 +441,13 @@ importers: version: 5.7.3 vite: specifier: ^5.4.14 - version: 5.4.14(@types/node@22.13.1)(terser@5.37.0) + version: 5.4.14(@types/node@22.13.1)(terser@5.38.0) vite-plugin-pwa: specifier: ^0.21.1 - version: 0.21.1(vite@5.4.14(@types/node@22.13.1)(terser@5.37.0))(workbox-build@7.3.0(@types/babel__core@7.20.5))(workbox-window@7.3.0) + version: 0.21.1(vite@5.4.14(@types/node@22.13.1)(terser@5.38.0))(workbox-build@7.3.0(@types/babel__core@7.20.5))(workbox-window@7.3.0) vite-tsconfig-paths: specifier: ^5.1.4 - version: 5.1.4(typescript@5.7.3)(vite@5.4.14(@types/node@22.13.1)(terser@5.37.0)) + version: 5.1.4(typescript@5.7.3)(vite@5.4.14(@types/node@22.13.1)(terser@5.38.0)) workbox-build: specifier: ^7.3.0 version: 7.3.0(@types/babel__core@7.20.5) @@ -1720,98 +1720,98 @@ packages: rollup: optional: true - '@rollup/rollup-android-arm-eabi@4.34.2': - resolution: {integrity: sha512-6Fyg9yQbwJR+ykVdT9sid1oc2ewejS6h4wzQltmJfSW53N60G/ah9pngXGANdy9/aaE/TcUFpWosdm7JXS1WTQ==} + '@rollup/rollup-android-arm-eabi@4.34.3': + resolution: {integrity: sha512-8kq/NjMKkMTGKMPldWihncOl62kgnLYk7cW+/4NCUWfS70/wz4+gQ7rMxMMpZ3dIOP/xw7wKNzIuUnN/H2GfUg==} cpu: [arm] os: [android] - '@rollup/rollup-android-arm64@4.34.2': - resolution: {integrity: sha512-K5GfWe+vtQ3kyEbihrimM38UgX57UqHp+oME7X/EX9Im6suwZfa7Hsr8AtzbJvukTpwMGs+4s29YMSO3rwWtsw==} + '@rollup/rollup-android-arm64@4.34.3': + resolution: {integrity: sha512-1PqMHiuRochQ6++SDI7SaRDWJKr/NgAlezBi5nOne6Da6IWJo3hK0TdECBDwd92IUDPG4j/bZmWuwOnomNT8wA==} cpu: [arm64] os: [android] - '@rollup/rollup-darwin-arm64@4.34.2': - resolution: {integrity: sha512-PSN58XG/V/tzqDb9kDGutUruycgylMlUE59f40ny6QIRNsTEIZsrNQTJKUN2keMMSmlzgunMFqyaGLmly39sug==} + '@rollup/rollup-darwin-arm64@4.34.3': + resolution: {integrity: sha512-fqbrykX4mGV3DlCDXhF4OaMGcchd2tmLYxVt3On5oOZWVDFfdEoYAV2alzNChl8OzNaeMAGqm1f7gk7eIw/uDg==} cpu: [arm64] os: [darwin] - '@rollup/rollup-darwin-x64@4.34.2': - resolution: {integrity: sha512-gQhK788rQJm9pzmXyfBB84VHViDERhAhzGafw+E5mUpnGKuxZGkMVDa3wgDFKT6ukLC5V7QTifzsUKdNVxp5qQ==} + '@rollup/rollup-darwin-x64@4.34.3': + resolution: {integrity: sha512-8Wxrx/KRvMsTyLTbdrMXcVKfpW51cCNW8x7iQD72xSEbjvhCY3b+w83Bea3nQfysTMR7K28esc+ZFITThXm+1w==} cpu: [x64] os: [darwin] - '@rollup/rollup-freebsd-arm64@4.34.2': - resolution: {integrity: sha512-eiaHgQwGPpxLC3+zTAcdKl4VsBl3r0AiJOd1Um/ArEzAjN/dbPK1nROHrVkdnoE6p7Svvn04w3f/jEZSTVHunA==} + '@rollup/rollup-freebsd-arm64@4.34.3': + resolution: {integrity: sha512-lpBmV2qSiELh+ATQPTjQczt5hvbTLsE0c43Rx4bGxN2VpnAZWy77we7OO62LyOSZNY7CzjMoceRPc+Lt4e9J6A==} cpu: [arm64] os: [freebsd] - '@rollup/rollup-freebsd-x64@4.34.2': - resolution: {integrity: sha512-lhdiwQ+jf8pewYOTG4bag0Qd68Jn1v2gO1i0mTuiD+Qkt5vNfHVK/jrT7uVvycV8ZchlzXp5HDVmhpzjC6mh0g==} + '@rollup/rollup-freebsd-x64@4.34.3': + resolution: {integrity: sha512-sNPvBIXpgaYcI6mAeH13GZMXFrrw5mdZVI1M9YQPRG2LpjwL8DSxSIflZoh/B5NEuOi53kxsR/S2GKozK1vDXA==} cpu: [x64] os: [freebsd] - '@rollup/rollup-linux-arm-gnueabihf@4.34.2': - resolution: {integrity: sha512-lfqTpWjSvbgQP1vqGTXdv+/kxIznKXZlI109WkIFPbud41bjigjNmOAAKoazmRGx+k9e3rtIdbq2pQZPV1pMig==} + '@rollup/rollup-linux-arm-gnueabihf@4.34.3': + resolution: {integrity: sha512-MW6N3AoC61OfE1VgnN5O1OW0gt8VTbhx9s/ZEPLBM11wEdHjeilPzOxVmmsrx5YmejpGPvez8QwGGvMU+pGxpw==} cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm-musleabihf@4.34.2': - resolution: {integrity: sha512-RGjqULqIurqqv+NJTyuPgdZhka8ImMLB32YwUle2BPTDqDoXNgwFjdjQC59FbSk08z0IqlRJjrJ0AvDQ5W5lpw==} + '@rollup/rollup-linux-arm-musleabihf@4.34.3': + resolution: {integrity: sha512-2SQkhr5xvatYq0/+H6qyW0zvrQz9LM4lxGkpWURLoQX5+yP8MsERh4uWmxFohOvwCP6l/+wgiHZ1qVwLDc7Qmw==} cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm64-gnu@4.34.2': - resolution: {integrity: sha512-ZvkPiheyXtXlFqHpsdgscx+tZ7hoR59vOettvArinEspq5fxSDSgfF+L5wqqJ9R4t+n53nyn0sKxeXlik7AY9Q==} + '@rollup/rollup-linux-arm64-gnu@4.34.3': + resolution: {integrity: sha512-R3JLYt8YoRwKI5shJsovLpcR6pwIMui/MGG/MmxZ1DYI3iRSKI4qcYrvYgDf4Ss2oCR3RL3F3dYK7uAGQgMIuQ==} cpu: [arm64] os: [linux] - '@rollup/rollup-linux-arm64-musl@4.34.2': - resolution: {integrity: sha512-UlFk+E46TZEoxD9ufLKDBzfSG7Ki03fo6hsNRRRHF+KuvNZ5vd1RRVQm8YZlGsjcJG8R252XFK0xNPay+4WV7w==} + '@rollup/rollup-linux-arm64-musl@4.34.3': + resolution: {integrity: sha512-4XQhG8v/t3S7Rxs7rmFUuM6j09hVrTArzONS3fUZ6oBRSN/ps9IPQjVhp62P0W3KhqJdQADo/MRlYRMdgxr/3w==} cpu: [arm64] os: [linux] - '@rollup/rollup-linux-loongarch64-gnu@4.34.2': - resolution: {integrity: sha512-hJhfsD9ykx59jZuuoQgYT1GEcNNi3RCoEmbo5OGfG8RlHOiVS7iVNev9rhLKh7UBYq409f4uEw0cclTXx8nh8Q==} + '@rollup/rollup-linux-loongarch64-gnu@4.34.3': + resolution: {integrity: sha512-QlW1jCUZ1LHUIYCAK2FciVw1ptHsxzApYVi05q7bz2A8oNE8QxQ85NhM4arLxkAlcnS42t4avJbSfzSQwbIaKg==} cpu: [loong64] os: [linux] - '@rollup/rollup-linux-powerpc64le-gnu@4.34.2': - resolution: {integrity: sha512-g/O5IpgtrQqPegvqopvmdCF9vneLE7eqYfdPWW8yjPS8f63DNam3U4ARL1PNNB64XHZDHKpvO2Giftf43puB8Q==} + '@rollup/rollup-linux-powerpc64le-gnu@4.34.3': + resolution: {integrity: sha512-kMbLToizVeCcN69+nnm20Dh0hrRIAjgaaL+Wh0gWZcNt8e542d2FUGtsyuNsHVNNF3gqTJrpzUGIdwMGLEUM7g==} cpu: [ppc64] os: [linux] - '@rollup/rollup-linux-riscv64-gnu@4.34.2': - resolution: {integrity: sha512-bSQijDC96M6PuooOuXHpvXUYiIwsnDmqGU8+br2U7iPoykNi9JtMUpN7K6xml29e0evK0/g0D1qbAUzWZFHY5Q==} + '@rollup/rollup-linux-riscv64-gnu@4.34.3': + resolution: {integrity: sha512-YgD0DnZ3CHtvXRH8rzjVSxwI0kMTr0RQt3o1N92RwxGdx7YejzbBO0ELlSU48DP96u1gYYVWfUhDRyaGNqJqJg==} cpu: [riscv64] os: [linux] - '@rollup/rollup-linux-s390x-gnu@4.34.2': - resolution: {integrity: sha512-49TtdeVAsdRuiUHXPrFVucaP4SivazetGUVH8CIxVsNsaPHV4PFkpLmH9LeqU/R4Nbgky9lzX5Xe1NrzLyraVA==} + '@rollup/rollup-linux-s390x-gnu@4.34.3': + resolution: {integrity: sha512-dIOoOz8altjp6UjAi3U9EW99s8nta4gzi52FeI45GlPyrUH4QixUoBMH9VsVjt+9A2RiZBWyjYNHlJ/HmJOBCQ==} cpu: [s390x] os: [linux] - '@rollup/rollup-linux-x64-gnu@4.34.2': - resolution: {integrity: sha512-j+jFdfOycLIQ7FWKka9Zd3qvsIyugg5LeZuHF6kFlXo6MSOc6R1w37YUVy8VpAKd81LMWGi5g9J25P09M0SSIw==} + '@rollup/rollup-linux-x64-gnu@4.34.3': + resolution: {integrity: sha512-lOyG3aF4FTKrhpzXfMmBXgeKUUXdAWmP2zSNf8HTAXPqZay6QYT26l64hVizBjq+hJx3pl0DTEyvPi9sTA6VGA==} cpu: [x64] os: [linux] - '@rollup/rollup-linux-x64-musl@4.34.2': - resolution: {integrity: sha512-aDPHyM/D2SpXfSNCVWCxyHmOqN9qb7SWkY1+vaXqMNMXslZYnwh9V/UCudl6psyG0v6Ukj7pXanIpfZwCOEMUg==} + '@rollup/rollup-linux-x64-musl@4.34.3': + resolution: {integrity: sha512-usztyYLu2i+mYzzOjqHZTaRXbUOqw3P6laNUh1zcqxbPH1P2Tz/QdJJCQSnGxCtsRQeuU2bCyraGMtMumC46rw==} cpu: [x64] os: [linux] - '@rollup/rollup-win32-arm64-msvc@4.34.2': - resolution: {integrity: sha512-LQRkCyUBnAo7r8dbEdtNU08EKLCJMgAk2oP5H3R7BnUlKLqgR3dUjrLBVirmc1RK6U6qhtDw29Dimeer8d5hzQ==} + '@rollup/rollup-win32-arm64-msvc@4.34.3': + resolution: {integrity: sha512-ojFOKaz/ZyalIrizdBq2vyc2f0kFbJahEznfZlxdB6pF9Do6++i1zS5Gy6QLf8D7/S57MHrmBLur6AeRYeQXSA==} cpu: [arm64] os: [win32] - '@rollup/rollup-win32-ia32-msvc@4.34.2': - resolution: {integrity: sha512-wt8OhpQUi6JuPFkm1wbVi1BByeag87LDFzeKSXzIdGcX4bMLqORTtKxLoCbV57BHYNSUSOKlSL4BYYUghainYA==} + '@rollup/rollup-win32-ia32-msvc@4.34.3': + resolution: {integrity: sha512-K/V97GMbNa+Da9mGcZqmSl+DlJmWfHXTuI9V8oB2evGsQUtszCl67+OxWjBKpeOnYwox9Jpmt/J6VhpeRCYqow==} cpu: [ia32] os: [win32] - '@rollup/rollup-win32-x64-msvc@4.34.2': - resolution: {integrity: sha512-rUrqINax0TvrPBXrFKg0YbQx18NpPN3NNrgmaao9xRNbTwek7lOXObhx8tQy8gelmQ/gLaGy1WptpU2eKJZImg==} + '@rollup/rollup-win32-x64-msvc@4.34.3': + resolution: {integrity: sha512-CUypcYP31Q8O04myV6NKGzk9GVXslO5EJNfmARNSzLF2A+5rmZUlDJ4et6eoJaZgBT9wrC2p4JZH04Vkic8HdQ==} cpu: [x64] os: [win32] @@ -2192,32 +2192,32 @@ packages: engines: {node: '>=8.0.0'} hasBin: true - applesauce-accounts@0.0.0-next-20250204170704: - resolution: {integrity: sha512-y80D4PfoT9gkd+TtUExeQdiq5grlchUbsdjRfmEG3JuAopTCzdgEAa2L7wfLT4DmsUwBvO8ISAm+zKRZ+GI/NQ==} + applesauce-accounts@0.0.0-next-20250204175150: + resolution: {integrity: sha512-b3zqfiDc6X9aKhrLXgSuyuivdn3GEQW8prwg/Bu7nZD7egoGcLsTX4fyAAzgBz6H2CO2oKxnwoyziugHEy6ZIQ==} - applesauce-content@0.0.0-next-20250204170704: - resolution: {integrity: sha512-hY6H2v6wSa/rzq6OCnjSL+y2Lv4/AR5z7irdqbSuzhSElslm78pqUPjsFlnVt7nu5K+1cAv0B/Ib/2yhaacgYw==} + applesauce-content@0.0.0-next-20250204175150: + resolution: {integrity: sha512-rFi/cWZbUYpMlFU8fNrEo0KkFy8lCyeGXxylcDW2zB6eMu8rUqQ2SZ9CiW9VUuBmjpxugetkhNJZtrINXhKj+w==} - applesauce-core@0.0.0-next-20250204170704: - resolution: {integrity: sha512-TcvcmFHYmduVFZsR+87/cPldZEUz/uafyHIMGPdM8Go4TWg/SMB2tRILdDuUrEjgIgtUVskAGlPF4uIoiH/bEA==} + applesauce-core@0.0.0-next-20250204175150: + resolution: {integrity: sha512-mirjWA0QdyKMGWqtmCWCr8vi+BH68KdWVjuP1mMn636rz1JvbseS0IG/TkuClJaZenZOaPQIfO0n/pK8EzzYzQ==} applesauce-core@0.10.0: resolution: {integrity: sha512-QMhUh4FIARcqY5soCB4Z8DIu+py0rYb28IgWT4gP9DLBGpDrY8lStXk7W1/46TLjEH97y0hbiXFK7kMCZ31oOQ==} - applesauce-factory@0.0.0-next-20250204170704: - resolution: {integrity: sha512-5lA2aWaKibpt3jNQkNSJJWjopk9CNSWJzDOiM156fBG2Qhe8GzdN7fBiCPlm+iPCRogGyDCAHabSS+JnZB6LTA==} + applesauce-factory@0.0.0-next-20250204175150: + resolution: {integrity: sha512-zYIg/5bh7xaGS8CiniHS50aTeAbKT3CTeu4BDv4Sbygu86b8R9Xd9LjxW8MsVDNwn6dlj+OqfC8r0mlUK/icEg==} - applesauce-loaders@0.0.0-next-20250204170704: - resolution: {integrity: sha512-7mYbE2qJA58A5cfdnpfQbdkohRvg6uhct+QieLlGOc/mNEmMxpA10GP9Wu7FprokWdCJEs0Pn7q7pobsJgPpKw==} + applesauce-loaders@0.0.0-next-20250204175150: + resolution: {integrity: sha512-z/cPftJvuIHWOaaPmq2YSQbkVIZ90K4QD7T+ZPh8IBZzlz2/tvdoidDBA174KXEVmBUn5fVE6Z1CAxrf/PBGDA==} applesauce-net@0.10.0: resolution: {integrity: sha512-ZsAs/MkeGHiPZ2/a8lwP8lx/Eh+5Dot0qG4BLTAqjg4emP/RsiqW+hyc6v6QcVbdvuR0+hP1gka3+wWtiy/cTA==} - applesauce-react@0.0.0-next-20250204170704: - resolution: {integrity: sha512-rHA9dO4k5UUeZESMtsrD0oGk7q26AFlpjLjWHBDKiFxRPsr5MusoKyW8X2fZOrN1fyNhgHD+lhCtesTWVUOU7Q==} + applesauce-react@0.0.0-next-20250204175150: + resolution: {integrity: sha512-J9ULdSeedSJXmFZtwECx+51I2cOVoCaOkWn7/HcFN4LiBtXuufx7viEZypWPv/nSdvpNK8Xb7jbOSuE75GmNWQ==} - applesauce-signers@0.0.0-next-20250204170704: - resolution: {integrity: sha512-SZUA5uZQChBReIRj34t1y4ZQnV8LR96oHyMelnhAPFJXZT57wUfMJB7Z6KVkxbMHwo2SYUP6qi4MpkC6KQyGng==} + applesauce-signers@0.0.0-next-20250204175150: + resolution: {integrity: sha512-n7tzmEHCnyLOULG2aYYsil6cEkmI3St2f8if6Dshu92avTRi83/rpn6g8nIFxXu5iBLzuEJup9kXsZtVfdfDAg==} arg@4.1.3: resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==} @@ -3033,8 +3033,8 @@ packages: engines: {node: '>=0.10.0'} hasBin: true - electron-to-chromium@1.5.91: - resolution: {integrity: sha512-sNSHHyq048PFmZY4S90ax61q+gLCs0X0YmcOII9wG9S2XwbVr+h4VW2wWhnbp/Eys3cCwTxVF292W3qPaxIapQ==} + electron-to-chromium@1.5.92: + resolution: {integrity: sha512-BeHgmNobs05N1HMmMZ7YIuHfYBGlq/UmvlsTgg+fsbFs9xVMj+xJHFg19GN04+9Q+r8Xnh9LXqaYIyEWElnNgQ==} elementtree@0.1.7: resolution: {integrity: sha512-wkgGT6kugeQk/P6VZ/f4T+4HB41BVgNBq5CDIZVbQ02nvTVqAiVTbskxxu3eA/X96lMlfYOwnLQpN2v5E1zDEg==} @@ -3667,8 +3667,8 @@ packages: resolution: {integrity: sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==} engines: {node: '>= 0.4'} - is-boolean-object@1.2.1: - resolution: {integrity: sha512-l9qO6eFlUETHtuihLcYOaLKByJ1f+N4kthcU9YjHy3N+B3hWv0y/2Nd0mu/7lTFnRQHTrSdXF50HQ3bl5fEnng==} + is-boolean-object@1.2.2: + resolution: {integrity: sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==} engines: {node: '>= 0.4'} is-callable@1.2.7: @@ -4456,8 +4456,8 @@ packages: resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} engines: {node: '>=0.10.0'} - object-inspect@1.13.3: - resolution: {integrity: sha512-kDCGIbxkDSXE3euJZZXzc6to7fCrKHNI/hSRQnRuQ+BWjFNzZwiFF8fj/6o2t2G9/jTj8PSIYTfCLelLZEeRpA==} + object-inspect@1.13.4: + resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} engines: {node: '>= 0.4'} object-keys@1.1.1: @@ -5135,8 +5135,8 @@ packages: engines: {node: '>=10.0.0'} hasBin: true - rollup@4.34.2: - resolution: {integrity: sha512-sBDUoxZEaqLu9QeNalL8v3jw6WjPku4wfZGyTU7l7m1oC+rpRihXc/n/H+4148ZkGz5Xli8CHMns//fFGKvpIQ==} + rollup@4.34.3: + resolution: {integrity: sha512-ORCtU0UBJyiAIn9m0llUXJXAswG/68pZptCrqxHG7//Z2DDzAUeyyY5hqf4XrsGlUxscMr9GkQ2QI7KTLqeyPw==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true @@ -5506,8 +5506,8 @@ packages: resolution: {integrity: sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==} engines: {node: '>=8'} - terser@5.37.0: - resolution: {integrity: sha512-B8wRRkmre4ERucLM/uXx4MOV5cbnOlVAqUst+1+iLKPI0dOgFO28f84ptoQt9HEI537PMzfYa/d+GEPKTRXmYA==} + terser@5.38.0: + resolution: {integrity: sha512-a4GD5R1TjEeuCT6ZRiYMHmIf7okbCPEuhQET8bczV6FrQMMlFXA1n+G0KKjdlFCm3TEHV77GxfZB3vZSUQGFpg==} engines: {node: '>=10'} hasBin: true @@ -7888,7 +7888,7 @@ snapshots: dependencies: serialize-javascript: 6.0.2 smob: 1.5.0 - terser: 5.37.0 + terser: 5.38.0 optionalDependencies: rollup: 2.79.2 @@ -7907,61 +7907,61 @@ snapshots: optionalDependencies: rollup: 2.79.2 - '@rollup/rollup-android-arm-eabi@4.34.2': + '@rollup/rollup-android-arm-eabi@4.34.3': optional: true - '@rollup/rollup-android-arm64@4.34.2': + '@rollup/rollup-android-arm64@4.34.3': optional: true - '@rollup/rollup-darwin-arm64@4.34.2': + '@rollup/rollup-darwin-arm64@4.34.3': optional: true - '@rollup/rollup-darwin-x64@4.34.2': + '@rollup/rollup-darwin-x64@4.34.3': optional: true - '@rollup/rollup-freebsd-arm64@4.34.2': + '@rollup/rollup-freebsd-arm64@4.34.3': optional: true - '@rollup/rollup-freebsd-x64@4.34.2': + '@rollup/rollup-freebsd-x64@4.34.3': optional: true - '@rollup/rollup-linux-arm-gnueabihf@4.34.2': + '@rollup/rollup-linux-arm-gnueabihf@4.34.3': optional: true - '@rollup/rollup-linux-arm-musleabihf@4.34.2': + '@rollup/rollup-linux-arm-musleabihf@4.34.3': optional: true - '@rollup/rollup-linux-arm64-gnu@4.34.2': + '@rollup/rollup-linux-arm64-gnu@4.34.3': optional: true - '@rollup/rollup-linux-arm64-musl@4.34.2': + '@rollup/rollup-linux-arm64-musl@4.34.3': optional: true - '@rollup/rollup-linux-loongarch64-gnu@4.34.2': + '@rollup/rollup-linux-loongarch64-gnu@4.34.3': optional: true - '@rollup/rollup-linux-powerpc64le-gnu@4.34.2': + '@rollup/rollup-linux-powerpc64le-gnu@4.34.3': optional: true - '@rollup/rollup-linux-riscv64-gnu@4.34.2': + '@rollup/rollup-linux-riscv64-gnu@4.34.3': optional: true - '@rollup/rollup-linux-s390x-gnu@4.34.2': + '@rollup/rollup-linux-s390x-gnu@4.34.3': optional: true - '@rollup/rollup-linux-x64-gnu@4.34.2': + '@rollup/rollup-linux-x64-gnu@4.34.3': optional: true - '@rollup/rollup-linux-x64-musl@4.34.2': + '@rollup/rollup-linux-x64-musl@4.34.3': optional: true - '@rollup/rollup-win32-arm64-msvc@4.34.2': + '@rollup/rollup-win32-arm64-msvc@4.34.3': optional: true - '@rollup/rollup-win32-ia32-msvc@4.34.2': + '@rollup/rollup-win32-ia32-msvc@4.34.3': optional: true - '@rollup/rollup-win32-x64-msvc@4.34.2': + '@rollup/rollup-win32-x64-msvc@4.34.3': optional: true '@sagold/json-pointer@5.1.2': {} @@ -8329,14 +8329,14 @@ snapshots: '@ungap/structured-clone@1.3.0': {} - '@vitejs/plugin-react@4.3.4(vite@5.4.14(@types/node@22.13.1)(terser@5.37.0))': + '@vitejs/plugin-react@4.3.4(vite@5.4.14(@types/node@22.13.1)(terser@5.38.0))': dependencies: '@babel/core': 7.26.7 '@babel/plugin-transform-react-jsx-self': 7.25.9(@babel/core@7.26.7) '@babel/plugin-transform-react-jsx-source': 7.25.9(@babel/core@7.26.7) '@types/babel__core': 7.20.5 react-refresh: 0.14.2 - vite: 5.4.14(@types/node@22.13.1)(terser@5.37.0) + vite: 5.4.14(@types/node@22.13.1)(terser@5.38.0) transitivePeerDependencies: - supports-color @@ -8423,10 +8423,10 @@ snapshots: dependencies: entities: 2.2.0 - applesauce-accounts@0.0.0-next-20250204170704(typescript@5.7.3): + applesauce-accounts@0.0.0-next-20250204175150(typescript@5.7.3): dependencies: '@noble/hashes': 1.7.1 - applesauce-signers: 0.0.0-next-20250204170704(typescript@5.7.3) + applesauce-signers: 0.0.0-next-20250204175150(typescript@5.7.3) nanoid: 5.0.9 nostr-tools: 2.10.4(typescript@5.7.3) rxjs: 7.8.1 @@ -8434,13 +8434,13 @@ snapshots: - supports-color - typescript - applesauce-content@0.0.0-next-20250204170704(typescript@5.7.3): + applesauce-content@0.0.0-next-20250204175150(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-20250204170704(typescript@5.7.3) + applesauce-core: 0.0.0-next-20250204175150(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 @@ -8451,7 +8451,7 @@ snapshots: - supports-color - typescript - applesauce-core@0.0.0-next-20250204170704(typescript@5.7.3): + applesauce-core@0.0.0-next-20250204175150(typescript@5.7.3): dependencies: '@scure/base': 1.2.4 debug: 4.4.0 @@ -8479,19 +8479,19 @@ snapshots: - supports-color - typescript - applesauce-factory@0.0.0-next-20250204170704(typescript@5.7.3): + applesauce-factory@0.0.0-next-20250204175150(typescript@5.7.3): dependencies: - applesauce-content: 0.0.0-next-20250204170704(typescript@5.7.3) - applesauce-core: 0.0.0-next-20250204170704(typescript@5.7.3) + applesauce-content: 0.0.0-next-20250204175150(typescript@5.7.3) + applesauce-core: 0.0.0-next-20250204175150(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-20250204170704(typescript@5.7.3): + applesauce-loaders@0.0.0-next-20250204175150(typescript@5.7.3): dependencies: - applesauce-core: 0.0.0-next-20250204170704(typescript@5.7.3) + applesauce-core: 0.0.0-next-20250204175150(typescript@5.7.3) nanoid: 5.0.9 nostr-tools: 2.10.4(typescript@5.7.3) rx-nostr: 3.5.0 @@ -8510,12 +8510,12 @@ snapshots: - supports-color - typescript - applesauce-react@0.0.0-next-20250204170704(typescript@5.7.3): + applesauce-react@0.0.0-next-20250204175150(typescript@5.7.3): dependencies: - applesauce-accounts: 0.0.0-next-20250204170704(typescript@5.7.3) - applesauce-content: 0.0.0-next-20250204170704(typescript@5.7.3) - applesauce-core: 0.0.0-next-20250204170704(typescript@5.7.3) - applesauce-factory: 0.0.0-next-20250204170704(typescript@5.7.3) + applesauce-accounts: 0.0.0-next-20250204175150(typescript@5.7.3) + applesauce-content: 0.0.0-next-20250204175150(typescript@5.7.3) + applesauce-core: 0.0.0-next-20250204175150(typescript@5.7.3) + applesauce-factory: 0.0.0-next-20250204175150(typescript@5.7.3) nostr-tools: 2.10.4(typescript@5.7.3) react: 18.3.1 rxjs: 7.8.1 @@ -8523,12 +8523,12 @@ snapshots: - supports-color - typescript - applesauce-signers@0.0.0-next-20250204170704(typescript@5.7.3): + applesauce-signers@0.0.0-next-20250204175150(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-20250204170704(typescript@5.7.3) + applesauce-core: 0.0.0-next-20250204175150(typescript@5.7.3) debug: 4.4.0 nanoid: 5.0.9 nostr-tools: 2.10.4(typescript@5.7.3) @@ -8753,7 +8753,7 @@ snapshots: browserslist@4.24.4: dependencies: caniuse-lite: 1.0.30001697 - electron-to-chromium: 1.5.91 + electron-to-chromium: 1.5.92 node-releases: 2.0.19 update-browserslist-db: 1.1.2(browserslist@4.24.4) @@ -9450,7 +9450,7 @@ snapshots: dependencies: jake: 10.9.2 - electron-to-chromium@1.5.91: {} + electron-to-chromium@1.5.92: {} elementtree@0.1.7: dependencies: @@ -9535,7 +9535,7 @@ snapshots: is-typed-array: 1.1.15 is-weakref: 1.1.1 math-intrinsics: 1.1.0 - object-inspect: 1.13.3 + object-inspect: 1.13.4 object-keys: 1.1.1 object.assign: 4.1.7 own-keys: 1.0.1 @@ -10194,7 +10194,7 @@ snapshots: dependencies: has-bigints: 1.1.0 - is-boolean-object@1.2.1: + is-boolean-object@1.2.2: dependencies: call-bound: 1.0.3 has-tostringtag: 1.0.2 @@ -11156,7 +11156,7 @@ snapshots: object-assign@4.1.1: {} - object-inspect@1.13.3: {} + object-inspect@1.13.4: {} object-keys@1.1.1: {} @@ -11911,29 +11911,29 @@ snapshots: optionalDependencies: fsevents: 2.3.3 - rollup@4.34.2: + rollup@4.34.3: dependencies: '@types/estree': 1.0.6 optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.34.2 - '@rollup/rollup-android-arm64': 4.34.2 - '@rollup/rollup-darwin-arm64': 4.34.2 - '@rollup/rollup-darwin-x64': 4.34.2 - '@rollup/rollup-freebsd-arm64': 4.34.2 - '@rollup/rollup-freebsd-x64': 4.34.2 - '@rollup/rollup-linux-arm-gnueabihf': 4.34.2 - '@rollup/rollup-linux-arm-musleabihf': 4.34.2 - '@rollup/rollup-linux-arm64-gnu': 4.34.2 - '@rollup/rollup-linux-arm64-musl': 4.34.2 - '@rollup/rollup-linux-loongarch64-gnu': 4.34.2 - '@rollup/rollup-linux-powerpc64le-gnu': 4.34.2 - '@rollup/rollup-linux-riscv64-gnu': 4.34.2 - '@rollup/rollup-linux-s390x-gnu': 4.34.2 - '@rollup/rollup-linux-x64-gnu': 4.34.2 - '@rollup/rollup-linux-x64-musl': 4.34.2 - '@rollup/rollup-win32-arm64-msvc': 4.34.2 - '@rollup/rollup-win32-ia32-msvc': 4.34.2 - '@rollup/rollup-win32-x64-msvc': 4.34.2 + '@rollup/rollup-android-arm-eabi': 4.34.3 + '@rollup/rollup-android-arm64': 4.34.3 + '@rollup/rollup-darwin-arm64': 4.34.3 + '@rollup/rollup-darwin-x64': 4.34.3 + '@rollup/rollup-freebsd-arm64': 4.34.3 + '@rollup/rollup-freebsd-x64': 4.34.3 + '@rollup/rollup-linux-arm-gnueabihf': 4.34.3 + '@rollup/rollup-linux-arm-musleabihf': 4.34.3 + '@rollup/rollup-linux-arm64-gnu': 4.34.3 + '@rollup/rollup-linux-arm64-musl': 4.34.3 + '@rollup/rollup-linux-loongarch64-gnu': 4.34.3 + '@rollup/rollup-linux-powerpc64le-gnu': 4.34.3 + '@rollup/rollup-linux-riscv64-gnu': 4.34.3 + '@rollup/rollup-linux-s390x-gnu': 4.34.3 + '@rollup/rollup-linux-x64-gnu': 4.34.3 + '@rollup/rollup-linux-x64-musl': 4.34.3 + '@rollup/rollup-win32-arm64-msvc': 4.34.3 + '@rollup/rollup-win32-ia32-msvc': 4.34.3 + '@rollup/rollup-win32-x64-msvc': 4.34.3 fsevents: 2.3.3 rtl-css-js@1.16.1: @@ -12084,27 +12084,27 @@ snapshots: side-channel-list@1.0.0: dependencies: es-errors: 1.3.0 - object-inspect: 1.13.3 + object-inspect: 1.13.4 side-channel-map@1.0.1: dependencies: call-bound: 1.0.3 es-errors: 1.3.0 get-intrinsic: 1.2.7 - object-inspect: 1.13.3 + object-inspect: 1.13.4 side-channel-weakmap@1.0.2: dependencies: call-bound: 1.0.3 es-errors: 1.3.0 get-intrinsic: 1.2.7 - object-inspect: 1.13.3 + object-inspect: 1.13.4 side-channel-map: 1.0.1 side-channel@1.1.0: dependencies: es-errors: 1.3.0 - object-inspect: 1.13.3 + object-inspect: 1.13.4 side-channel-list: 1.0.0 side-channel-map: 1.0.1 side-channel-weakmap: 1.0.2 @@ -12392,7 +12392,7 @@ snapshots: term-size@2.2.1: {} - terser@5.37.0: + terser@5.38.0: dependencies: '@jridgewell/source-map': 0.3.6 acorn: 8.14.0 @@ -12722,37 +12722,37 @@ snapshots: vite-plugin-funding@0.1.0: {} - vite-plugin-pwa@0.21.1(vite@5.4.14(@types/node@22.13.1)(terser@5.37.0))(workbox-build@7.3.0(@types/babel__core@7.20.5))(workbox-window@7.3.0): + vite-plugin-pwa@0.21.1(vite@5.4.14(@types/node@22.13.1)(terser@5.38.0))(workbox-build@7.3.0(@types/babel__core@7.20.5))(workbox-window@7.3.0): dependencies: debug: 4.4.0 pretty-bytes: 6.1.1 tinyglobby: 0.2.10 - vite: 5.4.14(@types/node@22.13.1)(terser@5.37.0) + vite: 5.4.14(@types/node@22.13.1)(terser@5.38.0) workbox-build: 7.3.0(@types/babel__core@7.20.5) workbox-window: 7.3.0 transitivePeerDependencies: - supports-color - vite-tsconfig-paths@5.1.4(typescript@5.7.3)(vite@5.4.14(@types/node@22.13.1)(terser@5.37.0)): + vite-tsconfig-paths@5.1.4(typescript@5.7.3)(vite@5.4.14(@types/node@22.13.1)(terser@5.38.0)): dependencies: debug: 4.4.0 globrex: 0.1.2 tsconfck: 3.1.4(typescript@5.7.3) optionalDependencies: - vite: 5.4.14(@types/node@22.13.1)(terser@5.37.0) + vite: 5.4.14(@types/node@22.13.1)(terser@5.38.0) transitivePeerDependencies: - supports-color - typescript - vite@5.4.14(@types/node@22.13.1)(terser@5.37.0): + vite@5.4.14(@types/node@22.13.1)(terser@5.38.0): dependencies: esbuild: 0.21.5 postcss: 8.5.1 - rollup: 4.34.2 + rollup: 4.34.3 optionalDependencies: '@types/node': 22.13.1 fsevents: 2.3.3 - terser: 5.37.0 + terser: 5.38.0 w3c-keyname@2.2.8: {} @@ -12790,7 +12790,7 @@ snapshots: which-boxed-primitive@1.1.1: dependencies: is-bigint: 1.1.0 - is-boolean-object: 1.2.1 + is-boolean-object: 1.2.2 is-number-object: 1.1.1 is-string: 1.1.1 is-symbol: 1.1.1 diff --git a/src/classes/relay-pool.ts b/src/classes/relay-pool.ts deleted file mode 100644 index 0bf9f8959..000000000 --- a/src/classes/relay-pool.ts +++ /dev/null @@ -1,243 +0,0 @@ -import { AbstractRelay } from "nostr-tools/abstract-relay"; -import { IConnectionPool } from "applesauce-net/connection"; -import dayjs from "dayjs"; -import { Subject, BehaviorSubject } from "rxjs"; - -import { logger } from "../helpers/debug"; -import { safeRelayUrl, validateRelayURL } from "../helpers/relay"; -import SuperMap from "./super-map"; -import verifyEventMethod from "../services/verify-event"; -import localSettings from "../services/local-settings"; - -export type Notice = { - message: string; - date: number; - relay: AbstractRelay; -}; - -export type RelayAuthMode = "always" | "ask" | "never"; - -export default class RelayPool implements IConnectionPool { - log = logger.extend("RelayPool"); - - relays = new Map(); - onRelayCreated = new Subject(); - onRelayChallenge = new Subject<[AbstractRelay, string]>(); - - notices = new SuperMap>(() => new BehaviorSubject([])); - - connectionErrors = new SuperMap(() => []); - connecting = new SuperMap>(() => new BehaviorSubject(false)); - - challenges = new SuperMap>( - () => new BehaviorSubject(undefined), - ); - authForPublish = new SuperMap>( - () => new BehaviorSubject(undefined), - ); - authForSubscribe = new SuperMap>( - () => new BehaviorSubject(undefined), - ); - - authenticated = new SuperMap>(() => new BehaviorSubject(false)); - - getRelay(relayOrUrl: string | URL | AbstractRelay) { - if (typeof relayOrUrl === "string") { - const safeURL = safeRelayUrl(relayOrUrl); - if (safeURL) { - return this.relays.get(safeURL) || this.requestRelay(safeURL); - } else return; - } else if (relayOrUrl instanceof URL) { - return this.relays.get(relayOrUrl.toString()) || this.requestRelay(relayOrUrl.toString()); - } - - return relayOrUrl; - } - - // TODO: for now this is just a copy of - getConnection(relayOrUrl: string | URL | AbstractRelay) { - if (typeof relayOrUrl === "string") { - const safeURL = safeRelayUrl(relayOrUrl); - if (safeURL) { - return this.relays.get(safeURL) || this.requestRelay(safeURL); - } else { - throw new Error(`Bad relay url ${relayOrUrl}`); - } - } else if (relayOrUrl instanceof URL) { - return this.relays.get(relayOrUrl.toString()) || this.requestRelay(relayOrUrl.toString()); - } - - return relayOrUrl; - } - - getRelays(urls?: Iterable) { - if (urls) { - const relays: AbstractRelay[] = []; - for (const url of urls) { - const relay = this.getRelay(url); - if (relay) relays.push(relay); - } - return relays; - } - - return Array.from(this.relays.values()); - } - - requestRelay(url: string | URL, connect = true) { - url = validateRelayURL(url); - - const key = url.toString(); - if (!this.relays.has(key)) { - const r = new AbstractRelay(key, { verifyEvent: verifyEventMethod }); - r._onauth = (challenge) => this.handleRelayChallenge(r, challenge); - r.onnotice = (notice) => this.handleRelayNotice(r, notice); - - this.relays.set(key, r); - this.onRelayCreated.next(r); - } - - const relay = this.relays.get(key) as AbstractRelay; - if (connect && !relay.connected) this.requestConnect(relay); - return relay; - } - - async waitForOpen(relayOrUrl: string | URL | AbstractRelay, quite = true) { - const relay = this.getRelay(relayOrUrl); - if (!relay) return Promise.reject("Missing relay"); - - if (relay.connected) return true; - - try { - // if the relay is connecting, wait. otherwise request a connection - // @ts-expect-error - (await relay.connectionPromise) || this.requestConnect(relay, quite); - return true; - } catch (err) { - if (quite) return false; - else throw err; - } - } - - async requestConnect(relayOrUrl: string | URL | AbstractRelay, quite = true) { - const relay = this.getRelay(relayOrUrl); - if (!relay) return; - - if (!relay.connected) { - this.connecting.get(relay).next(true); - try { - await relay.connect(); - this.connecting.get(relay).next(false); - } catch (e) { - e = e || new Error("Unknown error"); - if (e instanceof Error) { - this.log(`Failed to connect to ${relay.url}`, e.message); - this.connectionErrors.get(relay).push(e); - } - this.connecting.get(relay).next(false); - if (!quite) throw e; - } - } - } - - getRelayAuthStorageKey(relayOrUrl: string | URL | AbstractRelay) { - const relay = this.getRelay(relayOrUrl); - return `${relay!.url}-auth-mode`; - } - getRelayAuthMode(relayOrUrl: string | URL | AbstractRelay): RelayAuthMode | undefined { - const relay = this.getRelay(relayOrUrl); - if (!relay) return; - - const defaultMode = localSettings.defaultAuthenticationMode.value; - const mode = (localStorage.getItem(this.getRelayAuthStorageKey(relay)) as RelayAuthMode) ?? undefined; - - return mode || defaultMode; - } - setRelayAuthMode(relayOrUrl: string | URL | AbstractRelay, mode: RelayAuthMode) { - const relay = this.getRelay(relayOrUrl); - if (!relay) return; - - localStorage.setItem(this.getRelayAuthStorageKey(relay), mode); - } - - pendingAuth = new Map>(); - async authenticate( - relayOrUrl: string | URL | AbstractRelay, - sign: Parameters[0], - quite = true, - ) { - const relay = this.getRelay(relayOrUrl); - if (!relay) return; - - const pending = this.pendingAuth.get(relay); - if (pending) return pending; - - if (this.getRelayAuthMode(relay) === "never") throw new Error("Auth disabled for relay"); - - if (!relay.connected) throw new Error("Not connected"); - - const promise = new Promise(async (res) => { - if (!relay) return; - - try { - const message = await relay.auth(sign); - this.authenticated.get(relay).next(true); - res(message); - } catch (e) { - e = e || new Error("Unknown error"); - if (e instanceof Error) { - this.log(`Failed to authenticate to ${relay.url}`, e.message); - } - this.authenticated.get(relay).next(false); - if (!quite) throw e; - } - - this.pendingAuth.delete(relay); - }); - - this.pendingAuth.set(relay, promise); - - return await promise; - } - - canSubscribe(relayOrUrl: string | URL | AbstractRelay) { - const relay = this.getRelay(relayOrUrl); - if (!relay) return false; - - return this.authForSubscribe.get(relay).value !== false; - } - - private handleRelayChallenge(relay: AbstractRelay, challenge: string) { - this.onRelayChallenge.next([relay, challenge]); - this.challenges.get(relay).next(challenge); - } - - handleRelayNotice(relay: AbstractRelay, message: string) { - const subject = this.notices.get(relay); - subject.next([...subject.value, { message, date: dayjs().unix(), relay }]); - - if (message.includes("auth-required")) { - const authForSubscribe = this.authForSubscribe.get(relay); - if (!authForSubscribe.value) authForSubscribe.next(true); - } - } - - disconnectFromUnused() { - for (const [url, relay] of this.relays) { - if (!relay.connected) continue; - - // don't disconnect from authenticated relays - if (this.authenticated.get(relay).value) continue; - - let disconnect = false; - - if (disconnect) { - this.log(`No active processes using ${relay.url}, disconnecting`); - relay.close(); - - // NOTE: fix nostr-tools not resetting the connection promise - // @ts-expect-error - relay.connectionPromise = false; - } - } - } -} diff --git a/src/components/gif/gif-picker-modal.tsx b/src/components/gif/gif-picker-modal.tsx index 1011f2df0..e3fea6fda 100644 --- a/src/components/gif/gif-picker-modal.tsx +++ b/src/components/gif/gif-picker-modal.tsx @@ -52,13 +52,11 @@ type GifPickerProps = Omit & { onSelect: (gif: NostrEven export default function GifPickerModal({ onClose, isOpen, onSelect, ...props }: GifPickerProps) { const [search, setSearch] = useState(); - const [searchRelayUrl, setSearchRelayUrl] = useState(); + const [searchRelay, setSearchRelay] = useState(""); const [list, setList] = useState("global"); const { selected, setSelected, filter, listId } = usePeopleListSelect(list, setList); - // const searchRelay = useSearchRelay(searchRelayUrl); - const [debounceSearch, setDebounceSearch] = useState(); useEffect(() => { setDebounceSearch(undefined); @@ -75,8 +73,8 @@ export default function GifPickerModal({ onClose, isOpen, onSelect, ...props }: const readRelays = useReadRelays(); const { loader, timeline } = useTimelineLoader( - [listId, "gifs", searchRelayUrl ?? "all", debounceSearch ?? "all"].join("-"), - searchRelayUrl !== undefined ? [searchRelayUrl] : readRelays, + [listId, "gifs", searchRelay ?? "all", debounceSearch ?? "all"].join("-"), + !!searchRelay ? [searchRelay] : readRelays, debounceSearch !== undefined ? { ...baseFilter, search: debounceSearch } : baseFilter, ); @@ -96,7 +94,7 @@ export default function GifPickerModal({ onClose, isOpen, onSelect, ...props }: value={search} onChange={(e) => setSearch(e.target.value)} /> - setSearchRelayUrl(e.target.value)} /> + setSearchRelay(e.target.value)} /> diff --git a/src/components/relays/relay-auth-mode-select.tsx b/src/components/relays/relay-auth-mode-select.tsx index a5eca03a0..de2bd691c 100644 --- a/src/components/relays/relay-auth-mode-select.tsx +++ b/src/components/relays/relay-auth-mode-select.tsx @@ -1,8 +1,8 @@ import { Select, SelectProps } from "@chakra-ui/react"; import { useObservable } from "applesauce-react/hooks"; -import { RelayAuthMode } from "../../classes/relay-pool"; import localSettings from "../../services/local-settings"; +import { RelayAuthMode } from "../../services/authentication-signer"; export default function RelayAuthModeSelect({ relay, diff --git a/src/components/settings/default-auth-mode-select.tsx b/src/components/settings/default-auth-mode-select.tsx index 0dbadbc50..29c1ffccb 100644 --- a/src/components/settings/default-auth-mode-select.tsx +++ b/src/components/settings/default-auth-mode-select.tsx @@ -2,7 +2,7 @@ import { Select, SelectProps } from "@chakra-ui/react"; import { useObservable } from "applesauce-react/hooks"; import localSettings from "../../services/local-settings"; -import { RelayAuthMode } from "../../classes/relay-pool"; +import { RelayAuthMode } from "../../services/authentication-signer"; export default function DefaultAuthModeSelect({ ...props }: Omit) { const defaultAuthenticationMode = useObservable(localSettings.defaultAuthenticationMode); diff --git a/src/helpers/nostr/relay-stats.ts b/src/helpers/nostr/relay-stats.ts index 1798d6e05..1f92fcea6 100644 --- a/src/helpers/nostr/relay-stats.ts +++ b/src/helpers/nostr/relay-stats.ts @@ -1,15 +1,14 @@ +import { getReplaceableIdentifier, getTagValue } from "applesauce-core/helpers"; import { NostrEvent, isDTag } from "../../types/nostr-event"; -export const SELF_REPORTED_KIND = 10066; export const MONITOR_METADATA_KIND = 10166; -export const MONITOR_STATS_KIND = 30066; +export const MONITOR_STATS_KIND = 30166; export function getRelayURL(stats: NostrEvent) { - if (stats.kind === SELF_REPORTED_KIND) return stats.tags.find((t) => t[0] === "r")?.[1]; - return stats.tags.find(isDTag)?.[1]; + return getReplaceableIdentifier(stats); } export function getNetwork(stats: NostrEvent) { - return stats.tags.find((t) => t[0] === "n")?.[1]; + return getTagValue(stats, "n"); } export function getSupportedNIPs(stats: NostrEvent) { return stats.tags.filter((t) => t[0] === "N" && t[1]).map((t) => t[1] && parseInt(t[1])); diff --git a/src/helpers/relay.ts b/src/helpers/relay.ts index dfe91bf88..14621cfbc 100644 --- a/src/helpers/relay.ts +++ b/src/helpers/relay.ts @@ -1,7 +1,5 @@ import { ThemeTypings } from "@chakra-ui/react"; import { Filter } from "nostr-tools"; -import { SubCloser, SubscribeManyParams } from "nostr-tools/abstract-pool"; -import { AbstractRelay, Subscription } from "nostr-tools/abstract-relay"; import { ConnectionState } from "rx-nostr"; // NOTE: only use this for equality checks and querying @@ -96,85 +94,6 @@ export function splitQueryByPubkeys(query: Filter, relayPubkeyMap: Record(); - const subs: Subscription[] = []; - - // batch all EOSEs into a single - const eosesReceived: boolean[] = []; - let handleEose = (i: number) => { - eosesReceived[i] = true; - if (eosesReceived.filter((a) => a).length === relays.length) { - params.oneose?.(); - handleEose = () => {}; - } - }; - // batch all closes into a single - const closesReceived: string[] = []; - let handleClose = (i: number, reason: string) => { - handleEose(i); - closesReceived[i] = reason; - if (closesReceived.filter((a) => a).length === relays.length) { - params.onclose?.(closesReceived); - handleClose = () => {}; - } - }; - - const localAlreadyHaveEventHandler = (id: string) => { - if (params.alreadyHaveEvent?.(id)) { - return true; - } - const have = _knownIds.has(id); - _knownIds.add(id); - return have; - }; - - // open a subscription in all given relays - const allOpened = Promise.all( - relays.map(validateRelayURL).map(async (url, i, arr) => { - if (arr.indexOf(url) !== i) { - // duplicate - handleClose(i, "duplicate url"); - return; - } - - let relay: AbstractRelay; - try { - const { default: relayPoolService } = await import("../services/relay-pool"); - relay = relayPoolService.requestRelay(url); - await relayPoolService.requestConnect(relay); - // changed from nostr-tools - // relay = await this.ensureRelay(url, { - // connectionTimeout: params.maxWait ? Math.max(params.maxWait * 0.8, params.maxWait - 1000) : undefined, - // }); - } catch (err) { - handleClose(i, (err as any)?.message || String(err)); - return; - } - - const subscription = relay.subscribe(filters, { - ...params, - oneose: () => handleEose(i), - onclose: (reason) => handleClose(i, reason), - alreadyHaveEvent: localAlreadyHaveEventHandler, - eoseTimeout: params.maxWait, - }); - - subs.push(subscription); - }), - ); - - return { - async close() { - await allOpened; - subs.forEach((sub) => { - sub.close(); - }); - }, - }; -} - export function getConnectionStateColor(state: ConnectionState): ThemeTypings["colorSchemes"] { switch (state) { case "initialized": diff --git a/src/hooks/use-relay-stats.ts b/src/hooks/use-relay-stats.ts index 416b73de6..6eb4d2b00 100644 --- a/src/hooks/use-relay-stats.ts +++ b/src/hooks/use-relay-stats.ts @@ -1,17 +1,15 @@ -import { useObservable } from "applesauce-react/hooks"; -import relayStatsService from "../services/relay-stats"; +import { useEffect } from "react"; +import { useStoreQuery } from "applesauce-react/hooks"; +import { ReplaceableQuery } from "applesauce-core/queries"; + +import { MONITOR_PUBKEY, MONITOR_RELAY } from "../services/relay-status-loader"; +import monitorRelayStatusLoader from "../services/relay-status-loader"; +import { MONITOR_STATS_KIND } from "../helpers/nostr/relay-stats"; export default function useRelayStats(relay: string) { - const monitorSub = relayStatsService.requestMonitorStats(relay); - const selfReportedSub = relayStatsService.requestSelfReported(relay); + useEffect(() => { + monitorRelayStatusLoader.next({ value: relay, relays: [MONITOR_RELAY] }); + }, [relay]); - const monitor = useObservable(monitorSub); - const selfReported = useObservable(selfReportedSub); - const stats = monitor || selfReported || undefined; - - return { - monitor, - selfReported, - stats, - }; + return useStoreQuery(ReplaceableQuery, [MONITOR_STATS_KIND, MONITOR_PUBKEY, relay]); } diff --git a/src/hooks/use-search-relays.ts b/src/hooks/use-search-relays.ts index 832dc49a3..7ea23eaca 100644 --- a/src/hooks/use-search-relays.ts +++ b/src/hooks/use-search-relays.ts @@ -3,6 +3,19 @@ import { useActiveAccount } from "applesauce-react/hooks"; import { DEFAULT_SEARCH_RELAYS } from "../const"; import { getRelaysFromList } from "../helpers/nostr/lists"; import useUserSearchRelayList from "./use-user-search-relay-list"; +import useCacheRelay from "./use-cache-relay"; +import { useRelayInfo } from "./use-relay-info"; +import { AbstractRelay } from "nostr-tools/abstract-relay"; +import WasmRelay from "../services/wasm-relay"; + +export function useCacheRelaySupportsSearch() { + const cacheRelay = useCacheRelay(); + const { info: cacheRelayInfo } = useRelayInfo(cacheRelay instanceof AbstractRelay ? cacheRelay : undefined, true); + return ( + cacheRelay instanceof WasmRelay || + (cacheRelay instanceof AbstractRelay && !!cacheRelayInfo?.supported_nips?.includes(50)) + ); +} export default function useSearchRelays() { const account = useActiveAccount(); diff --git a/src/services/relay-pool.ts b/src/services/relay-pool.ts deleted file mode 100644 index 7d972136a..000000000 --- a/src/services/relay-pool.ts +++ /dev/null @@ -1,5 +0,0 @@ -import RelayPool from "../classes/relay-pool"; - -const relayPoolService = new RelayPool(); - -export default relayPoolService; diff --git a/src/services/relay-stats.ts b/src/services/relay-stats.ts deleted file mode 100644 index 35ec3e479..000000000 --- a/src/services/relay-stats.ts +++ /dev/null @@ -1,99 +0,0 @@ -import _throttle from "lodash.throttle"; -import { Filter } from "nostr-tools"; -import { BehaviorSubject } from "rxjs"; - -import SuperMap from "../classes/super-map"; -import { NostrEvent } from "../types/nostr-event"; -import relayInfoService from "./relay-info"; -import { MONITOR_STATS_KIND, SELF_REPORTED_KIND, getRelayURL } from "../helpers/nostr/relay-stats"; -import relayPoolService from "./relay-pool"; -import { alwaysVerify } from "./verify-event"; -import { eventStore } from "./event-store"; -import { getCacheRelay } from "./cache-relay"; - -const MONITOR_PUBKEY = "151c17c9d234320cf0f189af7b761f63419fd6c38c6041587a008b7682e4640f"; -const MONITOR_RELAY = "wss://relay.nostr.watch"; - -class RelayStatsService { - private selfReported = new SuperMap>( - () => new BehaviorSubject(undefined), - ); - private monitorStats = new SuperMap>( - () => new BehaviorSubject(undefined), - ); - - constructor() { - // load all stats from cache and subscribe to future ones - getCacheRelay()?.subscribe([{ kinds: [SELF_REPORTED_KIND, MONITOR_STATS_KIND] }], { - onevent: (e) => this.handleEvent(e), - }); - } - - handleEvent(event: NostrEvent) { - if (!alwaysVerify(event)) return; - - // ignore all events before NIP-66 start date - if (event.created_at < 1704196800) return; - - const relay = getRelayURL(event); - if (!relay) return; - - eventStore.add(event); - - const sub = this.monitorStats.get(relay); - if (event.kind === SELF_REPORTED_KIND) { - if (!sub.value || event.created_at > sub.value.created_at) sub.next(event); - } else if (event.kind === MONITOR_STATS_KIND) { - if (!sub.value || event.created_at > sub.value.created_at) sub.next(event); - } - } - - requestSelfReported(relay: string) { - const sub = this.selfReported.get(relay); - - if (sub.value === undefined) { - relayInfoService.getInfo(relay).then((info) => { - if (!info.pubkey) return sub.next(null); - - const filter: Filter = { kinds: [SELF_REPORTED_KIND], authors: [info.pubkey] }; - const subscription = relayPoolService - .requestRelay(MONITOR_RELAY) - .subscribe([filter], { onevent: (event) => this.handleEvent(event), oneose: () => subscription.close() }); - }); - } - - return sub; - } - - requestMonitorStats(relay: string) { - const sub = this.monitorStats.get(relay); - - if (sub.value === undefined) { - this.pendingMonitorStats.add(relay); - this.throttleBatchRequestMonitorStats(); - } - return sub; - } - - throttleBatchRequestMonitorStats = _throttle(this.batchRequestMonitorStats, 200); - pendingMonitorStats = new Set(); - private batchRequestMonitorStats() { - const relays = Array.from(this.pendingMonitorStats); - - const filter: Filter = { since: 1704196800, kinds: [MONITOR_STATS_KIND], "#d": relays, authors: [MONITOR_PUBKEY] }; - const sub = relayPoolService - .requestRelay(MONITOR_RELAY) - .subscribe([filter], { onevent: (event) => this.handleEvent(event), oneose: () => sub.close() }); - - this.pendingMonitorStats.clear(); - } -} - -const relayStatsService = new RelayStatsService(); - -if (import.meta.env.DEV) { - //@ts-expect-error debug - window.relayStatsService = relayStatsService; -} - -export default relayStatsService; diff --git a/src/services/relay-status-loader.ts b/src/services/relay-status-loader.ts new file mode 100644 index 000000000..f1edadcea --- /dev/null +++ b/src/services/relay-status-loader.ts @@ -0,0 +1,21 @@ +import { MONITOR_STATS_KIND } from "../helpers/nostr/relay-stats"; +import { TagValueLoader } from "applesauce-loaders"; +import rxNostr from "./rx-nostr"; +import { eventStore } from "./event-store"; + +export const MONITOR_PUBKEY = "151c17c9d234320cf0f189af7b761f63419fd6c38c6041587a008b7682e4640f"; +export const MONITOR_RELAY = "wss://relay.nostr.watch/"; + +const monitorRelayStatusLoader = new TagValueLoader(rxNostr, "d", { + name: "relay-monitor", + kinds: [MONITOR_STATS_KIND], + authors: [MONITOR_PUBKEY], + since: 1704196800, +}); + +// start the loader and send all events to the event store +monitorRelayStatusLoader.subscribe((packet) => { + eventStore.add(packet.event, packet.from); +}); + +export default monitorRelayStatusLoader; diff --git a/src/views/articles/article.tsx b/src/views/articles/article.tsx index 857eb98fe..9165bbab6 100644 --- a/src/views/articles/article.tsx +++ b/src/views/articles/article.tsx @@ -2,6 +2,7 @@ import { NostrEvent } from "nostr-tools"; import { Box, Button, Flex, Heading, Image, Spinner, Text, useDisclosure } from "@chakra-ui/react"; import dayjs from "dayjs"; +import { ThreadIcon } from "../../components/icons"; import useParamsAddressPointer from "../../hooks/use-params-address-pointer"; import useReplaceableEvent from "../../hooks/use-replaceable-event"; import VerticalPageLayout from "../../components/vertical-page-layout"; @@ -24,7 +25,6 @@ import BookmarkEventButton from "../../components/note/bookmark-event"; import EventQuoteButton from "../../components/note/event-quote-button"; import { GenericComments } from "../../components/comment/generic-comments"; import GenericCommentForm from "../../components/comment/generic-comment-form"; -import { ThreadIcon } from "../../components/icons"; function ArticlePage({ article }: { article: NostrEvent }) { const image = getArticleImage(article); diff --git a/src/views/relays/components/relay-card.tsx b/src/views/relays/components/relay-card.tsx index f383f58e1..f610ea064 100644 --- a/src/views/relays/components/relay-card.tsx +++ b/src/views/relays/components/relay-card.tsx @@ -45,7 +45,7 @@ export const Metadata = ({ name, children }: { name: string } & PropsWithChildre export function RelayMetadata({ url, extended }: { url: string; extended?: boolean }) { const { info } = useRelayInfo(url); - const { stats } = useRelayStats(url); + const stats = useRelayStats(url); return ( diff --git a/src/views/search/components/search-relay-picker.tsx b/src/views/search/components/search-relay-picker.tsx index fab831049..3e8a64b72 100644 --- a/src/views/search/components/search-relay-picker.tsx +++ b/src/views/search/components/search-relay-picker.tsx @@ -1,32 +1,18 @@ import { forwardRef } from "react"; import { Select, SelectProps } from "@chakra-ui/react"; -import { AbstractRelay } from "nostr-tools/abstract-relay"; -import useSearchRelays from "../../../hooks/use-search-relays"; -import { useRelayInfo } from "../../../hooks/use-relay-info"; -import WasmRelay from "../../../services/wasm-relay"; -import relayPoolService from "../../../services/relay-pool"; -import useCacheRelay from "../../../hooks/use-cache-relay"; +import useSearchRelays, { useCacheRelaySupportsSearch } from "../../../hooks/use-search-relays"; -export function useSearchRelay(relay?: string) { - const cacheRelay = useCacheRelay(); - if (!relay) return undefined; - if (relay === "local") return cacheRelay as AbstractRelay; - else return relayPoolService.requestRelay(relay); -} - -const SearchRelayPicker = forwardRef>(({ value, onChange, ...props }, ref) => { +const SearchRelayPicker = forwardRef< + any, + Omit & { value?: string; showLocal?: boolean } +>(({ value, onChange, showLocal, ...props }, ref) => { const searchRelays = useSearchRelays(); - const cacheRelay = useCacheRelay(); - - const { info: cacheRelayInfo } = useRelayInfo(cacheRelay instanceof AbstractRelay ? cacheRelay : undefined, true); - const localSearchSupported = - cacheRelay instanceof WasmRelay || - (cacheRelay instanceof AbstractRelay && !!cacheRelayInfo?.supported_nips?.includes(50)); + const localSearchSupported = useCacheRelaySupportsSearch(); return ( - {localSearchSupported && } - {searchRelays.map((url) => ( - - ))} - + } colorScheme="primary" /> - {shouldSearch ? : null} + {shouldSearch ? : null} ); diff --git a/src/views/tools/event-console/index.tsx b/src/views/tools/event-console/index.tsx index 904416ce5..20fe8cec6 100644 --- a/src/views/tools/event-console/index.tsx +++ b/src/views/tools/event-console/index.tsx @@ -1,4 +1,4 @@ -import { memo, useCallback, useRef, useState } from "react"; +import { memo, useCallback, useEffect, useRef, useState } from "react"; import { Alert, AlertDescription, @@ -9,23 +9,20 @@ import { ButtonGroup, CloseButton, Flex, - Heading, IconButton, Switch, Text, useDisclosure, } from "@chakra-ui/react"; import { NostrEvent } from "nostr-tools"; -import { AbstractRelay, Subscription } from "nostr-tools/abstract-relay"; import { useLocalStorage } from "react-use"; -import { Subscription as IDBSubscription } from "nostr-idb"; import _throttle from "lodash.throttle"; import stringify from "json-stringify-deterministic"; import { useLocation, useSearchParams } from "react-router-dom"; import { safeParse } from "applesauce-core/helpers/json"; +import { createRxForwardReq, EventPacket } from "rx-nostr"; +import { Subscription } from "rxjs"; -import VerticalPageLayout from "../../../components/vertical-page-layout"; -import BackButton from "../../../components/router/back-button"; import Play from "../../../components/icons/play"; import ClockRewind from "../../../components/icons/clock-rewind"; import HistoryDrawer from "./history-drawer"; @@ -35,10 +32,12 @@ import HelpModal from "./help-modal"; import HelpCircle from "../../../components/icons/help-circle"; import { DownloadIcon, ShareIcon } from "../../../components/icons"; import { RelayUrlInput } from "../../../components/relay-url-input"; -import { validateRelayURL } from "../../../helpers/relay"; import FilterEditor from "./filter-editor"; -import relayPoolService from "../../../services/relay-pool"; import useCacheRelay from "../../../hooks/use-cache-relay"; +import SimpleView from "../../../components/layout/presets/simple-view"; +import { cacheRequest } from "../../../services/cache-relay"; +import { eventStore } from "../../../services/event-store"; +import rxNostr from "../../../services/rx-nostr"; const EventTimeline = memo(({ events }: { events: NostrEvent[] }) => { return ( @@ -58,10 +57,9 @@ export default function EventConsoleView() { const [history, setHistory] = useLocalStorage("console-history", []); const helpModal = useDisclosure(); const queryRelay = useDisclosure({ defaultIsOpen: params.has("relay") }); - const [relayURL, setRelayURL] = useState(params.get("relay") || ""); - const [relay, setRelay] = useState(null); + const [relay, setRelay] = useState(params.get("relay") || ""); - const [sub, setSub] = useState(null); + const [sub, setSub] = useState(null); const [query, setQuery] = useState(() => { if (params.has("filter") || location.state?.filter) { @@ -82,54 +80,54 @@ export default function EventConsoleView() { const [events, setEvents] = useState([]); const loadEvents = useCallback(async () => { try { - if (queryRelay.isOpen && !relayURL) throw new Error("Must set relay"); - const filter = await processFilter(JSON.parse(query)); setLoading(true); setHistory((arr) => (arr ? (!arr.includes(query) ? [query, ...arr] : arr) : [query])); setEvents([]); + setError(""); - if (sub) sub.close(); + // stop previous subscription + if (sub) sub.unsubscribe(); + + const buffer: NostrEvent[] = []; + const flush = _throttle( + () => { + setEvents([...buffer]); + }, + 1000 / 10, + { trailing: true }, + ); + + const handleEvent = (event: NostrEvent) => { + event = eventStore.add(event); + buffer.push(event); + flush(); + }; + const handleEventPacket = (packet: EventPacket) => { + const event = eventStore.add(packet.event, packet.from); + buffer.push(event); + flush(); + }; - if (!cacheRelay) throw new Error("Local relay disabled"); - let r = cacheRelay!; if (queryRelay.isOpen) { - const url = validateRelayURL(relayURL); - if (!relay || relay.url !== url.toString()) { - r = await relayPoolService.requestRelay(url); - await relayPoolService.requestConnect(r); - setRelay(r as AbstractRelay); - } else r = relay; + if (!relay) throw new Error("Must set relay"); + + // query remote relay + const req = createRxForwardReq(); + const sub = rxNostr.use(req, { on: { relays: [relay] } }).subscribe(handleEventPacket); + req.emit([filter]); + setSub(sub); } else { - if (relay) setRelay(null); + // query cache relay + if (!cacheRelay) throw new Error("Local relay disabled"); + const sub = cacheRequest([filter]).subscribe(handleEvent); + setSub(sub); } - - await new Promise((res) => { - const buffer: NostrEvent[] = []; - const flush = _throttle(() => setEvents([...buffer]), 1000 / 10, { trailing: true }); - - setError(""); - - const s = r.subscribe([filter], { - onevent: (e) => { - buffer.push(e); - flush(); - }, - oneose: () => { - setEvents([...buffer]); - res(); - }, - onclose: (reason) => { - if (!buffer.length) setError(reason); - }, - }); - setSub(s); - }); } catch (e) { if (e instanceof Error) setError(e.message); } setLoading(false); - }, [queryRelay.isOpen, query, relayURL, relay, sub, cacheRelay]); + }, [queryRelay.isOpen, query, relay, relay, sub, cacheRelay]); const submitRef = useRef(loadEvents); submitRef.current = loadEvents; @@ -146,47 +144,57 @@ export default function EventConsoleView() { const updateSharedURL = () => { const p = new URLSearchParams(params); p.set("filter", query); - p.set("relay", relayURL); + if (relay) p.set("relay", relay); setParams(p, { replace: true }); }; return ( - - - - Event Console + + + } aria-label="Help" title="Help" size="sm" onClick={helpModal.onOpen} /> + } aria-label="Share" size="sm" onClick={updateSharedURL} /> + } + aria-label="History" + title="History" + size="sm" + onClick={historyDrawer.onOpen} + /> + + + } + > + Query Relay {queryRelay.isOpen && ( - setRelayURL(e.target.value)} - /> + setRelay(e.target.value)} /> )} - - } aria-label="Help" title="Help" size="sm" onClick={helpModal.onOpen} /> - {queryRelay.isOpen && ( - } aria-label="Share" size="sm" onClick={updateSharedURL} /> + + + + + {events.length} events + {sub && Subscribed} + + {events.length > 0 && ( + } + onClick={downloadEvents} + /> )} - } - aria-label="History" - title="History" - size="sm" - onClick={historyDrawer.onOpen} - /> - - - {error && ( @@ -205,23 +213,6 @@ export default function EventConsoleView() { )} - - {events.length} events - {sub && ( - - Subscribed - - )} - {events.length > 0 && ( - } - onClick={downloadEvents} - size="xs" - /> - )} - @@ -238,6 +229,6 @@ export default function EventConsoleView() { /> - + ); } diff --git a/src/views/tools/network-dm-graph.tsx b/src/views/tools/network-dm-graph.tsx index d8c9f74a1..27ff48742 100644 --- a/src/views/tools/network-dm-graph.tsx +++ b/src/views/tools/network-dm-graph.tsx @@ -1,11 +1,13 @@ -import { useEffect, useMemo, useState } from "react"; +import { useMemo, useState } from "react"; import { Box, Button, Flex, Input, Text } from "@chakra-ui/react"; import AutoSizer from "react-virtualized-auto-sizer"; import ForceGraph, { LinkObject, NodeObject } from "react-force-graph-3d"; import { Filter, kinds } from "nostr-tools"; -import dayjs from "dayjs"; +import { getProfileContent } from "applesauce-core/helpers"; +import { useStoreQuery } from "applesauce-react/hooks"; +import { TimelineQuery } from "applesauce-core/queries"; import { useNavigate } from "react-router-dom"; -import { useDebounce } from "react-use"; +import { useThrottle } from "react-use"; import { Group, Mesh, @@ -16,6 +18,7 @@ import { SpriteMaterial, TextureLoader, } from "three"; +import dayjs from "dayjs"; import { useActiveAccount } from "applesauce-react/hooks"; import RequireActiveAccount from "../../components/router/require-active-account"; @@ -25,12 +28,9 @@ import useUserProfile from "../../hooks/use-user-profile"; import { isPTag } from "../../types/nostr-event"; import { ChevronLeftIcon } from "../../components/icons"; import { useReadRelays } from "../../hooks/use-client-relays"; -import { subscribeMany } from "../../helpers/relay"; import useUserProfiles from "../../hooks/use-user-profiles"; import { eventStore } from "../../services/event-store"; -import { getProfileContent } from "applesauce-core/helpers"; -import { useStoreQuery } from "applesauce-react/hooks"; -import { TimelineQuery } from "applesauce-core/queries"; +import useForwardSubscription from "../../hooks/use-forward-subscription"; type NodeType = { id: string; image?: string; name?: string }; @@ -48,27 +48,20 @@ function NetworkDMGraphPage() { const [until, setUntil] = useState(dayjs().unix()); const [since, setSince] = useState(dayjs().subtract(1, "week").unix()); - const [fetchData] = useDebounce( - () => { - if (!contacts) return; - - const filter: Filter = { + const filters = useMemo( + () => [ + { authors: contactsPubkeys, kinds: [kinds.EncryptedDirectMessage], since, until, - }; - const sub = subscribeMany(Array.from(relays), [filter], { - onevent: (event) => eventStore.add(event), - oneose: () => sub.close(), - }); - }, - 2 * 1000, - [relays, contactsPubkeys, since, until], + }, + ], + [contactsPubkeys, since, until], ); - useEffect(() => { - fetchData(); - }, [relays, contactsPubkeys, since, until]); + + const throttledFilter = useThrottle(filters, 2 * 1000); + useForwardSubscription(relays, throttledFilter); const selfMetadata = useUserProfile(account.pubkey); const userProfiles = useUserProfiles(contactsPubkeys); diff --git a/src/views/wiki/search.tsx b/src/views/wiki/search.tsx index c5698c47d..897c4b9c3 100644 --- a/src/views/wiki/search.tsx +++ b/src/views/wiki/search.tsx @@ -1,25 +1,22 @@ -import { useEffect, useState } from "react"; +import { useEffect, useMemo, useState } from "react"; import { Navigate } from "react-router-dom"; import { Button, Flex, Heading, Input, Link } from "@chakra-ui/react"; import { Link as RouterLink } from "react-router-dom"; import { Filter, NostrEvent } from "nostr-tools"; import { useForm } from "react-hook-form"; -import { Subscription, getEventUID } from "nostr-idb"; +import { getEventUID } from "nostr-idb"; import VerticalPageLayout from "../../components/vertical-page-layout"; import useRouteSearchValue from "../../hooks/use-route-search-value"; -import { subscribeMany } from "../../helpers/relay"; import { DEFAULT_SEARCH_RELAYS, WIKI_RELAYS } from "../../const"; import { WIKI_PAGE_KIND } from "../../helpers/nostr/wiki"; -import { cacheRelay$ } from "../../services/cache-relay"; import WikiPageResult from "./components/wiki-page-result"; import { useWebOfTrust } from "../../providers/global/web-of-trust-provider"; -import { useObservable } from "applesauce-react/hooks"; import { eventStore } from "../../services/event-store"; import { ErrorBoundary } from "../../components/error-boundary"; +import { createSearchAction } from "../search/components/search-results"; export default function WikiSearchView() { - const cacheRelay = useObservable(cacheRelay$); const webOfTrust = useWebOfTrust(); const { value: query, setValue: setQuery } = useRouteSearchValue("q"); if (!query) return ; @@ -30,6 +27,7 @@ export default function WikiSearchView() { }); const [results, setResults] = useState([]); + const search = useMemo(() => createSearchAction([...DEFAULT_SEARCH_RELAYS, ...WIKI_RELAYS]), []); useEffect(() => { setResults([]); @@ -38,25 +36,18 @@ export default function WikiSearchView() { const seen = new Set(); const handleEvent = (event: NostrEvent) => { - eventStore.add(event); - if (seen.has(getEventUID(event))) return; setResults((arr) => arr.concat(event)); seen.add(getEventUID(event)); }; - const remoteSearchSub = subscribeMany([...DEFAULT_SEARCH_RELAYS, ...WIKI_RELAYS], [filter], { - onevent: handleEvent, - oneose: () => remoteSearchSub.close(), + const sub = search([filter]).subscribe((packet) => { + eventStore.add(packet.event, packet.from); + handleEvent(packet.event); }); - if (cacheRelay) { - const localSearchSub: Subscription = cacheRelay.subscribe([filter], { - onevent: handleEvent, - oneose: () => localSearchSub.close(), - }); - } - }, [query, setResults, cacheRelay]); + return () => sub.unsubscribe(); + }, [query, setResults]); const sorted = webOfTrust ? webOfTrust.sortByDistanceAndConnections(results, (p) => p.pubkey) : results;