Files
buzz/desktop/src/features/messages/lib/sendToChannelSemantics.ts
Logan Johnson cc096ca2a1 fix(desktop): preserve mention competitors through fallbacks
Compose edit fallback refs before exact occurrence selection. Keep ambiguous historical labels as non-authorizing blockers for rendering and body-based recipient fallbacks; qualified labels only disambiguate when they own an unambiguous occurrence.

Co-authored-by: Larry <627498bd4bd1f281a16431e3c6cce3b5c25b6692798c78672298aefbf2f8f8b5@buzz.block.builderlab.xyz>
Signed-off-by: Logan Johnson <loganj@squareup.com>
(cherry picked from commit 30545075a876136467c07d82abac83ad1904df23)
Signed-off-by: Logan Johnson <loganj@squareup.com>
(cherry picked from commit df75b5d1ac6d7aaa2bf0dfb4dfaf43b92539249a)
Signed-off-by: Logan Johnson <loganj@squareup.com>
2026-09-01 11:55:36 -04:00

90 lines
2.7 KiB
TypeScript

import type { TimelineMessage } from "@/features/messages/types";
import { orderMentionPubkeysByText } from "@/features/messages/lib/orderMentionPubkeys";
import type { UserProfileLookup } from "@/features/profile/lib/identity";
import { normalizePubkey } from "@/shared/lib/pubkey";
import { resolveMentionProps } from "@/shared/lib/resolveMentionNames";
const PUBKEY_PATTERN = /^[0-9a-f]{64}$/;
const SHAREABLE_TAG_KINDS = new Set([
"emoji",
"imeta",
"link-preview",
"mention",
]);
export type SendToChannelSemantics = {
mentionPubkeys: string[];
semanticTags: string[][];
};
/**
* Preserve the source message metadata that gives its body meaning without
* copying structural channel/thread tags or the source event's self `p` tag.
*/
export function getSendToChannelSemantics(
message: TimelineMessage,
profiles?: UserProfileLookup,
): SendToChannelSemantics {
const sourceAuthors = new Set(
[message.pubkey, message.signerPubkey]
.filter((pubkey): pubkey is string => Boolean(pubkey))
.map(normalizePubkey),
);
const seenMentions = new Set<string>();
const mentionPubkeys: string[] = [];
const mentionProps = resolveMentionProps(
message.tags,
profiles,
message.body,
);
const effectiveMentionPubkeys = message.edited
? new Set(
(message.tags ?? []).some((tag) => tag[0] === "buzz:mention-snapshot")
? (message.tags ?? [])
.filter((tag) => tag[0] === "mention")
.map((tag) => normalizePubkey(tag[1] ?? ""))
.filter((pubkey) => PUBKEY_PATTERN.test(pubkey))
: orderMentionPubkeysByText(
message.body,
mentionProps.mentionPubkeysByName,
() => true,
mentionProps.mentionNames,
),
)
: null;
const semanticTags: string[][] = [];
const hasPreviewSuppression = message.tags?.some(
(tag) => tag.length === 2 && tag[0] === "link-preview" && tag[1] === "none",
);
for (const tag of message.tags ?? []) {
if (tag[0] === "p") {
const pubkey = normalizePubkey(tag[1] ?? "");
if (
PUBKEY_PATTERN.test(pubkey) &&
!sourceAuthors.has(pubkey) &&
(effectiveMentionPubkeys === null ||
effectiveMentionPubkeys.has(pubkey)) &&
!seenMentions.has(pubkey)
) {
seenMentions.add(pubkey);
mentionPubkeys.push(pubkey);
}
continue;
}
if (SHAREABLE_TAG_KINDS.has(tag[0] ?? "")) {
if (
tag[0] === "link-preview" &&
hasPreviewSuppression &&
!(tag.length === 2 && tag[1] === "none")
) {
continue;
}
semanticTags.push([...tag]);
}
}
return { mentionPubkeys, semanticTags };
}