Changeset f1e0c1f in Klonkt


Ignore:
Timestamp:
06/25/2026 07:08:31 AM (3 months ago)
Author:
Robin Genis <roboburr@…>
Branches:
main
Children:
5085b1d
Parents:
75bda38
Message:

fediverse: push actor Update on pin/unpin so Mastodon refreshes the featured collection

Mastodon only re-fetches an actor's featured (pinned) collection on actor refresh, and
there is no 'featured changed' activity. deliverActorUpdate sends Update(Person) to
followers; /save fires it when a post's pin rank changes → pins propagate promptly.

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

Location:
src
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • src/routes/posts.js

    r75bda38 rf1e0c1f  
    365365    if (post.status !== 'published') ActivityPubService.deliverCreate(site, apPost).catch(() => { /* best-effort */ });
    366366    else ActivityPubService.deliverUpdate(site, apPost).catch(() => { /* best-effort */ });
     367  }
     368
     369  // Pin/unpin changed → push an actor Update so Mastodon re-fetches the featured
     370  // (pinned) collection promptly instead of waiting for its own actor refresh.
     371  if ((post.pinned || 0) !== parsePinnedRank(pinned)) {
     372    ActivityPubService.deliverActorUpdate(site).catch(() => { /* best-effort */ });
    367373  }
    368374
  • src/services/ActivityPubService.js

    r75bda38 rf1e0c1f  
    651651    type: 'Update', actor: me, to: [PUBLIC], cc: [`${me}/followers`],
    652652    object: note,
     653  };
     654  for (const inbox of inboxes) deliverWithRetry(site.slug, inbox, update, `${me}#main-key`, keys.private_pem);
     655}
     656
     657// Tell followers the ACTOR changed (Update + Person) so Mastodon re-processes the
     658// account AND re-fetches the featured (pinned) collection — there is no standard
     659// "featured changed" activity, so this is how a pin/unpin propagates promptly.
     660export async function deliverActorUpdate(site) {
     661  const base = (process.env.PUBLIC_BASE_URL || '').replace(/\/+$/, '');
     662  if (!base || !site || !site.slug) return;
     663  const followers = fStmts().list.all(site.slug);
     664  if (!followers.length) return;
     665  const inboxes = [...new Set(followers.map((f) => f.shared_inbox || f.inbox).filter(Boolean))];
     666  const keys = getOrCreateKeys(site.slug);
     667  const me = actorId(base, site.slug);
     668  const update = {
     669    '@context': ['https://www.w3.org/ns/activitystreams', 'https://w3id.org/security/v1'],
     670    id: `${me}#update-${Date.now()}`,
     671    type: 'Update', actor: me, to: [PUBLIC], cc: [`${me}/followers`],
     672    object: buildActor(base, site),
    653673  };
    654674  for (const inbox of inboxes) deliverWithRetry(site.slug, inbox, update, `${me}#main-key`, keys.private_pem);
     
    9851005  getOrCreateKeys, apWants, sendAP, actorId, noteId,
    9861006  buildActor, buildNote, buildCreate, buildOutbox, buildFollowers, buildFeatured,
    987   followerCount, deliver, fetchActor, verifyRequest, handleInbox, deliverCreate, deliverDelete, deliverUpdate,
     1007  followerCount, deliver, fetchActor, verifyRequest, handleInbox, deliverCreate, deliverDelete, deliverUpdate, deliverActorUpdate,
    9881008  getInteractions, getInteractionById, buildReplyNote, getOutboxNote, deliverReply, resolveRemoteNote,
    9891009  listOutbox, deliverOutboxDelete,
Note: See TracChangeset for help on using the changeset viewer.