2026-06-23 23:30:54 +00:00
|
|
|
import * as nip19 from "nostr-tools/nip19"
|
2026-07-28 16:16:26 +00:00
|
|
|
import {Address, fromNostrURI, getAddress, isReplaceable} from "@welshman/util"
|
2026-07-08 17:29:56 +00:00
|
|
|
import type {TrustedEvent} from "@welshman/util"
|
2026-07-28 16:16:26 +00:00
|
|
|
import type {PinReader, PinReference, PinWriter} from "@welshman/domain"
|
2026-07-27 22:16:21 +00:00
|
|
|
import {isLink, parse} from "@welshman/content"
|
2026-07-08 17:29:56 +00:00
|
|
|
|
2026-07-28 16:16:26 +00:00
|
|
|
const encodeReference = (reference: PinReference) => {
|
|
|
|
|
if (reference.type === "event") {
|
|
|
|
|
return nip19.neventEncode({id: reference.id, relays: reference.relay ? [reference.relay] : []})
|
2026-06-23 23:30:54 +00:00
|
|
|
}
|
|
|
|
|
|
2026-07-28 16:16:26 +00:00
|
|
|
if (reference.type === "address") {
|
|
|
|
|
const {kind, pubkey, identifier} = Address.from(reference.address)
|
2026-07-27 22:16:21 +00:00
|
|
|
|
2026-07-28 16:16:26 +00:00
|
|
|
return nip19.naddrEncode({
|
|
|
|
|
kind,
|
|
|
|
|
pubkey,
|
|
|
|
|
identifier,
|
|
|
|
|
relays: reference.relay ? [reference.relay] : [],
|
|
|
|
|
})
|
2026-06-23 23:30:54 +00:00
|
|
|
}
|
|
|
|
|
|
2026-07-28 16:16:26 +00:00
|
|
|
return reference.id
|
2026-06-23 23:30:54 +00:00
|
|
|
}
|
|
|
|
|
|
2026-07-28 16:16:26 +00:00
|
|
|
export const pinToReference = (pin: PinReader) => {
|
|
|
|
|
const reference = pin.reference()
|
|
|
|
|
|
|
|
|
|
return reference ? encodeReference(reference) : ""
|
|
|
|
|
}
|
2026-07-02 18:36:05 +00:00
|
|
|
|
2026-07-28 16:16:26 +00:00
|
|
|
export const eventToReference = (event: TrustedEvent) =>
|
|
|
|
|
encodeReference(
|
|
|
|
|
isReplaceable(event)
|
|
|
|
|
? {type: "address", address: getAddress(event)}
|
|
|
|
|
: {type: "event", id: event.id},
|
|
|
|
|
)
|
2026-07-02 18:36:05 +00:00
|
|
|
|
2026-07-28 16:16:26 +00:00
|
|
|
// Point a pin at a user-entered nostr link or external url, false if it's neither.
|
|
|
|
|
export const setPinReference = (writer: PinWriter, reference: string) => {
|
2026-06-23 23:30:54 +00:00
|
|
|
const trimmed = reference.trim()
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
const decoded = nip19.decode(fromNostrURI(trimmed))
|
|
|
|
|
|
2026-07-28 16:16:26 +00:00
|
|
|
if (decoded.type === "note") {
|
|
|
|
|
writer.setEvent(decoded.data)
|
|
|
|
|
return true
|
|
|
|
|
}
|
2026-06-23 23:30:54 +00:00
|
|
|
|
2026-07-28 16:16:26 +00:00
|
|
|
if (decoded.type === "nevent") {
|
|
|
|
|
writer.setEvent(decoded.data.id, decoded.data.relays?.[0])
|
|
|
|
|
return true
|
2026-06-23 23:30:54 +00:00
|
|
|
}
|
2026-07-27 22:16:21 +00:00
|
|
|
|
2026-07-28 16:16:26 +00:00
|
|
|
// Pins have no pubkey reference type, so a person gets stored as an external
|
|
|
|
|
// id — keep the bech32 the user gave us so it round-trips and still embeds.
|
|
|
|
|
if (decoded.type === "npub" || decoded.type === "nprofile") {
|
|
|
|
|
writer.setExternal(fromNostrURI(trimmed))
|
|
|
|
|
return true
|
2026-07-27 22:16:21 +00:00
|
|
|
}
|
2026-07-28 16:16:26 +00:00
|
|
|
|
2026-06-23 23:30:54 +00:00
|
|
|
if (decoded.type === "naddr") {
|
|
|
|
|
const {kind, pubkey, identifier, relays} = decoded.data
|
|
|
|
|
|
2026-07-28 16:16:26 +00:00
|
|
|
writer.setAddress(new Address(kind, pubkey, identifier).toString(), relays?.[0])
|
|
|
|
|
return true
|
2026-06-23 23:30:54 +00:00
|
|
|
}
|
2026-07-27 22:16:21 +00:00
|
|
|
|
2026-07-28 16:16:26 +00:00
|
|
|
return false
|
2026-06-23 23:30:54 +00:00
|
|
|
} catch {
|
|
|
|
|
// Not a nostr entity; fall through to external url handling.
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-27 22:16:21 +00:00
|
|
|
const parsed = parse({content: trimmed})
|
|
|
|
|
|
2026-07-28 16:16:26 +00:00
|
|
|
if (parsed.length === 1 && isLink(parsed[0])) {
|
|
|
|
|
writer.setExternal(trimmed)
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false
|
2026-06-23 23:30:54 +00:00
|
|
|
}
|