simple list of pds servers with open registration

Fix version display: backward compat fallback and semver extraction

Read legacy latest_pds_version key until cron populates new per-software
keys. Extract clean semver from version strings like "millipds v0.0.5.dev17+..."
for both software detection and trust score comparison.

+35 -4
+6
backend/routes/api.ts
··· 24 24 getServerCount(), 25 25 ]); 26 26 27 + // Backward compat: fall back to legacy key until cron populates new keys 28 + if (!latestVersions["bluesky-pds"]) { 29 + const legacy = await getMetadata("latest_pds_version"); 30 + if (legacy) latestVersions["bluesky-pds"] = legacy; 31 + } 32 + 27 33 c.header( 28 34 "Cache-Control", 29 35 "public, max-age=3600, stale-while-revalidate=3600",
+18 -2
backend/routes/pages.ts
··· 27 27 getServerCount(), 28 28 ]); 29 29 30 + // Backward compat: fall back to legacy key until cron populates new keys 31 + if (!latestVersions["bluesky-pds"]) { 32 + const legacy = await getMetadata("latest_pds_version"); 33 + if (legacy) latestVersions["bluesky-pds"] = legacy; 34 + } 35 + 30 36 const servers = await getOpenServers(latestVersions); 31 37 32 38 c.header( ··· 66 72 check(s.user_count != null && s.user_count > 5, "Active users (>5)"); 67 73 68 74 // Version check: compare against the server's own software latest version 75 + // Extract clean semver from strings like "millipds v0.0.5.dev17+..." 69 76 const softwareId = s.pds_software ?? "bluesky-pds"; 70 77 const expectedVersion = latestVersions[softwareId]; 71 78 if (!expectedVersion) { 72 79 // Link-only software with no tracked version: benefit of the doubt 73 80 check(true, "Latest version"); 74 81 } else { 75 - check(s.version === expectedVersion, "Latest version"); 82 + const cleanVersion = extractSemver(s.version); 83 + check(cleanVersion === expectedVersion, "Latest version"); 76 84 } 77 85 78 86 return { score, breakdown: signals.join("\n") }; ··· 304 312 const softwareId = s.pds_software ?? "bluesky-pds"; 305 313 const expectedVersion = latestVersions[softwareId]; 306 314 const versionText = s.version || "unknown"; 315 + const cleanVersion = extractSemver(s.version); 307 316 let versionClass = "version-outdated"; 308 - if (!expectedVersion || s.version === expectedVersion) { 317 + if (!expectedVersion || cleanVersion === expectedVersion) { 309 318 versionClass = "version-current"; 310 319 } 311 320 ··· 353 362 esc(hostname) 354 363 }" target="_blank" rel="noopener">Moove here</a></td> 355 364 </tr>`; 365 + } 366 + 367 + /** Extract a clean semver from a version string (e.g. "millipds v0.0.5.dev17+..." → "0.0.5") */ 368 + function extractSemver(version: string | null): string | null { 369 + if (!version) return null; 370 + const m = version.match(/(\d+\.\d+\.\d+)/); 371 + return m ? m[1] : version; 356 372 } 357 373 358 374 function esc(str: string): string {
+11 -2
cron/refresh.cron.ts
··· 148 148 149 149 for (const data of enriched) { 150 150 // Detect software by matching version against known version map 151 - if (data.version && versionToSoftware[data.version]) { 152 - data.pdsSoftware = versionToSoftware[data.version]; 151 + if (data.version) { 152 + if (versionToSoftware[data.version]) { 153 + // Exact match (e.g. "0.4.74" → bluesky-pds) 154 + data.pdsSoftware = versionToSoftware[data.version]; 155 + } else { 156 + // Extract semver from strings like "millipds v0.0.5.dev17+..." 157 + const m = data.version.match(/(\d+\.\d+\.\d+)/); 158 + if (m && m[1] !== data.version && versionToSoftware[m[1]]) { 159 + data.pdsSoftware = versionToSoftware[m[1]]; 160 + } 161 + } 153 162 } 154 163 155 164 await updateEnrichment(data.url, {