simple list of pds servers with open registration
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Detect all supported software at display time via version map

Load version_map metadata for all tracked software and use it for
detection at render time. This catches Cirrus, Cocoon, and any other
software with plain semver versions, not just name-prefixed ones.
Detection chain: DB field → exact version map → extracted semver map
→ version string prefix → default bluesky-pds.

+54 -13
+54 -13
backend/routes/pages.ts
··· 10 10 getTrackedSoftware, 11 11 PDS_SOFTWARE_REGISTRY, 12 12 } from "../../shared/constants.ts"; 13 - import type { LatestVersionMap, PdsServer } from "../../shared/types.ts"; 13 + import type { 14 + LatestVersionMap, 15 + PdsServer, 16 + VersionSoftwareMap, 17 + } from "../../shared/types.ts"; 14 18 import { isSafeHref } from "../../shared/url-validation.ts"; 15 19 16 20 const pages = new Hono(); 17 21 18 22 pages.get("/", async (c) => { 19 - // Fetch per-software latest versions 23 + // Fetch per-software latest versions and version maps 20 24 const tracked = getTrackedSoftware(); 21 25 const latestVersions: LatestVersionMap = {}; 22 - const versionPromises = tracked.map(async (sw) => { 23 - const v = await getMetadata(`latest_version:${sw.id}`); 24 - if (v) latestVersions[sw.id] = v; 26 + const versionToSoftware: VersionSoftwareMap = {}; 27 + const metadataPromises = tracked.map(async (sw) => { 28 + const [latest, versionsJson] = await Promise.all([ 29 + getMetadata(`latest_version:${sw.id}`), 30 + getMetadata(`version_map:${sw.id}`), 31 + ]); 32 + if (latest) latestVersions[sw.id] = latest; 33 + if (versionsJson) { 34 + for (const v of JSON.parse(versionsJson) as string[]) { 35 + versionToSoftware[v] = sw.id; 36 + } 37 + } 25 38 }); 26 39 const [, counts] = await Promise.all([ 27 - Promise.all(versionPromises), 40 + Promise.all(metadataPromises), 28 41 getServerCount(), 29 42 ]); 30 43 ··· 42 55 ); 43 56 return c.html(renderPage(servers, { 44 57 latestVersions, 58 + versionToSoftware, 45 59 openCount: counts.open, 46 60 totalCount: counts.total, 47 61 })); ··· 49 63 50 64 type PageOpts = { 51 65 latestVersions: LatestVersionMap; 66 + versionToSoftware: VersionSoftwareMap; 52 67 openCount: number; 53 68 totalCount: number; 54 69 }; ··· 58 73 function trustScore( 59 74 s: PdsServer, 60 75 latestVersions: LatestVersionMap, 76 + versionToSoftware: VersionSoftwareMap, 61 77 ): TrustResult { 62 78 const signals: string[] = []; 63 79 let score = 0; ··· 74 90 75 91 // Version check: compare against the server's own software latest version 76 92 // Extract clean semver from strings like "millipds v0.0.5.dev17+..." 77 - const softwareId = detectSoftwareId(s); 93 + const softwareId = detectSoftwareId(s, versionToSoftware); 78 94 const expectedVersion = latestVersions[softwareId]; 79 95 if (!expectedVersion) { 80 96 // Link-only software with no tracked version: benefit of the doubt ··· 88 104 } 89 105 90 106 function renderPage(servers: PdsServer[], opts: PageOpts): string { 91 - const { latestVersions, openCount, totalCount } = opts; 107 + const { latestVersions, versionToSoftware, openCount, totalCount } = opts; 92 108 93 109 const rows = servers 94 - .map((s) => renderRow(s, latestVersions, trustScore(s, latestVersions))) 110 + .map((s) => 111 + renderRow( 112 + s, 113 + latestVersions, 114 + versionToSoftware, 115 + trustScore(s, latestVersions, versionToSoftware), 116 + ) 117 + ) 95 118 .join("\n"); 96 119 97 120 // Build stats for tracked software versions ··· 301 324 function renderRow( 302 325 s: PdsServer, 303 326 latestVersions: LatestVersionMap, 327 + versionToSoftware: VersionSoftwareMap, 304 328 trust: TrustResult, 305 329 ): string { 306 330 const { score, breakdown } = trust; ··· 310 334 const country = s.country_name || ""; 311 335 312 336 // Determine version badge class based on per-software comparison 313 - const softwareId = detectSoftwareId(s); 337 + const softwareId = detectSoftwareId(s, versionToSoftware); 314 338 const expectedVersion = latestVersions[softwareId]; 315 339 const versionText = s.version || "unknown"; 316 340 const cleanVersion = extractSemver(s.version); ··· 372 396 return m ? m[1] : version; 373 397 } 374 398 375 - /** Detect software from DB field or by inspecting the version string */ 376 - function detectSoftwareId(server: PdsServer): string { 399 + /** Detect software from DB field, version-to-software map, or version string */ 400 + function detectSoftwareId( 401 + server: PdsServer, 402 + versionToSoftware: VersionSoftwareMap, 403 + ): string { 404 + // 1. Already detected by cron 377 405 if (server.pds_software) return server.pds_software; 378 406 if (!server.version) return "bluesky-pds"; 379 - // Check if version string contains a known software name (e.g. "millipds v0.0.5...") 407 + 408 + // 2. Exact version match against known versions from all tracked software 409 + if (versionToSoftware[server.version]) { 410 + return versionToSoftware[server.version]; 411 + } 412 + 413 + // 3. Extract semver and try again (handles "millipds v0.0.5.dev17+..." → "0.0.5") 414 + const semver = extractSemver(server.version); 415 + if (semver && semver !== server.version && versionToSoftware[semver]) { 416 + return versionToSoftware[semver]; 417 + } 418 + 419 + // 4. Check if version string starts with a known software name 380 420 const vLower = server.version.toLowerCase(); 381 421 for (const sw of PDS_SOFTWARE_REGISTRY) { 382 422 if (sw.id !== "bluesky-pds" && vLower.startsWith(sw.id)) { 383 423 return sw.id; 384 424 } 385 425 } 426 + 386 427 return "bluesky-pds"; 387 428 } 388 429