Fix pin references for non-addressable events, malformed shelf addresses, and profile links
This commit is contained in:
parent
883528242c
commit
0f17e62e54
7 changed files with 50 additions and 25 deletions
|
|
@ -2,7 +2,7 @@
|
|||
import {onMount} from "svelte"
|
||||
import type {Snippet} from "svelte"
|
||||
import type {TrustedEvent} from "@welshman/util"
|
||||
import {COMMENT, getAddress, ManagementMethod} from "@welshman/util"
|
||||
import {COMMENT, ManagementMethod} from "@welshman/util"
|
||||
import {pubkey, repository, manageRelay} from "@welshman/app"
|
||||
import GalleryWide from "@assets/icons/gallery-wide.svg?dataurl"
|
||||
import ShareCircle from "@assets/icons/share-circle.svg?dataurl"
|
||||
|
|
@ -38,7 +38,7 @@
|
|||
|
||||
const showInfo = () => pushModal(EventInfo, {url, event})
|
||||
|
||||
const addToLibrary = () => pushModal(PinboardSelect, {url, address: getAddress(event)})
|
||||
const addToLibrary = () => pushModal(PinboardSelect, {url, event})
|
||||
|
||||
const share = () => shareEventToChat(url, noun, event)
|
||||
|
||||
|
|
|
|||
|
|
@ -18,6 +18,8 @@
|
|||
|
||||
if (type === "e") return "nostr:" + nip19.neventEncode({id: data})
|
||||
|
||||
if (type === "p") return "nostr:" + nip19.nprofileEncode({pubkey: data})
|
||||
|
||||
if (type === "a") {
|
||||
const {kind, pubkey, identifier} = Address.from(data)
|
||||
|
||||
|
|
@ -35,10 +37,10 @@
|
|||
{#if pin.description}
|
||||
<Content event={{content: pin.description, tags: []}} />
|
||||
{/if}
|
||||
{#if pin.value[0] === "i"}
|
||||
<Content event={{content, tags: []}} />
|
||||
{:else}
|
||||
{#if pin.value[0] === "e" || pin.value[0] === "a"}
|
||||
<PinContentEvent value={pin.value[1]} relays={pin.value[2] ? [pin.value[2]] : []} />
|
||||
{:else}
|
||||
<Content event={{content, tags: []}} />
|
||||
{/if}
|
||||
{#if pin.topics.length > 0}
|
||||
<div class="mt-auto flex flex-wrap gap-1">
|
||||
|
|
|
|||
|
|
@ -130,7 +130,7 @@
|
|||
Link
|
||||
{/snippet}
|
||||
{#snippet info()}
|
||||
<p>A URL or nostr link (note, nevent, or naddr).</p>
|
||||
<p>A URL or nostr link (note, nevent, naddr, npub, or nprofile).</p>
|
||||
{/snippet}
|
||||
{#snippet input()}
|
||||
<input bind:value class="input input-bordered w-full" placeholder="URL or nevent..." />
|
||||
|
|
|
|||
|
|
@ -25,6 +25,8 @@
|
|||
|
||||
if (type === "e") return "nostr:" + nip19.neventEncode({id: data, relays: [url]})
|
||||
|
||||
if (type === "p") return "nostr:" + nip19.nprofileEncode({pubkey: data, relays: [url]})
|
||||
|
||||
if (type === "a") {
|
||||
const {kind, pubkey, identifier} = Address.from(data)
|
||||
|
||||
|
|
@ -52,10 +54,10 @@
|
|||
{#if pin.description}
|
||||
<Content event={{content: pin.description, tags: []}} {url} />
|
||||
{/if}
|
||||
{#if pin.value[0] === "i"}
|
||||
<Content event={{content, tags: []}} {url} />
|
||||
{:else}
|
||||
{#if pin.value[0] === "e" || pin.value[0] === "a"}
|
||||
<PinContentEvent {url} value={pin.value[1]} relays={removeUndefined([pin.value[2], url])} />
|
||||
{:else}
|
||||
<Content event={{content, tags: []}} {url} />
|
||||
{/if}
|
||||
{#if !minimal && pin.topics.length > 0}
|
||||
<div class="mt-auto flex flex-wrap gap-1">
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
<script lang="ts">
|
||||
import type {TrustedEvent} from "@welshman/util"
|
||||
import AltArrowRight from "@assets/icons/alt-arrow-right.svg?dataurl"
|
||||
import Icon from "@lib/components/Icon.svelte"
|
||||
import Button from "@lib/components/Button.svelte"
|
||||
|
|
@ -10,19 +11,19 @@
|
|||
import ModalSubtitle from "@lib/components/ModalSubtitle.svelte"
|
||||
import RelayName from "@app/components/RelayName.svelte"
|
||||
import PinAdd from "@app/components/PinAdd.svelte"
|
||||
import {deriveBoards, addressToReference, type PublishedBoard} from "@app/pinboards"
|
||||
import {deriveBoards, eventToReference, type PublishedBoard} from "@app/pinboards"
|
||||
import {makeSpacePath} from "@app/routes"
|
||||
import {pushModal} from "@app/modal"
|
||||
|
||||
type Props = {
|
||||
url: string
|
||||
address: string
|
||||
event: TrustedEvent
|
||||
}
|
||||
|
||||
const {url, address}: Props = $props()
|
||||
const {url, event}: Props = $props()
|
||||
|
||||
const boards = deriveBoards(url)
|
||||
const reference = addressToReference(address)
|
||||
const reference = eventToReference(event)
|
||||
|
||||
const selectBoard = (board: PublishedBoard) =>
|
||||
pushModal(PinAdd, {url, address: board.address, reference})
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<script lang="ts">
|
||||
import type {TrustedEvent} from "@welshman/util"
|
||||
import {ManagementMethod, getAddress, getTagValue} from "@welshman/util"
|
||||
import {ManagementMethod, getTagValue} from "@welshman/util"
|
||||
import {pubkey, manageRelay, repository} from "@welshman/app"
|
||||
import Code2 from "@assets/icons/code-2.svg?dataurl"
|
||||
import GalleryWide from "@assets/icons/gallery-wide.svg?dataurl"
|
||||
|
|
@ -36,7 +36,7 @@
|
|||
|
||||
const addToLibrary = () => {
|
||||
onClick()
|
||||
pushModal(PinboardSelect, {url, address: getAddress(event)})
|
||||
pushModal(PinboardSelect, {url, event})
|
||||
}
|
||||
|
||||
const report = () => {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import {derived} from "svelte/store"
|
||||
import {derived, readable} from "svelte/store"
|
||||
import type {Readable} from "svelte/store"
|
||||
import * as nip19 from "nostr-tools/nip19"
|
||||
import {now, randomId} from "@welshman/lib"
|
||||
import {
|
||||
|
|
@ -10,10 +11,12 @@ import {
|
|||
getListTags,
|
||||
getTagValue,
|
||||
getTagValues,
|
||||
isReplaceableKind,
|
||||
readList,
|
||||
sortEventsDesc,
|
||||
} from "@welshman/util"
|
||||
import type {TrustedEvent} from "@welshman/util"
|
||||
import {isLink, parse} from "@welshman/content"
|
||||
import {deriveEventsForUrl, deriveRelaySignedEvents} from "@app/repository"
|
||||
import {signAsRelay} from "@app/relays"
|
||||
|
||||
|
|
@ -45,8 +48,9 @@ export type Pin = {
|
|||
description: string
|
||||
title: string
|
||||
topics: string[]
|
||||
// The pin's content reference: the first e/a/i tag found, e.g. ["e", <id>],
|
||||
// ["a", <coord>], or ["i", <external id>]. Empty when the pin has no reference.
|
||||
// The pin's content reference: the first e/a/p/i tag found, e.g. ["e", <id>],
|
||||
// ["a", <coord>], ["p", <pubkey>], or ["i", <url>]. Empty when the pin has no
|
||||
// reference.
|
||||
value: string[]
|
||||
}
|
||||
|
||||
|
|
@ -78,7 +82,7 @@ export const readPin = (event: TrustedEvent): PublishedPin => ({
|
|||
description: event.content,
|
||||
title: getTagValue("title", event.tags) ?? "",
|
||||
topics: getTagValues("t", event.tags),
|
||||
value: event.tags.find(tag => ["e", "a", "i"].includes(tag[0])) ?? [],
|
||||
value: event.tags.find(tag => ["e", "a", "p", "i"].includes(tag[0])) ?? [],
|
||||
})
|
||||
|
||||
export const deriveBoards = (url: string) =>
|
||||
|
|
@ -89,8 +93,13 @@ export const deriveBoard = (url: string, identifier: string) =>
|
|||
event ? readBoard(event) : undefined,
|
||||
)
|
||||
|
||||
export const deriveBoardByAddress = (url: string, address: string) =>
|
||||
deriveBoard(url, Address.from(address).identifier)
|
||||
export const deriveBoardByAddress = (
|
||||
url: string,
|
||||
address: string,
|
||||
): Readable<PublishedBoard | undefined> =>
|
||||
Address.isAddress(address)
|
||||
? deriveBoard(url, Address.from(address).identifier)
|
||||
: readable(undefined)
|
||||
|
||||
export const derivePins = (url: string, address: string) =>
|
||||
derived(deriveRelaySignedEvents(url, [{kinds: [PIN], "#A": [address]}]), $events =>
|
||||
|
|
@ -175,6 +184,8 @@ const valueToReference = (value: string[]): string => {
|
|||
|
||||
if (type === "e") return nip19.neventEncode({id: data, relays})
|
||||
|
||||
if (type === "p") return nip19.nprofileEncode({pubkey: data, relays})
|
||||
|
||||
if (type === "a") {
|
||||
const {kind, pubkey, identifier} = Address.from(data)
|
||||
|
||||
|
|
@ -186,31 +197,40 @@ const valueToReference = (value: string[]): string => {
|
|||
|
||||
export const pinToReference = (pin: Pin): string => valueToReference(pin.value)
|
||||
|
||||
export const addressToReference = (address: string): string => valueToReference(["a", address])
|
||||
export const eventToReference = (event: TrustedEvent): string =>
|
||||
valueToReference(isReplaceableKind(event.kind) ? ["a", getAddress(event)] : ["e", event.id])
|
||||
|
||||
export const referenceToPin = (reference: string): Partial<Pin> | undefined => {
|
||||
const trimmed = reference.trim()
|
||||
|
||||
if (!trimmed) return undefined
|
||||
|
||||
try {
|
||||
const decoded = nip19.decode(fromNostrURI(trimmed))
|
||||
|
||||
if (decoded.type === "note") return {value: ["e", decoded.data]}
|
||||
if (decoded.type === "npub") return {value: ["p", decoded.data]}
|
||||
if (decoded.type === "nevent") {
|
||||
const {id, relays} = decoded.data
|
||||
|
||||
return {value: relays?.[0] ? ["e", id, relays[0]] : ["e", id]}
|
||||
}
|
||||
if (decoded.type === "nprofile") {
|
||||
const {pubkey, relays} = decoded.data
|
||||
|
||||
return {value: relays?.[0] ? ["p", pubkey, relays[0]] : ["p", pubkey]}
|
||||
}
|
||||
if (decoded.type === "naddr") {
|
||||
const {kind, pubkey, identifier, relays} = decoded.data
|
||||
const coordinate = `${kind}:${pubkey}:${identifier}`
|
||||
|
||||
return {value: relays?.[0] ? ["a", coordinate, relays[0]] : ["a", coordinate]}
|
||||
}
|
||||
|
||||
return undefined
|
||||
} catch {
|
||||
// Not a nostr entity; fall through to external url handling.
|
||||
}
|
||||
|
||||
return {value: ["i", trimmed]}
|
||||
const parsed = parse({content: trimmed})
|
||||
|
||||
return parsed.length === 1 && isLink(parsed[0]) ? {value: ["i", trimmed]} : undefined
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue