Changeset e9c9ae1 in Klonkt for src/services/ActivityPubService.js
- Timestamp:
- 07/19/2026 10:48:15 PM (7 weeks ago)
- Branches:
- main
- Children:
- ff3b8ce
- Parents:
- 5190152
- git-author:
- Robin <roboburr@…> (07/19/2026 10:47:10 PM)
- git-committer:
- Robin <roboburr@…> (07/19/2026 10:48:15 PM)
- File:
-
- 1 edited
-
src/services/ActivityPubService.js (modified) (7 diffs)
Legend:
- Unmodified
- Added
- Removed
-
src/services/ActivityPubService.js
r5190152 re9c9ae1 822 822 nodes.push({ 823 823 noteId: r.object_uri, parent: r.parent_uri || null, mine: false, id: r.id, 824 actor_uri: r.actor_uri, 824 825 actor_name: r.actor_name, actor_handle: r.actor_handle, actor_url: r.actor_url, 825 826 actor_icon: r.actor_icon, content: stripLeadingMentions(r.content), created_at: r.published || r.created_at, … … 839 840 840 841 const byId = new Map(nodes.map((n) => [n.noteId, n])); 842 // Conversation partners per node (u02, the reply editor's mentions bar): the 843 // node's author plus the ancestor authors up the chain. Our own nodes are 844 // skipped (we do not mention ourselves), deduped by actor, capped at 8. 845 for (const n of nodes) { 846 const seen = new Set(); 847 const list = []; 848 let cur = n, guard = 0; 849 while (cur && guard++ < 12 && list.length < 8) { 850 if (!cur.mine && cur.actor_uri && !seen.has(cur.actor_uri)) { 851 seen.add(cur.actor_uri); 852 list.push({ 853 uri: cur.actor_uri, 854 url: cur.actor_url || cur.actor_uri, 855 handle: cur.actor_handle || deriveHandle(cur.actor_uri), 856 }); 857 } 858 cur = cur.parent ? byId.get(cur.parent) : null; 859 } 860 n.participants = list; 861 } 841 862 const isTop = (n) => !n.parent || n.parent === postNoteId || !byId.has(n.parent); 842 863 const tops = []; … … 1872 1893 // Send a reply FROM this site to a remote actor (in reply to their inbound reply). 1873 1894 // `parent` = an ap_interactions row (actor_uri, actor_url, actor_handle, object_uri). 1874 export async function deliverReply(site, { postId, postSlug, parent, text, html, language, attachments }) {1895 export async function deliverReply(site, { postId, postSlug, parent, text, html, language, attachments, mentions }) { 1875 1896 const base = (process.env.PUBLIC_BASE_URL || '').replace(/\/+$/, ''); 1876 1897 // Rich replies: `html` is the reply editor's HTML (sanitized here); `text` is … … 1888 1909 if (!base || !site || !site.slug || !parent || (!String(text || '').trim() && !rich && !media.length)) return null; 1889 1910 const me = actorId(base, site.slug); 1911 // u02, the mentions bar: `mentions` undefined = legacy behavior (mention the 1912 // parent author). An ARRAY (possibly empty) = the kept conversation partners 1913 // exactly as the bar shows them; the mention prefix, the Mention tags (via 1914 // mentionTags over the content) and the delivery targets all follow it. 1915 const kept = Array.isArray(mentions) 1916 ? mentions 1917 .filter((m) => m && typeof m.uri === 'string' && /^https?:\/\//i.test(m.uri)) 1918 .slice(0, 8) 1919 .map((m) => ({ 1920 uri: m.uri, 1921 url: (typeof m.url === 'string' && /^https?:\/\//i.test(m.url)) ? m.url : m.uri, 1922 handle: String(m.handle || deriveHandle(m.uri)).slice(0, 120), 1923 })) 1924 : null; 1925 const mentionAnchor = (uri, url, h) => { 1926 const disp = h && h[0] === '@' ? h : '@' + (h || ''); 1927 return `<a href="${escHtml(url || uri)}" class="u-url mention" data-actor="${escHtml(uri)}">${escHtml(disp)}</a> `; 1928 }; 1890 1929 const handle = parent.actor_handle || deriveHandle(parent.actor_uri); 1891 const dispHandle = handle && handle[0] === '@' ? handle : '@' + (handle || ''); 1892 const mention = parent.actor_uri 1893 ? `<a href="${escHtml(parent.actor_url || parent.actor_uri)}" class="u-url mention" data-actor="${escHtml(parent.actor_uri)}">${escHtml(dispHandle)}</a> ` : ''; 1930 const mention = kept 1931 ? kept.map((k) => mentionAnchor(k.uri, k.url, k.handle)).join('') 1932 : (parent.actor_uri ? mentionAnchor(parent.actor_uri, parent.actor_url, handle) : ''); 1933 // Who the stored reply is "to": the parent when kept, else the first kept chip. 1934 const parentKept = !kept || kept.some((k) => k.uri === parent.actor_uri); 1935 const toActorUri = parentKept ? (parent.actor_uri || null) : (kept[0] ? kept[0].uri : null); 1936 const toHandle = parentKept ? handle : (kept[0] ? kept[0].handle : null); 1894 1937 let content; 1895 1938 let mres; … … 1920 1963 if (dup) { console.log('[AP] outreply skipped (duplicate)'); return { duplicate: true, delivered: 0 }; } 1921 1964 const id = crypto.randomUUID(); 1922 iStmts().insO.run(id, site.slug, postId, postSlug || null, parent.object_uri || null, parent.actor_uri || null, handle, content, replyLang, mediaJson);1965 iStmts().insO.run(id, site.slug, postId, postSlug || null, parent.object_uri || null, toActorUri, toHandle, content, replyLang, mediaJson); 1923 1966 const row = iStmts().getO.get(id); 1924 1967 const note = buildReplyNote(base, site, row); … … 1931 1974 const keyId = `${me}#main-key`; 1932 1975 const inboxes = new Set(); 1933 if (parent.actor_uri) { 1934 const a = await fetchActor(parent.actor_uri).catch(() => null); 1976 // Everyone the mentions bar kept gets pinged; legacy path = the parent only. 1977 const mentionTargets = kept ? kept.map((k) => k.uri) : (parent.actor_uri ? [parent.actor_uri] : []); 1978 for (const uri of mentionTargets) { 1979 const a = await fetchActor(uri).catch(() => null); 1935 1980 if (a) inboxes.add((a.endpoints && a.endpoints.sharedInbox) || a.inbox); 1936 1981 } … … 2092 2137 const _h = row.to_handle || deriveHandle(row.to_actor); 2093 2138 const toHandle = _h && _h[0] === '@' ? _h : '@' + (_h || ''); 2094 const mention = row.to_actor 2095 ? `<a href="${escHtml(toProfile)}" class="u-url mention" data-actor="${escHtml(row.to_actor)}">${escHtml(toHandle)}</a> ` : ''; 2139 // An edit must not drop co-mentions (u02): reuse the OLD content's leading 2140 // mention anchors (the bar's kept list at send time) when present; only fall 2141 // back to rebuilding the single to_actor mention for legacy rows. 2142 const oldPrefix = (String(row.content || '') 2143 .match(/^\s*(?:<p[^>]*>)?\s*((?:<a\b[^>]*class="u-url mention"[^>]*>\s*@[^<]+<\/a>[\s ]*)+)/i) || [])[1] || ''; 2144 const mention = oldPrefix || (row.to_actor 2145 ? `<a href="${escHtml(toProfile)}" class="u-url mention" data-actor="${escHtml(row.to_actor)}">${escHtml(toHandle)}</a> ` : ''); 2096 2146 let content; 2097 2147 let mres;
Note:
See TracChangeset
for help on using the changeset viewer.
![(please configure the [header_logo] section in trac.ini)](/chrome/site/your_project_logo.png)