Changeset 8240e80 in Klonkt for src/services/ActivityPubService.js
- Timestamp:
- 07/22/2026 07:12:11 AM (7 weeks ago)
- Branches:
- main
- Children:
- 96c714f
- Parents:
- 053bf51
- git-author:
- Robin <roboburr@…> (07/22/2026 07:09:32 AM)
- git-committer:
- Robin <roboburr@…> (07/22/2026 07:12:11 AM)
- File:
-
- 1 edited
-
src/services/ActivityPubService.js (modified) (6 diffs)
Legend:
- Unmodified
- Added
- Removed
-
src/services/ActivityPubService.js
r053bf51 r8240e80 22 22 import HtmlSanitizerService from './HtmlSanitizerService.js'; 23 23 import AudioEmbedService from './AudioEmbedService.js'; 24 import Push from './PushService.js'; 25 import { getTenancy } from './SettingsService.js'; 24 26 25 27 const PUBLIC = 'https://www.w3.org/ns/activitystreams#Public'; … … 1262 1264 } 1263 1265 1266 // ── Web push to the owner (docs/webpush-design.md, slice 3) ───────── 1267 // Fire-and-forget: a notification must never block or break inbox processing. 1268 function pushEvent(slug, event) { 1269 try { Push.notifySite(slug, event).catch(() => {}); } catch { /* never throw */ } 1270 } 1271 // Hub-aware path prefix for a site's pages ('' in solo). 1272 function pushPrefix(slug) { 1273 try { return getTenancy() === 'hub' ? `/user/${slug}` : ''; } catch { return ''; } 1274 } 1275 // Site slug, target URL and title for a post-scoped notification. 1276 function pushPostCtx(postId) { 1277 try { 1278 const r = db.prepare('SELECT p.slug AS post, p.title, s.slug AS site FROM posts p JOIN sites s ON s.id = p.site_id WHERE p.id = ?').get(postId); 1279 if (!r) return null; 1280 return { site: r.site, title: r.title || r.post, url: `${pushPrefix(r.site)}/${r.post}#fediverse` }; 1281 } catch { return null; } 1282 } 1283 1264 1284 // Handle an incoming inbox POST. slugParam = null for the shared /ap/inbox. 1265 1285 export async function handleInbox(req, slugParam) { … … 1323 1343 fStmts().ins.run(slug, who, remote.inbox, sharedInbox, fi.name, fi.handle, fi.icon); 1324 1344 try { _updFDisp.run(fi.name, fi.handle, fi.icon, slug, who); } catch { /* best effort */ } 1345 pushEvent(slug, { type: 'follow', title: 'Nieuwe volger', body: `${fi.name || fi.handle || 'Iemand'} volgt je nu`, url: `${pushPrefix(slug)}/connect` }); 1325 1346 const me = actorId(base, slug); 1326 1347 const keys = getOrCreateKeys(slug); … … 1385 1406 iStmts().ins.run('reply', tgt.post_id, o.id || '', actorUri, ai.name, ai.handle, ai.url, ai.icon, html, o.published || null, tgt.parent_uri, noteVisibility(o)); 1386 1407 console.log('[AP] reply', actorUri, '→', tgt.post_id); 1408 { 1409 // Private (followers/direct) replies push as a DM ping WITHOUT content 1410 // (the push service should never carry private text, design decision); 1411 // public replies carry a short snippet. 1412 const ctx = pushPostCtx(tgt.post_id); 1413 const vis = noteVisibility(o); 1414 const priv = vis === 'direct' || vis === 'followers'; 1415 const who = ai.name || ai.handle || 'Iemand'; 1416 if (ctx) { 1417 if (priv) pushEvent(ctx.site, { type: 'dm', title: 'Privébericht', body: `Nieuw bericht van ${who}`, url: `${pushPrefix(ctx.site)}/messages` }); 1418 else pushEvent(ctx.site, { type: 'reply', title: `Reactie op "${ctx.title}"`, body: `${who}: ${HtmlSanitizerService.toPlainText(html).slice(0, 90)}`, url: ctx.url }); 1419 } 1420 } 1387 1421 return 202; 1388 1422 } … … 1427 1461 const r = db.prepare('INSERT OR IGNORE INTO ap_mentions (slug, object_uri, note_url, actor_uri, actor_name, actor_handle, actor_icon, actor_url, content, published, created_at) VALUES (?,?,?,?,?,?,?,?,?,?,CURRENT_TIMESTAMP)') 1428 1462 .run(slug, o.id, safeUrl(o.url) || null, actorUri, ai.name, ai.handle, ai.icon, ai.url, html, o.published || null); 1429 if (r.changes) console.log('[AP] mention', actorUri, '→', slug); 1463 if (r.changes) { 1464 console.log('[AP] mention', actorUri, '→', slug); 1465 const vis = noteVisibility(o); 1466 const priv = vis === 'direct' || vis === 'followers'; 1467 const who = ai.name || ai.handle || 'Iemand'; 1468 // Same privacy rule as replies: private mentions push without content. 1469 if (priv) pushEvent(slug, { type: 'dm', title: 'Privébericht', body: `Nieuw bericht van ${who}`, url: `${pushPrefix(slug)}/messages` }); 1470 else pushEvent(slug, { type: 'reply', title: 'Vermelding', body: `${who}: ${HtmlSanitizerService.toPlainText(html).slice(0, 90)}`, url: `${pushPrefix(slug)}/messages` }); 1471 } 1430 1472 } catch { /* ignore */ } 1431 1473 } … … 1482 1524 iStmts().ins.run(type.toLowerCase(), pid, '', actorUri, ai.name, ai.handle, ai.url, ai.icon, null, null, null, noteVisibility(act)); 1483 1525 console.log('[AP]', type === 'Like' ? 'like' : 'boost', actorUri, '→', pid); 1526 { 1527 const ctx = pushPostCtx(pid); 1528 const who = ai.name || ai.handle || 'Iemand'; 1529 if (ctx) { 1530 if (type === 'Like') pushEvent(ctx.site, { type: 'like', title: 'Nieuwe waardering', body: `${who} waardeerde "${ctx.title}"`, url: ctx.url }); 1531 else pushEvent(ctx.site, { type: 'boost', title: 'Geboost', body: `${who} boostte "${ctx.title}"`, url: ctx.url }); 1532 } 1533 } 1484 1534 } else if (type === 'Announce' && objUrl && actorUri && !isLocalActor) { 1485 1535 // A boost FROM an account we follow, of a REMOTE post → show it in the News feed.
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)