Changeset 6a99668 in Klonkt for src/routes


Ignore:
Timestamp:
07/30/2026 12:38:57 PM (6 weeks ago)
Author:
Robin <roboburr@…>
Branches:
main
Children:
55eca8b
Parents:
f9b1c5c
Message:

Reply op een ander gefixt: gesigneerd resolven, eigen replies terug in de feed, duplicaat idempotent

Robins waarneming (30-7) legde de keten bloot: reply op jezelf lukt,
reply op een ander geeft 502. Drie oorzaken, drie fixes.

Een: resolveRemoteNote haalde de parent-note ANONIEM op. Een publieke
note (je eigen post) geeft dat, maar een friends-only note (de
Shaer-standaard!) weigert een anonieme GET terecht. Het reply-, like-
en boost-pad over C2S resolven nu gesigneerd als de eigen actor
(asSlug), zodat de andere server ziet wie er vraagt en serveert wat de
vriendschap verdient. Zelfde principe als friends-get-the-history, nu
ook aan de vraagkant.

Twee: je eigen verzonden replies (ap_outbox) werden nergens over C2S
geserveerd. Je reply bestond overal behalve in je eigen app: dus je
probeerde het opnieuw. De C2S inbox-read krijgt een derde leg:
getSentNotes bouwt ze via buildReplyNote (inReplyTo, Mention-tags,
attachments, friends-adressering), met de eigen shaer:author erop en de
leidende mention gestript zoals de DM-leg dat doet.

Drie: die herhaalpoging liep in de duplicate-guard, die zonder id
antwoordde; de ingest maakte daar 502 reply_failed van. Een duplicaat
is nu idempotent succes met het BESTAANDE id.

Changed files:
src/services/ActivityPubService.js

  • resolveRemoteNote(url, {asSlug}): gesigneerde fetches (note, actor en de ancestor-keten); reply/like/boost/undo geven site.slug mee
  • getSentNotes(base, site): eigen ap_outbox-rijen als AS2 Notes
  • duplicate-guard geeft het bestaande id terug

src/routes/activitypub.js

  • C2S inbox-read: sent-leg naast timeline en messages, zelfde vorm

New file:
test/sent-notes.test.js

  • sent reply komt terug als threadbare Note (parent in to, Mention, media absoluut, ISO-published); duplicaat = zelfde id

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

File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/routes/activitypub.js

    rf9b1c5c r6a99668  
    280280    },
    281281  }));
    282   // Newest first over both, so the app can keep treating this as one feed.
    283   const items = [...posts, ...messages].sort((a, b) => String(b.published || '').localeCompare(String(a.published || '')));
     282  // Your OWN sent notes (replies and direct messages, ap_outbox): without
     283  // them a reply existed everywhere except in your own app, Messages showed
     284  // half a conversation, and a retry ran into the duplicate guard (Robins
     285  // melding, 30-7). Served like the other legs: same shape, one parser.
     286  const mine = AP.selfAuthor(base, auth.site);
     287  const sent = AP.getSentNotes(base, auth.site, 60).map((n) => ({
     288    id: `${n.id}#create`,
     289    type: 'Create',
     290    actor: me,
     291    published: n.published,
     292    // The leading mention anchor is addressing, not prose (the DM leg strips
     293    // it the same way); the Mention tags built from the full content stay.
     294    object: { ...n, content: AP.stripLeadingMentions(n.content), 'shaer:author': mine },
     295  }));
     296  // Newest first over all legs, so the app can keep treating this as one feed.
     297  const items = [...posts, ...messages, ...sent].sort((a, b) => String(b.published || '').localeCompare(String(a.published || '')));
    284298  AP.sendAP(res, {
    285299    '@context': AP.AP_CONTEXT,
Note: See TracChangeset for help on using the changeset viewer.