flotilla/src/app/pinboards.ts

84 lines
2.3 KiB
TypeScript
Raw Normal View History

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"
import type {TrustedEvent} from "@welshman/util"
2026-07-28 16:16:26 +00:00
import type {PinReader, PinReference, PinWriter} from "@welshman/domain"
import {isLink, parse} from "@welshman/content"
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-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-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-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-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-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-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.
}
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
}