diff --git a/.changeset/giant-pumas-joke.md b/.changeset/giant-pumas-joke.md new file mode 100644 index 000000000..18d7c7875 --- /dev/null +++ b/.changeset/giant-pumas-joke.md @@ -0,0 +1,5 @@ +--- +"nostrudel": minor +--- + +Update task manager to reflect rx-nostr relay connections and auth diff --git a/package.json b/package.json index daa70d3f9..a6ef0e5ae 100644 --- a/package.json +++ b/package.json @@ -90,6 +90,7 @@ "nostr-idb": "^2.2.0", "nostr-signer-capacitor-plugin": "^0.0.3", "nostr-tools": "^2.10.4", + "nostr-typedef": "^0.11.0", "nostr-wasm": "^0.1.0", "nuka-carousel": "^8.2.0", "prettier": "^3.4.2", @@ -118,7 +119,7 @@ "rxjs": "^7.8.1", "three": "^0.170.0", "three-spritetext": "^1.9.4", - "three-stdlib": "^2.35.12", + "three-stdlib": "^2.35.13", "tiny-lru": "^11.2.11", "unified": "^11.0.5", "uuid": "^11.0.5", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 29a513ffa..dffcf5328 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-20250128190416(typescript@5.7.3) + version: 0.0.0-next-20250129183155(typescript@5.7.3) applesauce-content: specifier: next - version: 0.0.0-next-20250128190416(typescript@5.7.3) + version: 0.0.0-next-20250129183155(typescript@5.7.3) applesauce-core: specifier: next - version: 0.0.0-next-20250128190416(typescript@5.7.3) + version: 0.0.0-next-20250129183155(typescript@5.7.3) applesauce-factory: specifier: next - version: 0.0.0-next-20250128190416(typescript@5.7.3) + version: 0.0.0-next-20250129183155(typescript@5.7.3) applesauce-loaders: specifier: next - version: 0.0.0-next-20250128190416(typescript@5.7.3) + version: 0.0.0-next-20250129183155(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-20250128190416(typescript@5.7.3) + version: 0.0.0-next-20250129183155(typescript@5.7.3) applesauce-signers: specifier: next - version: 0.0.0-next-20250128190416(typescript@5.7.3) + version: 0.0.0-next-20250129183155(typescript@5.7.3) bech32: specifier: ^2.0.0 version: 2.0.0 @@ -225,6 +225,9 @@ importers: nostr-tools: specifier: ^2.10.4 version: 2.10.4(typescript@5.7.3) + nostr-typedef: + specifier: ^0.11.0 + version: 0.11.0 nostr-wasm: specifier: ^0.1.0 version: 0.1.0 @@ -310,8 +313,8 @@ importers: specifier: ^1.9.4 version: 1.9.4(three@0.170.0) three-stdlib: - specifier: ^2.35.12 - version: 2.35.12(three@0.170.0) + specifier: ^2.35.13 + version: 2.35.13(three@0.170.0) tiny-lru: specifier: ^11.2.11 version: 11.2.11 @@ -2192,32 +2195,32 @@ packages: engines: {node: '>=8.0.0'} hasBin: true - applesauce-accounts@0.0.0-next-20250128190416: - resolution: {integrity: sha512-GtfoLOGxey2SlglPJorFCFwHIFuiDJqp5jnsL14Mtm6I1NkZBNHlugyvgH2sMhWuA3CkyOQkpVvS31JczGM/IQ==} + applesauce-accounts@0.0.0-next-20250129183155: + resolution: {integrity: sha512-mO03NJ1uZXj964OW4joh7nBW74dH5keIsDVol9E87FK6kWJEOrkOIS3x1Mi5gvZvllJ2tBRJTEZdeHfV7eCdSQ==} - applesauce-content@0.0.0-next-20250128190416: - resolution: {integrity: sha512-k5hsFzLzWreWK5EaAUhVKRFDT8CbgJfBuZxFK2McBo3Jaxz34YguAdQJKOdBzKcKwTMKtHKsay9BHV2ghckDxQ==} + applesauce-content@0.0.0-next-20250129183155: + resolution: {integrity: sha512-LSRRQ8IsrSp/kycpAZonW0aIuOquRg7SWNwGio8VBsSpH7p/1VuH+gWA1QRzI+Jzb9+uV+1fghYQR7cq/dC2vA==} - applesauce-core@0.0.0-next-20250128190416: - resolution: {integrity: sha512-DCvQHl9TKu+qDdEbUO35SFkC7lyeNvZRs1KNdmUjsQhnhmvuvdJ8s0XJNJvkrSQeHgcXXNzHDU906RxBxqjytA==} + applesauce-core@0.0.0-next-20250129183155: + resolution: {integrity: sha512-B0gKQtpUqJfEcQSDIfJdAAsZTKACS6lzio/OMu34aricEne2XOS+FLeumoMDet9P2oK2MASkbAy2j6eCyFD/7A==} applesauce-core@0.10.0: resolution: {integrity: sha512-QMhUh4FIARcqY5soCB4Z8DIu+py0rYb28IgWT4gP9DLBGpDrY8lStXk7W1/46TLjEH97y0hbiXFK7kMCZ31oOQ==} - applesauce-factory@0.0.0-next-20250128190416: - resolution: {integrity: sha512-zYduxpOyk5aswWDoRgdc+90ARQZnQNdOwRnB9VBTB8rxlWzF5v49+rCxcuKUwl/cn5/S2XB5TytDYumCOy5SpQ==} + applesauce-factory@0.0.0-next-20250129183155: + resolution: {integrity: sha512-s6V+HHg+4yG0XELZMsdhUca976teqRhTlf+XCENQC9qW4bAYfkYrP3fZfelVBXhDP4mTzereK6yO2cgH53aQUw==} - applesauce-loaders@0.0.0-next-20250128190416: - resolution: {integrity: sha512-26M/ax+6oVlncREUxEjTneNXYxhfFNrhl94kVJyw78Gx+frmNZLbTts3US3ng+ziKB5lnKZvBJJCXkiev4f9kQ==} + applesauce-loaders@0.0.0-next-20250129183155: + resolution: {integrity: sha512-JxFoSLtJoscdj4D4nUxbjJVk4f5K5Ssjt9gecQQz3XgPAOQasyT8ZkCyhhL+3VkvvT4jYNOMK84kwa9/yEtqlQ==} applesauce-net@0.10.0: resolution: {integrity: sha512-ZsAs/MkeGHiPZ2/a8lwP8lx/Eh+5Dot0qG4BLTAqjg4emP/RsiqW+hyc6v6QcVbdvuR0+hP1gka3+wWtiy/cTA==} - applesauce-react@0.0.0-next-20250128190416: - resolution: {integrity: sha512-0jWnZBDDesc7OnT20ZTW3kC/hnHYRwFy2XtOPMpBc2TZAKnAIfQIKnrQqa5YwlCdBo7L/EFL02vz6XnIDS8P+w==} + applesauce-react@0.0.0-next-20250129183155: + resolution: {integrity: sha512-79tWla4qdr5YzZXMIBj0cqbIrY1t7Kr/0kF4BL1Amvx09OYYLVS1rr4YwdXzdEtmCqMr/cotL5K167Fhe6KKMg==} - applesauce-signers@0.0.0-next-20250128190416: - resolution: {integrity: sha512-EDQruPuY+cxSQ6HIRrG2aRDazKUrSvWLH3Ey896/LEqYKwcPMxwzUm2Ppuy+d1GsNJ5O6Nz5txKgfSDRfk2t5Q==} + applesauce-signers@0.0.0-next-20250129183155: + resolution: {integrity: sha512-666Gj7cDThnHR4eT+ExcHo7mN8vWlOJIsEy0FeU+lpFdsZd391AmXSReH0LaV7ja4aHOWqJmQr0M6PkkUKwloQ==} arg@4.1.3: resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==} @@ -2454,8 +2457,8 @@ packages: resolution: {integrity: sha512-8WB3Jcas3swSvjIeA2yvCJ+Miyz5l1ZmB6HFb9R1317dt9LCQoswg/BGrmAmkWVEszSrrg4RwmO46qIm2OEnSA==} engines: {node: '>=16'} - caniuse-lite@1.0.30001695: - resolution: {integrity: sha512-vHyLade6wTgI2u1ec3WQBxv+2BrTERV28UXQu9LO6lZ9pYeMk34vjXFLOxo1A4UBA8XTL4njRQZdno/yYaSmWw==} + caniuse-lite@1.0.30001696: + resolution: {integrity: sha512-pDCPkvzfa39ehJtJ+OwGT/2yvT2SbjfHhiIW2LWOAcMQ7BzwxT/XuyUp4OTOd0XFWA6BKw0JalnBHgSi5DGJBQ==} canvas-color-tracker@1.3.1: resolution: {integrity: sha512-eNycxGS7oQ3IS/9QQY41f/aQjiO9Y/MtedhCgSdsbLSxC9EyUD8L3ehl/Q3Kfmvt8um79S45PBV+5Rxm5ztdSw==} @@ -4434,6 +4437,9 @@ packages: typescript: optional: true + nostr-typedef@0.11.0: + resolution: {integrity: sha512-grXIdS0dnfi3fUQNJFRNKjQZaFl3sYUpQ+U67XRtAFpl/ZAwFWkboJpryv72PS7pQ/Gkd0Q2uEoX8wm9H2uaQg==} + nostr-typedef@0.9.0: resolution: {integrity: sha512-nLTzhlYcRnLQGUJ5YfvGAUDyGFHjGH6Qozltl/wV3UXelmiUwjrwI8IIxQNkbgVMv+zmbFi/m1xKHxIvVfG09w==} @@ -4715,9 +4721,6 @@ packages: queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} - queue-tick@1.0.1: - resolution: {integrity: sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==} - quick-lru@4.0.1: resolution: {integrity: sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==} engines: {node: '>=8'} @@ -5194,8 +5197,8 @@ packages: resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} hasBin: true - semver@7.6.3: - resolution: {integrity: sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==} + semver@7.7.0: + resolution: {integrity: sha512-DrfFnPzblFmNrIZzg5RzHegbiRWg7KMR7btwi2yjHwx06zsUbO5g613sVwEV7FTwmzJu+Io0lJe2GJ3LxqpvBQ==} engines: {node: '>=10'} hasBin: true @@ -5386,8 +5389,8 @@ packages: resolution: {integrity: sha512-uyQK/mx5QjHun80FLJTfaWE7JtwfRMKBLkMne6udYOmvH0CawotVa7TfgYHzAnpphn4+TweIx1QKMnRIbipmUg==} engines: {node: '>= 0.10.0'} - streamx@2.21.1: - resolution: {integrity: sha512-PhP9wUnFLa+91CPy3N6tiQsK+gnYyUNuk15S3YG/zjYE7RuPeCjJngqnzpC31ow0lzBHQ+QGO4cNJnd0djYUsw==} + streamx@2.22.0: + resolution: {integrity: sha512-sLh1evHOzBy/iWRiR6d1zRcLao4gGZr3C1kzNz4fopCOKJb6xD9ub8Mpi9Mr1R6id5o43S+d93fI48UC5uM9aw==} strict-uri-encode@2.0.0: resolution: {integrity: sha512-QwiXZgpRcKkhTj2Scnn++4PKtWsH0kpzZ62L2R6c/LUVYv7hVnZqcg2+sMuT6R7Jusu1vviK/MFsu6kNJfWlEQ==} @@ -5539,8 +5542,8 @@ packages: peerDependencies: three: '>=0.86.0' - three-stdlib@2.35.12: - resolution: {integrity: sha512-3Mb3U7gtf1orCb6j2BBcc8BJsBVoCYUjFtwaq9KM8I7ippz4o9G+aDQdT5AF8Sg5FXXZfnPPccP6ufsP8bgG3g==} + three-stdlib@2.35.13: + resolution: {integrity: sha512-AbXVObkM0OFCKX0r4VmHguGTdebiUQA+Yl+4VNta1wC158gwY86tCkjp2LFfmABtjYJhdK6aP13wlLtxZyLMAA==} peerDependencies: three: '>=0.128.0' @@ -6894,7 +6897,7 @@ snapshots: plist: 3.1.0 prompts: 2.4.2 rimraf: 4.4.1 - semver: 7.6.3 + semver: 7.7.0 tar: 6.2.1 tslib: 2.6.2 xml2js: 0.5.0 @@ -6916,7 +6919,7 @@ snapshots: plist: 3.1.0 prompts: 2.4.2 rimraf: 4.4.1 - semver: 7.6.3 + semver: 7.7.0 tar: 6.2.1 tslib: 2.8.1 xml2js: 0.5.0 @@ -7169,7 +7172,7 @@ snapshots: outdent: 0.5.0 prettier: 2.8.8 resolve-from: 5.0.0 - semver: 7.6.3 + semver: 7.7.0 '@changesets/assemble-release-plan@6.0.5': dependencies: @@ -7178,7 +7181,7 @@ snapshots: '@changesets/should-skip-package': 0.1.1 '@changesets/types': 6.0.0 '@manypkg/get-packages': 1.1.3 - semver: 7.6.3 + semver: 7.7.0 '@changesets/changelog-git@0.2.0': dependencies: @@ -7211,7 +7214,7 @@ snapshots: package-manager-detector: 0.2.8 picocolors: 1.1.1 resolve-from: 5.0.0 - semver: 7.6.3 + semver: 7.7.0 spawndamnit: 3.0.1 term-size: 2.2.1 @@ -7234,7 +7237,7 @@ snapshots: '@changesets/types': 6.0.0 '@manypkg/get-packages': 1.1.3 picocolors: 1.1.1 - semver: 7.6.3 + semver: 7.7.0 '@changesets/get-release-plan@4.0.6': dependencies: @@ -8431,10 +8434,10 @@ snapshots: dependencies: entities: 2.2.0 - applesauce-accounts@0.0.0-next-20250128190416(typescript@5.7.3): + applesauce-accounts@0.0.0-next-20250129183155(typescript@5.7.3): dependencies: '@noble/hashes': 1.7.1 - applesauce-signers: 0.0.0-next-20250128190416(typescript@5.7.3) + applesauce-signers: 0.0.0-next-20250129183155(typescript@5.7.3) nanoid: 5.0.9 nostr-tools: 2.10.4(typescript@5.7.3) rxjs: 7.8.1 @@ -8442,13 +8445,13 @@ snapshots: - supports-color - typescript - applesauce-content@0.0.0-next-20250128190416(typescript@5.7.3): + applesauce-content@0.0.0-next-20250129183155(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-20250128190416(typescript@5.7.3) + applesauce-core: 0.0.0-next-20250129183155(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 @@ -8459,7 +8462,7 @@ snapshots: - supports-color - typescript - applesauce-core@0.0.0-next-20250128190416(typescript@5.7.3): + applesauce-core@0.0.0-next-20250129183155(typescript@5.7.3): dependencies: '@scure/base': 1.2.4 debug: 4.4.0 @@ -8487,19 +8490,19 @@ snapshots: - supports-color - typescript - applesauce-factory@0.0.0-next-20250128190416(typescript@5.7.3): + applesauce-factory@0.0.0-next-20250129183155(typescript@5.7.3): dependencies: - applesauce-content: 0.0.0-next-20250128190416(typescript@5.7.3) - applesauce-core: 0.0.0-next-20250128190416(typescript@5.7.3) + applesauce-content: 0.0.0-next-20250129183155(typescript@5.7.3) + applesauce-core: 0.0.0-next-20250129183155(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-20250128190416(typescript@5.7.3): + applesauce-loaders@0.0.0-next-20250129183155(typescript@5.7.3): dependencies: - applesauce-core: 0.0.0-next-20250128190416(typescript@5.7.3) + applesauce-core: 0.0.0-next-20250129183155(typescript@5.7.3) nanoid: 5.0.9 nostr-tools: 2.10.4(typescript@5.7.3) rx-nostr: 3.5.0 @@ -8518,12 +8521,12 @@ snapshots: - supports-color - typescript - applesauce-react@0.0.0-next-20250128190416(typescript@5.7.3): + applesauce-react@0.0.0-next-20250129183155(typescript@5.7.3): dependencies: - applesauce-accounts: 0.0.0-next-20250128190416(typescript@5.7.3) - applesauce-content: 0.0.0-next-20250128190416(typescript@5.7.3) - applesauce-core: 0.0.0-next-20250128190416(typescript@5.7.3) - applesauce-factory: 0.0.0-next-20250128190416(typescript@5.7.3) + applesauce-accounts: 0.0.0-next-20250129183155(typescript@5.7.3) + applesauce-content: 0.0.0-next-20250129183155(typescript@5.7.3) + applesauce-core: 0.0.0-next-20250129183155(typescript@5.7.3) + applesauce-factory: 0.0.0-next-20250129183155(typescript@5.7.3) nostr-tools: 2.10.4(typescript@5.7.3) react: 18.3.1 rxjs: 7.8.1 @@ -8531,12 +8534,12 @@ snapshots: - supports-color - typescript - applesauce-signers@0.0.0-next-20250128190416(typescript@5.7.3): + applesauce-signers@0.0.0-next-20250129183155(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-20250128190416(typescript@5.7.3) + applesauce-core: 0.0.0-next-20250129183155(typescript@5.7.3) debug: 4.4.0 nanoid: 5.0.9 nostr-tools: 2.10.4(typescript@5.7.3) @@ -8651,7 +8654,7 @@ snapshots: bare-stream@2.6.4(bare-events@2.5.4): dependencies: - streamx: 2.21.1 + streamx: 2.22.0 optionalDependencies: bare-events: 2.5.4 optional: true @@ -8760,7 +8763,7 @@ snapshots: browserslist@4.24.4: dependencies: - caniuse-lite: 1.0.30001695 + caniuse-lite: 1.0.30001696 electron-to-chromium: 1.5.88 node-releases: 2.0.19 update-browserslist-db: 1.1.2(browserslist@4.24.4) @@ -8810,7 +8813,7 @@ snapshots: camelcase@8.0.0: {} - caniuse-lite@1.0.30001695: {} + caniuse-lite@1.0.30001696: {} canvas-color-tracker@1.3.1: dependencies: @@ -11081,7 +11084,7 @@ snapshots: node-abi@3.73.0: dependencies: - semver: 7.6.3 + semver: 7.7.0 node-addon-api@6.1.0: {} @@ -11107,7 +11110,7 @@ snapshots: dependencies: hosted-git-info: 4.1.0 is-core-module: 2.16.1 - semver: 7.6.3 + semver: 7.7.0 validate-npm-package-license: 3.0.4 nostr-idb@2.2.0(typescript@5.7.3): @@ -11147,6 +11150,8 @@ snapshots: nostr-wasm: 0.1.0 typescript: 5.7.3 + nostr-typedef@0.11.0: {} + nostr-typedef@0.9.0: {} nostr-wasm@0.1.0: {} @@ -11415,8 +11420,6 @@ snapshots: queue-microtask@1.2.3: {} - queue-tick@1.0.1: {} - quick-lru@4.0.1: {} railroad-diagrams@1.0.0: {} @@ -11998,7 +12001,7 @@ snapshots: semver@6.3.1: {} - semver@7.6.3: {} + semver@7.7.0: {} send@0.19.0: dependencies: @@ -12065,7 +12068,7 @@ snapshots: detect-libc: 2.0.3 node-addon-api: 6.1.0 prebuild-install: 7.1.3 - semver: 7.6.3 + semver: 7.7.0 simple-get: 4.0.1 tar-fs: 3.0.8 tunnel-agent: 0.6.0 @@ -12232,10 +12235,9 @@ snapshots: stream-buffers@2.2.0: {} - streamx@2.21.1: + streamx@2.22.0: dependencies: fast-fifo: 1.3.2 - queue-tick: 1.0.1 text-decoder: 1.2.3 optionalDependencies: bare-events: 2.5.4 @@ -12371,7 +12373,7 @@ snapshots: dependencies: b4a: 1.6.7 fast-fifo: 1.3.2 - streamx: 2.21.1 + streamx: 2.22.0 tar@6.2.1: dependencies: @@ -12443,7 +12445,7 @@ snapshots: dependencies: three: 0.170.0 - three-stdlib@2.35.12(three@0.170.0): + three-stdlib@2.35.13(three@0.170.0): dependencies: '@types/draco3d': 1.4.10 '@types/offscreencanvas': 2019.7.3 diff --git a/src/classes/bakery/bakery-connection.ts b/src/classes/bakery/bakery-connection.ts index 9d4a2924f..3fda88e9e 100644 --- a/src/classes/bakery/bakery-connection.ts +++ b/src/classes/bakery/bakery-connection.ts @@ -1,8 +1,8 @@ import { BehaviorSubject, Subject } from "rxjs"; import { EventTemplate, Relay, VerifiedEvent } from "nostr-tools"; import { ControlMessage, ControlResponse } from "@satellite-earth/core/types"; +import { createDefer, Deferred } from "applesauce-core/promise"; -import createDefer, { Deferred } from "../deferred"; import { logger } from "../../helpers/debug"; export default class BakeryRelay extends Relay { diff --git a/src/classes/batch-identifier-loader.ts b/src/classes/batch-identifier-loader.ts index 851f13192..44e29f19a 100644 --- a/src/classes/batch-identifier-loader.ts +++ b/src/classes/batch-identifier-loader.ts @@ -4,12 +4,12 @@ import _throttle from "lodash.throttle"; import debug, { Debugger } from "debug"; import { EventStore } from "applesauce-core"; import { getEventUID } from "applesauce-core/helpers"; +import { createDefer, Deferred } from "applesauce-core/promise"; import { Subject } from "rxjs"; import PersistentSubscription from "./persistent-subscription"; import Process from "./process"; import processManager from "../services/process-manager"; -import createDefer, { Deferred } from "./deferred"; import Dataflow04 from "../components/icons/dataflow-04"; import SuperMap from "./super-map"; diff --git a/src/classes/batch-relation-loader.ts b/src/classes/batch-relation-loader.ts index 37e19fc4f..f82055caf 100644 --- a/src/classes/batch-relation-loader.ts +++ b/src/classes/batch-relation-loader.ts @@ -2,12 +2,12 @@ import { NostrEvent } from "nostr-tools"; import { AbstractRelay } from "nostr-tools/abstract-relay"; import _throttle from "lodash.throttle"; import debug, { Debugger } from "debug"; +import { createDefer, Deferred } from "applesauce-core/promise"; import { Subject } from "rxjs"; import PersistentSubscription from "./persistent-subscription"; import Process from "./process"; import processManager from "../services/process-manager"; -import createDefer, { Deferred } from "./deferred"; import Dataflow04 from "../components/icons/dataflow-04"; import SuperMap from "./super-map"; import { eventStore } from "../services/event-store"; diff --git a/src/classes/chunked-request.ts b/src/classes/chunked-request.ts index fa28cf4bd..02beacd14 100644 --- a/src/classes/chunked-request.ts +++ b/src/classes/chunked-request.ts @@ -8,9 +8,7 @@ import { Subject } from "rxjs"; import { logger } from "../helpers/debug"; import EventStore from "./event-store"; -import deleteEventService from "../services/delete-events"; import { mergeFilter } from "../helpers/nostr/filter"; -import { isATag, isETag } from "../types/nostr-event"; import relayPoolService from "../services/relay-pool"; import Process from "./process"; import processManager from "../services/process-manager"; @@ -49,9 +47,6 @@ export default class ChunkedRequest { this.log = log || logger.extend(relay.url); this.events = new EventStore(relay.url); - // TODO: find a better place for this - this.subs.push(deleteEventService.stream.subscribe((e) => this.handleDeleteEvent(e))); - processManager.registerProcess(this.process); } @@ -118,14 +113,6 @@ export default class ChunkedRequest { return this.events.addEvent(event); } - private handleDeleteEvent(deleteEvent: NostrEvent) { - const cord = deleteEvent.tags.find(isATag)?.[1]; - const eventId = deleteEvent.tags.find(isETag)?.[1]; - - if (cord) this.events.deleteEvent(cord); - if (eventId) this.events.deleteEvent(eventId); - } - getFirstEvent(nth = 0, eventFilter?: EventFilter) { return this.events.getFirstEvent(nth, eventFilter); } diff --git a/src/classes/deferred.ts b/src/classes/deferred.ts deleted file mode 100644 index eaa94e740..000000000 --- a/src/classes/deferred.ts +++ /dev/null @@ -1,21 +0,0 @@ -export type Deferred = Promise & { - resolve: (value?: T | PromiseLike) => void; - reject: (reason?: any) => void; -}; - -export default function createDefer() { - let _resolve: (value?: T | PromiseLike) => void; - let _reject: (reason?: any) => void; - const promise = new Promise((resolve, reject) => { - // @ts-ignore - _resolve = resolve; - _reject = reject; - }) as Deferred; - - // @ts-ignore - promise.resolve = _resolve; - // @ts-ignore - promise.reject = _reject; - - return promise; -} diff --git a/src/classes/event-store.ts b/src/classes/event-store.ts index b87def182..e628529d8 100644 --- a/src/classes/event-store.ts +++ b/src/classes/event-store.ts @@ -4,7 +4,6 @@ import { nanoid } from "nanoid"; import { getEventUID, sortByDate } from "../helpers/nostr/event"; import ControlledObservable from "./controlled-observable"; import SuperMap from "./super-map"; -import deleteEventService from "../services/delete-events"; export type EventFilter = (event: NostrEvent) => boolean; @@ -19,17 +18,9 @@ export default class EventStore { customSort?: typeof sortByDate; - private deleteSub: ZenObservable.Subscription; - constructor(name?: string, customSort?: typeof sortByDate) { this.name = name; this.customSort = customSort; - - this.deleteSub = deleteEventService.stream.subscribe((event) => { - const uid = getEventUID(event); - this.deleteEvent(uid); - if (uid !== event.id) this.deleteEvent(event.id); - }); } getSortedEvents() { @@ -89,7 +80,6 @@ export default class EventStore { for (const sub of subs) sub.unsubscribe(); } this.storeSubs.clear(); - this.deleteSub.unsubscribe(); } getFirstEvent(nth = 0, filter?: EventFilter) { diff --git a/src/classes/local-settings/types.ts b/src/classes/local-settings/types.ts index 8d6aa3556..af3e9b456 100644 --- a/src/classes/local-settings/types.ts +++ b/src/classes/local-settings/types.ts @@ -1,3 +1,4 @@ +import { safeParse } from "applesauce-core/helpers"; import { LocalStorageEntry, NullableLocalStorageEntry } from "./entry"; export class NumberLocalStorageEntry extends LocalStorageEntry { @@ -32,3 +33,18 @@ export class BooleanLocalStorageEntry extends LocalStorageEntry { ); } } + +export class ArrayLocalStorageEntry extends LocalStorageEntry { + constructor(key: string, fallback: T[]) { + super( + key, + fallback, + (raw) => { + const value = safeParse(raw); + if (value && Array.isArray(value)) return value; + else return [] as T[]; + }, + (value) => JSON.stringify(value), + ); + } +} diff --git a/src/components/debug-modal/pages/relays.tsx b/src/components/debug-modal/pages/relays.tsx index 3d91bdfa3..64af9b2e7 100644 --- a/src/components/debug-modal/pages/relays.tsx +++ b/src/components/debug-modal/pages/relays.tsx @@ -4,7 +4,7 @@ import { Button, Text } from "@chakra-ui/react"; import { getSeenRelays } from "applesauce-core/helpers"; import { usePublishEvent } from "../../../providers/global/publish-provider"; -import { RelayFavicon } from "../../relay-favicon"; +import RelayFavicon from "../../relay-favicon"; export default function DebugEventRelaysPage({ event }: { event: NostrEvent }) { const publish = usePublishEvent(); diff --git a/src/components/layout/nav-items/account-switcher.tsx b/src/components/layout/components/account-switcher.tsx similarity index 100% rename from src/components/layout/nav-items/account-switcher.tsx rename to src/components/layout/components/account-switcher.tsx diff --git a/src/components/layout/components/connections-button.tsx b/src/components/layout/components/connections-button.tsx new file mode 100644 index 000000000..be60a3097 --- /dev/null +++ b/src/components/layout/components/connections-button.tsx @@ -0,0 +1,18 @@ +import { Button, ButtonProps } from "@chakra-ui/react"; +import { useObservable } from "applesauce-react/hooks"; + +import { useTaskManagerContext } from "../../../views/task-manager/provider"; +import { connections$ } from "../../../services/rx-nostr"; + +export default function RelayConnectionButton({ ...props }: Omit) { + const { openTaskManager } = useTaskManagerContext(); + + const connections = useObservable(connections$); + const connected = Object.values(connections).reduce((t, s) => (s === "connected" ? t + 1 : t), 0); + + return ( + + ); +} diff --git a/src/components/layout/nav-items/index.tsx b/src/components/layout/components/index.tsx similarity index 97% rename from src/components/layout/nav-items/index.tsx rename to src/components/layout/components/index.tsx index bd4ac9ae8..c97a0e6a6 100644 --- a/src/components/layout/nav-items/index.tsx +++ b/src/components/layout/components/index.tsx @@ -2,13 +2,13 @@ import { useMemo } from "react"; import { Divider, Spacer } from "@chakra-ui/react"; import { useActiveAccount } from "applesauce-react/hooks"; import { ReadonlyAccount } from "applesauce-accounts/accounts"; +import { QuestionIcon } from "@chakra-ui/icons"; import { LightningIcon, SettingsIcon } from "../../icons"; import Package from "../../icons/package"; import useRecentIds from "../../../hooks/use-recent-ids"; import { defaultFavoriteApps, internalApps, internalTools } from "../../navigation/apps"; import NavItem from "./nav-item"; -import { QuestionIcon } from "@chakra-ui/icons"; import Plus from "../../icons/plus"; import useFavoriteInternalIds from "../../../hooks/use-favorite-internal-ids"; @@ -51,7 +51,6 @@ export default function NavItems() { - {/* */} ); } diff --git a/src/components/layout/nav-items/nav-item.tsx b/src/components/layout/components/nav-item.tsx similarity index 100% rename from src/components/layout/nav-items/nav-item.tsx rename to src/components/layout/components/nav-item.tsx diff --git a/src/components/layout/components/publish-log-button.tsx b/src/components/layout/components/publish-log-button.tsx new file mode 100644 index 000000000..3a97078b3 --- /dev/null +++ b/src/components/layout/components/publish-log-button.tsx @@ -0,0 +1,28 @@ +import { useContext } from "react"; +import { Button, ButtonProps } from "@chakra-ui/react"; + +import { PublishContext, PublishLogEntry } from "../../../providers/global/publish-provider"; +import { useTaskManagerContext } from "../../../views/task-manager/provider"; +import { usePublishLogEntryStatus } from "../../../views/task-manager/publish-log/action-status-tag"; + +function PublishLogEntryButton({ entry, ...props }: Omit & { entry: PublishLogEntry }) { + const { openTaskManager } = useTaskManagerContext(); + + const { icon, color, successful, total } = usePublishLogEntryStatus(entry); + + return ( + + ); +} + +export default function PublishLogButton({ ...props }: Omit) { + const { log } = useContext(PublishContext); + const { openTaskManager } = useTaskManagerContext(); + + const entry = log[log.length - 1]; + if (!entry) return null; + + return openTaskManager("/publish-log")} {...props} />; +} diff --git a/src/components/layout/desktop/side-nav.tsx b/src/components/layout/desktop/side-nav.tsx index 9a8512669..7d340556b 100644 --- a/src/components/layout/desktop/side-nav.tsx +++ b/src/components/layout/desktop/side-nav.tsx @@ -1,11 +1,13 @@ import { useState } from "react"; -import { Flex, FlexProps, IconButton } from "@chakra-ui/react"; +import { ButtonGroup, Flex, FlexProps, IconButton } from "@chakra-ui/react"; import { ChevronLeftIcon, ChevronRightIcon } from "../../icons"; -import NavItems from "../nav-items"; +import NavItems from "../components"; import useRootPadding from "../../../hooks/use-root-padding"; -import AccountSwitcher from "../nav-items/account-switcher"; +import AccountSwitcher from "../components/account-switcher"; import { CollapsedContext } from "../context"; +import RelayConnectionButton from "../components/connections-button"; +import PublishLogButton from "../components/publish-log-button"; export default function DesktopSideNav({ ...props }: Omit) { const [collapsed, setCollapsed] = useState(false); @@ -36,14 +38,20 @@ export default function DesktopSideNav({ ...props }: Omit > - setCollapsed(!collapsed)} - icon={collapsed ? : } - /> + + setCollapsed(!collapsed)} + icon={collapsed ? : } + /> + {!collapsed && ( + <> + + + + )} + ); diff --git a/src/components/layout/mobile/index.tsx b/src/components/layout/mobile/index.tsx index c7a4ebf7a..e8d21470a 100644 --- a/src/components/layout/mobile/index.tsx +++ b/src/components/layout/mobile/index.tsx @@ -2,13 +2,17 @@ import { Outlet } from "react-router-dom"; import MobileBottomNav from "./bottom-nav"; import { ErrorBoundary } from "../../error-boundary"; +import { Suspense } from "react"; +import { Spinner } from "@chakra-ui/react"; export default function MobileLayout() { return ( <> - - - + }> + + + + ); diff --git a/src/components/layout/mobile/nav-drawer.tsx b/src/components/layout/mobile/nav-drawer.tsx index 4953290b4..d81a110ce 100644 --- a/src/components/layout/mobile/nav-drawer.tsx +++ b/src/components/layout/mobile/nav-drawer.tsx @@ -1,19 +1,47 @@ -import { Avatar, Drawer, DrawerBody, DrawerContent, DrawerOverlay, DrawerProps, Flex, Text } from "@chakra-ui/react"; +import { + Avatar, + ButtonGroup, + Drawer, + DrawerBody, + DrawerContent, + DrawerOverlay, + DrawerProps, + Flex, + Text, +} from "@chakra-ui/react"; import { useActiveAccount } from "applesauce-react/hooks"; -import AccountSwitcher from "../nav-items/account-switcher"; -import NavItems from "../nav-items"; +import AccountSwitcher from "../components/account-switcher"; +import NavItems from "../components"; import { CollapsedContext } from "../context"; +import RelayConnectionButton from "../components/connections-button"; +import PublishLogButton from "../components/publish-log-button"; +import { MouseEventHandler } from "react"; -export default function NavDrawer({ ...props }: Omit) { +export default function NavDrawer({ onClose, ...props }: Omit) { const account = useActiveAccount(); + const handleClickItem: MouseEventHandler = (e) => { + if (e.target instanceof HTMLAnchorElement || e.target instanceof HTMLButtonElement) { + onClose(); + } + }; + return ( - + - + {!account && ( @@ -22,6 +50,10 @@ export default function NavDrawer({ ...props }: Omit) { )} + + + + diff --git a/src/components/legacy-layout/ghost/timeline.tsx b/src/components/legacy-layout/ghost/timeline.tsx deleted file mode 100644 index 61bfdfb49..000000000 --- a/src/components/legacy-layout/ghost/timeline.tsx +++ /dev/null @@ -1,113 +0,0 @@ -import { Code, Flex, FlexProps, LinkBox, Text } from "@chakra-ui/react"; -import { NostrEvent, kinds, nip19, nip25 } from "nostr-tools"; -import { Link as RouterLink } from "react-router-dom"; -import { useActiveAccount } from "applesauce-react/hooks"; - -import { useReadRelays } from "../../../hooks/use-client-relays"; -import useTimelineLoader from "../../../hooks/use-timeline-loader"; -import TimelineActionAndStatus from "../../timeline/timeline-action-and-status"; -import IntersectionObserverProvider from "../../../providers/local/intersection-observer"; -import Timestamp from "../../timestamp"; -import { useTimelineCurserIntersectionCallback } from "../../../hooks/use-timeline-cursor-intersection-callback"; -import { getDMRecipient, getDMSender } from "../../../helpers/nostr/dms"; -import UserName from "../../user/user-name"; -import HoverLinkOverlay from "../../hover-link-overlay"; -import useEventIntersectionRef from "../../../hooks/use-event-intersection-ref"; -import { getSharableEventAddress } from "../../../services/relay-hints"; - -const kindColors: Record = { - [kinds.ShortTextNote]: "blue.500", - [kinds.EncryptedDirectMessage]: "orange.500", - [kinds.Repost]: "yellow.500", - [kinds.GenericRepost]: "yellow.500", - [kinds.Reaction]: "green.500", - [kinds.LongFormArticle]: "purple.500", -}; - -function KindTag({ event }: { event: NostrEvent }) { - return ( - - {event.kind} - - ); -} - -function TimelineItem({ event }: { event: NostrEvent }) { - const ref = useEventIntersectionRef(event); - - const renderContent = () => { - switch (event.kind) { - case kinds.EncryptedDirectMessage: { - const sender = getDMSender(event); - const recipient = getDMRecipient(event); - return ( - - messaged - - ); - } - case kinds.Contacts: { - return ( - - Updated contacts - - ); - } - case kinds.Reaction: { - const pointer = nip25.getReactedEventPointer(event); - return ( - - {event.content} - - ); - } - default: { - return ( - - {event.content} - - ); - } - } - }; - - return ( - - - {renderContent()} - - - ); -} - -export default function GhostTimeline({ ...props }: Omit) { - const account = useActiveAccount()!; - const readRelays = useReadRelays(); - - const { loader, timeline: events } = useTimelineLoader(`${account.pubkey}-ghost`, readRelays, { - authors: [account.pubkey], - }); - - const callback = useTimelineCurserIntersectionCallback(loader); - - return ( - - - {events?.map((event) => )} - - - - ); -} diff --git a/src/components/legacy-layout/task-manager-buttons.tsx b/src/components/legacy-layout/task-manager-buttons.tsx deleted file mode 100644 index ac2450718..000000000 --- a/src/components/legacy-layout/task-manager-buttons.tsx +++ /dev/null @@ -1,46 +0,0 @@ -import { useContext } from "react"; -import { Button, Flex, FlexProps } from "@chakra-ui/react"; - -import { PublishContext } from "../../providers/global/publish-provider"; -import { useTaskManagerContext } from "../../views/task-manager/provider"; -import PublishActionStatusTag from "../../views/task-manager/publish-log/action-status-tag"; -import PasscodeLock from "../icons/passcode-lock"; -import relayPoolService from "../../services/relay-pool"; - -export default function TaskManagerButtons({ ...props }: Omit) { - const { log } = useContext(PublishContext); - const { openTaskManager } = useTaskManagerContext(); - - const pendingAuth = Array.from(relayPoolService.challenges.entries()).filter( - ([r, c]) => r.connected && !!c.value && !relayPoolService.authenticated.get(r).value, - ); - - return ( - - - {pendingAuth.length > 0 && ( - - )} - - ); -} diff --git a/src/components/loading-nostr-link.tsx b/src/components/loading-nostr-link.tsx index 199359ae8..f99ae9ae9 100644 --- a/src/components/loading-nostr-link.tsx +++ b/src/components/loading-nostr-link.tsx @@ -26,7 +26,7 @@ import UserLink from "./user/user-link"; import relayPoolService from "../services/relay-pool"; import { isValidRelayURL } from "../helpers/relay"; import relayScoreboardService from "../services/relay-scoreboard"; -import { RelayFavicon } from "./relay-favicon"; +import RelayFavicon from "./relay-favicon"; import singleEventLoader from "../services/single-event-loader"; import replaceableEventLoader from "../services/replaceable-loader"; import { AppHandlerContext } from "../providers/route/app-handler-provider"; diff --git a/src/components/relay-favicon.tsx b/src/components/relay-favicon.tsx index 95aeb4450..0236a43cd 100644 --- a/src/components/relay-favicon.tsx +++ b/src/components/relay-favicon.tsx @@ -3,12 +3,16 @@ import { Avatar, AvatarProps } from "@chakra-ui/react"; import { RelayIcon } from "./icons"; import { useRelayInfo } from "../hooks/use-relay-info"; +import useRelayConnectionState from "../hooks/use-relay-connection-state"; +import { getConnectionStateColor } from "../helpers/relay"; export type RelayFaviconProps = Omit & { relay: string; }; -export const RelayFavicon = React.memo(({ relay, ...props }: RelayFaviconProps) => { +const RelayFavicon = React.memo(({ relay, showStatus, ...props }: RelayFaviconProps & { showStatus?: boolean }) => { const { info } = useRelayInfo(relay); + const state = useRelayConnectionState(relay); + const color = getConnectionStateColor(state); const url = useMemo(() => { if (info?.icon) return info.icon; @@ -19,6 +23,18 @@ export const RelayFavicon = React.memo(({ relay, ...props }: RelayFaviconProps) return url.toString(); }, [relay, info]); - return } overflow="hidden" {...props} />; + return ( + } + overflow="hidden" + colorScheme={color} + outline={showStatus ? "2px solid" : "none"} + outlineColor={showStatus ? color + ".500" : undefined} + {...props} + /> + ); }); RelayFavicon.displayName = "RelayFavicon"; + +export default RelayFavicon; diff --git a/src/components/relay-icon-stack.tsx b/src/components/relay-icon-stack.tsx index c9d72f324..505092361 100644 --- a/src/components/relay-icon-stack.tsx +++ b/src/components/relay-icon-stack.tsx @@ -14,7 +14,7 @@ import { } from "@chakra-ui/react"; import { Link as RouterLink } from "react-router-dom"; -import { RelayFavicon } from "./relay-favicon"; +import RelayFavicon from "./relay-favicon"; import relayScoreboardService from "../services/relay-scoreboard"; export type RelayIconStackProps = { relays: string[]; maxRelays?: number } & Omit; diff --git a/src/components/relay-management-drawer/index.tsx b/src/components/relay-management-drawer/index.tsx deleted file mode 100644 index ba769c56b..000000000 --- a/src/components/relay-management-drawer/index.tsx +++ /dev/null @@ -1,180 +0,0 @@ -import { useMemo, useState } from "react"; -import { - Button, - Drawer, - DrawerBody, - DrawerCloseButton, - DrawerContent, - DrawerHeader, - DrawerOverlay, - DrawerProps, - Flex, - IconButton, - Link, - Select, - useDisclosure, -} from "@chakra-ui/react"; -import { CloseIcon } from "@chakra-ui/icons"; -import { Link as RouterLink } from "react-router-dom"; -import { useActiveAccount, useObservable } from "applesauce-react/hooks"; -import { NostrEvent } from "nostr-tools"; - -import { useReadRelays, useWriteRelays } from "../../hooks/use-client-relays"; -import relayPoolService from "../../services/relay-pool"; -import clientRelaysService from "../../services/client-relays"; -import { RelayMode } from "../../classes/relay"; -import RelaySet from "../../classes/relay-set"; -import UploadCloud01 from "../icons/upload-cloud-01"; -import { RelayFavicon } from "../relay-favicon"; -import useUserRelaySets from "../../hooks/use-user-relay-sets"; -import { getListName } from "../../helpers/nostr/lists"; -import { getEventCoordinate } from "../../helpers/nostr/event"; -import AddRelayForm from "../../views/relays/app/add-relay-form"; -import { SaveRelaySetForm } from "./save-relay-set-form"; - -function RelayControl({ url }: { url: string }) { - const relay = useMemo(() => relayPoolService.requestRelay(url, false), [url]); - const writeRelays = useObservable(clientRelaysService.writeRelays); - - const color = relay.connected ? "green" : "red"; - - const onChange = () => { - if (writeRelays.has(url)) clientRelaysService.removeRelay(url, RelayMode.WRITE); - else clientRelaysService.addRelay(url, RelayMode.WRITE); - }; - - return ( - - - - {url} - - } - size="sm" - variant={writeRelays.has(url) ? "solid" : "ghost"} - colorScheme={writeRelays.has(url) ? "green" : "gray"} - onClick={onChange} - title="Toggle Write" - /> - } - size="sm" - colorScheme="red" - onClick={() => clientRelaysService.removeRelay(url, RelayMode.ALL)} - /> - - ); -} - -function SelectRelaySet({ - value, - onChange, - relaySets, -}: { - relaySets: NostrEvent[]; - value?: string; - onChange: (cord: string) => void; -}) { - return ( - - ); -} - -export default function RelayManagementDrawer({ isOpen, onClose, ...props }: Omit) { - const account = useActiveAccount(); - const readRelays = useReadRelays(); - const writeRelays = useWriteRelays(); - - const sorted = useMemo(() => RelaySet.from(readRelays, writeRelays).urls.sort(), [readRelays, writeRelays]); - const others = Array.from(relayPoolService.relays.values()) - .filter((r) => !r.connected && !sorted.includes(r.url)) - .map((r) => r.url) - .sort(); - - const save = useDisclosure(); - const [selected, setSelected] = useState(); - const relaySets = useUserRelaySets(account?.pubkey) ?? []; - - const changeSet = (cord: string) => { - setSelected(cord); - - const set = relaySets.find((s) => getEventCoordinate(s) === cord); - if (set) { - clientRelaysService.setRelaysFromRelaySet(set); - } - }; - - const renderContent = () => { - if (save.isOpen) { - return ( - <> - getEventCoordinate(s) === selected)} - onCancel={save.onClose} - onSaved={(set) => { - save.onClose(); - setSelected(getEventCoordinate(set)); - }} - writeRelays={clientRelaysService.writeRelays.value} - readRelays={clientRelaysService.readRelays.value} - /> - - ); - } - return ( - <> - - - - - {sorted.map((url) => ( - - ))} - { - clientRelaysService.addRelay(url, RelayMode.ALL); - setSelected(undefined); - }} - /> - {/* Other Relays - {others.map((url) => ( - - ))} */} - - ); - }; - - return ( - - - - - - Relays - - - - {renderContent()} - - - - ); -} diff --git a/src/components/relay-management-drawer/save-relay-set-form.tsx b/src/components/relay-management-drawer/save-relay-set-form.tsx deleted file mode 100644 index 09b68cfd8..000000000 --- a/src/components/relay-management-drawer/save-relay-set-form.tsx +++ /dev/null @@ -1,65 +0,0 @@ -import { Button, Flex, FormControl, FormLabel, Input, Textarea } from "@chakra-ui/react"; -import { NostrEvent, kinds } from "nostr-tools"; -import { useForm } from "react-hook-form"; - -import { getListDescription, getListName, setListDescription, setListName } from "../../helpers/nostr/lists"; -import { isRTag } from "../../types/nostr-event"; -import { cloneEvent, ensureDTag } from "../../helpers/nostr/event"; -import { createRTagsFromRelaySets } from "../../helpers/nostr/mailbox"; -import { usePublishEvent } from "../../providers/global/publish-provider"; - -export function SaveRelaySetForm({ - relaySet, - onCancel, - onSaved, - writeRelays, - readRelays, -}: { - relaySet?: NostrEvent; - onCancel: () => void; - onSaved?: (event: NostrEvent) => void; - writeRelays: Iterable; - readRelays: Iterable; -}) { - const publish = usePublishEvent(); - const { register, formState, handleSubmit } = useForm({ - defaultValues: { - name: relaySet ? (getListName(relaySet) ?? "") : "", - description: relaySet ? (getListDescription(relaySet) ?? "") : "", - }, - mode: "all", - resetOptions: { keepDirtyValues: true }, - }); - - const submit = handleSubmit(async (values) => { - const draft = cloneEvent(kinds.Relaysets, relaySet); - ensureDTag(draft); - setListName(draft, values.name); - setListDescription(draft, values.description); - - draft.tags = draft.tags.filter((t) => !isRTag(t)); - draft.tags.push(...createRTagsFromRelaySets(readRelays, writeRelays)); - - const pub = await publish("Save Relay Set", draft); - if (pub && onSaved) onSaved(pub.event); - }); - - return ( - - - Name - - - - Description -