diff options
| author | Adam Soltys <[email protected]> | 2026-03-06 23:46:17 -0800 |
|---|---|---|
| committer | Adam Soltys <[email protected]> | 2026-03-06 23:46:17 -0800 |
| commit | 797d30c172fbec5e98e3a8d77d24f8e708aaa0bd (patch) | |
| tree | 0413da05c2ff55e5c50ec83c092eb40de1eaa319 | |
| parent | 76e0e08ce6575b43901b777ee75b048dce9097ff (diff) | |
| download | coinos-ui-797d30c172fbec5e98e3a8d77d24f8e708aaa0bd.tar.gz coinos-ui-797d30c172fbec5e98e3a8d77d24f8e708aaa0bd.zip | |
render images from MLS messages by preserving rumor tags
Extract tags from decrypted MLS rumors and pass them through to
ChatMessage. Handle imeta tags (NIP-92) for image attachments
sent from clients like White Noise.
Co-Authored-By: Claude Opus 4.6 <[email protected]>
| -rw-r--r-- | src/components/ChatMessage.svelte | 10 | ||||
| -rw-r--r-- | src/lib/mls-relay.ts | 8 |
2 files changed, 14 insertions, 4 deletions
diff --git a/src/components/ChatMessage.svelte b/src/components/ChatMessage.svelte index 7283430f..dbdde5a0 100644 --- a/src/components/ChatMessage.svelte +++ b/src/components/ChatMessage.svelte @@ -3,7 +3,15 @@ let { content, tags = [] }: { content: string; tags?: any[] } = $props(); - let parts = $derived(parseContent({ content, tags })); + // Extract image URLs from imeta tags not already in content + let imetaUrls = $derived( + tags + .filter((t) => t[0] === "imeta") + .map((t) => t.find((v) => v.startsWith("url "))?.slice(4)) + .filter((url): url is string => !!url && !content.includes(url)), + ); + + let parts = $derived(parseContent({ content: [content, ...imetaUrls].join("\n"), tags })); const truncUrl = (url: string) => { const short = url.replace(/^https?:\/\/(www\.)?/, ""); diff --git a/src/lib/mls-relay.ts b/src/lib/mls-relay.ts index 8ca18b15..8ab89e98 100644 --- a/src/lib/mls-relay.ts +++ b/src/lib/mls-relay.ts @@ -592,10 +592,12 @@ async function handleGroupMessageEvent( const raw = new TextDecoder().decode(result.result.message); let content: string; let senderPubkey: string; + let tags: string[][] = []; try { const rumor = JSON.parse(raw); content = rumor.content ?? raw; senderPubkey = rumor.pubkey ?? event.pubkey; + if (Array.isArray(rumor.tags)) tags = rumor.tags; } catch { content = raw; senderPubkey = event.pubkey; @@ -609,7 +611,7 @@ async function handleGroupMessageEvent( return null; } - const rumour = makeRumour(content, senderPubkey, mlsGroupIdHex); + const rumour = makeRumour(content, senderPubkey, mlsGroupIdHex, tags); cacheGroupRumour(mlsGroupIdHex, rumour); processedEventIds.add(event.id); saveLocalCache(); @@ -688,14 +690,14 @@ export async function fetchGroupHistory(user: any, relays: string[] = DM_RELAYS) // Helpers // --------------------------------------------------------------------------- -function makeRumour(content: string, senderPubkey: string, groupId: string): any { +function makeRumour(content: string, senderPubkey: string, groupId: string, tags: string[][] = []): any { return { id: bytesToHex(crypto.getRandomValues(new Uint8Array(32))), kind: 14, created_at: Math.floor(Date.now() / 1000), pubkey: senderPubkey, content, - tags: [], + tags, _groupId: groupId, }; } |
