@rmdes/indiekit-endpoint-activitypub 2.0.31 → 2.0.32
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/fedidb.js +75 -28
- package/package.json +1 -1
package/lib/fedidb.js
CHANGED
|
@@ -2,10 +2,13 @@
|
|
|
2
2
|
* FediDB API client with MongoDB caching.
|
|
3
3
|
*
|
|
4
4
|
* Wraps https://api.fedidb.org/v1/ endpoints:
|
|
5
|
-
* - /servers
|
|
5
|
+
* - /servers — cursor-paginated list of known fediverse instances (ranked by size)
|
|
6
6
|
* - /popular-accounts — top accounts by follower count
|
|
7
7
|
*
|
|
8
|
-
*
|
|
8
|
+
* NOTE: The /servers endpoint ignores query params (q, search, name) and always
|
|
9
|
+
* returns the same ranked list. We paginate through ~500 servers, cache the full
|
|
10
|
+
* corpus for 24 hours, and filter locally when the user searches.
|
|
11
|
+
*
|
|
9
12
|
* Cache TTL: 24 hours for both datasets.
|
|
10
13
|
*/
|
|
11
14
|
|
|
@@ -71,46 +74,90 @@ async function writeToCache(kvCollection, cacheKey, data) {
|
|
|
71
74
|
}
|
|
72
75
|
|
|
73
76
|
/**
|
|
74
|
-
*
|
|
75
|
-
*
|
|
77
|
+
* Fetch the FediDB server catalogue by paginating through cursor-based results.
|
|
78
|
+
* Cached for 24 hours as a single entry. The API ignores the `q` param and
|
|
79
|
+
* always returns a ranked list, so we collect a large corpus and filter locally.
|
|
76
80
|
*
|
|
77
|
-
*
|
|
81
|
+
* Paginates up to MAX_PAGES (13 pages × 40 = ~520 servers), which covers
|
|
82
|
+
* all well-known instances. Results are cached in ap_kv for 24 hours.
|
|
78
83
|
*
|
|
79
84
|
* @param {object} kvCollection - MongoDB ap_kv collection
|
|
80
|
-
* @param {string} query - Search term (e.g. "mast")
|
|
81
|
-
* @param {number} [limit=10] - Max results
|
|
82
85
|
* @returns {Promise<Array>}
|
|
83
86
|
*/
|
|
84
|
-
|
|
85
|
-
const q = (query || "").trim().toLowerCase();
|
|
86
|
-
if (!q) return [];
|
|
87
|
+
const MAX_PAGES = 13;
|
|
87
88
|
|
|
88
|
-
|
|
89
|
+
async function getAllServers(kvCollection) {
|
|
90
|
+
const cacheKey = "fedidb:servers-all";
|
|
89
91
|
const cached = await getFromCache(kvCollection, cacheKey);
|
|
90
92
|
if (cached) return cached;
|
|
91
93
|
|
|
94
|
+
const results = [];
|
|
95
|
+
|
|
92
96
|
try {
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
97
|
+
let cursor = null;
|
|
98
|
+
|
|
99
|
+
for (let page = 0; page < MAX_PAGES; page++) {
|
|
100
|
+
let url = `${API_BASE}/servers?limit=40`;
|
|
101
|
+
if (cursor) url += `&cursor=${cursor}`;
|
|
102
|
+
|
|
103
|
+
const res = await fetchWithTimeout(url);
|
|
104
|
+
if (!res.ok) break;
|
|
105
|
+
|
|
106
|
+
const json = await res.json();
|
|
107
|
+
const servers = json.data || [];
|
|
108
|
+
if (servers.length === 0) break;
|
|
109
|
+
|
|
110
|
+
for (const s of servers) {
|
|
111
|
+
results.push({
|
|
112
|
+
domain: s.domain,
|
|
113
|
+
software: s.software?.name || "Unknown",
|
|
114
|
+
description: s.description || "",
|
|
115
|
+
mau: s.stats?.monthly_active_users || 0,
|
|
116
|
+
userCount: s.stats?.user_count || 0,
|
|
117
|
+
openRegistration: s.open_registration || false,
|
|
118
|
+
});
|
|
119
|
+
}
|
|
96
120
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
const results = servers.map((s) => ({
|
|
101
|
-
domain: s.domain,
|
|
102
|
-
software: s.software?.name || "Unknown",
|
|
103
|
-
description: s.description || "",
|
|
104
|
-
mau: s.stats?.monthly_active_users || 0,
|
|
105
|
-
userCount: s.stats?.user_count || 0,
|
|
106
|
-
openRegistration: s.open_registration || false,
|
|
107
|
-
}));
|
|
121
|
+
cursor = json.meta?.next_cursor;
|
|
122
|
+
if (!cursor) break;
|
|
123
|
+
}
|
|
108
124
|
|
|
109
|
-
|
|
110
|
-
|
|
125
|
+
if (results.length > 0) {
|
|
126
|
+
await writeToCache(kvCollection, cacheKey, results);
|
|
127
|
+
}
|
|
111
128
|
} catch {
|
|
112
|
-
|
|
129
|
+
// Return whatever we collected so far
|
|
113
130
|
}
|
|
131
|
+
|
|
132
|
+
return results;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Search FediDB for instances matching a query.
|
|
137
|
+
* Returns a flat array of { domain, software, description, mau, openRegistration }.
|
|
138
|
+
*
|
|
139
|
+
* Fetches the full server list once (cached 24h) and filters by domain/software match.
|
|
140
|
+
* FediDB's /v1/servers endpoint ignores the `q` param and always returns a static
|
|
141
|
+
* ranked list, so server-side filtering is the only way to get relevant results.
|
|
142
|
+
*
|
|
143
|
+
* @param {object} kvCollection - MongoDB ap_kv collection
|
|
144
|
+
* @param {string} query - Search term (e.g. "mast")
|
|
145
|
+
* @param {number} [limit=10] - Max results
|
|
146
|
+
* @returns {Promise<Array>}
|
|
147
|
+
*/
|
|
148
|
+
export async function searchInstances(kvCollection, query, limit = 10) {
|
|
149
|
+
const q = (query || "").trim().toLowerCase();
|
|
150
|
+
if (!q) return [];
|
|
151
|
+
|
|
152
|
+
const allServers = await getAllServers(kvCollection);
|
|
153
|
+
|
|
154
|
+
return allServers
|
|
155
|
+
.filter(
|
|
156
|
+
(s) =>
|
|
157
|
+
s.domain.toLowerCase().includes(q) ||
|
|
158
|
+
s.software.toLowerCase().includes(q),
|
|
159
|
+
)
|
|
160
|
+
.slice(0, limit);
|
|
114
161
|
}
|
|
115
162
|
|
|
116
163
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rmdes/indiekit-endpoint-activitypub",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.32",
|
|
4
4
|
"description": "ActivityPub federation endpoint for Indiekit via Fedify. Adds full fediverse support: actor, inbox, outbox, followers, following, syndication, and Mastodon migration.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"indiekit",
|