diff --git a/package.json b/package.json index b340d8b0..ce21269f 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ "dependencies": { "@headlessui/react": "^1.7.15", "@nostr-dev-kit/ndk": "^0.7.5", + "@nostr-fetch/adapter-ndk": "^0.11.0", "@radix-ui/react-popover": "^1.0.6", "@radix-ui/react-tooltip": "^1.0.6", "@tanstack/react-query": "^4.29.19", @@ -31,6 +32,7 @@ "get-urls": "^11.0.0", "immer": "^10.0.2", "light-bolt11-decoder": "^3.0.0", + "nostr-fetch": "^0.11.0", "nostr-tools": "^1.12.1", "react": "^18.2.0", "react-dom": "^18.2.0", @@ -57,8 +59,8 @@ "@types/react": "^18.2.14", "@types/react-dom": "^18.2.6", "@types/youtube-player": "^5.5.7", - "@typescript-eslint/eslint-plugin": "^5.61.0", - "@typescript-eslint/parser": "^5.61.0", + "@typescript-eslint/eslint-plugin": "^5.62.0", + "@typescript-eslint/parser": "^5.62.0", "@vitejs/plugin-react-swc": "^3.3.2", "autoprefixer": "^10.4.14", "cross-env": "^7.0.3", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 815d383e..6a2b61fb 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -7,6 +7,9 @@ dependencies: '@nostr-dev-kit/ndk': specifier: ^0.7.5 version: 0.7.5(typescript@4.9.5) + '@nostr-fetch/adapter-ndk': + specifier: ^0.11.0 + version: 0.11.0(@nostr-dev-kit/ndk@0.7.5)(nostr-fetch@0.11.0) '@radix-ui/react-popover': specifier: ^1.0.6 version: 1.0.6(@types/react-dom@18.2.6)(@types/react@18.2.14)(react-dom@18.2.0)(react@18.2.0) @@ -46,6 +49,9 @@ dependencies: light-bolt11-decoder: specifier: ^3.0.0 version: 3.0.0 + nostr-fetch: + specifier: ^0.11.0 + version: 0.11.0 nostr-tools: specifier: ^1.12.1 version: 1.12.1 @@ -121,11 +127,11 @@ devDependencies: specifier: ^5.5.7 version: 5.5.7 '@typescript-eslint/eslint-plugin': - specifier: ^5.61.0 - version: 5.61.0(@typescript-eslint/parser@5.61.0)(eslint@8.44.0)(typescript@4.9.5) + specifier: ^5.62.0 + version: 5.62.0(@typescript-eslint/parser@5.62.0)(eslint@8.44.0)(typescript@4.9.5) '@typescript-eslint/parser': - specifier: ^5.61.0 - version: 5.61.0(eslint@8.44.0)(typescript@4.9.5) + specifier: ^5.62.0 + version: 5.62.0(eslint@8.44.0)(typescript@4.9.5) '@vitejs/plugin-react-swc': specifier: ^3.3.2 version: 3.3.2(vite@4.4.2) @@ -882,6 +888,10 @@ packages: engines: {node: '>= 16'} dev: false + /@noble/secp256k1@1.7.1: + resolution: {integrity: sha512-hOUk6AyBFmqVrv7k5WAw/LpszxVbj9gGN4JRkIX52fdFAj1UA61KXmZDvqVEm+pOyec3+fIeZB02LYa/pWOArw==} + dev: false + /@noble/secp256k1@2.0.0: resolution: {integrity: sha512-rUGBd95e2a45rlmFTqQJYEFA4/gdIARFfuTuTqLglz0PZ6AKyzyXsEZZq7UZn8hZsvaBgpCzKKBJizT2cJERXw==} dev: false @@ -910,14 +920,14 @@ packages: '@noble/hashes': 1.3.1 '@noble/secp256k1': 2.0.0 '@scure/base': 1.1.1 - '@typescript-eslint/eslint-plugin': 5.61.0(@typescript-eslint/parser@5.61.0)(eslint@8.44.0)(typescript@4.9.5) - '@typescript-eslint/parser': 5.61.0(eslint@8.44.0)(typescript@4.9.5) + '@typescript-eslint/eslint-plugin': 5.62.0(@typescript-eslint/parser@5.62.0)(eslint@8.44.0)(typescript@4.9.5) + '@typescript-eslint/parser': 5.62.0(eslint@8.44.0)(typescript@4.9.5) debug: 4.3.4 esbuild: 0.17.19 esbuild-plugin-alias: 0.2.1 eslint: 8.44.0 eslint-config-prettier: 8.8.0(eslint@8.44.0) - eslint-plugin-import: 2.27.5(@typescript-eslint/parser@5.61.0)(eslint@8.44.0) + eslint-plugin-import: 2.27.5(@typescript-eslint/parser@5.62.0)(eslint@8.44.0) esm-loader-typescript: 1.0.5 eventemitter3: 5.0.1 light-bolt11-decoder: 3.0.0 @@ -933,6 +943,24 @@ packages: - typescript dev: false + /@nostr-fetch/adapter-ndk@0.11.0(@nostr-dev-kit/ndk@0.7.5)(nostr-fetch@0.11.0): + resolution: {integrity: sha512-Otl7SEzm9ecqyHB10bpYXBu1qpqJEnipp7dZ4qcA9LeJAtM38fnYKUD34HX0JXA9EDjtc6VS5UNZe544xC9GCg==} + peerDependencies: + '@nostr-dev-kit/ndk': ^0.5.0 + nostr-fetch: ^0.11.0 + dependencies: + '@nostr-dev-kit/ndk': 0.7.5(typescript@4.9.5) + '@nostr-fetch/kernel': 0.11.0 + nostr-fetch: 0.11.0 + dev: false + + /@nostr-fetch/kernel@0.11.0: + resolution: {integrity: sha512-OQGAfrGckWkUmFBbE85hq/njVmFrWP21uO8XgXQ1ISS7yrD2N5zcOs1XXXRnaTwIMCv25E8s5Gsgf0AhVWtDEw==} + dependencies: + '@noble/hashes': 1.3.1 + '@noble/secp256k1': 1.7.1 + dev: false + /@npmcli/fs@3.1.0: resolution: {integrity: sha512-7kZUAaLscfgbwBQRbvdMYaZOWyMEcPTH/tJjnyAWJ/dvvs9Ef+CERx/qJb9GExJpl1qipaDGn7KqHnFGGixd0w==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} @@ -1793,8 +1821,8 @@ packages: resolution: {integrity: sha512-W8F4eoTIvzXeNrT3JroQPimZLXnlJA8smYygHZUKFPVoYwgs/OhJkA1VBhL3iSs57OQkuINqHlY4SmMT5wtnJg==} dev: true - /@typescript-eslint/eslint-plugin@5.61.0(@typescript-eslint/parser@5.61.0)(eslint@8.44.0)(typescript@4.9.5): - resolution: {integrity: sha512-A5l/eUAug103qtkwccSCxn8ZRwT+7RXWkFECdA4Cvl1dOlDUgTpAOfSEElZn2uSUxhdDpnCdetrf0jvU4qrL+g==} + /@typescript-eslint/eslint-plugin@5.62.0(@typescript-eslint/parser@5.62.0)(eslint@8.44.0)(typescript@4.9.5): + resolution: {integrity: sha512-TiZzBSJja/LbhNPvk6yc0JrX9XqhQ0hdh6M2svYfsHGejaKFIAGd9MQ+ERIMzLGlN/kZoYIgdxFV0PuljTKXag==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: '@typescript-eslint/parser': ^5.0.0 @@ -1805,10 +1833,10 @@ packages: optional: true dependencies: '@eslint-community/regexpp': 4.5.1 - '@typescript-eslint/parser': 5.61.0(eslint@8.44.0)(typescript@4.9.5) - '@typescript-eslint/scope-manager': 5.61.0 - '@typescript-eslint/type-utils': 5.61.0(eslint@8.44.0)(typescript@4.9.5) - '@typescript-eslint/utils': 5.61.0(eslint@8.44.0)(typescript@4.9.5) + '@typescript-eslint/parser': 5.62.0(eslint@8.44.0)(typescript@4.9.5) + '@typescript-eslint/scope-manager': 5.62.0 + '@typescript-eslint/type-utils': 5.62.0(eslint@8.44.0)(typescript@4.9.5) + '@typescript-eslint/utils': 5.62.0(eslint@8.44.0)(typescript@4.9.5) debug: 4.3.4 eslint: 8.44.0 graphemer: 1.4.0 @@ -1820,8 +1848,8 @@ packages: transitivePeerDependencies: - supports-color - /@typescript-eslint/parser@5.61.0(eslint@8.44.0)(typescript@4.9.5): - resolution: {integrity: sha512-yGr4Sgyh8uO6fSi9hw3jAFXNBHbCtKKFMdX2IkT3ZqpKmtAq3lHS4ixB/COFuAIJpwl9/AqF7j72ZDWYKmIfvg==} + /@typescript-eslint/parser@5.62.0(eslint@8.44.0)(typescript@4.9.5): + resolution: {integrity: sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 @@ -1830,24 +1858,24 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/scope-manager': 5.61.0 - '@typescript-eslint/types': 5.61.0 - '@typescript-eslint/typescript-estree': 5.61.0(typescript@4.9.5) + '@typescript-eslint/scope-manager': 5.62.0 + '@typescript-eslint/types': 5.62.0 + '@typescript-eslint/typescript-estree': 5.62.0(typescript@4.9.5) debug: 4.3.4 eslint: 8.44.0 typescript: 4.9.5 transitivePeerDependencies: - supports-color - /@typescript-eslint/scope-manager@5.61.0: - resolution: {integrity: sha512-W8VoMjoSg7f7nqAROEmTt6LoBpn81AegP7uKhhW5KzYlehs8VV0ZW0fIDVbcZRcaP3aPSW+JZFua+ysQN+m/Nw==} + /@typescript-eslint/scope-manager@5.62.0: + resolution: {integrity: sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dependencies: - '@typescript-eslint/types': 5.61.0 - '@typescript-eslint/visitor-keys': 5.61.0 + '@typescript-eslint/types': 5.62.0 + '@typescript-eslint/visitor-keys': 5.62.0 - /@typescript-eslint/type-utils@5.61.0(eslint@8.44.0)(typescript@4.9.5): - resolution: {integrity: sha512-kk8u//r+oVK2Aj3ph/26XdH0pbAkC2RiSjUYhKD+PExemG4XSjpGFeyZ/QM8lBOa7O8aGOU+/yEbMJgQv/DnCg==} + /@typescript-eslint/type-utils@5.62.0(eslint@8.44.0)(typescript@4.9.5): + resolution: {integrity: sha512-xsSQreu+VnfbqQpW5vnCJdq1Z3Q0U31qiWmRhr98ONQmcp/yhiPJFPq8MXiJVLiksmOKSjIldZzkebzHuCGzew==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: '*' @@ -1856,8 +1884,8 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/typescript-estree': 5.61.0(typescript@4.9.5) - '@typescript-eslint/utils': 5.61.0(eslint@8.44.0)(typescript@4.9.5) + '@typescript-eslint/typescript-estree': 5.62.0(typescript@4.9.5) + '@typescript-eslint/utils': 5.62.0(eslint@8.44.0)(typescript@4.9.5) debug: 4.3.4 eslint: 8.44.0 tsutils: 3.21.0(typescript@4.9.5) @@ -1865,12 +1893,12 @@ packages: transitivePeerDependencies: - supports-color - /@typescript-eslint/types@5.61.0: - resolution: {integrity: sha512-ldyueo58KjngXpzloHUog/h9REmHl59G1b3a5Sng1GfBo14BkS3ZbMEb3693gnP1k//97lh7bKsp6/V/0v1veQ==} + /@typescript-eslint/types@5.62.0: + resolution: {integrity: sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - /@typescript-eslint/typescript-estree@5.61.0(typescript@4.9.5): - resolution: {integrity: sha512-Fud90PxONnnLZ36oR5ClJBLTLfU4pIWBmnvGwTbEa2cXIqj70AEDEmOmpkFComjBZ/037ueKrOdHuYmSFVD7Rw==} + /@typescript-eslint/typescript-estree@5.62.0(typescript@4.9.5): + resolution: {integrity: sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: typescript: '*' @@ -1878,8 +1906,8 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/types': 5.61.0 - '@typescript-eslint/visitor-keys': 5.61.0 + '@typescript-eslint/types': 5.62.0 + '@typescript-eslint/visitor-keys': 5.62.0 debug: 4.3.4 globby: 11.1.0 is-glob: 4.0.3 @@ -1889,8 +1917,8 @@ packages: transitivePeerDependencies: - supports-color - /@typescript-eslint/utils@5.61.0(eslint@8.44.0)(typescript@4.9.5): - resolution: {integrity: sha512-mV6O+6VgQmVE6+xzlA91xifndPW9ElFW8vbSF0xCT/czPXVhwDewKila1jOyRwa9AE19zKnrr7Cg5S3pJVrTWQ==} + /@typescript-eslint/utils@5.62.0(eslint@8.44.0)(typescript@4.9.5): + resolution: {integrity: sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 @@ -1898,9 +1926,9 @@ packages: '@eslint-community/eslint-utils': 4.4.0(eslint@8.44.0) '@types/json-schema': 7.0.12 '@types/semver': 7.5.0 - '@typescript-eslint/scope-manager': 5.61.0 - '@typescript-eslint/types': 5.61.0 - '@typescript-eslint/typescript-estree': 5.61.0(typescript@4.9.5) + '@typescript-eslint/scope-manager': 5.62.0 + '@typescript-eslint/types': 5.62.0 + '@typescript-eslint/typescript-estree': 5.62.0(typescript@4.9.5) eslint: 8.44.0 eslint-scope: 5.1.1 semver: 7.5.4 @@ -1908,11 +1936,11 @@ packages: - supports-color - typescript - /@typescript-eslint/visitor-keys@5.61.0: - resolution: {integrity: sha512-50XQ5VdbWrX06mQXhy93WywSFZZGsv3EOjq+lqp6WC2t+j3mb6A9xYVdrRxafvK88vg9k9u+CT4l6D8PEatjKg==} + /@typescript-eslint/visitor-keys@5.62.0: + resolution: {integrity: sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dependencies: - '@typescript-eslint/types': 5.61.0 + '@typescript-eslint/types': 5.62.0 eslint-visitor-keys: 3.4.1 /@vitejs/plugin-react-swc@3.3.2(vite@4.4.2): @@ -2126,7 +2154,7 @@ packages: postcss: ^8.1.0 dependencies: browserslist: 4.21.9 - caniuse-lite: 1.0.30001514 + caniuse-lite: 1.0.30001515 fraction.js: 4.2.0 normalize-range: 0.1.2 picocolors: 1.0.0 @@ -2184,8 +2212,8 @@ packages: engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true dependencies: - caniuse-lite: 1.0.30001514 - electron-to-chromium: 1.4.454 + caniuse-lite: 1.0.30001515 + electron-to-chromium: 1.4.455 node-releases: 2.0.13 update-browserslist-db: 1.0.11(browserslist@4.21.9) dev: true @@ -2245,8 +2273,8 @@ packages: engines: {node: '>=6'} dev: false - /caniuse-lite@1.0.30001514: - resolution: {integrity: sha512-ENcIpYBmwAAOm/V2cXgM7rZUrKKaqisZl4ZAI520FIkqGXUxJjmaIssbRW5HVVR5tyV6ygTLIm15aU8LUmQSaQ==} + /caniuse-lite@1.0.30001515: + resolution: {integrity: sha512-eEFDwUOZbE24sb+Ecsx3+OvNETqjWIdabMy52oOkIgcUtAsQifjUG9q4U9dgTHJM2mfk4uEPxc0+xuFdJ629QA==} dev: true /chalk@2.4.2: @@ -2419,7 +2447,7 @@ packages: dependencies: nice-try: 1.0.5 path-key: 2.0.1 - semver: 5.7.1 + semver: 5.7.2 shebang-command: 1.2.0 which: 1.3.1 dev: false @@ -2625,8 +2653,8 @@ packages: /eastasianwidth@0.2.0: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} - /electron-to-chromium@1.4.454: - resolution: {integrity: sha512-pmf1rbAStw8UEQ0sr2cdJtWl48ZMuPD9Sto8HVQOq9vx9j2WgDEN6lYoaqFvqEHYOmGA9oRGn7LqWI9ta0YugQ==} + /electron-to-chromium@1.4.455: + resolution: {integrity: sha512-8tgdX0Odl24LtmLwxotpJCVjIndN559AvaOtd67u+2mo+IDsgsTF580NB+uuDCqsHw8yFg53l5+imFV9Fw3cbA==} dev: true /emoji-regex@8.0.0: @@ -2697,7 +2725,7 @@ packages: string.prototype.trimstart: 1.0.6 typed-array-length: 1.0.4 unbox-primitive: 1.0.2 - which-typed-array: 1.1.9 + which-typed-array: 1.1.10 /es-set-tostringtag@2.0.1: resolution: {integrity: sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==} @@ -2854,7 +2882,7 @@ packages: - supports-color dev: false - /eslint-module-utils@2.8.0(@typescript-eslint/parser@5.61.0)(eslint-import-resolver-node@0.3.7)(eslint@8.44.0): + /eslint-module-utils@2.8.0(@typescript-eslint/parser@5.62.0)(eslint-import-resolver-node@0.3.7)(eslint@8.44.0): resolution: {integrity: sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==} engines: {node: '>=4'} peerDependencies: @@ -2875,7 +2903,7 @@ packages: eslint-import-resolver-webpack: optional: true dependencies: - '@typescript-eslint/parser': 5.61.0(eslint@8.44.0)(typescript@4.9.5) + '@typescript-eslint/parser': 5.62.0(eslint@8.44.0)(typescript@4.9.5) debug: 3.2.7 eslint: 8.44.0 eslint-import-resolver-node: 0.3.7 @@ -2883,7 +2911,7 @@ packages: - supports-color dev: false - /eslint-plugin-import@2.27.5(@typescript-eslint/parser@5.61.0)(eslint@8.44.0): + /eslint-plugin-import@2.27.5(@typescript-eslint/parser@5.62.0)(eslint@8.44.0): resolution: {integrity: sha512-LmEt3GVofgiGuiE+ORpnvP+kAm3h6MLZJ4Q5HCyHADofsb4VzXFsRiWj3c0OFiV+3DWFh0qg3v9gcPlfc3zRow==} engines: {node: '>=4'} peerDependencies: @@ -2893,7 +2921,7 @@ packages: '@typescript-eslint/parser': optional: true dependencies: - '@typescript-eslint/parser': 5.61.0(eslint@8.44.0)(typescript@4.9.5) + '@typescript-eslint/parser': 5.62.0(eslint@8.44.0)(typescript@4.9.5) array-includes: 3.1.6 array.prototype.flat: 1.3.1 array.prototype.flatmap: 1.3.1 @@ -2901,14 +2929,14 @@ packages: doctrine: 2.1.0 eslint: 8.44.0 eslint-import-resolver-node: 0.3.7 - eslint-module-utils: 2.8.0(@typescript-eslint/parser@5.61.0)(eslint-import-resolver-node@0.3.7)(eslint@8.44.0) + eslint-module-utils: 2.8.0(@typescript-eslint/parser@5.62.0)(eslint-import-resolver-node@0.3.7)(eslint@8.44.0) has: 1.0.3 is-core-module: 2.12.1 is-glob: 4.0.3 minimatch: 3.1.2 object.values: 1.1.6 resolve: 1.22.2 - semver: 6.3.0 + semver: 6.3.1 tsconfig-paths: 3.14.2 transitivePeerDependencies: - eslint-import-resolver-typescript @@ -2938,7 +2966,7 @@ packages: minimatch: 3.1.2 object.entries: 1.1.6 object.fromentries: 2.0.6 - semver: 6.3.0 + semver: 6.3.1 dev: true /eslint-plugin-react@7.32.2(eslint@8.44.0): @@ -2961,7 +2989,7 @@ packages: object.values: 1.1.6 prop-types: 15.8.1 resolve: 2.0.0-next.4 - semver: 6.3.0 + semver: 6.3.1 string.prototype.matchall: 4.0.8 dev: true @@ -4267,7 +4295,7 @@ packages: dependencies: hosted-git-info: 2.8.9 resolve: 1.22.2 - semver: 5.7.1 + semver: 5.7.2 validate-npm-package-license: 3.0.4 dev: false @@ -4296,6 +4324,12 @@ packages: engines: {node: '>=12.20'} dev: false + /nostr-fetch@0.11.0: + resolution: {integrity: sha512-l4GNnS7y4Zc58ROF43uiMPvPVVB8x/hAFqzJpEEqO0IQFQNZ90t6jQIzqPQfy8tFdaPN/n89uaY7KZbNQ7HJsQ==} + dependencies: + '@nostr-fetch/kernel': 0.11.0 + dev: false + /nostr-tools@1.12.1: resolution: {integrity: sha512-ZeoV7g3jBUAlb4mKa3C+6hrc84htPkbebMShfGNgV4vAiz18e/sQukUBFL6vb/+sxZy+dBQFkRwsJIaVFs8Gfw==} dependencies: @@ -5101,13 +5135,13 @@ packages: compute-scroll-into-view: 1.0.20 dev: false - /semver@5.7.1: - resolution: {integrity: sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==} + /semver@5.7.2: + resolution: {integrity: sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==} hasBin: true dev: false - /semver@6.3.0: - resolution: {integrity: sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==} + /semver@6.3.1: + resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} hasBin: true /semver@7.5.4: @@ -5882,8 +5916,8 @@ packages: is-string: 1.0.7 is-symbol: 1.0.4 - /which-typed-array@1.1.9: - resolution: {integrity: sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==} + /which-typed-array@1.1.10: + resolution: {integrity: sha512-uxoA5vLUfRPdjCuJ1h5LlYdmTLbYfums398v3WLkM+i/Wltl2/XyZpQWKbN++ck5L64SR/grOHqtXCUKmlZPNA==} engines: {node: '>= 0.4'} dependencies: available-typed-arrays: 1.0.5 diff --git a/src/app/root.tsx b/src/app/root.tsx index 5d0ba5d2..81aab4f6 100644 --- a/src/app/root.tsx +++ b/src/app/root.tsx @@ -1,53 +1,67 @@ -import { NDKFilter } from '@nostr-dev-kit/ndk'; -import { useEffect, useRef } from 'react'; +import { NDKUser } from '@nostr-dev-kit/ndk'; +import { nip19 } from 'nostr-tools'; +import { useEffect } from 'react'; import { useNavigate } from 'react-router-dom'; import { useNDK } from '@libs/ndk/provider'; -import { prefetchEvents } from '@libs/ndk/utils'; import { countTotalNotes, createChat, createNote, getLastLogin, + updateAccount, updateLastLogin, } from '@libs/storage'; import { LoaderIcon, LumeIcon } from '@shared/icons'; -import { dateToUnix, getHourAgo } from '@utils/date'; +import { nHoursAgo } from '@utils/date'; import { useAccount } from '@utils/hooks/useAccount'; const totalNotes = await countTotalNotes(); const lastLogin = await getLastLogin(); export function Root() { - const now = useRef(new Date()); const navigate = useNavigate(); - const { ndk } = useNDK(); + const { ndk, relayUrls, fetcher } = useNDK(); const { status, account } = useAccount(); + async function getFollows() { + const authors: string[] = []; + + const user = ndk.getUser({ hexpubkey: account.pubkey }); + const follows = await user.follows(); + + follows.forEach((follow: NDKUser) => { + authors.push(nip19.decode(follow.npub).data as string); + }); + + // update follows in db + await updateAccount('follows', authors, account.pubkey); + + return authors; + } + async function fetchNotes() { try { - const follows = JSON.parse(account.follows); + const follows = await getFollows(); if (follows.length > 0) { let since: number; - if (totalNotes === 0 || lastLogin === 0) { - since = dateToUnix(getHourAgo(48, now.current)); + since = nHoursAgo(48); } else { since = lastLogin; } - const filter: NDKFilter = { - kinds: [1, 6], - authors: follows, - since: since, - }; - - const events = await prefetchEvents(ndk, filter); - for (const event of events) { + const events = fetcher.allEventsIterator( + relayUrls, + { kinds: [1], authors: follows }, + { since: since }, + { skipVerification: true } + ); + for await (const event of events) { await createNote( event.id, event.pubkey, @@ -67,20 +81,23 @@ export function Root() { async function fetchChats() { try { - const sendFilter: NDKFilter = { - kinds: [4], - authors: [account.pubkey], - since: lastLogin, - }; + const sendMessages = await fetcher.fetchAllEvents( + relayUrls, + { + kinds: [4], + authors: [account.pubkey], + }, + { since: lastLogin } + ); - const receiveFilter: NDKFilter = { - kinds: [4], - '#p': [account.pubkey], - since: lastLogin, - }; - - const sendMessages = await prefetchEvents(ndk, sendFilter); - const receiveMessages = await prefetchEvents(ndk, receiveFilter); + const receiveMessages = await fetcher.fetchAllEvents( + relayUrls, + { + kinds: [4], + '#p': [account.pubkey], + }, + { since: lastLogin } + ); const events = [...sendMessages, ...receiveMessages]; for (const event of events) { diff --git a/src/app/user/components/feed.tsx b/src/app/user/components/feed.tsx index 5778834a..0132aac2 100644 --- a/src/app/user/components/feed.tsx +++ b/src/app/user/components/feed.tsx @@ -1,24 +1,22 @@ -import { NDKFilter } from '@nostr-dev-kit/ndk'; import { useQuery } from '@tanstack/react-query'; import { useNDK } from '@libs/ndk/provider'; import { Note } from '@shared/notes/note'; -import { dateToUnix, getHourAgo } from '@utils/date'; +import { nHoursAgo } from '@utils/date'; import { LumeEvent } from '@utils/types'; export function UserFeed({ pubkey }: { pubkey: string }) { - const { ndk } = useNDK(); + const { fetcher, relayUrls } = useNDK(); const { status, data } = useQuery(['user-feed', pubkey], async () => { - const now = new Date(); - const filter: NDKFilter = { - kinds: [1], - authors: [pubkey], - since: dateToUnix(getHourAgo(48, now)), - }; - const events = await ndk.fetchEvents(filter); - return [...events]; + const events = await fetcher.fetchAllEvents( + relayUrls, + { kinds: [1], authors: [pubkey] }, + { since: nHoursAgo(48) }, + { sort: true } + ); + return events as unknown as LumeEvent[]; }); return ( diff --git a/src/libs/ndk/instance.ts b/src/libs/ndk/instance.ts index cbd3ecb5..c66f3e12 100644 --- a/src/libs/ndk/instance.ts +++ b/src/libs/ndk/instance.ts @@ -1,15 +1,18 @@ // source: https://github.com/nostr-dev-kit/ndk-react/ import NDK from '@nostr-dev-kit/ndk'; +import { ndkAdapter } from '@nostr-fetch/adapter-ndk'; +import { NostrFetcher, normalizeRelayUrls } from 'nostr-fetch'; import { useEffect, useState } from 'react'; import { getSetting } from '@libs/storage'; const setting = await getSetting('relays'); -const relays = JSON.parse(setting); +const relays = normalizeRelayUrls(JSON.parse(setting)); export const NDKInstance = () => { const [ndk, setNDK] = useState(undefined); const [relayUrls, setRelayUrls] = useState(relays); + const [fetcher, setFetcher] = useState(undefined); useEffect(() => { loadNdk(relays); @@ -26,11 +29,13 @@ export const NDKInstance = () => { setNDK(ndkInstance); setRelayUrls(explicitRelayUrls); + setFetcher(NostrFetcher.withCustomPool(ndkAdapter(ndkInstance))); } return { ndk, relayUrls, + fetcher, loadNdk, }; }; diff --git a/src/libs/ndk/provider.tsx b/src/libs/ndk/provider.tsx index bb74bd49..6ebef78f 100644 --- a/src/libs/ndk/provider.tsx +++ b/src/libs/ndk/provider.tsx @@ -1,5 +1,6 @@ // source: https://github.com/nostr-dev-kit/ndk-react/ import NDK from '@nostr-dev-kit/ndk'; +import { NostrFetcher } from 'nostr-fetch'; import { PropsWithChildren, createContext, useContext } from 'react'; import { NDKInstance } from '@libs/ndk/instance'; @@ -7,17 +8,19 @@ import { NDKInstance } from '@libs/ndk/instance'; interface NDKContext { ndk: NDK; relayUrls: string[]; + fetcher: NostrFetcher; loadNdk: (_: string[]) => void; } const NDKContext = createContext({ ndk: new NDK({}), relayUrls: [], + fetcher: undefined, loadNdk: undefined, }); const NDKProvider = ({ children }: PropsWithChildren) => { - const { ndk, relayUrls, loadNdk } = NDKInstance(); + const { ndk, relayUrls, fetcher, loadNdk } = NDKInstance(); if (ndk) return ( @@ -25,6 +28,7 @@ const NDKProvider = ({ children }: PropsWithChildren) => { value={{ ndk, relayUrls, + fetcher, loadNdk, }} > diff --git a/src/libs/ndk/utils.tsx b/src/libs/ndk/utils.tsx deleted file mode 100644 index 78beb34f..00000000 --- a/src/libs/ndk/utils.tsx +++ /dev/null @@ -1,23 +0,0 @@ -import NDK, { NDKEvent, NDKFilter } from '@nostr-dev-kit/ndk'; - -export async function prefetchEvents( - ndk: NDK, - filter: NDKFilter -): Promise> { - return new Promise((resolve) => { - const events: Map = new Map(); - - const relaySetSubscription = ndk.subscribe(filter, { - closeOnEose: true, - }); - - relaySetSubscription.on('event', (event: NDKEvent) => { - event.ndk = ndk; - events.set(event.tagId(), event); - }); - - relaySetSubscription.on('eose', () => { - setTimeout(() => resolve(new Set(events.values())), 3000); - }); - }); -} diff --git a/src/libs/storage.tsx b/src/libs/storage.tsx index 00e69c1c..6071619c 100644 --- a/src/libs/storage.tsx +++ b/src/libs/storage.tsx @@ -440,7 +440,9 @@ export async function createMetadata(id: string, pubkey: string, content: string // get metadata export async function getUserMetadata(pubkey: string) { const db = await connect(); - const result = await db.select(`SELECT content FROM metadata WHERE id = "${pubkey}";`); + const result = await db.select( + `SELECT content, created_at FROM metadata WHERE id = "${pubkey}";` + ); if (result[0]) { return JSON.parse(result[0].content); } else { diff --git a/src/shared/notification/modal.tsx b/src/shared/notification/modal.tsx index 0ddebff9..2ff02db3 100644 --- a/src/shared/notification/modal.tsx +++ b/src/shared/notification/modal.tsx @@ -1,7 +1,7 @@ import { Dialog, Transition } from '@headlessui/react'; -import { NDKEvent, NDKFilter } from '@nostr-dev-kit/ndk'; +import { NDKEvent } from '@nostr-dev-kit/ndk'; import { useQuery } from '@tanstack/react-query'; -import { Fragment, useRef, useState } from 'react'; +import { Fragment, useState } from 'react'; import { useNDK } from '@libs/ndk/provider'; @@ -9,29 +9,26 @@ import { BellIcon, CancelIcon, LoaderIcon } from '@shared/icons'; import { NotificationUser } from '@shared/notification/user'; import { User } from '@shared/user'; -import { dateToUnix, getHourAgo } from '@utils/date'; +import { nHoursAgo } from '@utils/date'; +import { LumeEvent } from '@utils/types'; export function NotificationModal({ pubkey }: { pubkey: string }) { - const now = useRef(new Date()); const [isOpen, setIsOpen] = useState(false); - const { ndk } = useNDK(); + const { fetcher, relayUrls } = useNDK(); const { status, data } = useQuery( - ['user-notification', pubkey], + ['notification', pubkey], async () => { - const filter: NDKFilter = { - '#p': [pubkey], - kinds: [1, 6, 7, 9735], - since: dateToUnix(getHourAgo(48, now.current)), - }; - const events = await ndk.fetchEvents(filter); - return [...events]; + const events = await fetcher.fetchAllEvents( + relayUrls, + { '#p': [pubkey], kinds: [1, 6, 7, 9735] }, + { since: nHoursAgo(48) }, + { sort: true } + ); + return events as unknown as LumeEvent[]; }, { - refetchOnMount: false, - refetchOnReconnect: false, refetchOnWindowFocus: false, - staleTime: Infinity, } ); diff --git a/src/utils/date.tsx b/src/utils/date.tsx index 6c981663..e289a359 100644 --- a/src/utils/date.tsx +++ b/src/utils/date.tsx @@ -20,3 +20,6 @@ export function dateToUnix(_date?: Date) { return Math.floor(date.getTime() / 1000); } + +export const nHoursAgo = (hrs: number): number => + Math.floor((Date.now() - hrs * 60 * 60 * 1000) / 1000); diff --git a/src/utils/hooks/useSocial.tsx b/src/utils/hooks/useSocial.tsx index 5841c027..5a3062e6 100644 --- a/src/utils/hooks/useSocial.tsx +++ b/src/utils/hooks/useSocial.tsx @@ -4,26 +4,26 @@ import { useQuery, useQueryClient } from '@tanstack/react-query'; import { useNDK } from '@libs/ndk/provider'; import { createNote } from '@libs/storage'; -import { dateToUnix, getHourAgo } from '@utils/date'; +import { dateToUnix, getHourAgo, nHoursAgo } from '@utils/date'; import { useAccount } from '@utils/hooks/useAccount'; import { usePublish } from '@utils/hooks/usePublish'; import { nip02ToArray } from '@utils/transform'; +import { LumeEvent } from '@utils/types'; export function useSocial() { const queryClient = useQueryClient(); const publish = usePublish(); - const { ndk } = useNDK(); + const { ndk, fetcher, relayUrls } = useNDK(); const { account } = useAccount(); const { status, data: userFollows } = useQuery( ['userFollows', account.pubkey], async () => { - const res = await ndk.fetchEvents({ + const res = await fetcher.fetchLastEvent(relayUrls, { kinds: [3], authors: [account.pubkey], }); - const latest = [...res].slice(-1)[0]; - const list = nip02ToArray(latest.tags); + const list = nip02ToArray(res.tags); return list; }, { @@ -68,14 +68,14 @@ export function useSocial() { }); // fetch events - const filter: NDKFilter = { - authors: [pubkey], - kinds: [1, 6], - since: dateToUnix(getHourAgo(48, new Date())), - }; - const events = await ndk.fetchEvents(filter); - events.forEach((event: NDKEvent) => { - createNote( + const events = await fetcher.fetchAllEvents( + relayUrls, + { authors: [pubkey], kinds: [1, 6] }, + { since: nHoursAgo(48) } + ); + + for (const event of events) { + await createNote( event.id, event.pubkey, event.kind, @@ -83,7 +83,7 @@ export function useSocial() { event.content, event.created_at ); - }); + } }; return { status, userFollows, follow, unfollow };