()
| 223 | * @returns Map of plugin ID (name@marketplace) to install count, or null if unavailable |
| 224 | */ |
| 225 | export async function getInstallCounts(): Promise<Map<string, number> | null> { |
| 226 | // Try to load from cache first |
| 227 | const cache = await loadInstallCountsCache() |
| 228 | if (cache) { |
| 229 | logForDebugging('Using cached install counts') |
| 230 | logPluginFetch('install_counts', INSTALL_COUNTS_URL, 'cache_hit', 0) |
| 231 | const map = new Map<string, number>() |
| 232 | for (const entry of cache.counts) { |
| 233 | map.set(entry.plugin, entry.unique_installs) |
| 234 | } |
| 235 | return map |
| 236 | } |
| 237 | |
| 238 | // Cache miss or stale - fetch from GitHub |
| 239 | try { |
| 240 | const counts = await fetchInstallCountsFromGitHub() |
| 241 | |
| 242 | // Save to cache |
| 243 | const newCache: InstallCountsCache = { |
| 244 | version: INSTALL_COUNTS_CACHE_VERSION, |
| 245 | fetchedAt: new Date().toISOString(), |
| 246 | counts, |
| 247 | } |
| 248 | await saveInstallCountsCache(newCache) |
| 249 | |
| 250 | // Convert to Map |
| 251 | const map = new Map<string, number>() |
| 252 | for (const entry of counts) { |
| 253 | map.set(entry.plugin, entry.unique_installs) |
| 254 | } |
| 255 | return map |
| 256 | } catch (error) { |
| 257 | // Log error and return null so UI can hide counts |
| 258 | logError(error) |
| 259 | logForDebugging(`Failed to fetch install counts: ${errorMessage(error)}`) |
| 260 | return null |
| 261 | } |
| 262 | } |
| 263 | |
| 264 | /** |
| 265 | * Format an install count for display. |
no test coverage detected