Changeset 4838760 in Klonkt for src/routes/activitypub.js


Ignore:
Timestamp:
08/08/2026 05:23:46 PM (4 weeks ago)
Author:
Robin <roboburr@…>
Branches:
main
Children:
d1075a1
Parents:
abcf51a
Message:

De kaart op je eigen post, en de composer-preview (shaer-k3f)

Het bead-uitgangspunt "serverkant is klaar" bleek half waar: AP-quotes
kregen bij publiceren een quote_uri, maar eigen posts hadden geen kolom
voor een kaart-snapshot en de outbox serveerde geen shaer:quote of
shaer:embed -- de app kon een eigen post dus nooit als kaart tonen, ook
na publicatie niet.

Drie stukken, allemaal langs de pijplijn die er al was:

OPSLAAN deliverCreate resolvet de eerste externe link net als de

inbox dat voor binnenkomende posts doet: een fediverse-
object wordt een quote-snapshot (resolveQuoteByUri, de kern
van resolveQuote maar vanaf een kale URI), anders probeert
de link een externe kaart (resolveExternalEmbed). In
posts.quote_json/embed_json, VOOR de vroege return: ook een
post zonder volgers hoort zijn kaart te krijgen, de app
leest hem uit de outbox en niet uit een bezorging.

SERVEREN de friend-poot van de outbox draagt shaer:quote en -- alleen

voor de bearer en langs zijn eigen embeds-poort --
shaer:embed. Een remote vriend krijgt de embed niet: diens
server resolvet en gate zelf bij ontvangst.

PREVIEW GET /ap/users/:slug/card?url= (bearer-only): een URL langs

exact dezelfde pijplijn, zodat de preview in de composer
nooit iets belooft dat de post niet waarmaakt. Zelfde
gate-regels als de tijdlijn.

Drie tests met gestubde fetch: extern -> embed-snapshot, fediverse ->
quote-snapshot (en niet allebei), en de preview die voor dezelfde links
dezelfde kaarten geeft. Alle 723 groen.

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

File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/routes/activitypub.js

    rabcf51a r4838760  
    191191    // entries carry, so your own cards get a header too (avatar + name).
    192192    const me = AP.selfAuthor(baseUrl(req), site);
     193    // De kaart op je eigen post (shaer-k3f): dezelfde shaer:quote/shaer:embed
     194    // die de tijdlijn voor andermans posts draagt, uit de snapshots die
     195    // deliverCreate bij het publiceren opsloeg. Op note-id gekoppeld, want
     196    // buildOutbox sorteert en mengt tracks erdoorheen. De embed alleen voor de
     197    // BEARER en langs zijn eigen poort: een remote vriend krijgt hem niet
     198    // (diens server resolvet en gate zelf bij ontvangst), en een ward zonder
     199    // open embeds-poort krijgt hem hier net zo min als in de tijdlijn.
     200    const byNote = new Map(posts.map((p) => [AP.noteId(baseUrl(req), p.id), p]));
     201    const bearerEmbeds = bearer ? (() => {
     202      const isWard = (() => { try { return Guardianship.listGuardians(bearer.site.slug).length > 0; } catch { return false; } })();
     203      return Guardianship.externalEmbedsAllowed(bearer.site.external_embeds, isWard)
     204        ? { playback: Guardianship.externalPlaybackAllowed(bearer.site.external_playback, isWard) } : null;
     205    })() : null;
    193206    for (const it of ob.orderedItems) {
    194       if (it && it.object && typeof it.object === 'object') it.object['shaer:author'] = me;
     207      if (it && it.object && typeof it.object === 'object') {
     208        it.object['shaer:author'] = me;
     209        const row = byNote.get(it.object.id);
     210        if (row) {
     211          it.object['shaer:quote'] = AP.timelineQuote(row.quote_json);
     212          if (bearerEmbeds) it.object['shaer:embed'] = AP.timelineEmbed(row.embed_json, { playback: bearerEmbeds.playback });
     213        }
     214      }
    195215    }
    196216  }
     
    813833
    814834// ── Replies collection ── lets remote servers fetch a post's whole thread.
     835// ── De composer-preview (shaer-k3f): een URL wordt alvast een kaart ──
     836//
     837// Bearer-only, net als de thread: dit is de eigen app die tijdens het typen
     838// vraagt wat een link gaat worden. Dezelfde pijplijn als publiceren, dus de
     839// preview kan niet iets beloven dat de post niet waarmaakt. De embed gaat
     840// langs de eigen poort van de lezer -- een ward zonder open embeds-poort
     841// krijgt in de composer geen kaart die zijn feed hem ook niet zou tonen.
     842router.get('/ap/users/:slug/card', async (req, res) => {
     843  const auth = OAuth.verifyBearer(req.headers.authorization);
     844  if (!auth || auth.site.slug !== req.params.slug) return res.status(403).end();
     845  const uit = await AP.previewCard(String(req.query.url || ''));
     846  const isWard = (() => { try { return Guardianship.listGuardians(auth.site.slug).length > 0; } catch { return false; } })();
     847  const embedsAllowed = Guardianship.externalEmbedsAllowed(auth.site.external_embeds, isWard);
     848  const playback = embedsAllowed && Guardianship.externalPlaybackAllowed(auth.site.external_playback, isWard);
     849  AP.sendAP(res, {
     850    '@context': AP.AP_CONTEXT,
     851    'shaer:quote': AP.timelineQuote(uit.quoteJson),
     852    'shaer:embed': embedsAllowed ? AP.timelineEmbed(uit.embedJson, { playback }) : undefined,
     853  }, 'private, no-store');
     854});
     855
    815856// ── De thread onder een post (shaer-tqz): ophalen, niet bewaren ────
    816857//
Note: See TracChangeset for help on using the changeset viewer.