From 4aff8895c04a18e695d0b12256eda88c9241d4db Mon Sep 17 00:00:00 2001 From: Ricardo Date: Fri, 27 Feb 2026 11:45:27 +0100 Subject: [PATCH] chore: bump version to 2.0.32 --- lib/fedidb.js | 68 ++++++++++++++++++++++++++++++++++----------------- package.json | 2 +- 2 files changed, 47 insertions(+), 23 deletions(-) diff --git a/lib/fedidb.js b/lib/fedidb.js index 9ba8b74..f5e1768 100644 --- a/lib/fedidb.js +++ b/lib/fedidb.js @@ -2,10 +2,13 @@ * FediDB API client with MongoDB caching. * * Wraps https://api.fedidb.org/v1/ endpoints: - * - /servers?q=... — search known fediverse instances + * - /servers — cursor-paginated list of known fediverse instances (ranked by size) * - /popular-accounts — top accounts by follower count * - * Responses are cached in ap_kv to avoid hitting the API on every keystroke. + * NOTE: The /servers endpoint ignores query params (q, search, name) and always + * returns the same ranked list. We paginate through ~500 servers, cache the full + * corpus for 24 hours, and filter locally when the user searches. + * * Cache TTL: 24 hours for both datasets. */ @@ -71,41 +74,62 @@ async function writeToCache(kvCollection, cacheKey, data) { } /** - * Get the full FediDB server list (up to 40, the API max). - * Cached for 24 hours as a single entry. The API ignores query params - * and always returns the same ranked-by-MAU list, so we fetch once - * and filter client-side in searchInstances(). + * Fetch the FediDB server catalogue by paginating through cursor-based results. + * Cached for 24 hours as a single entry. The API ignores the `q` param and + * always returns a ranked list, so we collect a large corpus and filter locally. + * + * Paginates up to MAX_PAGES (13 pages × 40 = ~520 servers), which covers + * all well-known instances. Results are cached in ap_kv for 24 hours. * * @param {object} kvCollection - MongoDB ap_kv collection * @returns {Promise} */ +const MAX_PAGES = 13; + async function getAllServers(kvCollection) { const cacheKey = "fedidb:servers-all"; const cached = await getFromCache(kvCollection, cacheKey); if (cached) return cached; + const results = []; + try { - const url = `${API_BASE}/servers?limit=40`; - const res = await fetchWithTimeout(url); - if (!res.ok) return []; + let cursor = null; - const json = await res.json(); - const servers = json.data || []; + for (let page = 0; page < MAX_PAGES; page++) { + let url = `${API_BASE}/servers?limit=40`; + if (cursor) url += `&cursor=${cursor}`; - const results = servers.map((s) => ({ - domain: s.domain, - software: s.software?.name || "Unknown", - description: s.description || "", - mau: s.stats?.monthly_active_users || 0, - userCount: s.stats?.user_count || 0, - openRegistration: s.open_registration || false, - })); + const res = await fetchWithTimeout(url); + if (!res.ok) break; - await writeToCache(kvCollection, cacheKey, results); - return results; + const json = await res.json(); + const servers = json.data || []; + if (servers.length === 0) break; + + for (const s of servers) { + results.push({ + domain: s.domain, + software: s.software?.name || "Unknown", + description: s.description || "", + mau: s.stats?.monthly_active_users || 0, + userCount: s.stats?.user_count || 0, + openRegistration: s.open_registration || false, + }); + } + + cursor = json.meta?.next_cursor; + if (!cursor) break; + } + + if (results.length > 0) { + await writeToCache(kvCollection, cacheKey, results); + } } catch { - return []; + // Return whatever we collected so far } + + return results; } /** diff --git a/package.json b/package.json index 00fcbd0..23d1ef1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@rmdes/indiekit-endpoint-activitypub", - "version": "2.0.31", + "version": "2.0.32", "description": "ActivityPub federation endpoint for Indiekit via Fedify. Adds full fediverse support: actor, inbox, outbox, followers, following, syndication, and Mastodon migration.", "keywords": [ "indiekit",