Changeset 4e5fe29 in Klonkt


Ignore:
Timestamp:
08/21/2026 08:58:20 AM (3 weeks ago)
Author:
Robin <roboburr@…>
Branches:
main
Children:
8ed36de
Parents:
e311202
Message:

Tell an ex-follower they are one: Reject(Follow) on removal

Removing a follower was silent, so the other side kept us in its books
as a live relationship while nothing was ever delivered again — the hub
sat there 'following' dev.klonkt.com for days. Reject(Follow) is the
standard signal for exactly this, and the removal itself never waits on
it: the row is gone first, the notice is a courtesy that may fail.

Blocking already carries the stronger Block signal, so this covers the
other door: the owner removing someone by hand.

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

Files:
2 edited

Legend:

Unmodified
Added
Removed
  • src/services/ActivityPubService.js

    re311202 r4e5fe29  
    12631263}
    12641264// Manually drop a follower after a check (a still-live account would have to re-follow).
     1265/**
     1266 * Een volger verwijderen, en het hem ook LATEN WETEN (Robin, 21-8).
     1267 *
     1268 * Reject(Follow) is het standaardsignaal voor "je volgt me niet meer": de
     1269 * andere kant ruimt de relatie dan op in plaats van te blijven denken dat hij
     1270 * volgt. Zonder dit merkte de hub niets -- die bleef als volger in zijn eigen
     1271 * boeken staan terwijl er nooit meer iets werd bezorgd.
     1272 *
     1273 * Verwijderen gaat altijd door; de melding is een gunst en mag mislukken.
     1274 */
    12651275export function removeFollower(slug, id) {
     1276  const rij = db.prepare('SELECT actor_uri FROM ap_followers WHERE slug = ? AND id = ?').get(slug, id);
    12661277  const info = db.prepare('DELETE FROM ap_followers WHERE slug = ? AND id = ?').run(slug, id);
     1278  if (info.changes > 0 && rij && rij.actor_uri) meldNietLangerVolger(slug, rij.actor_uri);
    12671279  return info.changes > 0;
     1280}
     1281
     1282/** Reject(Follow) naar een ex-volger; faalt stil, want de relatie is al weg. */
     1283export function meldNietLangerVolger(slug, actorUri) {
     1284  try {
     1285    const base = (process.env.PUBLIC_BASE_URL || '').replace(/\/+$/, '');
     1286    const me = actorId(base, slug);
     1287    const site = db.prepare('SELECT * FROM sites WHERE slug = ?').get(slug);
     1288    if (!site) return;
     1289    const reject = {
     1290      '@context': AP_CONTEXT,
     1291      id: `${me}#reject-follow-${Date.now()}-${rid()}`,
     1292      type: 'Reject',
     1293      actor: me,
     1294      to: [actorUri],
     1295      object: { type: 'Follow', actor: actorUri, object: me },
     1296    };
     1297    deliverToActor(site, actorUri, reject)
     1298      .then((r) => console.log('[AP] Reject(Follow)', slug, '→', actorUri, r && r.delivered ? 'bezorgd' : 'niet bezorgd'))
     1299      .catch(() => {});
     1300  } catch { /* nooit blokkerend */ }
    12681301}
    12691302
  • test/block-federeert.test.js

    re311202 r4e5fe29  
    7676  assert.equal(db.prepare('SELECT count(*) c FROM ap_blocks WHERE target = ?').get('https://203.0.113.99/ap/actor').c, 1);
    7777});
     78
     79test('een verwijderde volger krijgt een Reject(Follow)', async () => {
     80  bezorgd.length = 0;
     81  const VOLGER = 'https://203.0.113.81/ap/actor';
     82  db.prepare(`INSERT INTO ap_followers (slug, actor_uri, inbox, created_at)
     83              VALUES ('dev', ?, ?, CURRENT_TIMESTAMP)`).run(VOLGER, `${VOLGER}/inbox`);
     84  const rij = db.prepare('SELECT id FROM ap_followers WHERE actor_uri = ?').get(VOLGER);
     85  assert.equal(AP.removeFollower('dev', rij.id), true);
     86  await new Promise((r) => setTimeout(r, 150));   // bezorging is fire-and-forget
     87  const rej = bezorgd.find((b) => b.activiteit.type === 'Reject');
     88  assert.ok(rej, 'er is een Reject bezorgd');
     89  assert.equal(rej.activiteit.object.type, 'Follow');
     90  assert.equal(rej.activiteit.object.actor, VOLGER, 'het gaat om ZIJN follow op ons');
     91  assert.equal(db.prepare('SELECT count(*) c FROM ap_followers WHERE actor_uri = ?').get(VOLGER).c, 0);
     92});
Note: See TracChangeset for help on using the changeset viewer.