Changeset 33e1dbd in Klonkt for src/services/ActivityPubService.js
- Timestamp:
- 07/19/2026 05:08:32 PM (7 weeks ago)
- Branches:
- main
- Children:
- feced2c
- Parents:
- 2d66d66
- git-author:
- Robin <roboburr@…> (07/19/2026 05:08:12 PM)
- git-committer:
- Robin <roboburr@…> (07/19/2026 05:08:32 PM)
- File:
-
- 1 edited
-
src/services/ActivityPubService.js (modified) (4 diffs)
Legend:
- Unmodified
- Added
- Removed
-
src/services/ActivityPubService.js
r2d66d66 r33e1dbd 233 233 inReplyTo: post.in_reply_to || undefined, 234 234 content: post.content, 235 // Reply language (rich replies): the AS2 language map next to `content`. 236 contentMap: post.language ? { [post.language]: post.content } : undefined, 235 237 url: post.post_slug ? `${base}/${encodeURIComponent(post.post_slug)}` : undefined, 236 238 published: toISO(post.created_at), … … 710 712 _listI = db.prepare('SELECT id, kind, object_uri, parent_uri, actor_uri, actor_name, actor_handle, actor_url, actor_icon, content, published, created_at, acted_boost, acted_like, visibility FROM ap_interactions WHERE post_id = ? ORDER BY created_at ASC'); 711 713 _getI = db.prepare('SELECT * FROM ap_interactions WHERE id = ?'); 712 _insO = db.prepare('INSERT INTO ap_outbox (id, site_slug, post_id, post_slug, in_reply_to, to_actor, to_handle, content, created_at) VALUES (?,?,?,?,?,?,?,?,CURRENT_TIMESTAMP)');714 _insO = db.prepare('INSERT INTO ap_outbox (id, site_slug, post_id, post_slug, in_reply_to, to_actor, to_handle, content, language, created_at) VALUES (?,?,?,?,?,?,?,?,?,CURRENT_TIMESTAMP)'); 713 715 _listO = db.prepare('SELECT * FROM ap_outbox WHERE post_id = ? ORDER BY created_at ASC'); 714 716 _getO = db.prepare('SELECT * FROM ap_outbox WHERE id = ?'); … … 1854 1856 // Send a reply FROM this site to a remote actor (in reply to their inbound reply). 1855 1857 // `parent` = an ap_interactions row (actor_uri, actor_url, actor_handle, object_uri). 1856 export async function deliverReply(site, { postId, postSlug, parent, text }) {1858 export async function deliverReply(site, { postId, postSlug, parent, text, html, language }) { 1857 1859 const base = (process.env.PUBLIC_BASE_URL || '').replace(/\/+$/, ''); 1858 if (!base || !site || !site.slug || !parent || !String(text || '').trim()) return null; 1860 // Rich replies: `html` is the reply editor's HTML (sanitized here); `text` is 1861 // the plain-text fallback (no-JS path, C2S `source`). Either may carry the reply. 1862 const richClean = html ? HtmlSanitizerService.sanitize(String(html)) : ''; 1863 const rich = richClean && HtmlSanitizerService.toPlainText(richClean).trim() ? richClean : ''; 1864 if (!base || !site || !site.slug || !parent || (!String(text || '').trim() && !rich)) return null; 1859 1865 const me = actorId(base, site.slug); 1860 1866 const handle = parent.actor_handle || deriveHandle(parent.actor_uri); 1861 1867 const dispHandle = handle && handle[0] === '@' ? handle : '@' + (handle || ''); 1862 const body = escHtml(String(text).trim()).replace(/\r?\n/g, '<br>');1863 const mres = await resolveMentionsInText(base, body); // link inline @mentions + collect their inboxes1864 1868 const mention = parent.actor_uri 1865 1869 ? `<a href="${escHtml(parent.actor_url || parent.actor_uri)}" class="u-url mention" data-actor="${escHtml(parent.actor_uri)}">${escHtml(dispHandle)}</a> ` : ''; 1866 const content = `<p>${mention}${linkUrls(linkHashtags(base, mres.html))}</p>`; 1870 let content; 1871 let mres; 1872 if (rich) { 1873 // Same enrichment pipeline as the plain path (mentions/hashtags/URLs), on 1874 // sanitized editor HTML. The parent mention goes inline into the first 1875 // paragraph (Mastodon convention), or becomes its own leading one. 1876 mres = await resolveMentionsInText(base, rich); 1877 const processed = linkUrls(linkHashtags(base, mres.html)); 1878 if (processed.startsWith('<p>')) { 1879 content = processed.replace('<p>', `<p>${mention}`); // inline in the first paragraph 1880 } else if (/^<(blockquote|ul|ol|pre|h[1-6]|div|hr)\b/i.test(processed)) { 1881 content = `<p>${mention}</p>${processed}`; // block content: own leading paragraph 1882 } else { 1883 content = `<p>${mention}${processed}</p>`; // bare inline text: one paragraph together 1884 } 1885 } else { 1886 const body = escHtml(String(text).trim()).replace(/\r?\n/g, '<br>'); 1887 mres = await resolveMentionsInText(base, body); // link inline @mentions + collect their inboxes 1888 content = `<p>${mention}${linkUrls(linkHashtags(base, mres.html))}</p>`; 1889 } 1890 const replyLang = /^[a-z]{2,3}(-[A-Za-z0-9-]+)?$/.test(String(language || '')) ? language : null; 1867 1891 // Dedup: skip if the exact same reply was already sent (double-submit guard). 1868 1892 const dup = db.prepare('SELECT 1 FROM ap_outbox WHERE site_slug = ? AND IFNULL(in_reply_to, \'\') = ? AND content = ? LIMIT 1') … … 1870 1894 if (dup) { console.log('[AP] outreply skipped (duplicate)'); return { duplicate: true, delivered: 0 }; } 1871 1895 const id = crypto.randomUUID(); 1872 iStmts().insO.run(id, site.slug, postId, postSlug || null, parent.object_uri || null, parent.actor_uri || null, handle, content );1896 iStmts().insO.run(id, site.slug, postId, postSlug || null, parent.object_uri || null, parent.actor_uri || null, handle, content, replyLang); 1873 1897 const row = iStmts().getO.get(id); 1874 1898 const note = buildReplyNote(base, site, row);
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)