Changeset 8455dac in Klonkt for src/routes/activitypub.js


Ignore:
Timestamp:
08/13/2026 01:05:47 PM (4 weeks ago)
Author:
Robin <roboburr@…>
Branches:
main
Children:
a117862
Parents:
783b9ff
Message:

De outbox bladert nu echt door (shaer-sk4)

Wat er stond was geen paginering maar een KAP: de route haalde twintig posts uit
SQL en hield daar twintig items van over. Alles daarvoor lag niet op een volgende
pagina maar was helemaal onbereikbaar -- ook voor een lezer die netjes next
volgt.

DE MOEILIJKHEID, en waarom dit niet met een tweede slice kon: de outbox mengt
twee bronnen, posts en open tracks, gevlochten op datum. Met twee losse queries
en een offset per tabel weet je niet hoeveel van elk er in pagina drie horen.
outboxSlice doet daarom een UNION met de datum als sleutel, zet de LIMIT/OFFSET
daaroverheen, en haalt pas dan de rijen zelf op -- twee kleine queries voor de
ids van die ene pagina.

De fans-only voorwaarde zit in de UNION, dus de telling klopt per lezer: een
vreemde ziet 50 en een vriend 51, en niet allebei hetzelfde getal met een andere
lijst eronder.

pagedCollection kent nu alGesneden. Zonder dat zou een volle pagina zichzelf
als de enige zien -- hij telt het aantal pagina's uit de LIJST, en die is bij
SQL-paginering precies een pagina lang. Nu telt hij uit totalItems en biedt hij
een next zolang er meer is.

TWEE DINGEN DIE IK BIJNA VERKEERD DEED. outboxSlice en PAGINA_GROOTTE stonden
niet in de DEFAULT export, en de routes importeren AP zo -- dan is het undefined
bij het VERZOEK, niet bij het importeren. Nagelopen op de server: function,
number. En mijn eigen testdata maakte "2026-01-45" voor de 45e post; dat is geen
datum, en toISOString viel er terecht over om.

Zes tests, waaronder de kern: opeenvolgende pagina's overlappen niet en laten
niets vallen -- drie pagina's dekken alle 50, en niets twee keer.

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

File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/routes/activitypub.js

    r783b9ff r8455dac  
    197197    return AP.sendAP(res, AP.buildOutbox(baseUrl(req), site, [], [], { page: paginaNr(req) }), 'private, no-store');
    198198  }
    199   const fanClause = audience === 'friend' ? '' : "AND (fan_only IS NULL OR fan_only = 0)";
    200   const posts = db.prepare(
    201     `SELECT id, slug, title, content, cover_image_url, cover_video_url, nsfw, content_warning, c2s_attachments, quote_json, embed_json, published_at, created_at
    202      FROM posts WHERE site_id = ? AND status = 'published' ${fanClause}
    203      ORDER BY COALESCE(published_at, created_at) DESC LIMIT 20`
    204   ).all(site.id);
     199  // ECHT DOORBLADEREN (shaer-sk4). Hier stonden twintig posts uit SQL met een
     200  // tweede kap van twintig eroverheen: alles daarvoor was niet op een volgende
     201  // pagina maar helemaal onbereikbaar. outboxSlice pagineert over de UNION van
     202  // posts en tracks, want die vlechten op datum en zijn met twee losse queries
     203  // niet te offsetten.
     204  //
    205205  // De tracks gaan mee voor iedereen die de deur door mag; de blocked-tak
    206206  // hierboven levert bewust een outbox ZONDER posts en zonder tracks.
    207   const ob = AP.buildOutbox(baseUrl(req), site, posts, AP.siteOpenTracks(site.id), { page: paginaNr(req) });
     207  const nr = paginaNr(req);
     208  const { posts, tracks, totaal } = AP.outboxSlice(site.id, {
     209    fanOnly: audience === 'friend',
     210    offset: (Math.max(1, nr || 1) - 1) * AP.PAGINA_GROOTTE,
     211    limit: AP.PAGINA_GROOTTE,
     212  });
     213  const ob = AP.buildOutbox(baseUrl(req), site, posts, tracks, { page: nr, totalItems: totaal, alGesneden: true });
    208214  if (audience === 'friend') {
    209215    // The owner's app builds its feed from this leg, and every note here is
Note: See TracChangeset for help on using the changeset viewer.