diff --git a/package-lock.json b/package-lock.json index 6a0852a..0926388 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,12 @@ "version": "0.1.0", "dependencies": { "@tanstack/vue-query": "^5.92.9", + "applesauce-accounts": "^5.1.0", + "applesauce-common": "^5.1.0", + "applesauce-core": "^5.1.0", + "applesauce-loaders": "^5.1.0", + "applesauce-relay": "^5.1.0", + "applesauce-signers": "^5.1.0", "axios": "^1.13.5", "nostr-tools": "^2.23.0", "pinia": "^3.0.4", @@ -23,6 +29,7 @@ "postcss": "^8.5.6", "sharp": "^0.34.5", "tailwindcss": "^3.4.18", + "tsx": "^4.21.0", "typescript": "~5.9.3", "vite": "^7.2.2", "vite-plugin-pwa": "^1.2.0", @@ -2664,6 +2671,18 @@ "url": "https://paulmillr.com/funding/" } }, + "node_modules/@noble/secp256k1": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/@noble/secp256k1/-/secp256k1-1.7.2.tgz", + "integrity": "sha512-/qzwYl5eFLH8OWIecQWM31qld2g1NfjgylK+TNhqtaUKP37Nm+Y+z30Fjhw0Ct8p9yCQEm2N3W/AckdIb3SMcQ==", + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "license": "MIT" + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -3629,6 +3648,491 @@ "node": ">= 8" } }, + "node_modules/applesauce-accounts": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/applesauce-accounts/-/applesauce-accounts-5.1.0.tgz", + "integrity": "sha512-xFNqofcQx+GjLbJKqkhEGWPMKPA0Y523ZiLuPwiLxwxiQRN053Rsq+uOTV0qmg/Hspylg3EGR49wwCIE8WnNGg==", + "license": "MIT", + "dependencies": { + "applesauce-core": "^5.1.0", + "applesauce-signers": "^5.1.0", + "nanoid": "^5.1.5", + "rxjs": "^7.8.1" + }, + "funding": { + "type": "lightning", + "url": "lightning:nostrudel@geyser.fund" + } + }, + "node_modules/applesauce-accounts/node_modules/nanoid": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.1.6.tgz", + "integrity": "sha512-c7+7RQ+dMB5dPwwCp4ee1/iV/q2P6aK1mTZcfr1BTuVlyW9hJYiMPybJCcnBlQtuSmTIWNeazm/zqNoZSSElBg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.js" + }, + "engines": { + "node": "^18 || >=20" + } + }, + "node_modules/applesauce-common": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/applesauce-common/-/applesauce-common-5.1.0.tgz", + "integrity": "sha512-qUEJibEtawkCgrxoyj0u+ECk3C/PKwGSmOq9kCupGjHVG21BU6Nh29BxU4vcmmBXH2ByiA6VuZgyJZb3t2JJuA==", + "license": "MIT", + "dependencies": { + "@scure/base": "^1.2.4", + "applesauce-core": "^5.1.0", + "hash-sum": "^2.0.0", + "light-bolt11-decoder": "^3.2.0", + "rxjs": "^7.8.1" + }, + "funding": { + "type": "lightning", + "url": "lightning:nostrudel@geyser.fund" + } + }, + "node_modules/applesauce-common/node_modules/@scure/base": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.2.6.tgz", + "integrity": "sha512-g/nm5FgUa//MCj1gV09zTJTaM6KBAHqLN907YVQqf7zC49+DcO4B1so4ZX07Ef10Twr6nuqYEH9GEggFXA4Fmg==", + "license": "MIT", + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/applesauce-core": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/applesauce-core/-/applesauce-core-5.1.0.tgz", + "integrity": "sha512-kk4nHndK4zjS8Sa6mC8LGtQ0LDSP4hlCGPJ9lpyIln7MkZaNFWD9eFd+fsEhfE9kyrne9IyYuVfJNp+EqY1b9w==", + "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "fast-deep-equal": "^3.1.3", + "hash-sum": "^2.0.0", + "nanoid": "^5.0.9", + "nostr-tools": "~2.19", + "rxjs": "^7.8.1" + }, + "funding": { + "type": "lightning", + "url": "lightning:nostrudel@geyser.fund" + } + }, + "node_modules/applesauce-core/node_modules/@noble/ciphers": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/@noble/ciphers/-/ciphers-0.5.3.tgz", + "integrity": "sha512-B0+6IIHiqEs3BPMT0hcRmHvEj2QHOLu+uwt+tqDDeVd0oyVzh7BPrDcPjRnV1PV/5LaknXJJQvOuRGR0zQJz+w==", + "license": "MIT", + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/applesauce-core/node_modules/@noble/curves": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.2.0.tgz", + "integrity": "sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "1.3.2" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/applesauce-core/node_modules/@noble/curves/node_modules/@noble/hashes": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.2.tgz", + "integrity": "sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ==", + "license": "MIT", + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/applesauce-core/node_modules/@noble/hashes": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.1.tgz", + "integrity": "sha512-EbqwksQwz9xDRGfDST86whPBgM65E0OH/pCgqW0GBVzO22bNE+NuIbeTb714+IfSjU3aRk47EUvXIb5bTsenKA==", + "license": "MIT", + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/applesauce-core/node_modules/@scure/base": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.1.tgz", + "integrity": "sha512-ZxOhsSyxYwLJj3pLZCefNitxsj093tb2vq90mp2txoYeBqbcjDjqFhyM8eUjq/uFm6zJ+mUuqxlS2FkuSY1MTA==", + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "license": "MIT" + }, + "node_modules/applesauce-core/node_modules/@scure/bip32": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.3.1.tgz", + "integrity": "sha512-osvveYtyzdEVbt3OfwwXFr4P2iVBL5u1Q3q4ONBfDY/UpOuXmOlbgwc1xECEboY8wIays8Yt6onaWMUdUbfl0A==", + "license": "MIT", + "dependencies": { + "@noble/curves": "~1.1.0", + "@noble/hashes": "~1.3.1", + "@scure/base": "~1.1.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/applesauce-core/node_modules/@scure/bip32/node_modules/@noble/curves": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.1.0.tgz", + "integrity": "sha512-091oBExgENk/kGj3AZmtBDMpxQPDtxQABR2B9lb1JbVTs6ytdzZNwvhxQ4MWasRNEzlbEH8jCWFCwhF/Obj5AA==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "1.3.1" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/applesauce-core/node_modules/@scure/bip39": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.2.1.tgz", + "integrity": "sha512-Z3/Fsz1yr904dduJD0NpiyRHhRYHdcnyh73FZWiV+/qhWi83wNJ3NWolYqCEN+ZWsUz2TWwajJggcRE9r1zUYg==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "~1.3.0", + "@scure/base": "~1.1.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/applesauce-core/node_modules/nanoid": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.1.6.tgz", + "integrity": "sha512-c7+7RQ+dMB5dPwwCp4ee1/iV/q2P6aK1mTZcfr1BTuVlyW9hJYiMPybJCcnBlQtuSmTIWNeazm/zqNoZSSElBg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.js" + }, + "engines": { + "node": "^18 || >=20" + } + }, + "node_modules/applesauce-core/node_modules/nostr-tools": { + "version": "2.19.4", + "resolved": "https://registry.npmjs.org/nostr-tools/-/nostr-tools-2.19.4.tgz", + "integrity": "sha512-qVLfoTpZegNYRJo5j+Oi6RPu0AwLP6jcvzcB3ySMnIT5DrAGNXfs5HNBspB/2HiGfH3GY+v6yXkTtcKSBQZwSg==", + "license": "Unlicense", + "dependencies": { + "@noble/ciphers": "^0.5.1", + "@noble/curves": "1.2.0", + "@noble/hashes": "1.3.1", + "@scure/base": "1.1.1", + "@scure/bip32": "1.3.1", + "@scure/bip39": "1.2.1", + "nostr-wasm": "0.1.0" + }, + "peerDependencies": { + "typescript": ">=5.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/applesauce-loaders": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/applesauce-loaders/-/applesauce-loaders-5.1.0.tgz", + "integrity": "sha512-xllWYl7KxG0oaJqKVdZNzxN8OZQoDMaMmaTAO9Ao1Son+mmJyR9Q4UVicSwSlzzHarf59WCfvJeSdrSHIitkHg==", + "license": "MIT", + "dependencies": { + "applesauce-core": "^5.1.0", + "nanoid": "^5.0.9", + "rxjs": "^7.8.1" + }, + "funding": { + "type": "lightning", + "url": "lightning:nostrudel@geyser.fund" + } + }, + "node_modules/applesauce-loaders/node_modules/nanoid": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.1.6.tgz", + "integrity": "sha512-c7+7RQ+dMB5dPwwCp4ee1/iV/q2P6aK1mTZcfr1BTuVlyW9hJYiMPybJCcnBlQtuSmTIWNeazm/zqNoZSSElBg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.js" + }, + "engines": { + "node": "^18 || >=20" + } + }, + "node_modules/applesauce-relay": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/applesauce-relay/-/applesauce-relay-5.1.0.tgz", + "integrity": "sha512-d0LTJmQmr5gsYFm9A6efPEo2Bx/ewoL7LNsIdieMx34QohZBpPb137RvU9KQ1lFIXTm0tudd8VYfAPncqti2OQ==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "^1.7.1", + "applesauce-core": "^5.1.0", + "nanoid": "^5.0.9", + "nostr-tools": "~2.19", + "rxjs": "^7.8.1" + }, + "funding": { + "type": "lightning", + "url": "lightning:nostrudel@geyser.fund" + } + }, + "node_modules/applesauce-relay/node_modules/@noble/ciphers": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/@noble/ciphers/-/ciphers-0.5.3.tgz", + "integrity": "sha512-B0+6IIHiqEs3BPMT0hcRmHvEj2QHOLu+uwt+tqDDeVd0oyVzh7BPrDcPjRnV1PV/5LaknXJJQvOuRGR0zQJz+w==", + "license": "MIT", + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/applesauce-relay/node_modules/@noble/curves": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.2.0.tgz", + "integrity": "sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "1.3.2" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/applesauce-relay/node_modules/@noble/curves/node_modules/@noble/hashes": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.2.tgz", + "integrity": "sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ==", + "license": "MIT", + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/applesauce-relay/node_modules/@noble/hashes": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", + "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", + "license": "MIT", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/applesauce-relay/node_modules/@scure/base": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.1.tgz", + "integrity": "sha512-ZxOhsSyxYwLJj3pLZCefNitxsj093tb2vq90mp2txoYeBqbcjDjqFhyM8eUjq/uFm6zJ+mUuqxlS2FkuSY1MTA==", + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "license": "MIT" + }, + "node_modules/applesauce-relay/node_modules/@scure/bip32": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.3.1.tgz", + "integrity": "sha512-osvveYtyzdEVbt3OfwwXFr4P2iVBL5u1Q3q4ONBfDY/UpOuXmOlbgwc1xECEboY8wIays8Yt6onaWMUdUbfl0A==", + "license": "MIT", + "dependencies": { + "@noble/curves": "~1.1.0", + "@noble/hashes": "~1.3.1", + "@scure/base": "~1.1.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/applesauce-relay/node_modules/@scure/bip32/node_modules/@noble/curves": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.1.0.tgz", + "integrity": "sha512-091oBExgENk/kGj3AZmtBDMpxQPDtxQABR2B9lb1JbVTs6ytdzZNwvhxQ4MWasRNEzlbEH8jCWFCwhF/Obj5AA==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "1.3.1" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/applesauce-relay/node_modules/@scure/bip32/node_modules/@noble/curves/node_modules/@noble/hashes": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.1.tgz", + "integrity": "sha512-EbqwksQwz9xDRGfDST86whPBgM65E0OH/pCgqW0GBVzO22bNE+NuIbeTb714+IfSjU3aRk47EUvXIb5bTsenKA==", + "license": "MIT", + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/applesauce-relay/node_modules/@scure/bip32/node_modules/@noble/hashes": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.3.tgz", + "integrity": "sha512-V7/fPHgl+jsVPXqqeOzT8egNj2iBIVt+ECeMMG8TdcnTikP3oaBtUVqpT/gYCR68aEBJSF+XbYUxStjbFMqIIA==", + "license": "MIT", + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/applesauce-relay/node_modules/@scure/bip39": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.2.1.tgz", + "integrity": "sha512-Z3/Fsz1yr904dduJD0NpiyRHhRYHdcnyh73FZWiV+/qhWi83wNJ3NWolYqCEN+ZWsUz2TWwajJggcRE9r1zUYg==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "~1.3.0", + "@scure/base": "~1.1.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/applesauce-relay/node_modules/@scure/bip39/node_modules/@noble/hashes": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.3.tgz", + "integrity": "sha512-V7/fPHgl+jsVPXqqeOzT8egNj2iBIVt+ECeMMG8TdcnTikP3oaBtUVqpT/gYCR68aEBJSF+XbYUxStjbFMqIIA==", + "license": "MIT", + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/applesauce-relay/node_modules/nanoid": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.1.6.tgz", + "integrity": "sha512-c7+7RQ+dMB5dPwwCp4ee1/iV/q2P6aK1mTZcfr1BTuVlyW9hJYiMPybJCcnBlQtuSmTIWNeazm/zqNoZSSElBg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.js" + }, + "engines": { + "node": "^18 || >=20" + } + }, + "node_modules/applesauce-relay/node_modules/nostr-tools": { + "version": "2.19.4", + "resolved": "https://registry.npmjs.org/nostr-tools/-/nostr-tools-2.19.4.tgz", + "integrity": "sha512-qVLfoTpZegNYRJo5j+Oi6RPu0AwLP6jcvzcB3ySMnIT5DrAGNXfs5HNBspB/2HiGfH3GY+v6yXkTtcKSBQZwSg==", + "license": "Unlicense", + "dependencies": { + "@noble/ciphers": "^0.5.1", + "@noble/curves": "1.2.0", + "@noble/hashes": "1.3.1", + "@scure/base": "1.1.1", + "@scure/bip32": "1.3.1", + "@scure/bip39": "1.2.1", + "nostr-wasm": "0.1.0" + }, + "peerDependencies": { + "typescript": ">=5.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/applesauce-relay/node_modules/nostr-tools/node_modules/@noble/hashes": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.1.tgz", + "integrity": "sha512-EbqwksQwz9xDRGfDST86whPBgM65E0OH/pCgqW0GBVzO22bNE+NuIbeTb714+IfSjU3aRk47EUvXIb5bTsenKA==", + "license": "MIT", + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/applesauce-signers": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/applesauce-signers/-/applesauce-signers-5.1.0.tgz", + "integrity": "sha512-sdQe6J1txYV1GVX8/zSGZDyyXuuZomePHSfUDozZmNAnXhCXE0wqVfhLK0yegVMnomSgoeDUCsGmJiTE2BHqoQ==", + "license": "MIT", + "dependencies": { + "@noble/secp256k1": "^1.7.1", + "applesauce-core": "^5.1.0", + "debug": "^4.4.0", + "nanoid": "^5.0.9", + "rxjs": "^7.8.2" + }, + "funding": { + "type": "lightning", + "url": "lightning:nostrudel@geyser.fund" + } + }, + "node_modules/applesauce-signers/node_modules/nanoid": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.1.6.tgz", + "integrity": "sha512-c7+7RQ+dMB5dPwwCp4ee1/iV/q2P6aK1mTZcfr1BTuVlyW9hJYiMPybJCcnBlQtuSmTIWNeazm/zqNoZSSElBg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.js" + }, + "engines": { + "node": "^18 || >=20" + } + }, "node_modules/arg": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", @@ -4226,7 +4730,6 @@ "version": "4.4.3", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "dev": true, "license": "MIT", "dependencies": { "ms": "^2.1.3" @@ -4586,7 +5089,6 @@ "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true, "license": "MIT" }, "node_modules/fast-glob": { @@ -4925,6 +5427,19 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/get-tsconfig": { + "version": "4.13.6", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.6.tgz", + "integrity": "sha512-shZT/QMiSHc/YBLxxOkMtgSid5HFoauqCE3/exfsEcwg1WkeqjG+V40yBbBrsD+jW2HDXcs28xOfcbm2jI8Ddw==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, "node_modules/glob": { "version": "11.1.0", "resolved": "https://registry.npmjs.org/glob/-/glob-11.1.0.tgz", @@ -5067,6 +5582,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/hash-sum": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/hash-sum/-/hash-sum-2.0.0.tgz", + "integrity": "sha512-WdZTbAByD+pHfl/g9QSsBIIwy8IT+EsPiKDs0KNX+zSHhdDLFKdZu0BQHljvO+0QI/BasbMSUa8wYNCZTvhslg==", + "license": "MIT" + }, "node_modules/hasown": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", @@ -5713,6 +6234,27 @@ "node": ">=6" } }, + "node_modules/light-bolt11-decoder": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/light-bolt11-decoder/-/light-bolt11-decoder-3.2.0.tgz", + "integrity": "sha512-3QEofgiBOP4Ehs9BI+RkZdXZNtSys0nsJ6fyGeSiAGCBsMwHGUDS/JQlY/sTnWs91A2Nh0S9XXfA8Sy9g6QpuQ==", + "license": "MIT", + "dependencies": { + "@scure/base": "1.1.1" + } + }, + "node_modules/light-bolt11-decoder/node_modules/@scure/base": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.1.tgz", + "integrity": "sha512-ZxOhsSyxYwLJj3pLZCefNitxsj093tb2vq90mp2txoYeBqbcjDjqFhyM8eUjq/uFm6zJ+mUuqxlS2FkuSY1MTA==", + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "license": "MIT" + }, "node_modules/lilconfig": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", @@ -5863,7 +6405,6 @@ "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true, "license": "MIT" }, "node_modules/muggle-string": { @@ -6550,6 +7091,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, "node_modules/reusify": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", @@ -6636,6 +7187,15 @@ "queue-microtask": "^1.2.2" } }, + "node_modules/rxjs": { + "version": "7.8.2", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", + "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.1.0" + } + }, "node_modules/safe-array-concat": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.3.tgz", @@ -7497,9 +8057,28 @@ "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/tsx": { + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.21.0.tgz", + "integrity": "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==", "dev": true, - "license": "0BSD", - "optional": true + "license": "MIT", + "peer": true, + "dependencies": { + "esbuild": "~0.27.0", + "get-tsconfig": "^4.7.5" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } }, "node_modules/type-fest": { "version": "0.16.0", diff --git a/package.json b/package.json index 21c10d3..47dd689 100644 --- a/package.json +++ b/package.json @@ -4,13 +4,23 @@ "version": "0.1.0", "type": "module", "scripts": { - "dev": "vite", + "dev": "vite --port 5174", + "start": "bash scripts/start.sh", "build": "vue-tsc -b && vite build", "preview": "vite preview", - "type-check": "vue-tsc --noEmit" + "type-check": "vue-tsc --noEmit", + "seed:profiles": "npx tsx scripts/seed-profiles.ts", + "seed:activity": "npx tsx scripts/seed-activity.ts", + "seed": "npx tsx scripts/seed-profiles.ts && npx tsx scripts/seed-activity.ts" }, "dependencies": { "@tanstack/vue-query": "^5.92.9", + "applesauce-accounts": "^5.1.0", + "applesauce-common": "^5.1.0", + "applesauce-core": "^5.1.0", + "applesauce-loaders": "^5.1.0", + "applesauce-relay": "^5.1.0", + "applesauce-signers": "^5.1.0", "axios": "^1.13.5", "nostr-tools": "^2.23.0", "pinia": "^3.0.4", @@ -25,6 +35,7 @@ "postcss": "^8.5.6", "sharp": "^0.34.5", "tailwindcss": "^3.4.18", + "tsx": "^4.21.0", "typescript": "~5.9.3", "vite": "^7.2.2", "vite-plugin-pwa": "^1.2.0", diff --git a/public/images/films/backdrops/2b0d7349-c010-47a0-b584-49e1bf86ab2f.jpg b/public/images/films/backdrops/2b0d7349-c010-47a0-b584-49e1bf86ab2f.jpg new file mode 100644 index 0000000..0fed161 Binary files /dev/null and b/public/images/films/backdrops/2b0d7349-c010-47a0-b584-49e1bf86ab2f.jpg differ diff --git a/public/images/films/backdrops/2b0d7349-c010-47a0-b584-49e1bf86ab2f.png b/public/images/films/backdrops/2b0d7349-c010-47a0-b584-49e1bf86ab2f.png deleted file mode 100644 index 06ae311..0000000 Binary files a/public/images/films/backdrops/2b0d7349-c010-47a0-b584-49e1bf86ab2f.png and /dev/null differ diff --git a/public/images/films/backdrops/3c113b66-3bb5-4cac-90eb-965ecedc4aa2.jpg b/public/images/films/backdrops/3c113b66-3bb5-4cac-90eb-965ecedc4aa2.jpg new file mode 100644 index 0000000..b1da90f Binary files /dev/null and b/public/images/films/backdrops/3c113b66-3bb5-4cac-90eb-965ecedc4aa2.jpg differ diff --git a/public/images/films/backdrops/3c113b66-3bb5-4cac-90eb-965ecedc4aa2.png b/public/images/films/backdrops/3c113b66-3bb5-4cac-90eb-965ecedc4aa2.png deleted file mode 100644 index 1bd6372..0000000 Binary files a/public/images/films/backdrops/3c113b66-3bb5-4cac-90eb-965ecedc4aa2.png and /dev/null differ diff --git a/public/images/films/backdrops/584f310b-2269-4b05-a09d-261a0a3c1f78.jpg b/public/images/films/backdrops/584f310b-2269-4b05-a09d-261a0a3c1f78.jpg new file mode 100644 index 0000000..70c49f2 Binary files /dev/null and b/public/images/films/backdrops/584f310b-2269-4b05-a09d-261a0a3c1f78.jpg differ diff --git a/public/images/films/backdrops/584f310b-2269-4b05-a09d-261a0a3c1f78.webp b/public/images/films/backdrops/584f310b-2269-4b05-a09d-261a0a3c1f78.webp deleted file mode 100644 index fbdd1ff..0000000 Binary files a/public/images/films/backdrops/584f310b-2269-4b05-a09d-261a0a3c1f78.webp and /dev/null differ diff --git a/public/images/films/backdrops/5bd753b7-9ff1-4966-a1c4-b3b93c62ed5d.jpg b/public/images/films/backdrops/5bd753b7-9ff1-4966-a1c4-b3b93c62ed5d.jpg new file mode 100644 index 0000000..90b63aa Binary files /dev/null and b/public/images/films/backdrops/5bd753b7-9ff1-4966-a1c4-b3b93c62ed5d.jpg differ diff --git a/public/images/films/backdrops/5bd753b7-9ff1-4966-a1c4-b3b93c62ed5d.webp b/public/images/films/backdrops/5bd753b7-9ff1-4966-a1c4-b3b93c62ed5d.webp deleted file mode 100644 index dafeccc..0000000 Binary files a/public/images/films/backdrops/5bd753b7-9ff1-4966-a1c4-b3b93c62ed5d.webp and /dev/null differ diff --git a/public/images/films/backdrops/665a4095-73b9-480d-a0a4-b2aafaf2bce4.jpg b/public/images/films/backdrops/665a4095-73b9-480d-a0a4-b2aafaf2bce4.jpg new file mode 100644 index 0000000..71741eb Binary files /dev/null and b/public/images/films/backdrops/665a4095-73b9-480d-a0a4-b2aafaf2bce4.jpg differ diff --git a/public/images/films/backdrops/665a4095-73b9-480d-a0a4-b2aafaf2bce4.png b/public/images/films/backdrops/665a4095-73b9-480d-a0a4-b2aafaf2bce4.png deleted file mode 100644 index b38717d..0000000 Binary files a/public/images/films/backdrops/665a4095-73b9-480d-a0a4-b2aafaf2bce4.png and /dev/null differ diff --git a/public/images/films/backdrops/bbdb0178-0b96-4ab5-addf-ba1f029c1cb3.jpg b/public/images/films/backdrops/bbdb0178-0b96-4ab5-addf-ba1f029c1cb3.jpg new file mode 100644 index 0000000..588d276 Binary files /dev/null and b/public/images/films/backdrops/bbdb0178-0b96-4ab5-addf-ba1f029c1cb3.jpg differ diff --git a/public/images/films/backdrops/bbdb0178-0b96-4ab5-addf-ba1f029c1cb3.webp b/public/images/films/backdrops/bbdb0178-0b96-4ab5-addf-ba1f029c1cb3.webp deleted file mode 100644 index c391dd2..0000000 Binary files a/public/images/films/backdrops/bbdb0178-0b96-4ab5-addf-ba1f029c1cb3.webp and /dev/null differ diff --git a/public/images/films/backdrops/god-bless-bitcoin.jpg b/public/images/films/backdrops/god-bless-bitcoin.jpg new file mode 100644 index 0000000..98e4438 Binary files /dev/null and b/public/images/films/backdrops/god-bless-bitcoin.jpg differ diff --git a/public/images/films/backdrops/god-bless-bitcoin.webp b/public/images/films/backdrops/god-bless-bitcoin.webp deleted file mode 100644 index 86aea34..0000000 Binary files a/public/images/films/backdrops/god-bless-bitcoin.webp and /dev/null differ diff --git a/scripts/seed-activity.ts b/scripts/seed-activity.ts new file mode 100644 index 0000000..cab793f --- /dev/null +++ b/scripts/seed-activity.ts @@ -0,0 +1,340 @@ +/** + * Seeds the local relay with reactions (kind 17) and comments (kind 1111) + * for all IndeeHub content, so the UI has real data to display. + * + * Run after seed-profiles.ts and with the relay already running. + */ +import { Relay } from 'applesauce-relay' +import { PrivateKeySigner } from 'applesauce-signers/signers/private-key-signer' +import { + TEST_PERSONAS, + TASTEMAKER_PERSONAS, +} from '../src/data/testPersonas.js' + +const RELAY_URL = 'ws://localhost:7777' +const ORIGIN = 'http://localhost:5174' + +// ── Content catalog (matching src/data/indeeHubFilms.ts) ────────── +const CONTENT = [ + { id: 'god-bless-bitcoin', title: 'God Bless Bitcoin' }, + { id: 'thethingswecarry', title: 'The Things We Carry' }, + { id: 'duel', title: 'Duel' }, + { id: '2b0d7349-c010-47a0-b584-49e1bf86ab2f', title: 'Hard Money' }, + { id: '665a4095-73b9-480d-a0a4-b2aafaf2bce4', title: 'Bitcoiners' }, + { id: '3c113b66-3bb5-4cac-90eb-965ecedc4aa2', title: 'Lekker Feeling' }, + { id: 'stranded', title: 'STRANDED' }, + { id: 'bbdb0178-0b96-4ab5-addf-ba1f029c1cb3', title: 'The Housing Bubble' }, + { id: '584f310b-2269-4b05-a09d-261a0a3c1f78', title: 'Menger' }, + { id: 'ef92cd99-7188-4c48-b4bf-0b31fdd8934e', title: 'Everybody Does It' }, + { id: 'e1bd64d6-63c9-4c91-8d91-c69f5376286e', title: 'Gods of Their Own Religion' }, + { id: 'forgingacountry', title: 'Forging a Country' }, + { id: 'home', title: 'HOME' }, + { id: 'e1f58162-9288-418e-803d-196dcde00782', title: 'Kismet' }, + { id: 'identity-theft', title: 'Identity Theft' }, + { id: 'comingto', title: 'Coming To' }, + { id: 'down-the-pch', title: 'Down the P.C.H.' }, + { id: '0cb9de15-566d-4130-b80c-d42e952bb803', title: 'Breaking Up Is Hard to Do' }, + { id: '24b6f7c6-8f56-40f2-831a-54f40b03c427', title: 'The Florist' }, + { id: '311f772f-6559-4982-8918-d0f4be9e1b76', title: 'Plastic Money' }, + { id: '5bd753b7-9ff1-4966-a1c4-b3b93c62ed5d', title: 'Time Traveling Thieves' }, + { id: '34f042bd-23d6-40f4-9707-4b3bb62fdd58', title: 'Little Billy' }, +] + +// ── helpers ────────────────────────────────────────────────────── +type Persona = { name: string; nsec: string; pubkey: string } + +function contentUrl(contentId: string): string { + return `${ORIGIN}/content/${contentId}` +} + +function pick(arr: T[], n: number): T[] { + const shuffled = [...arr].sort(() => Math.random() - 0.5) + return shuffled.slice(0, n) +} + +function randomInt(min: number, max: number): number { + return Math.floor(Math.random() * (max - min + 1)) + min +} + +// ── personas ──────────────────────────────────────────────────── +const allPersonas: Persona[] = [ + ...(TEST_PERSONAS as unknown as Persona[]), + ...(TASTEMAKER_PERSONAS as unknown as Persona[]), +] +const tastemakers: Persona[] = TASTEMAKER_PERSONAS as unknown as Persona[] + +const now = Math.floor(Date.now() / 1000) +const ONE_DAY = 86400 +const ONE_WEEK = 7 * ONE_DAY + +// Content subsets for different activity patterns +const topContent = CONTENT.slice(0, 8) +const midContent = CONTENT.slice(8, 16) +const trendingContent = pick(CONTENT.slice(0, 12), 5) +const tastemakerFaves = pick(CONTENT.slice(0, 10), 6) + +// ── sample comments ───────────────────────────────────────────── +const POSITIVE_COMMENTS = [ + 'Absolutely incredible film. A masterpiece in every sense.', + 'This movie changed my perspective on cinema. Must watch!', + 'The cinematography alone is worth the price of admission.', + 'One of the greatest performances I\'ve ever seen on screen.', + 'Every frame is a painting. Stunning work.', + 'I\'ve seen this at least 5 times and it gets better every watch.', + 'The screenplay is tight, the pacing is perfect.', + 'A landmark achievement in filmmaking.', + 'This deserves every award it got and more.', + 'Rewatched it last night — still holds up beautifully.', + 'Such an important documentary. Everyone should see this.', + 'The storytelling here is on another level.', +] + +const MIXED_COMMENTS = [ + 'Good but I think it\'s a bit overrated honestly.', + 'Solid film, though the third act drags a little.', + 'Worth watching once for sure, but I wouldn\'t rewatch.', + 'Technically impressive but emotionally I felt nothing.', + 'The hype is a bit much, but it\'s still a decent movie.', + 'Some great moments, but also some really slow stretches.', + 'I can see why people love it, just not my cup of tea.', + 'Better than I expected, worse than the reviews suggest.', +] + +const NEGATIVE_COMMENTS = [ + 'I really don\'t understand the hype around this one.', + 'Couldn\'t finish it. Way too slow for my taste.', + 'Overrated. There are much better films in this genre.', +] + +// ── publishing helper ─────────────────────────────────────────── +async function publishEvent( + relay: Relay, + signer: PrivateKeySigner, + event: { kind: number; content: string; tags: string[][]; created_at: number }, + label: string, +): Promise { + const signed = await signer.signEvent(event) + try { + const res = await relay.publish(signed, { timeout: 5000 }) + if (!res.ok) console.warn(` ⚠ ${label}: ${res.message}`) + return true + } catch (err) { + console.error(` ✗ ${label}:`, err instanceof Error ? err.message : err) + return false + } +} + +// ── seed reactions (kind 17) ──────────────────────────────────── +async function seedReactions(relay: Relay) { + console.log('\n📊 Seeding reactions (kind 17)...') + let count = 0 + + // Top content: lots of positive reactions + for (const item of topContent) { + const voters = pick(allPersonas, randomInt(5, 10)) + for (const persona of voters) { + const signer = PrivateKeySigner.fromKey(persona.nsec) + const emoji = Math.random() < 0.9 ? '+' : '-' + const age = randomInt(1 * ONE_DAY, 30 * ONE_DAY) + const ok = await publishEvent(relay, signer, { + kind: 17, + content: emoji, + tags: [ + ['i', contentUrl(item.id)], + ['k', 'web'], + ], + created_at: now - age, + }, `reaction ${persona.name}->${item.title}`) + if (ok) count++ + } + } + + // Mid content: moderate reactions, more mixed + for (const item of pick(midContent, 5)) { + const voters = pick(allPersonas, randomInt(2, 5)) + for (const persona of voters) { + const signer = PrivateKeySigner.fromKey(persona.nsec) + const emoji = Math.random() < 0.6 ? '+' : '-' + const age = randomInt(2 * ONE_DAY, 60 * ONE_DAY) + const ok = await publishEvent(relay, signer, { + kind: 17, + content: emoji, + tags: [ + ['i', contentUrl(item.id)], + ['k', 'web'], + ], + created_at: now - age, + }, `reaction ${persona.name}->${item.title}`) + if (ok) count++ + } + } + + // Trending content: recent reactions + for (const item of trendingContent) { + const voters = pick(allPersonas, randomInt(4, 8)) + for (const persona of voters) { + const signer = PrivateKeySigner.fromKey(persona.nsec) + const age = randomInt(0, ONE_WEEK) + const ok = await publishEvent(relay, signer, { + kind: 17, + content: '+', + tags: [ + ['i', contentUrl(item.id)], + ['k', 'web'], + ], + created_at: now - age, + }, `trending-reaction ${persona.name}->${item.title}`) + if (ok) count++ + } + } + + // Tastemaker-specific reactions + for (const item of tastemakerFaves) { + const voters = pick(tastemakers, randomInt(2, 5)) + for (const persona of voters) { + const signer = PrivateKeySigner.fromKey(persona.nsec) + const age = randomInt(0, 14 * ONE_DAY) + const ok = await publishEvent(relay, signer, { + kind: 17, + content: '+', + tags: [ + ['i', contentUrl(item.id)], + ['k', 'web'], + ], + created_at: now - age, + }, `tastemaker-reaction ${persona.name}->${item.title}`) + if (ok) count++ + } + } + + console.log(` ✓ ${count} reactions seeded`) +} + +// ── seed comments (kind 1111) ─────────────────────────────────── +async function seedComments(relay: Relay) { + console.log('\n💬 Seeding comments (kind 1111)...') + let count = 0 + + // Top content: several comments + for (const item of topContent) { + const url = contentUrl(item.id) + const commenters = pick(allPersonas, randomInt(2, 5)) + + for (const persona of commenters) { + const signer = PrivateKeySigner.fromKey(persona.nsec) + const comments = + Math.random() < 0.7 ? POSITIVE_COMMENTS : MIXED_COMMENTS + const content = comments[randomInt(0, comments.length - 1)] + const age = randomInt(1 * ONE_DAY, 30 * ONE_DAY) + + const ok = await publishEvent(relay, signer, { + kind: 1111, + content, + tags: [ + ['I', url], + ['K', 'web'], + ['i', url], + ['k', 'web'], + ], + created_at: now - age, + }, `comment ${persona.name}->${item.title}`) + if (ok) count++ + } + } + + // Mid content: occasional comments + for (const item of pick(midContent, 4)) { + const url = contentUrl(item.id) + const commenters = pick(allPersonas, randomInt(1, 2)) + + for (const persona of commenters) { + const signer = PrivateKeySigner.fromKey(persona.nsec) + const pool = [...MIXED_COMMENTS, ...NEGATIVE_COMMENTS] + const content = pool[randomInt(0, pool.length - 1)] + const age = randomInt(3 * ONE_DAY, 45 * ONE_DAY) + + const ok = await publishEvent(relay, signer, { + kind: 1111, + content, + tags: [ + ['I', url], + ['K', 'web'], + ['i', url], + ['k', 'web'], + ], + created_at: now - age, + }, `comment ${persona.name}->${item.title}`) + if (ok) count++ + } + } + + // Tastemaker reviews on their faves + for (const item of tastemakerFaves.slice(0, 4)) { + const url = contentUrl(item.id) + const reviewers = pick(tastemakers, randomInt(1, 3)) + + for (const persona of reviewers) { + const signer = PrivateKeySigner.fromKey(persona.nsec) + const content = POSITIVE_COMMENTS[randomInt(0, POSITIVE_COMMENTS.length - 1)] + const age = randomInt(0, 10 * ONE_DAY) + + const ok = await publishEvent(relay, signer, { + kind: 1111, + content, + tags: [ + ['I', url], + ['K', 'web'], + ['i', url], + ['k', 'web'], + ], + created_at: now - age, + }, `tastemaker-comment ${persona.name}->${item.title}`) + if (ok) count++ + } + } + + // Trending content: recent comments + for (const item of trendingContent.slice(0, 3)) { + const url = contentUrl(item.id) + const commenters = pick(allPersonas, randomInt(2, 4)) + + for (const persona of commenters) { + const signer = PrivateKeySigner.fromKey(persona.nsec) + const content = POSITIVE_COMMENTS[randomInt(0, POSITIVE_COMMENTS.length - 1)] + const age = randomInt(0, 3 * ONE_DAY) + + const ok = await publishEvent(relay, signer, { + kind: 1111, + content, + tags: [ + ['I', url], + ['K', 'web'], + ['i', url], + ['k', 'web'], + ], + created_at: now - age, + }, `trending-comment ${persona.name}->${item.title}`) + if (ok) count++ + } + } + + console.log(` ✓ ${count} comments seeded`) +} + +// ── main ──────────────────────────────────────────────────────── +async function main() { + console.log('🎬 Seeding activity data into relay at', RELAY_URL) + + const relay = new Relay(RELAY_URL) + + await seedReactions(relay) + await seedComments(relay) + + console.log('\n✅ Done! Activity seeded successfully.') + setTimeout(() => process.exit(0), 1000) +} + +main().catch((err) => { + console.error('Fatal:', err) + process.exit(1) +}) diff --git a/scripts/seed-profiles.ts b/scripts/seed-profiles.ts new file mode 100644 index 0000000..4bed5ff --- /dev/null +++ b/scripts/seed-profiles.ts @@ -0,0 +1,63 @@ +import { Relay } from 'applesauce-relay' +import { PrivateKeySigner } from 'applesauce-signers/signers/private-key-signer' +import { + TEST_PERSONAS, + TASTEMAKER_PERSONAS, +} from '../src/data/testPersonas.js' + +const RELAY_URL = 'ws://localhost:7777' + +type Persona = { name: string; nsec: string; pubkey: string } + +function buildProfile(persona: Persona, role: 'test' | 'tastemaker') { + const about = + role === 'tastemaker' + ? `${persona.name} — tastemaker for IndeeHub` + : `${persona.name} — test persona for IndeeHub` + + return { + name: persona.name, + display_name: persona.name, + about, + picture: `https://robohash.org/${persona.pubkey}.png`, + bot: true, + } +} + +async function seedProfiles() { + const relay = new Relay(RELAY_URL) + + const allPersonas: { persona: Persona; role: 'test' | 'tastemaker' }[] = [ + ...TEST_PERSONAS.map((p) => ({ persona: p as Persona, role: 'test' as const })), + ...TASTEMAKER_PERSONAS.map((p) => ({ persona: p as Persona, role: 'tastemaker' as const })), + ] + + const now = Math.floor(Date.now() / 1000) + + for (const { persona, role } of allPersonas) { + const signer = PrivateKeySigner.fromKey(persona.nsec) + const profile = buildProfile(persona, role) + + const signed = await signer.signEvent({ + kind: 0, + created_at: now, + tags: [], + content: JSON.stringify(profile), + }) + + try { + const res = await relay.publish(signed, { timeout: 5000 }) + console.log(`✓ ${persona.name} (${role}): ${res.ok ? 'OK' : res.message}`) + } catch (err) { + console.error(`✗ ${persona.name} (${role}):`, err) + } + } + + // Give relay time to flush, then exit + setTimeout(() => process.exit(0), 1000) +} + +seedProfiles().catch((err) => { + console.error('Fatal:', err) + process.exit(1) +}) diff --git a/scripts/start.sh b/scripts/start.sh new file mode 100755 index 0000000..5f2a221 --- /dev/null +++ b/scripts/start.sh @@ -0,0 +1,75 @@ +#!/usr/bin/env bash +set -e + +RELAY_PORT=7777 +RELAY_URL="ws://localhost:$RELAY_PORT" +VITE_PORT=5174 + +cleanup() { + echo "" + echo "Shutting down..." + # Kill background jobs (relay) + kill $(jobs -p) 2>/dev/null + exit 0 +} +trap cleanup SIGINT SIGTERM + +# Check that nak is installed +if ! command -v nak &>/dev/null; then + echo "Error: 'nak' is not installed." + echo "Install with: brew install nak" + exit 1 +fi + +# Kill any existing process on the relay port +if lsof -i :$RELAY_PORT -P &>/dev/null; then + echo "Port $RELAY_PORT is already in use, killing existing process..." + lsof -ti :$RELAY_PORT | xargs kill -9 2>/dev/null + sleep 1 +fi + +# Start the local relay in the background +echo "Starting local Nostr relay on port $RELAY_PORT..." +nak serve --port $RELAY_PORT & +RELAY_PID=$! + +# Wait for the relay to be ready +echo "Waiting for relay to be ready..." +for i in $(seq 1 30); do + if curl -s -o /dev/null http://localhost:$RELAY_PORT 2>/dev/null; then + echo "Relay is ready at $RELAY_URL (pid $RELAY_PID)" + break + fi + if ! kill -0 $RELAY_PID 2>/dev/null; then + echo "Error: relay process died unexpectedly" + exit 1 + fi + sleep 0.5 +done + +# Verify relay is actually responding +if ! curl -s -o /dev/null http://localhost:$RELAY_PORT 2>/dev/null; then + echo "Error: relay did not start in time" + kill $RELAY_PID 2>/dev/null + exit 1 +fi + +# Seed test profiles and activity +echo "" +echo "Seeding test profiles..." +npx tsx scripts/seed-profiles.ts + +echo "" +echo "Seeding activity (reactions & comments)..." +npx tsx scripts/seed-activity.ts +echo "" + +# Start the Vite dev server (in foreground so Ctrl+C works) +echo "Starting dev server..." +echo "============================================" +echo " Relay: $RELAY_URL (pid $RELAY_PID)" +echo " App: http://localhost:$VITE_PORT" +echo " Press Ctrl+C to stop everything" +echo "============================================" +echo "" +npx vite --port $VITE_PORT diff --git a/src/App.vue b/src/App.vue index 50a8560..88d13bd 100644 --- a/src/App.vue +++ b/src/App.vue @@ -1,9 +1,20 @@ + + diff --git a/src/components/ContentDetailModal.vue b/src/components/ContentDetailModal.vue index fcf0f00..bd96ed6 100644 --- a/src/components/ContentDetailModal.vue +++ b/src/components/ContentDetailModal.vue @@ -56,19 +56,31 @@ - - @@ -113,16 +125,18 @@

Comments - ({{ comments.length }}) - Demo Mode + ({{ commentCount }}) + Relay Offline

-
+
-
- {{ userInitials }} -
+ You