diff --git a/.npmrc b/.npmrc new file mode 100644 index 00000000..521a9f7c --- /dev/null +++ b/.npmrc @@ -0,0 +1 @@ +legacy-peer-deps=true diff --git a/package-lock.json b/package-lock.json index c0599d41..b7bd5103 100644 --- a/package-lock.json +++ b/package-lock.json @@ -95,6 +95,7 @@ "@radix-ui/react-toggle": "^1.1.0", "@radix-ui/react-toggle-group": "^1.1.0", "@radix-ui/react-tooltip": "^1.2.8", + "@samthomson/nostr-messaging": "^0.14.0", "@scure/bip39": "^1.6.0", "@sentry/react": "^10.42.0", "@tanstack/react-query": "^5.56.2", @@ -196,6 +197,7 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", + "dev": true, "license": "MIT", "engines": { "node": ">=10" @@ -2564,6 +2566,7 @@ "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, "license": "MIT", "dependencies": { "@nodelib/fs.stat": "2.0.5", @@ -2577,6 +2580,7 @@ "version": "2.0.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, "license": "MIT", "engines": { "node": ">= 8" @@ -2586,6 +2590,7 @@ "version": "1.2.8", "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, "license": "MIT", "dependencies": { "@nodelib/fs.scandir": "2.1.5", @@ -6165,6 +6170,39 @@ "win32" ] }, + "node_modules/@samthomson/nostr-messaging": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@samthomson/nostr-messaging/-/nostr-messaging-0.14.0.tgz", + "integrity": "sha512-Ykqo+XJEPBPcfwZxHG8yvVseaUsvdzvfPrU5wY996H7tKbzeiJEIi6MVTaTkhUvdojeTne7HcPTm9As+hrKK3A==", + "license": "MIT", + "dependencies": { + "blurhash": "^2.0.5", + "buffer": "^6.0.3", + "fuse.js": "^7.1.0", + "idb": "^8.0.3", + "nostr-tools": "^2.13.0", + "react-blurhash": "^0.3.0" + }, + "peerDependencies": { + "@nostrify/nostrify": ">=0.47.0", + "@nostrify/react": "^0.2.0", + "@radix-ui/react-avatar": "^1.1.0", + "@radix-ui/react-dialog": "^1.1.2", + "@radix-ui/react-popover": "^1.1.0", + "@radix-ui/react-scroll-area": "^1.1.0", + "@radix-ui/react-select": "^2.1.1", + "@radix-ui/react-separator": "^1.1.0", + "@radix-ui/react-tabs": "^1.1.0", + "@radix-ui/react-tooltip": "^1.1.4", + "@tanstack/react-query": "^5.56.2", + "clsx": "^2.0.0", + "lucide-react": "^0.462.0", + "react": "^18.3.1", + "react-dom": "^18.3.1", + "react-router-dom": "^6.0.0", + "tailwind-merge": "^2.0.0" + } + }, "node_modules/@scure/base": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.1.tgz", @@ -6775,6 +6813,7 @@ "version": "19.2.14", "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.14.tgz", "integrity": "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==", + "dev": true, "license": "MIT", "dependencies": { "csstype": "^3.2.2" @@ -6784,7 +6823,7 @@ "version": "19.2.3", "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz", "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", - "devOptional": true, + "dev": true, "license": "MIT", "peerDependencies": { "@types/react": "^19.2.0" @@ -7475,12 +7514,14 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", + "dev": true, "license": "MIT" }, "node_modules/anymatch": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, "license": "ISC", "dependencies": { "normalize-path": "^3.0.0", @@ -7494,6 +7535,7 @@ "version": "5.0.2", "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", + "dev": true, "license": "MIT" }, "node_modules/argparse": { @@ -7722,6 +7764,7 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -7811,6 +7854,7 @@ "version": "3.0.3", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, "license": "MIT", "dependencies": { "fill-range": "^7.1.1" @@ -7935,6 +7979,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", + "dev": true, "license": "MIT", "engines": { "node": ">= 6" @@ -8068,6 +8113,7 @@ "version": "3.6.0", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, "license": "MIT", "dependencies": { "anymatch": "~3.1.2", @@ -8092,6 +8138,7 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, "license": "ISC", "dependencies": { "is-glob": "^4.0.1" @@ -8219,6 +8266,7 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "dev": true, "license": "MIT", "engines": { "node": ">= 6" @@ -8269,6 +8317,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true, "license": "MIT", "bin": { "cssesc": "bin/cssesc" @@ -8625,6 +8674,7 @@ "version": "1.2.2", "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", + "dev": true, "license": "Apache-2.0" }, "node_modules/dijkstrajs": { @@ -8637,6 +8687,7 @@ "version": "1.1.3", "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", + "dev": true, "license": "MIT" }, "node_modules/dom-accessibility-api": { @@ -9069,6 +9120,7 @@ "version": "3.3.3", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "dev": true, "license": "MIT", "dependencies": { "@nodelib/fs.stat": "^2.0.2", @@ -9085,6 +9137,7 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, "license": "ISC", "dependencies": { "is-glob": "^4.0.1" @@ -9111,6 +9164,7 @@ "version": "1.19.1", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", + "dev": true, "license": "ISC", "dependencies": { "reusify": "^1.0.4" @@ -9156,6 +9210,7 @@ "version": "7.1.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" @@ -9242,6 +9297,7 @@ "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, "hasInstallScript": true, "license": "MIT", "optional": true, @@ -9256,11 +9312,25 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/fuse.js": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/fuse.js/-/fuse.js-7.3.0.tgz", + "integrity": "sha512-plz8RVjfcDedTGfVngWH1jmJvBvAwi1v2jecfDerbEnMcmOYUEEwKFTHbNoCiYyzaK2Ws8lABkTCcRSqCY1q4w==", + "license": "Apache-2.0", + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/krisk" + } + }, "node_modules/get-caller-file": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", @@ -9303,6 +9373,7 @@ "version": "6.0.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, "license": "ISC", "dependencies": { "is-glob": "^4.0.3" @@ -9345,6 +9416,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, "license": "MIT", "dependencies": { "function-bind": "^1.1.2" @@ -9688,6 +9760,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, "license": "MIT", "dependencies": { "binary-extensions": "^2.0.0" @@ -9700,6 +9773,7 @@ "version": "2.16.1", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "dev": true, "license": "MIT", "dependencies": { "hasown": "^2.0.2" @@ -9741,6 +9815,7 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -9759,6 +9834,7 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, "license": "MIT", "dependencies": { "is-extglob": "^2.1.1" @@ -9829,6 +9905,7 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, "license": "MIT", "engines": { "node": ">=0.12.0" @@ -9887,6 +9964,7 @@ "version": "1.21.7", "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz", "integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==", + "dev": true, "license": "MIT", "bin": { "jiti": "bin/jiti.js" @@ -10327,6 +10405,7 @@ "version": "3.1.3", "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", + "dev": true, "license": "MIT", "engines": { "node": ">=14" @@ -10339,6 +10418,7 @@ "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true, "license": "MIT" }, "node_modules/locate-path": { @@ -10798,6 +10878,7 @@ "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, "license": "MIT", "engines": { "node": ">= 8" @@ -11389,6 +11470,7 @@ "version": "4.0.8", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, "license": "MIT", "dependencies": { "braces": "^3.0.3", @@ -11496,6 +11578,7 @@ "version": "2.7.0", "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "dev": true, "license": "MIT", "dependencies": { "any-promise": "^1.0.0", @@ -11594,6 +11677,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -11713,6 +11797,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", + "dev": true, "license": "MIT", "engines": { "node": ">= 6" @@ -11892,6 +11977,7 @@ "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true, "license": "MIT" }, "node_modules/pathe": { @@ -12023,6 +12109,7 @@ "version": "2.3.2", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "dev": true, "license": "MIT", "engines": { "node": ">=8.6" @@ -12035,6 +12122,7 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -12044,6 +12132,7 @@ "version": "4.0.7", "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", + "dev": true, "license": "MIT", "engines": { "node": ">= 6" @@ -12116,6 +12205,7 @@ "version": "15.1.0", "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", + "dev": true, "license": "MIT", "dependencies": { "postcss-value-parser": "^4.0.0", @@ -12133,6 +12223,7 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz", "integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==", + "dev": true, "license": "MIT", "dependencies": { "camelcase-css": "^2.0.1" @@ -12152,6 +12243,7 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.2.tgz", "integrity": "sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==", + "dev": true, "funding": [ { "type": "opencollective", @@ -12187,6 +12279,7 @@ "version": "6.2.0", "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.2.0.tgz", "integrity": "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==", + "dev": true, "funding": [ { "type": "opencollective", @@ -12212,6 +12305,7 @@ "version": "6.1.2", "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", + "dev": true, "license": "MIT", "dependencies": { "cssesc": "^3.0.0", @@ -12239,6 +12333,7 @@ "version": "4.2.0", "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "dev": true, "license": "MIT" }, "node_modules/postgres-array": { @@ -12655,6 +12750,7 @@ "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, "funding": [ { "type": "github", @@ -13032,6 +13128,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", + "dev": true, "license": "MIT", "dependencies": { "pify": "^2.3.0" @@ -13056,6 +13153,7 @@ "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, "license": "MIT", "dependencies": { "picomatch": "^2.2.1" @@ -13256,6 +13354,7 @@ "version": "1.22.10", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==", + "dev": true, "license": "MIT", "dependencies": { "is-core-module": "^2.16.0", @@ -13286,6 +13385,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "dev": true, "license": "MIT", "engines": { "iojs": ">=1.0.0", @@ -13441,7 +13541,7 @@ "version": "4.59.0", "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.59.0.tgz", "integrity": "sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "@types/estree": "1.0.8" @@ -13728,6 +13828,7 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, "funding": [ { "type": "github", @@ -14107,6 +14208,7 @@ "version": "3.35.1", "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.1.tgz", "integrity": "sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==", + "dev": true, "license": "MIT", "dependencies": { "@jridgewell/gen-mapping": "^0.3.2", @@ -14142,6 +14244,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -14171,6 +14274,7 @@ "version": "3.4.17", "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.17.tgz", "integrity": "sha512-w33E2aCvSDP0tW9RZuNXadXlkHXqFzSkQew/aIa2i/Sj8fThxwovwlXHSPXTbAHwEIhBFXAedUhP2tueAKP8Og==", + "dev": true, "license": "MIT", "dependencies": { "@alloc/quick-lru": "^5.2.0", @@ -14217,6 +14321,7 @@ "version": "6.1.2", "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", + "dev": true, "license": "MIT", "dependencies": { "cssesc": "^3.0.0", @@ -14284,6 +14389,7 @@ "version": "3.3.1", "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", + "dev": true, "license": "MIT", "dependencies": { "any-promise": "^1.0.0" @@ -14293,6 +14399,7 @@ "version": "1.6.0", "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", + "dev": true, "license": "MIT", "dependencies": { "thenify": ">= 3.1.0 < 4" @@ -14335,6 +14442,7 @@ "version": "0.2.15", "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "dev": true, "license": "MIT", "dependencies": { "fdir": "^6.5.0", @@ -14351,6 +14459,7 @@ "version": "6.5.0", "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, "license": "MIT", "engines": { "node": ">=12.0.0" @@ -14368,6 +14477,7 @@ "version": "4.0.4", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true, "license": "MIT", "engines": { "node": ">=12" @@ -14430,6 +14540,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, "license": "MIT", "dependencies": { "is-number": "^7.0.0" @@ -14511,6 +14622,7 @@ "version": "0.1.13", "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", + "dev": true, "license": "Apache-2.0" }, "node_modules/tslib": { @@ -14549,7 +14661,7 @@ "version": "5.8.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", - "devOptional": true, + "dev": true, "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", @@ -14924,6 +15036,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "devOptional": true, "license": "MIT" }, "node_modules/vaul": { @@ -16698,6 +16811,7 @@ "version": "2.8.3", "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.3.tgz", "integrity": "sha512-AvbaCLOO2Otw/lW5bmh9d/WEdcDFdQp2Z2ZUH3pX9U2ihyUY0nvLv7J6TrWowklRGPYbB/IuIMfYgxaCPg5Bpg==", + "dev": true, "license": "ISC", "bin": { "yaml": "bin.mjs" diff --git a/package.json b/package.json index 1fc0b582..00635f84 100644 --- a/package.json +++ b/package.json @@ -102,6 +102,7 @@ "@radix-ui/react-toggle": "^1.1.0", "@radix-ui/react-toggle-group": "^1.1.0", "@radix-ui/react-tooltip": "^1.2.8", + "@samthomson/nostr-messaging": "^0.14.0", "@scure/bip39": "^1.6.0", "@sentry/react": "^10.42.0", "@tanstack/react-query": "^5.56.2", diff --git a/src/App.tsx b/src/App.tsx index a54db4af..b95cb0bc 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -8,7 +8,7 @@ import { InferSeoMetaPlugin } from "@unhead/addons"; import { createHead, UnheadProvider } from "@unhead/react/client"; import { useEffect } from "react"; import { AppProvider } from "@/components/AppProvider"; -import { DMProvider, type DMConfig } from "@/components/DMProvider"; +import { DMProviderWrapper } from "@/components/DMProviderWrapper"; import { InitialSyncGate } from "@/components/InitialSyncGate"; import { NativeNotifications } from "@/components/NativeNotifications"; import NostrProvider from "@/components/NostrProvider"; @@ -22,17 +22,11 @@ import { useNsecPasteGuard } from "@/hooks/useNsecPasteGuard"; import type { AppConfig } from "@/contexts/AppContext"; import { NWCProvider } from "@/contexts/NWCContext"; import { SparkWalletProvider } from "@/contexts/SparkWalletContext"; -import { PROTOCOL_MODE } from "@/lib/dmConstants"; import { BuildConfigSchema, type BuildConfig } from "@/lib/schemas"; import { secureStorage } from "@/lib/secureStorage"; import { EmotionDevProvider } from "@/blobbi/dev/EmotionDevContext"; import AppRouter from "./AppRouter"; -const dmConfig: DMConfig = { - enabled: false, - protocolMode: PROTOCOL_MODE.NIP04_OR_NIP17, -}; - const head = createHead({ plugins: [InferSeoMetaPlugin()], }); @@ -130,6 +124,7 @@ const hardcodedConfig: AppConfig = { "badges", "feed", "notifications", + "messages", "profile", "settings", ], @@ -156,6 +151,13 @@ const hardcodedConfig: AppConfig = { { id: 'trends' }, { id: 'hot-posts' }, ], + messaging: { + enabled: true, + relayMode: 'hybrid', + renderInlineMedia: true, + soundEnabled: false, + devMode: false, + }, }; /** @@ -213,7 +215,7 @@ export function App() { - + @@ -221,7 +223,7 @@ export function App() { - + diff --git a/src/AppRouter.tsx b/src/AppRouter.tsx index 1e4011f8..bef352ea 100644 --- a/src/AppRouter.tsx +++ b/src/AppRouter.tsx @@ -48,6 +48,7 @@ const LetterComposePage = lazy(() => import("./pages/LetterComposePage").then(m const LetterPreferencesPage = lazy(() => import("./pages/LetterPreferencesPage").then(m => ({ default: m.LetterPreferencesPage }))); const LettersPage = lazy(() => import("./pages/LettersPage").then(m => ({ default: m.LettersPage }))); const MagicSettingsPage = lazy(() => import("./pages/MagicSettingsPage").then(m => ({ default: m.MagicSettingsPage }))); +const MessagesPage = lazy(() => import("./pages/Messages")); const NetworkSettingsPage = lazy(() => import("./pages/NetworkSettingsPage").then(m => ({ default: m.NetworkSettingsPage }))); const NIP19Page = lazy(() => import("./pages/NIP19Page").then(m => ({ default: m.NIP19Page }))); const NotificationSettings = lazy(() => import("./pages/NotificationSettings").then(m => ({ default: m.NotificationSettings }))); @@ -122,6 +123,7 @@ export function AppRouter() { } /> } /> } /> + } /> } /> } /> } /> diff --git a/src/components/DMProviderWrapper.tsx b/src/components/DMProviderWrapper.tsx new file mode 100644 index 00000000..6129ccbe --- /dev/null +++ b/src/components/DMProviderWrapper.tsx @@ -0,0 +1,118 @@ +import { type ReactNode, useCallback, useMemo } from "react"; +import { DMProvider } from "@samthomson/nostr-messaging/core"; +import { DEFAULT_NEW_MESSAGE_SOUNDS } from "@samthomson/nostr-messaging/core"; +import type { NostrEvent } from "@nostrify/nostrify"; +import { useNostr } from "@nostrify/react"; +import { toast } from "@/hooks/useToast"; +import { useCurrentUser } from "@/hooks/useCurrentUser"; +import { useAppContext } from "@/hooks/useAppContext"; +import { useNostrPublish } from "@/hooks/useNostrPublish"; +import { useUploadFile } from "@/hooks/useUploadFile"; +import { useProfileSupplementary } from "@/hooks/useProfileData"; +import { useIsMobile } from "@/hooks/useIsMobile"; +import { getDisplayName } from "@/lib/getDisplayName"; +import { useAuthors } from "@/hooks/useAuthors"; + +interface DMProviderWrapperProps { + children: ReactNode; +} + +export function DMProviderWrapper({ children }: DMProviderWrapperProps) { + const { nostr } = useNostr(); + const { user } = useCurrentUser(); + const { config } = useAppContext(); + const { mutateAsync: publishEvent } = useNostrPublish(); + const { mutateAsync: uploadFileMutation } = useUploadFile(); + const isMobile = useIsMobile(); + + const { data: profileData } = useProfileSupplementary(user?.pubkey); + const follows = useMemo(() => profileData?.following ?? [], [profileData]); + + const handlePublishEvent = useCallback(async ( + event: Omit, + ): Promise => { + await publishEvent(event); + }, [publishEvent]); + + const handleUploadFile = useCallback(async (file: File): Promise => { + const tags = await uploadFileMutation(file); + return tags[0][1] ?? ""; + }, [uploadFileMutation]); + + const handleGetDisplayName = useCallback(( + pubkey: string, + metadata?: Parameters[0], + ) => { + return getDisplayName(metadata, pubkey); + }, []); + + const handleNotify = useCallback((options: { title?: string; description?: string; variant?: "default" | "destructive" }) => { + toast(options); + }, []); + + const messaging = useMemo(() => config.messaging ?? {}, [config.messaging]); + + const discoveryRelays = useMemo(() => { + if (messaging.discoveryRelays?.length) { + return messaging.discoveryRelays; + } + + return config.relayMetadata.relays + .filter((relay) => relay.read) + .map((relay) => relay.url); + }, [messaging.discoveryRelays, config.relayMetadata.relays]); + + const relayMode = messaging.relayMode ?? "hybrid"; + const messagingEnabled = messaging.enabled ?? true; + const renderInlineMedia = messaging.renderInlineMedia ?? true; + const soundEnabled = messaging.soundEnabled ?? false; + const soundId = messaging.soundId ?? DEFAULT_NEW_MESSAGE_SOUNDS[0]?.id ?? ""; + const devMode = messaging.devMode ?? false; + + const messagingConfig = useMemo(() => ({ + enabled: messagingEnabled, + discoveryRelays, + relayMode, + renderInlineMedia, + devMode, + appName: config.appName, + appDescription: `Direct messages on ${config.appName}`, + soundPref: { + options: DEFAULT_NEW_MESSAGE_SOUNDS, + value: { enabled: soundEnabled, soundId }, + onChange: () => {}, + }, + }), [ + messagingEnabled, + discoveryRelays, + relayMode, + renderInlineMedia, + devMode, + config.appName, + soundEnabled, + soundId, + ]); + + const uiConfig = useMemo(() => ({ + showShorts: false, + showSearch: true, + isMobile, + }), [isMobile]); + + return ( + + {children} + + ); +} diff --git a/src/contexts/AppContext.ts b/src/contexts/AppContext.ts index 699b5ab8..afd49acd 100644 --- a/src/contexts/AppContext.ts +++ b/src/contexts/AppContext.ts @@ -247,6 +247,23 @@ export interface AppConfig { sandboxDomain: string; /** Ordered list of right sidebar widget configs. Each entry is a widget type ID with optional display settings. */ sidebarWidgets: WidgetConfig[]; + /** Direct messaging integration settings. */ + messaging?: { + /** Enable the DM experience. */ + enabled?: boolean; + /** Relay URLs used for DM discovery and querying. */ + discoveryRelays?: string[]; + /** Relay strategy for DM transport. */ + relayMode?: "discovery" | "hybrid" | "strict_outbox"; + /** Show inline media previews in conversations. */ + renderInlineMedia?: boolean; + /** Play a sound when new messages arrive. */ + soundEnabled?: boolean; + /** Selected sound ID for message notifications. */ + soundId?: string; + /** Show developer/debug DM UI affordances. */ + devMode?: boolean; + }; } /** Configuration for a single widget in the right sidebar. */ diff --git a/src/lib/schemas.ts b/src/lib/schemas.ts index 1d2af396..b374bf07 100644 --- a/src/lib/schemas.ts +++ b/src/lib/schemas.ts @@ -254,6 +254,15 @@ export const AppConfigSchema = z.object({ id: z.string(), height: z.number().optional(), })).optional(), + messaging: z.object({ + enabled: z.boolean().optional(), + discoveryRelays: z.array(z.string().url()).optional(), + relayMode: z.enum(['discovery', 'hybrid', 'strict_outbox']).optional(), + renderInlineMedia: z.boolean().optional(), + soundEnabled: z.boolean().optional(), + soundId: z.string().optional(), + devMode: z.boolean().optional(), + }).optional(), }); // ─── BuildConfigSchema (build-time app config) ─────────────────────── @@ -332,6 +341,15 @@ export const EncryptedSettingsSchema = z.looseObject({ id: z.string(), height: z.number().optional(), })).optional(), + messaging: z.object({ + enabled: z.boolean().optional(), + discoveryRelays: z.array(z.string().url()).optional(), + relayMode: z.enum(['discovery', 'hybrid', 'strict_outbox']).optional(), + renderInlineMedia: z.boolean().optional(), + soundEnabled: z.boolean().optional(), + soundId: z.string().optional(), + devMode: z.boolean().optional(), + }).optional(), homePage: z.string().optional(), showGlobalFeed: z.boolean().optional(), showCommunityFeed: z.boolean().optional(), diff --git a/src/lib/sidebarItems.tsx b/src/lib/sidebarItems.tsx index 528e64d2..8dd48760 100644 --- a/src/lib/sidebarItems.tsx +++ b/src/lib/sidebarItems.tsx @@ -113,6 +113,13 @@ export const SIDEBAR_ITEMS: SidebarItemDef[] = [ icon: Bell, requiresAuth: true, }, + { + id: "messages", + label: "Messages", + path: "/messages", + icon: MessageSquareMore, + requiresAuth: true, + }, { id: "search", label: "Search", path: "/search", icon: Search }, { id: "verified", diff --git a/src/pages/Messages.tsx b/src/pages/Messages.tsx index 00b4c680..75f48460 100644 --- a/src/pages/Messages.tsx +++ b/src/pages/Messages.tsx @@ -1,25 +1,42 @@ import { useSeoMeta } from '@unhead/react'; -import { DMMessagingInterface } from '@/components/dm/DMMessagingInterface'; +import { DMMessagingInterface } from '@samthomson/nostr-messaging/ui'; +import { Link } from 'react-router-dom'; import { useLayoutOptions } from '@/contexts/LayoutContext'; +import { useAppContext } from '@/hooks/useAppContext'; const Messages = () => { + const { config } = useAppContext(); + const messagingEnabled = config.messaging?.enabled ?? true; + useSeoMeta({ title: 'Messages', description: 'Private encrypted messaging on Nostr', }); - useLayoutOptions({ noOverscroll: true, rightSidebar: null, noMaxWidth: true }); + useLayoutOptions({ + rightSidebar: null, + noMaxWidth: true, + noOverscroll: true, + wrapperClassName: 'max-w-full', + }); return ( -
-
- {/* Header */} -
-

Messages

+
+ {messagingEnabled ? ( + + ) : ( +
+
+

Chats are turned off

+

+ Enable messaging in settings to start using chats. +

+ + Open Settings + +
- - -
+ )}
); }; diff --git a/tailwind.config.ts b/tailwind.config.ts index 57714c0b..31ebaf04 100644 --- a/tailwind.config.ts +++ b/tailwind.config.ts @@ -8,6 +8,7 @@ export default { "./components/**/*.{ts,tsx}", "./app/**/*.{ts,tsx}", "./src/**/*.{ts,tsx}", + "./node_modules/@samthomson/nostr-messaging/dist/**/*.js", ], prefix: "", theme: { diff --git a/vite.config.ts b/vite.config.ts index 2b6ae859..d541f65f 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -150,6 +150,11 @@ export default defineConfig(({ mode }) => { globals: true, environment: 'jsdom', setupFiles: './src/test/setup.ts', + server: { + deps: { + inline: ['@samthomson/nostr-messaging'], + }, + }, onConsoleLog(log) { return !log.includes("React Router Future Flag Warning"); },