Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/routes/activitypub.js

    rfa33214 r1e172f3  
    253253}
    254254queueRoute('offers', (id, slug, me) => Guardianship.offersCollection(id, slug, me));
    255 queueRoute('follows', (id) => Guardianship.followsCollection(id));
     255queueRoute('follows', (id, slug, me) => Guardianship.followsCollection(id, slug, me));
    256256// §5.3 turned around (shaer-p729): what this ward has asked to follow, still
    257257// waiting on its guardians. Owner-only like the rest — who a child wants to
     
    268268// they follow) as Create(Note) items, so an app (Shaer) can build a unified
    269269// feed. Anyone else gets 403; the inbox stays write-only for the public.
    270 router.get('/ap/users/:slug/inbox', (req, res) => {
     270router.get('/ap/users/:slug/inbox', async (req, res) => {
    271271  const auth = OAuth.verifyBearer(req.headers.authorization);
    272272  if (!auth || auth.site.slug !== req.params.slug) return res.status(403).end();
    273273  const base = baseUrl(req);
     274  // Wachten is een UITBREIDING van deze lezing, geen tweede endpoint (shaer-n05).
     275  // Geef `since` (de shaer:cursor van je vorige antwoord) en `wait` mee, en het
     276  // antwoord blijft hangen tot er iets is of de tijd om is. Zonder die twee
     277  // gedraagt de route zich exact zoals altijd.
     278  //
     279  // Bewust hetzelfde antwoord in plaats van een "er is nieuws"-seintje: dan
     280  // hoeft er niets nieuws geparsed te worden, is er geen tweede beschrijving van
     281  // de kaartvorm die uit de pas kan lopen, en scheelt het de client een tweede
     282  // ronde.
     283  const wachtS = Math.min(Math.max(parseInt(req.query.wait, 10) || 0, 0), 50);
     284  if (req.query.since && wachtS > 0) {
     285    const afbreken = new AbortController();
     286    res.on('close', () => afbreken.abort());   // client hing op: niet doorgaan met wachten
     287    const uit = await AP.waitForFeedChange(auth.site.slug, {
     288      since: String(req.query.since), waitMs: wachtS * 1000, signal: afbreken.signal,
     289    });
     290    if (res.writableEnded || afbreken.signal.aborted) return undefined;
     291    // Niets veranderd? Dan een LEEG antwoord (Barts punt): de hele collectie
     292    // terugsturen terwijl er niets gebeurd is, is elke 25 seconden een tijdlijn
     293    // over de mobiele verbinding voor niets. Met 304 kost stilte niets en kost
     294    // nieuws nog steeds maar één rondje -- beter dan een apart seintje-endpoint,
     295    // dat voor nieuws twee rondjes nodig heeft.
     296    //
     297    // De '0'-uitzondering is geen franje. Ontbreekt ap_feed_state (een instance
     298    // die de migratie nog niet draaide), dan geeft feedCursor altijd '0' terug,
     299    // en zou een client hier eeuwig 304 krijgen en nooit meer inhoud zien. Bij
     300    // een lege merksteen sturen we dus gewoon de collectie.
     301    if (!uit.changed && uit.cursor !== '0') {
     302      res.set('Vary', 'Authorization');
     303      return res.status(304).end();
     304    }
     305  }
    274306  // Gated feature (FEP-633c): may this account see EXTERNAL embeds? A ward's
    275307  // world outside the fediverse is the guardians' call. The gate is applied
     
    285317  const playbackAllowed = embedsAllowed
    286318    && Guardianship.externalPlaybackAllowed(auth.site.external_playback, isWard);
    287   const posts = AP.getTimeline(auth.site.slug, 60).map((t) => ({
     319  const rows = AP.getTimeline(auth.site.slug, 60);
     320  // Eén query voor de hele pagina (shaer-9e9 fase 2): shaer:liked komt uit de
     321  // tussentabel, de bron van waarheid, en niet meer uit de afgeleide kolom op
     322  // ap_timeline. Per rij vragen zou hier een N+1 opleveren.
     323  const reacties = AP.getReactionsFor(auth.site.slug, rows.map((t) => t.id));
     324  const posts = rows.map((t) => ({
    288325    id: `${t.id}#create`,
    289326    type: 'Create',
     
    333370      // Whether THIS account already liked/boosted the note, so the app's
    334371      // detail-view buttons show the current state (and can toggle/undo).
    335       'shaer:liked': !!t.liked,
    336       'shaer:boosted': !!t.boosted,
     372      'shaer:liked': !!(reacties.get(t.id) || {}).liked,
     373      'shaer:boosted': !!(reacties.get(t.id) || {}).boosted,
    337374      // An external (non-fediverse) embed, thumbnail-only and never an iframe.
    338375      // Omitted entirely when the gate is closed (see above).
     
    439476      'shaer:externalLinks': playbackAllowed,
    440477    },
     478    // Het merk van wat hierin zit. Geef hem terug als `since` om op het
     479    // volgende te wachten. NA het samenstellen bepaald, zodat hij precies dekt
     480    // wat je in handen hebt en niet iets dat er ondertussen bij kwam.
     481    'shaer:cursor': AP.feedCursor(auth.site.slug),
    441482    totalItems: items.length,
    442483    orderedItems: items,
    443484  });
     485  return undefined;
    444486});
    445487
Note: See TracChangeset for help on using the changeset viewer.