Changeset 03583f6 in Klonkt for src/routes/activitypub.js


Ignore:
Timestamp:
08/08/2026 12:26:52 AM (5 weeks ago)
Author:
Robin <roboburr@…>
Branches:
main
Children:
457e87b
Parents:
2d13bf3
git-author:
Robin <roboburr@…> (08/08/2026 12:16:05 AM)
git-committer:
Robin <roboburr@…> (08/08/2026 12:26:52 AM)
Message:

De thread onder een vreemde post: ophalen via je eigen server, nooit bewaren

shaer-tqz, Barts besluit van 7-8. GET /ap/users/:slug/thread?object=<uri>,
bearer-only: de eigen app vraagt, Klonkt doet de ondertekende GET die de
app niet kan (de sleutel woont hier), loopt EEN pagina van de AS2
replies-collectie af (cap 30), normaliseert en geeft terug. Cache twee
minuten in het geheugen, weg bij een herstart. Geen tabel, geen migratie:
Klonkt is hier een tolk, geen archief. Dat is de afwijking van wat
Mastodon doet (dat bewaart /context in zijn database) en dat is bewust --
bij een instance van een persoon slaat die opslag alleen surfgedrag op.

NIET hetzelfde als maybeCrawlThread: die kruipt de thread onder je EIGEN
posts af en bewaart in ap_interactions -- dat zijn de jouwe, die horen te
blijven. De naambotsing die dat bijna opleverde (THREAD_TTL_MS) is met
THREAD_VIEW_* opgelost en het onderscheid staat nu in het commentaar.

Voor een ward geldt de veiligste stand tot shaer-vw4 beslist is: alleen
antwoorden uit de kring die de guardians al kennen (gevolgd of volgend),
en shaer:hidden telt wat erbuiten viel -- geteld, nooit stil weggelaten.
Geblokkeerden zijn een andere categorie: onzichtbaar, ook als getal.

Vier tests: de gewone lezer (schonen, sorteren, blokkade onzichtbaar), de
ward met de telling, de onbereikbare bron die dat zegt in plaats van een
lege thread te veinzen, en de cache die de tweede lezing nul fetches kost.

Co-Authored-By: Claude Opus 5 <noreply@…>

File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/routes/activitypub.js

    r2d13bf3 r03583f6  
    704704
    705705// ── Replies collection ── lets remote servers fetch a post's whole thread.
     706// ── De thread onder een post (shaer-tqz): ophalen, niet bewaren ────
     707//
     708// Bearer-only: dit is de eigen app van deze account die vraagt, nooit een
     709// vreemde. Klonkt doet de ondertekende GET die de app zelf niet kan (de
     710// sleutel staat hier), loopt één pagina van de replies-collectie af en geeft
     711// genormaliseerde notes terug. Er wordt NIETS opgeslagen; zie getThread.
     712//
     713// Voor een ward geldt de veiligste stand tot shaer-vw4 beslist is: alleen
     714// antwoorden uit de kring die de guardians al kennen, en shaer:hidden telt wat
     715// er buiten viel. De telling staat er zodat de UI eerlijk kan zijn -- OF hij
     716// getoond wordt is onderdeel van datzelfde besluit.
     717router.get('/ap/users/:slug/thread', async (req, res) => {
     718  const auth = OAuth.verifyBearer(req.headers.authorization);
     719  if (!auth || auth.site.slug !== req.params.slug) return res.status(403).end();
     720  const objectUri = String(req.query.object || '');
     721  if (!/^https:\/\//i.test(objectUri)) return res.status(400).json({ error: 'object must be an https URI' });
     722  const isWard = (() => { try { return Guardianship.listGuardians(auth.site.slug).length > 0; } catch { return false; } })();
     723  const uit = await AP.getThread(auth.site.slug, objectUri, { isWard });
     724  if (!uit.found) return res.status(404).json({ error: 'note not reachable' });
     725  AP.sendAP(res, {
     726    '@context': AP.AP_CONTEXT,
     727    id: `${baseUrl(req)}/ap/users/${encodeURIComponent(auth.site.slug)}/thread?object=${encodeURIComponent(objectUri)}`,
     728    type: 'OrderedCollection',
     729    totalItems: uit.notes.length,
     730    orderedItems: uit.notes,
     731    'shaer:hidden': uit.hidden || undefined,
     732  }, 'private, no-store');
     733});
     734
    706735router.get('/ap/notes/:id/replies', (req, res) => {
    707736  const base = baseUrl(req);
Note: See TracChangeset for help on using the changeset viewer.