diff --git a/package-lock.json b/package-lock.json index 5924c6f..c784919 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,7 +12,15 @@ "@noble/hashes": "^1.4.0", "@poppanator/sveltekit-svg": "^4.2.1", "@sveltejs/adapter-static": "^3.0.4", - "@tiptap/starter-kit": "^2.6.4", + "@tiptap/extension-code": "^2.6.6", + "@tiptap/extension-code-block": "^2.6.6", + "@tiptap/extension-document": "^2.6.6", + "@tiptap/extension-dropcursor": "^2.6.6", + "@tiptap/extension-gapcursor": "^2.6.6", + "@tiptap/extension-hard-break": "^2.6.6", + "@tiptap/extension-history": "^2.6.6", + "@tiptap/extension-paragraph": "^2.6.6", + "@tiptap/extension-text": "^2.6.6", "@tiptap/suggestion": "^2.6.4", "@types/throttle-debounce": "^5.0.2", "@welshman/lib": "^0.0.15", @@ -1116,39 +1124,15 @@ } }, "node_modules/@tiptap/core": { - "version": "2.6.4", - "resolved": "https://registry.npmjs.org/@tiptap/core/-/core-2.6.4.tgz", - "integrity": "sha512-lv+JyBI+5C6C7BMLYg2bloB00HvAZkcvgO3CzmFia28Vtt1P9yhS44elvBemhUf7IP7Hu12FUzDWY+2GQqiqkw==", + "version": "2.6.6", + "resolved": "https://registry.npmjs.org/@tiptap/core/-/core-2.6.6.tgz", + "integrity": "sha512-VO5qTsjt6rwworkuo0s5AqYMfDA0ZwiTiH6FHKFSu2G/6sS7HKcc/LjPq+5Legzps4QYdBDl3W28wGsGuS1GdQ==", "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" }, "peerDependencies": { - "@tiptap/pm": "^2.6.4" - } - }, - "node_modules/@tiptap/extension-blockquote": { - "version": "2.6.4", - "resolved": "https://registry.npmjs.org/@tiptap/extension-blockquote/-/extension-blockquote-2.6.4.tgz", - "integrity": "sha512-BzeQ52qHL4AEryPqgvPNRJ2siSTfSi2s3k7hVC29QYUTOidLSSDWVihn7lzJoBnqDMAOYj7yUhnEUEdjvOFGqw==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/ueberdosis" - }, - "peerDependencies": { - "@tiptap/core": "^2.6.4" - } - }, - "node_modules/@tiptap/extension-bold": { - "version": "2.6.4", - "resolved": "https://registry.npmjs.org/@tiptap/extension-bold/-/extension-bold-2.6.4.tgz", - "integrity": "sha512-DIKUiO2aqO9D3dAQngBacWk/vYwDY13+q3t5dlawRTCIHxgV571vGb+YbcLswbWPQjOziIBc5QgwUVZLjA8OkA==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/ueberdosis" - }, - "peerDependencies": { - "@tiptap/core": "^2.6.4" + "@tiptap/pm": "^2.6.6" } }, "node_modules/@tiptap/extension-bubble-menu": { @@ -1168,66 +1152,54 @@ "@tiptap/pm": "^2.6.4" } }, - "node_modules/@tiptap/extension-bullet-list": { - "version": "2.6.4", - "resolved": "https://registry.npmjs.org/@tiptap/extension-bullet-list/-/extension-bullet-list-2.6.4.tgz", - "integrity": "sha512-SsEqWNvbcLjgPYQXWT+gm8Mdtd6SnM9kr5xdfOvfe9W1RCYi7U7SQjaYGLGQXuy3E8NDugNiG+ss2POMj4RaUQ==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/ueberdosis" - }, - "peerDependencies": { - "@tiptap/core": "^2.6.4" - } - }, "node_modules/@tiptap/extension-code": { - "version": "2.6.4", - "resolved": "https://registry.npmjs.org/@tiptap/extension-code/-/extension-code-2.6.4.tgz", - "integrity": "sha512-qCt/CRhV+s1E9XVCDxGgFwyQRjcLsqBuY5UTwH3Zp8MIBniyLyJDD0Rv9DgvVqalzRC8RoRxVey9Al3YhYNqsw==", + "version": "2.6.6", + "resolved": "https://registry.npmjs.org/@tiptap/extension-code/-/extension-code-2.6.6.tgz", + "integrity": "sha512-JrEFKsZiLvfvOFhOnnrpA0TzCuJjDeysfbMeuKUZNV4+DhYOL28d39H1++rEtJAX0LcbBU60oC5/PrlU9SpvRQ==", "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" }, "peerDependencies": { - "@tiptap/core": "^2.6.4" + "@tiptap/core": "^2.6.6" } }, "node_modules/@tiptap/extension-code-block": { - "version": "2.6.4", - "resolved": "https://registry.npmjs.org/@tiptap/extension-code-block/-/extension-code-block-2.6.4.tgz", - "integrity": "sha512-dnZYiKVNdHfqZqYgoCElLk8ETLlV3Q0rw3IVDKDTwrhanSSooGfkVts/Gn/jtJUIulRdu8lH/0qZCgM4ihznfw==", + "version": "2.6.6", + "resolved": "https://registry.npmjs.org/@tiptap/extension-code-block/-/extension-code-block-2.6.6.tgz", + "integrity": "sha512-1YLp/zHMHSkE2xzht8nPR6T4sQJJ3ket798czxWuQEbetFv/l0U/mpiPpYSLObj6oTAoqYZ0kWXZj5eQSpPB8Q==", "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" }, "peerDependencies": { - "@tiptap/core": "^2.6.4", - "@tiptap/pm": "^2.6.4" + "@tiptap/core": "^2.6.6", + "@tiptap/pm": "^2.6.6" } }, "node_modules/@tiptap/extension-document": { - "version": "2.6.4", - "resolved": "https://registry.npmjs.org/@tiptap/extension-document/-/extension-document-2.6.4.tgz", - "integrity": "sha512-fEQzou6J/w7GWiMqxxiwX2TEB6hgjBsImkHCxU05a4IOnIkzC8C9pV+NWa8u1LGvbERmVPBQqWYJG6phDhtYkg==", + "version": "2.6.6", + "resolved": "https://registry.npmjs.org/@tiptap/extension-document/-/extension-document-2.6.6.tgz", + "integrity": "sha512-6qlH5VWzLHHRVeeciRC6C4ZHpMsAGPNG16EF53z0GeMSaaFD/zU3B239QlmqXmLsAl8bpf8Bn93N0t2ABUvScw==", "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" }, "peerDependencies": { - "@tiptap/core": "^2.6.4" + "@tiptap/core": "^2.6.6" } }, "node_modules/@tiptap/extension-dropcursor": { - "version": "2.6.4", - "resolved": "https://registry.npmjs.org/@tiptap/extension-dropcursor/-/extension-dropcursor-2.6.4.tgz", - "integrity": "sha512-maTQi2R63i1S3CCJTjyuHMpk0BvnFuUxq7krZ3LBCOJgUeS78PF/XPirbbR7s2jOVsHK77LYsgdoS3ApDu1zdQ==", + "version": "2.6.6", + "resolved": "https://registry.npmjs.org/@tiptap/extension-dropcursor/-/extension-dropcursor-2.6.6.tgz", + "integrity": "sha512-O6CeKriA9uyHsg7Ui4z5ZjEWXQxrIL+1zDekffW0wenGC3G4LUsCzAiFS4LSrR9a3u7tnwqGApW10rdkmCGF4w==", "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" }, "peerDependencies": { - "@tiptap/core": "^2.6.4", - "@tiptap/pm": "^2.6.4" + "@tiptap/core": "^2.6.6", + "@tiptap/pm": "^2.6.6" } }, "node_modules/@tiptap/extension-floating-menu": { @@ -1261,66 +1233,41 @@ } }, "node_modules/@tiptap/extension-gapcursor": { - "version": "2.6.4", - "resolved": "https://registry.npmjs.org/@tiptap/extension-gapcursor/-/extension-gapcursor-2.6.4.tgz", - "integrity": "sha512-g5fa1RLNpFZoiE5PIvG/pFIz88CvtiWkBUp5OOYrPxNzByazcbBsBI8Sa5ptDVrbDqerayUZYAVFPhXnq7MSlQ==", + "version": "2.6.6", + "resolved": "https://registry.npmjs.org/@tiptap/extension-gapcursor/-/extension-gapcursor-2.6.6.tgz", + "integrity": "sha512-O2lQ2t0X0Vsbn3yLWxFFHrXY6C2N9Y6ZF/M7LWzpcDTUZeWuhoNkFE/1yOM0h6ZX1DO2A9hNIrKpi5Ny8yx+QA==", "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" }, "peerDependencies": { - "@tiptap/core": "^2.6.4", - "@tiptap/pm": "^2.6.4" + "@tiptap/core": "^2.6.6", + "@tiptap/pm": "^2.6.6" } }, "node_modules/@tiptap/extension-hard-break": { - "version": "2.6.4", - "resolved": "https://registry.npmjs.org/@tiptap/extension-hard-break/-/extension-hard-break-2.6.4.tgz", - "integrity": "sha512-kBGGSBtp9oQlRBH7PfRvhbrauEphiJEuFUP9n/amAbrrNSabwmvBgyMl6wFXgMdfHF6CSv2YDgndE1sk8SjPSg==", + "version": "2.6.6", + "resolved": "https://registry.npmjs.org/@tiptap/extension-hard-break/-/extension-hard-break-2.6.6.tgz", + "integrity": "sha512-bsUuyYBrMDEiudx1dOQSr9MzKv13m0xHWrOK+DYxuIDYJb5g+c9un5cK7Js+et/HEYYSPOoH/iTW6h+4I5YeUg==", "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" }, "peerDependencies": { - "@tiptap/core": "^2.6.4" - } - }, - "node_modules/@tiptap/extension-heading": { - "version": "2.6.4", - "resolved": "https://registry.npmjs.org/@tiptap/extension-heading/-/extension-heading-2.6.4.tgz", - "integrity": "sha512-GHwDguzRXRrB5htGPx6T0f0uN9RPAkjbjrl28T7LFXX5Lb2XO+Esr1l4LNsTU49H4wR9nL/89ZjEcd36BUWkog==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/ueberdosis" - }, - "peerDependencies": { - "@tiptap/core": "^2.6.4" + "@tiptap/core": "^2.6.6" } }, "node_modules/@tiptap/extension-history": { - "version": "2.6.4", - "resolved": "https://registry.npmjs.org/@tiptap/extension-history/-/extension-history-2.6.4.tgz", - "integrity": "sha512-Hr3SrvMsyDHKcsF4u3QPdY/NBYG9V0g5pPmZs/tdysXot3NUdkEYowjs9K9o5osKom364KjxQS0c9mOjyeKu1g==", + "version": "2.6.6", + "resolved": "https://registry.npmjs.org/@tiptap/extension-history/-/extension-history-2.6.6.tgz", + "integrity": "sha512-tPTzAmPGqMX5Bd5H8lzRpmsaMvB9DvI5Dy2za/VQuFtxgXmDiFVgHRkRXIuluSkPTuANu84XBOQ0cBijqY8x4w==", "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" }, "peerDependencies": { - "@tiptap/core": "^2.6.4", - "@tiptap/pm": "^2.6.4" - } - }, - "node_modules/@tiptap/extension-horizontal-rule": { - "version": "2.6.4", - "resolved": "https://registry.npmjs.org/@tiptap/extension-horizontal-rule/-/extension-horizontal-rule-2.6.4.tgz", - "integrity": "sha512-lL29Hxsj1qFwRqtg41JlBOK/hmN+qnwIWvNCyZpKEVHs7d0iELj2REB/7R1KKAAdsvYo7pJrgqwBd1Ph6xRLpw==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/ueberdosis" - }, - "peerDependencies": { - "@tiptap/core": "^2.6.4", - "@tiptap/pm": "^2.6.4" + "@tiptap/core": "^2.6.6", + "@tiptap/pm": "^2.6.6" } }, "node_modules/@tiptap/extension-image": { @@ -1335,18 +1282,6 @@ "@tiptap/core": "^2.6.4" } }, - "node_modules/@tiptap/extension-italic": { - "version": "2.6.4", - "resolved": "https://registry.npmjs.org/@tiptap/extension-italic/-/extension-italic-2.6.4.tgz", - "integrity": "sha512-XG/zaKVuorKr1vGEWEgLQTnQwOpNn/JyGxO7oC7wfYx5eYpbbCtMTEMvuqNvkm7kpvVAUx3ugi/D8DWyWZEtYg==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/ueberdosis" - }, - "peerDependencies": { - "@tiptap/core": "^2.6.4" - } - }, "node_modules/@tiptap/extension-link": { "version": "2.6.4", "resolved": "https://registry.npmjs.org/@tiptap/extension-link/-/extension-link-2.6.4.tgz", @@ -1363,70 +1298,34 @@ "@tiptap/pm": "^2.6.4" } }, - "node_modules/@tiptap/extension-list-item": { - "version": "2.6.4", - "resolved": "https://registry.npmjs.org/@tiptap/extension-list-item/-/extension-list-item-2.6.4.tgz", - "integrity": "sha512-NLP0nshX8eCZMLospdCsUApUQHPL1+T/MIi/Hhr0aNeaAg7KwBNH8/rFPuxPNs4BQkHOCuYq4Fm+klkebkFYJA==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/ueberdosis" - }, - "peerDependencies": { - "@tiptap/core": "^2.6.4" - } - }, - "node_modules/@tiptap/extension-ordered-list": { - "version": "2.6.4", - "resolved": "https://registry.npmjs.org/@tiptap/extension-ordered-list/-/extension-ordered-list-2.6.4.tgz", - "integrity": "sha512-ecAEFpRKZc+b3f54EGvaRp7hsVza2i1nRhxHoPElqVR5DiCCSuSgAPCsKhUUT1rKweK9h56HiC4xswAyFrU5Ag==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/ueberdosis" - }, - "peerDependencies": { - "@tiptap/core": "^2.6.4" - } - }, "node_modules/@tiptap/extension-paragraph": { - "version": "2.6.4", - "resolved": "https://registry.npmjs.org/@tiptap/extension-paragraph/-/extension-paragraph-2.6.4.tgz", - "integrity": "sha512-JVlvhZPzjz0Q+29KmnrmLr3A3SvAMfKOZxbZZVnzee6vtI6rqjdYGBOtyyyWwrAliNQB6GkHiKmT3GxH76dz7A==", + "version": "2.6.6", + "resolved": "https://registry.npmjs.org/@tiptap/extension-paragraph/-/extension-paragraph-2.6.6.tgz", + "integrity": "sha512-fD/onCr16UQWx+/xEmuFC2MccZZ7J5u4YaENh8LMnAnBXf78iwU7CAcmuc9rfAEO3qiLoYGXgLKiHlh2ZfD4wA==", "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" }, "peerDependencies": { - "@tiptap/core": "^2.6.4" - } - }, - "node_modules/@tiptap/extension-strike": { - "version": "2.6.4", - "resolved": "https://registry.npmjs.org/@tiptap/extension-strike/-/extension-strike-2.6.4.tgz", - "integrity": "sha512-EV4hEA5qnRtKViaLKcucFvXP9xEUJOFgpFeOrp2xIgSXJLSmutkaDfz7nxJ2RLzwwYvPfWUL7ay97JSCzSuaIA==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/ueberdosis" - }, - "peerDependencies": { - "@tiptap/core": "^2.6.4" + "@tiptap/core": "^2.6.6" } }, "node_modules/@tiptap/extension-text": { - "version": "2.6.4", - "resolved": "https://registry.npmjs.org/@tiptap/extension-text/-/extension-text-2.6.4.tgz", - "integrity": "sha512-QfspuCTTpmFrSLbDs2z/0W7GLaoNanwj4OCKPSPz5XcraZJgFLsWAqZxZE4aLgZbJH2hcGWMe5ZHmvLf5dJogw==", + "version": "2.6.6", + "resolved": "https://registry.npmjs.org/@tiptap/extension-text/-/extension-text-2.6.6.tgz", + "integrity": "sha512-e84uILnRzNzcwK1DVQNpXVmBG1Cq3BJipTOIDl1LHifOok7MBjhI/X+/NR0bd3N2t6gmDTWi63+4GuJ5EeDmsg==", "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" }, "peerDependencies": { - "@tiptap/core": "^2.6.4" + "@tiptap/core": "^2.6.6" } }, "node_modules/@tiptap/pm": { - "version": "2.6.4", - "resolved": "https://registry.npmjs.org/@tiptap/pm/-/pm-2.6.4.tgz", - "integrity": "sha512-k/AyigUioZVxFTcF7kWcUh5xeOV0bdGzHz+wmtP33md2jo8SJP29yEZ4Kshvk0IcFnVFEDrsfKiGhLRWpKx+YQ==", + "version": "2.6.6", + "resolved": "https://registry.npmjs.org/@tiptap/pm/-/pm-2.6.6.tgz", + "integrity": "sha512-56FGLPn3fwwUlIbLs+BO21bYfyqP9fKyZQbQyY0zWwA/AG2kOwoXaRn7FOVbjP6CylyWpFJnpRRmgn694QKHEg==", "dependencies": { "prosemirror-changeset": "^2.2.1", "prosemirror-collab": "^1.3.1", @@ -1452,37 +1351,6 @@ "url": "https://github.com/sponsors/ueberdosis" } }, - "node_modules/@tiptap/starter-kit": { - "version": "2.6.4", - "resolved": "https://registry.npmjs.org/@tiptap/starter-kit/-/starter-kit-2.6.4.tgz", - "integrity": "sha512-uvGXOI6h+AjyyOgJOmBSFrDR7xJ841+gtwzGbAolVM2a7LCEkocyHjLBWFYVfQu2vvMIqA63+0+yAsw6ghwUgw==", - "dependencies": { - "@tiptap/core": "^2.6.4", - "@tiptap/extension-blockquote": "^2.6.4", - "@tiptap/extension-bold": "^2.6.4", - "@tiptap/extension-bullet-list": "^2.6.4", - "@tiptap/extension-code": "^2.6.4", - "@tiptap/extension-code-block": "^2.6.4", - "@tiptap/extension-document": "^2.6.4", - "@tiptap/extension-dropcursor": "^2.6.4", - "@tiptap/extension-gapcursor": "^2.6.4", - "@tiptap/extension-hard-break": "^2.6.4", - "@tiptap/extension-heading": "^2.6.4", - "@tiptap/extension-history": "^2.6.4", - "@tiptap/extension-horizontal-rule": "^2.6.4", - "@tiptap/extension-italic": "^2.6.4", - "@tiptap/extension-list-item": "^2.6.4", - "@tiptap/extension-ordered-list": "^2.6.4", - "@tiptap/extension-paragraph": "^2.6.4", - "@tiptap/extension-strike": "^2.6.4", - "@tiptap/extension-text": "^2.6.4", - "@tiptap/pm": "^2.6.4" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/ueberdosis" - } - }, "node_modules/@tiptap/suggestion": { "version": "2.6.4", "resolved": "https://registry.npmjs.org/@tiptap/suggestion/-/suggestion-2.6.4.tgz", diff --git a/package.json b/package.json index beaa68e..5614fbf 100644 --- a/package.json +++ b/package.json @@ -37,7 +37,15 @@ "@noble/hashes": "^1.4.0", "@poppanator/sveltekit-svg": "^4.2.1", "@sveltejs/adapter-static": "^3.0.4", - "@tiptap/starter-kit": "^2.6.4", + "@tiptap/extension-code": "^2.6.6", + "@tiptap/extension-code-block": "^2.6.6", + "@tiptap/extension-document": "^2.6.6", + "@tiptap/extension-dropcursor": "^2.6.6", + "@tiptap/extension-gapcursor": "^2.6.6", + "@tiptap/extension-hard-break": "^2.6.6", + "@tiptap/extension-history": "^2.6.6", + "@tiptap/extension-paragraph": "^2.6.6", + "@tiptap/extension-text": "^2.6.6", "@tiptap/suggestion": "^2.6.4", "@types/throttle-debounce": "^5.0.2", "@welshman/lib": "^0.0.15", diff --git a/src/app/base.ts b/src/app/base.ts index 289f1a0..e35a250 100644 --- a/src/app/base.ts +++ b/src/app/base.ts @@ -1,6 +1,6 @@ import {derived} from "svelte/store" import {memoize, assoc} from "@welshman/lib" -import type {TrustedEvent} from "@welshman/util" +import type {TrustedEvent, HashedEvent} from "@welshman/util" import {Repository, createEvent, Relay} from "@welshman/util" import {withGetter} from "@welshman/store" import {NetworkContext, Tracker} from "@welshman/net" @@ -8,13 +8,17 @@ import {Nip46Broker, Nip46Signer, Nip07Signer, Nip01Signer} from "@welshman/sign import {synced} from "@lib/util" import type {Session} from "@app/types" -export const DEFAULT_RELAYS = ["wss://groups.fiatjaf.com/"] +export const DEFAULT_RELAYS = [ + "wss://groups.fiatjaf.com/", + "wss://relay29.galaxoidlabs.com/", + "wss://devrelay.highlighter.com/", +] export const INDEXER_RELAYS = ["wss://purplepag.es/", "wss://relay.damus.io/", "wss://nos.lol/"] export const DUFFLEPUD_URL = "https://dufflepud.onrender.com" -export const repository = new Repository() +export const repository = new Repository() export const relay = new Relay(repository) diff --git a/src/app/commands.ts b/src/app/commands.ts index edfe46b..f9a9680 100644 --- a/src/app/commands.ts +++ b/src/app/commands.ts @@ -1,6 +1,7 @@ -import {uniqBy, uniq, now} from "@welshman/lib" +import {uniqBy, uniq, now, choice} from "@welshman/lib" import { GROUPS, + GROUP_JOIN, asDecryptedEvent, getGroupTags, getRelayTagValues, @@ -9,6 +10,7 @@ import { makeList, createList, createEvent, + displayProfile, } from "@welshman/util" import {pk, signer, repository, INDEXER_RELAYS} from "@app/base" import { @@ -23,8 +25,34 @@ import { makeThunk, publishThunk, ensurePlaintext, + getProfilesByPubkey, } from "@app/state" +// Utils + +export const getPubkeyHints = (pubkey: string) => { + const selections = getRelaySelectionsByPubkey().get(pubkey) + const relays = selections ? getWriteRelayUrls(selections) : [] + const hints = relays.length ? relays : INDEXER_RELAYS + + return hints +} + +export const getPubkeyPetname = (pubkey: string) => { + const profile = getProfilesByPubkey().get(pubkey) + const display = displayProfile(profile) + + return display +} + +export const makeMention = (pubkey: string, hints?: string[]) => + ["p", pubkey, choice(hints || getPubkeyHints(pubkey)), getPubkeyPetname(pubkey)] + +export const makeIMeta = (url: string, data: Record) => + ["imeta", `url ${url}`, ...Object.entries(data).map(([k, v]) => [k, v].join(' '))] + +// Loaders + export const loadUserData = async (pubkey: string, hints: string[] = []) => { const relaySelections = await loadRelaySelections(pubkey, INDEXER_RELAYS) const relays = uniq([ @@ -46,6 +74,8 @@ export const loadUserData = async (pubkey: string, hints: string[] = []) => { await Promise.all(promises) } +// Updates + export type ModifyTags = (tags: string[][]) => string[][] export const updateList = async (kind: number, modifyTags: ModifyTags) => { @@ -67,3 +97,10 @@ export const addGroupMemberships = (newTags: string[][]) => export const removeGroupMemberships = (noms: string[]) => updateList(GROUPS, (tags: string[][]) => tags.filter(t => !noms.includes(t[1]))) + +export const sendJoinRequest = async (nom: string, url: string) => { + const event = createEvent(GROUP_JOIN, {tags: [["h", nom]]}) + const result = await publishThunk(makeThunk({event, relays: [url]})) + + return result[url] +} diff --git a/src/app/components/GroupCompose.svelte b/src/app/components/GroupCompose.svelte index d0b4f5c..4af5ea5 100644 --- a/src/app/components/GroupCompose.svelte +++ b/src/app/components/GroupCompose.svelte @@ -1,9 +1,17 @@ diff --git a/src/app/components/GroupComposeBolt11.svelte b/src/app/components/GroupComposeBolt11.svelte index 2f80b11..5be8d9c 100644 --- a/src/app/components/GroupComposeBolt11.svelte +++ b/src/app/components/GroupComposeBolt11.svelte @@ -1,10 +1,20 @@ - - {node.attrs.lnbc.slice(0, 16)}... + + diff --git a/src/app/components/GroupComposeMention.svelte b/src/app/components/GroupComposeMention.svelte index d50b8b5..7a9bb4d 100644 --- a/src/app/components/GroupComposeMention.svelte +++ b/src/app/components/GroupComposeMention.svelte @@ -7,10 +7,13 @@ import {deriveProfile} from '@app/state' export let node: NodeViewProps['node'] + export let selected: NodeViewProps['selected'] $: profile = deriveProfile(node.attrs.pubkey, node.attrs.relays) - @{displayProfile($profile)} + + @{displayProfile($profile)} + diff --git a/src/app/components/GroupComposeTopic.svelte b/src/app/components/GroupComposeTopic.svelte index 7168eff..105b39a 100644 --- a/src/app/components/GroupComposeTopic.svelte +++ b/src/app/components/GroupComposeTopic.svelte @@ -1,10 +1,15 @@ - - #{node.attrs.name} + + + #{node.attrs.name} + diff --git a/src/app/components/GroupNote.svelte b/src/app/components/GroupNote.svelte index 5c8040f..2a2f2c0 100644 --- a/src/app/components/GroupNote.svelte +++ b/src/app/components/GroupNote.svelte @@ -1,13 +1,15 @@
@@ -65,13 +74,28 @@ {#if showPubkey} {:else} -
+
{/if}
{#if showPubkey} {$profileDisplay} {/if} -

{event.content}

+

+ {event.content} + {#if isPending} + + + Sending... + + {:else if failure} + + + Failed to send! + + {/if} +

+ import {displayRelayUrl} from '@welshman/util' import Button from "@lib/components/Button.svelte" import Link from "@lib/components/Link.svelte" import Icon from "@lib/components/Icon.svelte" + import {DEFAULT_RELAYS} from "@app/base" import {clip} from "@app/toast" @@ -21,14 +23,16 @@ >. If you do decide to join someone else's, make sure to follow their directions for registering as a user.

-
-
- - groups.fiatjaf.com + {#each DEFAULT_RELAYS as url} +
+
+ + {displayRelayUrl(url)} +
+
- -
+ {/each}
diff --git a/src/app/components/PrimaryNav.svelte b/src/app/components/PrimaryNav.svelte index fbb2c1c..f21b4fe 100644 --- a/src/app/components/PrimaryNav.svelte +++ b/src/app/components/PrimaryNav.svelte @@ -52,9 +52,12 @@ {#each $userGroupsByNom.entries() as [nom, qualifiedGroups] (nom)} {@const qualifiedGroup = qualifiedGroups[0]} -
- {displayGroup(qualifiedGroup?.group)} -
+
{/each} diff --git a/src/app/components/SpaceJoin.svelte b/src/app/components/SpaceJoin.svelte index 5b7643f..cea1ffc 100644 --- a/src/app/components/SpaceJoin.svelte +++ b/src/app/components/SpaceJoin.svelte @@ -1,14 +1,17 @@ {#if $toast} + {@const theme = $toast.theme || "info"} {#key $toast.id}
diff --git a/src/app/state.ts b/src/app/state.ts index a96b615..c62f137 100644 --- a/src/app/state.ts +++ b/src/app/state.ts @@ -5,6 +5,7 @@ import {get, writable, readable, derived} from "svelte/store" import type {Maybe} from "@welshman/lib" import { max, + append, between, uniqBy, groupBy, @@ -38,6 +39,8 @@ import { displayPubkey, GROUP_JOIN, GROUP_ADD_USER, + isStampedEvent, + isEventTemplate, } from "@welshman/util" import type {SignedEvent, HashedEvent, EventTemplate, TrustedEvent, PublishedProfile, PublishedList} from "@welshman/util" import type {SubscribeRequest, PublishRequest} from "@welshman/net" @@ -129,9 +132,13 @@ export type Thunk = { relays: string[] } -export const thunkWorker = new Worker() +export type ThunkWithResolve = Thunk & { + resolve: (data: PublishStatusDataByUrl) => void +} -thunkWorker.addGlobalHandler(async ({event, relays}: Thunk) => { +export const thunkWorker = new Worker() + +thunkWorker.addGlobalHandler(async ({event, relays, resolve}: ThunkWithResolve) => { const session = getSession(event.pubkey) if (!session) { @@ -139,26 +146,20 @@ thunkWorker.addGlobalHandler(async ({event, relays}: Thunk) => { } const signedEvent = await getSigner(session)!.sign(event) - const savedEvent = repository.getEvent(signedEvent.id) const pub = basePublish({event: signedEvent, relays}) // Copy the signature over since we had deferred it - if (savedEvent) { - savedEvent.sig = signedEvent.sig - } + ;(repository.getEvent(signedEvent.id) as SignedEvent).sig = signedEvent.sig - const failures = new Set() + // Track publish success + const {id} = event + const statusByUrl: PublishStatusDataByUrl = {} - // Watch for failures - pub.emitter.on('*', (status: PublishStatus, url: string) => { - console.log('pub status', status, url) + pub.emitter.on('*', (status: PublishStatus, url: string, message: string) => { + publishStatusData.update(assoc(id, Object.assign(statusByUrl, {[url]: {id, url, status, message}}))) - if ([PublishStatus.Failure, PublishStatus.Timeout].includes(status)) { - failures.add(url) - } - - if (failures.size === relays.length) { - console.warn("Failed to publish", pub) + if (Object.values(statusByUrl).filter(s => s.status !== PublishStatus.Pending).length === relays.length) { + resolve(statusByUrl) } }) }) @@ -178,17 +179,20 @@ export const makeThunk = ({event, relays}: ThunkParams) => { return {event: hash(own(stamp(event), $pk)), relays} } -export const publishThunk = (thunk: Thunk) => { - thunkWorker.push(thunk) - repository.publish(thunk.event) -} +export const publishThunk = (thunk: Thunk) => + new Promise(resolve => { + thunkWorker.push({...thunk, resolve}) + repository.publish(thunk.event) + }) // Subscribe export const subscribe = (request: SubscribeRequest) => { const sub = baseSubscribe({delay: 50, authTimeout: 3000, ...request}) - sub.emitter.on("event", (url: string, e: SignedEvent) => repository.publish(e)) + sub.emitter.on("event", (url: string, e: SignedEvent) => { + repository.publish(e) + }) return sub } @@ -198,14 +202,27 @@ export const load = (request: SubscribeRequest) => const sub = subscribe({closeOnEose: true, timeout: 3000, ...request}) const events: TrustedEvent[] = [] - sub.emitter.on("event", (url: string, e: SignedEvent) => { - repository.publish(e) - events.push(e) - }) + sub.emitter.on("event", (url: string, e: SignedEvent) => events.push(e)) sub.emitter.on("complete", () => resolve(events)) }) +// Publish status + +export type PublishStatusData = { + id: string + url: string + message: string + status: PublishStatus +} + + +export type PublishStatusDataByUrl = Record + +export type PublishStatusDataByUrlById = Record + +export const publishStatusData = writable({}) + // Freshness export const freshness = withGetter(writable>({})) @@ -255,7 +272,7 @@ export type Topic = { count: number } -export const topics = custom(setter => { +export const topics = custom(setter => { const getTopics = () => { const topics = new Map() for (const tagString of repository.eventsByTag.keys()) { @@ -290,7 +307,7 @@ export const searchTopics = derived(topics, $topics => export const relays = writable([]) export const relaysByPubkey = derived(relays, $relays => - groupBy(($relay: Relay) => $relay.pubkey, $relays), + groupBy(($relay: Relay) => $relay.pubkey, $relays.filter(r => r.pubkey)), ) export const { @@ -508,7 +525,7 @@ export const getGroupName = (e?: TrustedEvent) => e?.tags.find(nthEq(0, "name")) export const getGroupPicture = (e?: TrustedEvent) => e?.tags.find(nthEq(0, "picture"))?.[1] -export const displayGroup = (group?: Group) => group?.name || "[no name]" +export const displayGroup = (group?: Group) => group?.name || group?.nom || "[no name]" export type Group = { nom: string @@ -524,8 +541,8 @@ export type PublishedGroup = Omit & { export const readGroup = (event: TrustedEvent) => { const nom = getIdentifier(event)! - const name = event?.tags.find(nthEq(0, "name"))?.[1] || "[no name]" - const about = event?.tags.find(nthEq(0, "about"))?.[1] || "" + const name = event?.tags.find(nthEq(0, "name"))?.[1] + const about = event?.tags.find(nthEq(0, "about"))?.[1] const picture = event?.tags.find(nthEq(0, "picture"))?.[1] return {nom, name, about, picture, event} @@ -759,3 +776,18 @@ export const userGroupsByNom = withGetter( return $userGroupsByNom }), ) + +export const userRelayUrlsByNom = derived( + userGroupsByNom, + $userGroupsByNom => { + const $userRelayUrlsByNom = new Map() + + for (const [nom, groups] of $userGroupsByNom.entries()) { + for (const group of groups) { + pushToMapKey($userRelayUrlsByNom, nom, group.relay.url) + } + } + + return $userRelayUrlsByNom + } +) diff --git a/src/app/storage.ts b/src/app/storage.ts index 063fced..12bbc94 100644 --- a/src/app/storage.ts +++ b/src/app/storage.ts @@ -21,8 +21,6 @@ export const subs: Unsubscriber[] = [] export const DB_NAME = "flotilla" -export const DB_VERSION = 1 - export const getAll = async (name: string) => { const tx = db.transaction(name, "readwrite") const store = tx.objectStore(name) @@ -81,12 +79,12 @@ export const initIndexedDbAdapter = async (name: string, adapter: IndexedDbAdapt ) } -export const initStorage = async (adapters: Record) => { +export const initStorage = async (version: number, adapters: Record) => { if (!window.indexedDB) return window.addEventListener("beforeunload", () => closeStorage()) - db = await openDB(DB_NAME, DB_VERSION, { + db = await openDB(DB_NAME, version, { upgrade(db: IDBPDatabase) { const names = Object.keys(adapters) diff --git a/src/assets/icons/Bolt.svg b/src/assets/icons/Bolt.svg new file mode 100644 index 0000000..2de5140 --- /dev/null +++ b/src/assets/icons/Bolt.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/icons/Danger.svg b/src/assets/icons/Danger.svg new file mode 100644 index 0000000..4553fc5 --- /dev/null +++ b/src/assets/icons/Danger.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/lib/components/Avatar.svelte b/src/lib/components/Avatar.svelte index 564bf75..118d097 100644 --- a/src/lib/components/Avatar.svelte +++ b/src/lib/components/Avatar.svelte @@ -3,15 +3,17 @@ import Icon from "@lib/components/Icon.svelte" export let src + export let alt = "" export let size = 7 + export let icon = "user-rounded"
{#if src} - + {:else} - + {/if}
diff --git a/src/lib/components/Icon.svelte b/src/lib/components/Icon.svelte index d299d3e..fd9a573 100644 --- a/src/lib/components/Icon.svelte +++ b/src/lib/components/Icon.svelte @@ -6,6 +6,7 @@
diff --git a/src/lib/tiptap/util.ts b/src/lib/tiptap/util.ts index d20d558..44ed5b8 100644 --- a/src/lib/tiptap/util.ts +++ b/src/lib/tiptap/util.ts @@ -5,7 +5,7 @@ export const createPasteRuleMatch = >( data: T, ): PasteRuleMatch => ({ index: match.index!, replaceWith: match[2], text: match[0], match, data }) -export const findNodes = (json: JSONContent, type: string) => { +export const findNodes = (type: string, json: JSONContent) => { const results: JSONContent[] = [] for (const node of json.content || []) { @@ -13,7 +13,7 @@ export const findNodes = (json: JSONContent, type: string) => { results.push(node) } - for (const result of findNodes(node, type)) { + for (const result of findNodes(type, node)) { results.push(result) } } diff --git a/src/lib/transition.ts b/src/lib/transition.ts index b9ddc61..b46acd0 100644 --- a/src/lib/transition.ts +++ b/src/lib/transition.ts @@ -1,5 +1,7 @@ import type {FlyParams} from "svelte/transition" import {fly as baseFly} from "svelte/transition" +export {fade} from 'svelte/transition' + export const fly = (node: Element, params?: FlyParams | undefined) => baseFly(node, {y: 20, ...params}) diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte index 833a2e6..d0a1673 100644 --- a/src/routes/+layout.svelte +++ b/src/routes/+layout.svelte @@ -1,10 +1,11 @@