Skip to content

Commit e90737c

Browse files
committed
fix(modules): gracefully handle missing npm packages
1 parent b1d5de9 commit e90737c

2 files changed

Lines changed: 48 additions & 28 deletions

File tree

server/utils/module.ts

Lines changed: 42 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -17,40 +17,54 @@ export const fetchModules = cachedFunction(async (_event: H3Event): Promise<Modu
1717
maxAge: 10 * 60 // 10 minutes
1818
})
1919

20-
export async function fetchModuleStats(event: H3Event, module: BaseModule, preloadedNpmStats?: NpmDownloadStats) {
20+
export async function fetchModuleStats(event: H3Event, module: BaseModule, preloadedNpmStats?: NpmDownloadStats): Promise<ModuleStats> {
2121
const key = `module:stats:${module.name}`
2222
const cached = await kv.get<ModuleStats>(key)
2323
if (cached) {
2424
return cached
2525
}
2626
console.info(`Fetching module ${module.name} stats...`)
27-
const ghRepo = module.repo.split('#')[0]!
28-
const [owner, name] = ghRepo.split('/')
29-
const [npmInfos, npmStats, repo] = await Promise.all([
30-
npm.fetchPackage(module.npm),
31-
preloadedNpmStats || npm.fetchPackageStats(module.npm, 'last-month'),
32-
github.fetchRepo(event, owner!, name!)
33-
.then((repo) => {
34-
return {
35-
stars: repo.stars,
36-
watchers: repo.watchers,
37-
forks: repo.forks,
38-
defaultBranch: repo.defaultBranch
39-
}
40-
})
41-
])
42-
const stats = {
43-
version: npmInfos?.['dist-tags']?.latest || '0.0.0',
44-
downloads: npmStats.downloads,
45-
stars: repo.stars,
46-
watchers: repo.watchers,
47-
forks: repo.forks,
48-
defaultBranch: repo.defaultBranch,
49-
publishedAt: +new Date(npmInfos?.time?.modified || Date.now()),
50-
createdAt: +new Date(npmInfos?.time?.created || Date.now())
51-
} satisfies ModuleStats
52-
await kv.set(key, stats, { ttl: 60 * 60 * 24 }) // cache for 1 day
53-
return stats
27+
try {
28+
const ghRepo = module.repo.split('#')[0]!
29+
const [owner, name] = ghRepo.split('/')
30+
const [npmInfos, npmStats, repo] = await Promise.all([
31+
npm.fetchPackage(module.npm),
32+
preloadedNpmStats || npm.fetchPackageStats(module.npm, 'last-month'),
33+
github.fetchRepo(event, owner!, name!)
34+
.then((repo) => {
35+
return {
36+
stars: repo.stars,
37+
watchers: repo.watchers,
38+
forks: repo.forks,
39+
defaultBranch: repo.defaultBranch
40+
}
41+
})
42+
])
43+
const stats = {
44+
version: npmInfos?.['dist-tags']?.latest || '0.0.0',
45+
downloads: npmStats.downloads,
46+
stars: repo.stars,
47+
watchers: repo.watchers,
48+
forks: repo.forks,
49+
defaultBranch: repo.defaultBranch,
50+
publishedAt: +new Date(npmInfos?.time?.modified || Date.now()),
51+
createdAt: +new Date(npmInfos?.time?.created || Date.now())
52+
} satisfies ModuleStats
53+
await kv.set(key, stats, { ttl: 60 * 60 * 24 }) // cache for 1 day
54+
return stats
55+
} catch (err) {
56+
console.error(`Failed to fetch stats for module ${module.name}: ${err}`)
57+
return {
58+
version: '0.0.0',
59+
downloads: 0,
60+
stars: 0,
61+
watchers: 0,
62+
forks: 0,
63+
defaultBranch: 'main',
64+
publishedAt: Date.now(),
65+
createdAt: Date.now()
66+
} satisfies ModuleStats
67+
}
5468
}
5569

5670
interface UnghContributor {

server/utils/npm.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,12 @@ async function npmFetch<T>(url: string): Promise<T | null> {
2626
const isRateLimited = err?.status === 429 || err?.statusCode === 429
2727
const isServerError = err?.status >= 500 || err?.statusCode >= 500
2828

29+
const isNotFound = err?.status === 404 || err?.statusCode === 404
30+
if (isNotFound) {
31+
console.warn(`Package not found: ${url}`)
32+
return null
33+
}
34+
2935
if (!isRateLimited && !isServerError) {
3036
throw err
3137
}

0 commit comments

Comments
 (0)