From 5660459b16b4a3e1c2cff64b51e0762c7abad384 Mon Sep 17 00:00:00 2001 From: Jon Staab Date: Wed, 25 Sep 2024 13:51:32 -0700 Subject: [PATCH] Add app tag utils --- packages/app/src/index.ts | 1 + packages/app/src/tags.ts | 107 ++++++++++++++++++++++++++++++++++++++ packages/util/src/Tags.ts | 4 +- 3 files changed, 111 insertions(+), 1 deletion(-) create mode 100644 packages/app/src/tags.ts diff --git a/packages/app/src/index.ts b/packages/app/src/index.ts index e70fda8..3fa01f4 100644 --- a/packages/app/src/index.ts +++ b/packages/app/src/index.ts @@ -12,6 +12,7 @@ export * from './relaySelections' export * from './router' export * from './session' export * from './storage' +export * from './tags' export * from './thunk' export * from './topics' export * from './util' diff --git a/packages/app/src/tags.ts b/packages/app/src/tags.ts new file mode 100644 index 0000000..b682a91 --- /dev/null +++ b/packages/app/src/tags.ts @@ -0,0 +1,107 @@ +import {ctx} from '@welshman/lib' +import {getAddress, isReplaceable, getAncestorTags, getPubkeyTagValues, getIdAndAddress} from '@welshman/util' +import type {TrustedEvent} from '@welshman/util' +import {displayProfileByPubkey} from './profiles' +import {pubkey} from './session' + +export const tagZapSplit = (pubkey: string, split = 1) => [ + "zap", + pubkey, + ctx.app.router.FromPubkeys([pubkey]).getUrl(), + String(split), +] + +export const tagPubkey = (pubkey: string, ...args: unknown[]) => [ + "p", + pubkey, + ctx.app.router.FromPubkeys([pubkey]).getUrl(), + displayProfileByPubkey(pubkey), +] + +export const tagEvent = (event: TrustedEvent, mark = "") => { + const url = ctx.app.router.Event(event).getUrl() + const tags = [["e", event.id, url, mark, event.pubkey]] + + if (isReplaceable(event)) { + tags.push(["a", getAddress(event), url, mark, event.pubkey]) + } + + return tags +} + +export const tagReplyTo = (event: TrustedEvent) => { + const $pubkey = pubkey.get() + const tagValues = getIdAndAddress(event) + const tags: string[][] = [] + + // Mention the event's author + if (event.pubkey !== $pubkey) { + tags.push(tagPubkey(event.pubkey)) + } + + // Inherit p-tag mentions + for (const pubkey of getPubkeyTagValues(tags)) { + if (pubkey !== $pubkey) { + tags.push(tagPubkey(pubkey)) + } + } + + // Based on NIP 10 legacy tags, order is root, mentions, reply + const {roots, replies, mentions} = getAncestorTags(tags) + + // Root comes first + if (roots.length > 0) { + for (const t of roots) { + tags.push([...t.slice(0, 2), ctx.app.router.EventRoots(event).getUrl(), "root"]) + } + } else { + for (const t of replies) { + tags.push([...t.slice(0, 2), ctx.app.router.EventParents(event).getUrl(), "root"]) + } + } + + // Make sure we don't repeat any tag values + const isRepeated = (v: string) => tagValues.includes(v) || tags.find(t => t[1] === v) + + // Inherit mentions + for (const t of mentions) { + if (!isRepeated(t[1])) { + tags.push([...t.slice(0, 3), "mention"]) + } + } + + // Inherit replies if they weren't already included + if (roots.length > 0) { + for (const t of replies) { + if (!isRepeated(t[1])) { + tags.push([...t.slice(0, 3), "mention"]) + } + } + } + + // Add a/e-tags for the event event + for (const t of tagEvent(event, replies.length > 0 ? "reply" : "root")) { + tags.push(t) + } + + return tags +} + +export const tagReactionTo = (event: TrustedEvent) => { + const tags: string[][] = [] + + // Mention the event's author + if (event.pubkey !== pubkey.get()) { + tags.push(tagPubkey(event.pubkey)) + } + + // Add a/e-tags for the event + for (const t of tagEvent(event, "root")) { + tags.push(t) + } + + return tags +} + + + diff --git a/packages/util/src/Tags.ts b/packages/util/src/Tags.ts index 6fac671..78250d4 100644 --- a/packages/util/src/Tags.ts +++ b/packages/util/src/Tags.ts @@ -1,5 +1,5 @@ import type {OmitStatics} from '@welshman/lib' -import {Fluent, mapVals, nth, nthEq, ensurePlural} from '@welshman/lib' +import {Fluent, uniqBy, mapVals, nth, nthEq, ensurePlural} from '@welshman/lib' import {isRelayUrl, normalizeRelayUrl} from './Relay' import {Address, isContextAddress} from './Address' import {GROUP, COMMUNITY} from './Kinds' @@ -252,3 +252,5 @@ export const getAncestorTags = (tags: string[][]) => { export const getAncestorTagValues = (tags: string[][]) => mapVals(tags => tags.map(nth(1)), getAncestorTags(tags)) + +export const uniqTags = (tags: string[][]) => uniqBy(t => t.join(":"), tags)