Changeset 6e9bc70 in Klonkt for src/routes/activitypub.js


Ignore:
Timestamp:
10/12/2026 04:15:08 PM (2 days ago)
Author:
Bart <bart@…>
Branches:
main
Children:
61d52ed
Parents:
746d98a
Message:

Zachte groepen: een gesprek is de set deelnemers, niet één tegenpartij

Een direct bericht aan Anna en Ben bestond al als groep -- to_actors droeg de
hele set -- maar elke lezing sleutelde op één other. Een uitgaand bericht
aan twee mensen viel in twee gesprekken uiteen, en een binnenkomend bericht
van Anna aan jou en Ben kwam alleen bij Anna terecht: Ben viel eruit, want de
adressering van een binnenkomer werd nergens bewaard.

Nu is er een sleutel, één keer berekend bij het schrijven
(conversation-key.js): voor één ander zijn kale URI, precies zoals het altijd
was, dus bestaande gesprekken, leesmarkeringen en ?with=-URL's blijven geldig
zonder migratie; voor een groep de gesorteerde set, gescheiden door een
spatie. Koppen, geschiedenis, leesmarkeringen en ongelezen lezen hem allemaal
via dezelfde unie, en werken daarmee per gesprek zonder dat er in die queries
iets hoefde te veranderen. Oude rijen hebben geen sleutel en lezen zoals ze
altijd lazen.

Alleen directe berichten groeperen: een openbare post aan jou en Ben is geen
besloten gesprek met z'n drieën.

/messages neemt meer dan één with, en elk item draagt shaer:conversation en
shaer:participants. Uitgaande directe notes krijgen een FEP-7888 context --
die van de ouder als het een antwoord is, anders een nieuwe -- die bewaard en
uitgestuurd wordt, maar geen bubbels samenvoegt: een bubbel die Carla toont
terwijl je antwoord haar niet bereikt, zou liegen over wie meeleest.

shaer-mbji
Co-Authored-By: Claude Opus 5.5 <claude@…>

File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/routes/activitypub.js

    r746d98a r6e9bc70  
    2020import OAuth from '../services/OAuthService.js';
    2121import * as Guardianship from '../services/guardianship/index.js';
     22import * as ConversationKey from '../services/conversation-key.js';
    2223import * as Migration from '../services/MigrationService.js';
    2324import { getPrimarySite } from '../middleware/site.js';
    … …  
    626627    }
    627628  }
     629  // WELK GESPREK, EN MET WIE (shaer-mbji). De client kon dat afleiden uit de
     630  // adressering van de note -- maar een binnenkomer draagt die niet mee in zijn
     631  // kaart, dus een bericht van Anna aan jou en Ben las als iets van Anna alleen.
     632  // De server weet het: de sleutel staat in de kop. Twee termen, zodat een
     633  // client die alleen de deelnemers wil niet een sleutel hoeft te ontleden.
     634  for (const { head, item } of pairs) {
     635    const obj = item && item.object;
     636    if (!obj || !head.other) continue;
     637    obj['shaer:conversation'] = head.other;
     638    obj['shaer:participants'] = ConversationKey.participantsOfKey(head.other);
     639  }
    628640  return pairs;
    629641}
    … …  
    673685  const auth = OAuth.verifyBearer(req.headers.authorization);
    674686  if (!auth || auth.site.slug !== req.params.slug) return res.status(403).end();
    675   const other = String(req.query.with || '');
    676   if (!/^https?:\/\//i.test(other)) return res.status(400).json({ error: 'with must be an actor URI' });
     687  // EÉN OF MEER `with` (shaer-mbji). Eén is het gesprek met die persoon, zoals
     688  // altijd; meer is de zachte groep van precies die mensen. De sleutel komt
     689  // uit dezelfde functie als bij het schrijven, dus {Anna, Ben} en {Ben, Anna}
     690  // vragen hetzelfde gesprek op.
     691  const withs = [].concat(req.query.with || []).map(String);
     692  if (!withs.length || !withs.every((u) => /^https?:\/\//i.test(u))) {
     693    return res.status(400).json({ error: 'with must be one or more actor URIs' });
     694  }
     695  const other = ConversationKey.conversationKey(withs);
     696  if (!other) return res.status(400).json({ error: 'with must be one or more actor URIs' });
    677697  const page = AP.conversationHistory(auth.site.slug, other, {
    678698    before: req.query.before ? String(req.query.before) : null,
    … …  
    684704  // dan klopt het ritme van een 'load more' niet meer met wat de gebruiker ziet.
    685705  const size = req.query.limit ? `&limit=${encodeURIComponent(String(req.query.limit))}` : '';
    686   const self = `${baseUrl(req)}/ap/users/${encodeURIComponent(auth.site.slug)}/messages?with=${encodeURIComponent(other)}`;
     706  // Elke deelnemer een eigen `with`, zodat de next-link hetzelfde gesprek
     707  // opvraagt. De sleutel zelf er kaal in zetten zou bij een groep een spatie in
     708  // de URL leggen, en wie die als één adres leest vraagt iets anders op.
     709  const withQuery = ConversationKey.participantsOfKey(other).map((u) => `with=${encodeURIComponent(u)}`).join('&');
     710  const self = `${baseUrl(req)}/ap/users/${encodeURIComponent(auth.site.slug)}/messages?${withQuery}`;
    687711  AP.sendAP(res, {
    688712    '@context': AP.AP_CONTEXT,
Note: See TracChangeset for help on using the changeset viewer.