diff --git a/package.json b/package.json
index c75d72f..fecaa33 100644
--- a/package.json
+++ b/package.json
@@ -68,6 +68,7 @@
"daisyui": "^4.4",
"dayjs": "^1.11.10",
"highlight.js": "^11.9.0",
+ "nostr-tools": "^2.5.0",
"parse-diff": "^0.11.1",
"ramda": "^0.29.1",
"svelte-markdown": "^0.4.1"
diff --git a/src/lib/components/events/content/ParsedContent.svelte b/src/lib/components/events/content/ParsedContent.svelte
index 1eeadc3..2567eb3 100644
--- a/src/lib/components/events/content/ParsedContent.svelte
+++ b/src/lib/components/events/content/ParsedContent.svelte
@@ -4,10 +4,13 @@
isImage,
isParsedLink,
isParsedNewLine,
+ isParsedNprofile,
+ isParsedNpub,
isParsedText,
parseContent,
type ParsedPart,
} from './utils'
+ import UserHeader from '$lib/components/users/UserHeader.svelte'
export let content: string = ''
export let tags: NDKTag[] = []
@@ -31,6 +34,10 @@
{part.url.replace(/https?:\/\/(www\.)?/, '')}
{/if}
+ {:else if isParsedNpub(part) || isParsedNprofile(part)}
+
+
+
{:else if isParsedText(part)}
{part.value}
{/if}
diff --git a/src/lib/components/events/content/utils.ts b/src/lib/components/events/content/utils.ts
index 12394a9..8463421 100644
--- a/src/lib/components/events/content/utils.ts
+++ b/src/lib/components/events/content/utils.ts
@@ -1,4 +1,5 @@
import type { NDKTag } from '@nostr-dev-kit/ndk'
+import { nip19 } from 'nostr-tools'
import { last } from 'ramda'
export const TOPIC = 'topic'
@@ -7,8 +8,6 @@ export const HTML = 'html'
export const INVOICE = 'invoice'
export const NOSTR_NOTE = 'nostr:note'
export const NOSTR_NEVENT = 'nostr:nevent'
-export const NOSTR_NPUB = 'nostr:npub'
-export const NOSTR_NPROFILE = 'nostr:nprofile'
export const NOSTR_NADDR = 'nostr:naddr'
// eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -53,6 +52,22 @@ type Imeta = {
blurhash: string | undefined
}
+export const NOSTR_NPUB = 'nostr:npub'
+type PartTypeNpub = 'nostr:npub'
+export type ParsedNpub = {
+ type: PartTypeNpub
+ hex: string
+}
+export const NOSTR_NPROFILE = 'nostr:nprofile'
+type PartTypeNprofile = 'nostr:nprofile'
+export type ParsedNprofile = {
+ type: PartTypeNprofile
+ hex: string
+ relays: string[]
+}
+
+export type ParsedNostrLink = ParsedNpub | ParsedNprofile
+
export const TEXT = 'text'
type PartTypeText = 'text'
export type ParsedText = {
@@ -60,7 +75,11 @@ export type ParsedText = {
value: string
}
-export type ParsedPart = ParsedNewLine | ParsedText | ParsedLink
+export type ParsedPart =
+ | ParsedNewLine
+ | ParsedText
+ | ParsedNostrLink
+ | ParsedLink
export const isParsedNewLine = (part: ParsedPart): part is ParsedNewLine =>
part.type == NEWLINE
@@ -68,6 +87,15 @@ export const isParsedNewLine = (part: ParsedPart): part is ParsedNewLine =>
export const isParsedLink = (part: ParsedPart): part is ParsedLink =>
part.type == LINK
+export const isParsedNostrLink = (part: ParsedPart): part is ParsedNostrLink =>
+ part.type == NOSTR_NPUB || part.type == NOSTR_NPROFILE
+
+export const isParsedNpub = (part: ParsedPart): part is ParsedNpub =>
+ part.type == NOSTR_NPUB
+
+export const isParsedNprofile = (part: ParsedPart): part is ParsedNprofile =>
+ part.type == NOSTR_NPROFILE
+
export const isParsedText = (part: ParsedPart): part is ParsedText =>
part.type == TEXT
@@ -140,9 +168,29 @@ export const parseContent = (content: string, tags: NDKTag[]): ParsedPart[] => {
]
}
+ const parseNostrLinks = (): undefined | [string, ParsedNostrLink] => {
+ const bech32: string = first(
+ text.match(
+ /^(web\+)?(nostr:)?\/?\/?n(event|ote|profile|pub|addr)1[\d\w]+/i
+ )
+ )
+ if (bech32) {
+ try {
+ const entity = fromNostrURI(bech32)
+ const decoded = nip19.decode(entity)
+ if (decoded.type === 'npub') {
+ return [bech32, { type: NOSTR_NPUB, hex: decoded.data }]
+ }
+ if (decoded.type === 'nprofile') {
+ return [bech32, { type: NOSTR_NPUB, hex: decoded.data.pubkey }]
+ }
+ } catch {}
+ }
+ }
+
while (text) {
// The order that this runs matters
- const part = parseNewline() || parseUrl()
+ const part = parseNewline() || parseUrl() || parseNostrLinks()
if (part) {
if (buffer) {
diff --git a/yarn.lock b/yarn.lock
index b76d104..587ce1f 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1971,6 +1971,11 @@
resolved "https://registry.yarnpkg.com/@noble/ciphers/-/ciphers-0.2.0.tgz#a12cda60f3cf1ab5d7c77068c3711d2366649ed7"
integrity sha512-6YBxJDAapHSdd3bLDv6x2wRPwq4QFMUaB3HvljNBUTThDd12eSm7/3F+2lnfzx2jvM+S6Nsy0jEt9QbPqSwqRw==
+"@noble/ciphers@^0.5.1":
+ version "0.5.2"
+ resolved "https://registry.yarnpkg.com/@noble/ciphers/-/ciphers-0.5.2.tgz#879367fd51d59185259eb844d5b9a78f408b4a12"
+ integrity sha512-GADtQmZCdgbnNp+daPLc3OY3ibEtGGDV/+CzeM3MFnhiQ7ELQKlsHWYq0YbYUXx4jU3/Y1erAxU6r+hwpewqmQ==
+
"@noble/curves@1.1.0", "@noble/curves@~1.1.0":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.1.0.tgz#f13fc667c89184bc04cccb9b11e8e7bae27d8c3d"
@@ -1978,11 +1983,23 @@
dependencies:
"@noble/hashes" "1.3.1"
+"@noble/curves@1.2.0":
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.2.0.tgz#92d7e12e4e49b23105a2555c6984d41733d65c35"
+ integrity sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw==
+ dependencies:
+ "@noble/hashes" "1.3.2"
+
"@noble/hashes@1.3.1":
version "1.3.1"
resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.1.tgz#8831ef002114670c603c458ab8b11328406953a9"
integrity sha512-EbqwksQwz9xDRGfDST86whPBgM65E0OH/pCgqW0GBVzO22bNE+NuIbeTb714+IfSjU3aRk47EUvXIb5bTsenKA==
+"@noble/hashes@1.3.2":
+ version "1.3.2"
+ resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.2.tgz#6f26dbc8fbc7205873ce3cee2f690eba0d421b39"
+ integrity sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ==
+
"@noble/hashes@^1.3.1":
version "1.4.0"
resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.4.0.tgz#45814aa329f30e4fe0ba49426f49dfccdd066426"
@@ -8606,6 +8623,25 @@ nostr-tools@^1.15.0:
"@scure/bip32" "1.3.1"
"@scure/bip39" "1.2.1"
+nostr-tools@^2.5.0:
+ version "2.5.0"
+ resolved "https://registry.yarnpkg.com/nostr-tools/-/nostr-tools-2.5.0.tgz#083c8a22eb88c65f30d88a25e200ea2274348663"
+ integrity sha512-G02O3JYNCfhx9NDjd3NOCw/5ck8PX5hiOIhHKpsXyu49ZtZbxGH3OLP9tf0fpUZ+EVWdjIYFR689sV0i7+TOng==
+ 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"
+ optionalDependencies:
+ nostr-wasm v0.1.0
+
+nostr-wasm@v0.1.0:
+ version "0.1.0"
+ resolved "https://registry.yarnpkg.com/nostr-wasm/-/nostr-wasm-0.1.0.tgz#17af486745feb2b7dd29503fdd81613a24058d94"
+ integrity sha512-78BTryCLcLYv96ONU8Ws3Q1JzjlAt+43pWQhIl86xZmWeegYCNLPml7yQ+gG3vR6V5h4XGj+TxO+SS5dsThQIA==
+
npm-run-path@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea"