Changeset d71ed03 in Klonkt


Ignore:
Timestamp:
06/26/2026 09:28:16 AM (2 months ago)
Author:
Robin Genis <roboburr@…>
Branches:
main
Children:
355364c
Parents:
1968592
Message:

feat(cirkel): auto-migrate legacy circle_links to auto-boost on boot (once)

A site that updates past the old Cirkels protocol would silently lose its cirkel
(circle_links no longer feed /cirkel, and no auto-boost follows existed yet).
autoMigrateCircles() runs once per instance at startup (guarded by a
circles_migrated_v1 flag, async, best-effort) and converts active circle_links
into AP follows with auto-boost — so sound-fabrics/deno/self-hosters self-heal
without the manual scripts/migrate-circles.mjs step.

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

Location:
src
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • src/server.js

    r1968592 rd71ed03  
    5858import ogRoutes from './routes/og.js';
    5959import apRoutes from './routes/activitypub.js';
    60 import { apWants, startDeliveryWorker } from './services/ActivityPubService.js';
     60import { apWants, startDeliveryWorker, autoMigrateCircles } from './services/ActivityPubService.js';
    6161
    6262// SESSION_SECRET: use the env var if set. Otherwise auto-generate a strong one
     
    161161startScheduler(); // release planning: publish scheduled posts when publish_at is reached
    162162startDeliveryWorker(); // retry failed fediverse deliveries with backoff
     163autoMigrateCircles(); // one-time: convert legacy circle_links -> AP auto-boost follows
    163164
    164165// Safety net: guarantee that there is always a primary site (solo/hub/circle).
  • src/services/ActivityPubService.js

    r1968592 rd71ed03  
    10541054}
    10551055
     1056// One-time, best-effort migration of the old Cirkels (pull-protocol circle_links)
     1057// into ActivityPub follows with auto-boost. Runs once per instance at boot so a
     1058// site that updates past the old protocol keeps its cirkel without a manual step.
     1059async function resolveApActor(siteUrl) {
     1060  try {
     1061    const r = await fetch(siteUrl, { headers: { Accept: 'application/activity+json' }, redirect: 'manual' });
     1062    // A Klonkt site's root 302s to /ap/users/<slug> (Location may be relative).
     1063    if (r.status >= 300 && r.status < 400) { const loc = r.headers.get('location'); if (loc) return new URL(loc, siteUrl).href; }
     1064    if (r.ok) return siteUrl;
     1065  } catch { /* unreachable */ }
     1066  return null;
     1067}
     1068let _circlesMigrating = false;
     1069export async function autoMigrateCircles() {
     1070  if (_circlesMigrating) return; _circlesMigrating = true;
     1071  try {
     1072    let done; try { done = db.prepare('SELECT value FROM app_settings WHERE key = ?').get('circles_migrated_v1'); } catch { return; }
     1073    if (done && done.value === '1') return;
     1074    let links = [];
     1075    try { links = db.prepare("SELECT cl.remote_url AS url, s.id AS sid, s.slug AS slug FROM circle_links cl JOIN sites s ON s.id = cl.local_site_id WHERE cl.status = 'active'").all(); } catch { /* no legacy table */ }
     1076    let ok = 0;
     1077    for (const l of links) {
     1078      try {
     1079        const actor = await resolveApActor(l.url);
     1080        if (actor) { const r = await followActor({ id: l.sid, slug: l.slug }, actor, true); if (!(r && r.error)) ok++; }
     1081      } catch { /* best-effort per link */ }
     1082    }
     1083    try { db.prepare('INSERT OR REPLACE INTO app_settings (key, value) VALUES (?, ?)').run('circles_migrated_v1', '1'); } catch { /* ignore */ }
     1084    if (links.length) console.log(`[AP] circle migration: ${ok}/${links.length} legacy link(s) -> auto-boost`);
     1085  } catch { /* never block boot */ } finally { _circlesMigrating = false; }
     1086}
     1087
    10561088// Follow a fediverse account by @handle (WebFinger → actor → signed Follow).
    10571089export async function followActor(site, handle, autoBoost = false) {
     
    12121244  listOutbox, deliverOutboxDelete,
    12131245  webfingerResolve, followActor, resolveRemoteActor, unfollowActor, listFollowing, setAutoBoost, getTimeline, sendInteraction,
    1214   autoBoostCount, getCirkelPosts, getCirkelMembers,
     1246  autoBoostCount, getCirkelPosts, getCirkelMembers, autoMigrateCircles,
    12151247  getNotifications, listBlocks, isBlockedAny, blockTarget, unblock,
    12161248  deliverWithRetry, enqueueDelivery, processDeliveryQueue, startDeliveryWorker,
Note: See TracChangeset for help on using the changeset viewer.