Skip to content

Commit d46b860

Browse files
committed
refactor: use built-in $fetch helper
1 parent 18bcb8a commit d46b860

File tree

7 files changed

+99
-92
lines changed

7 files changed

+99
-92
lines changed

server/api/auth/atproto.get.ts

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -119,25 +119,24 @@ export default defineEventHandler(async event => {
119119
const agent = new Agent(authSession)
120120
event.context.agent = agent
121121

122-
const response = await fetch(
123-
`https://${SLINGSHOT_HOST}/xrpc/com.bad-example.identity.resolveMiniDoc?identifier=${agent.did}`,
124-
{ headers: { 'User-Agent': 'npmx' } },
125-
)
126-
if (response.ok) {
127-
const miniDoc: PublicUserSession = await response.json()
122+
try {
123+
const miniDoc = await $fetch<PublicUserSession>(
124+
`https://${SLINGSHOT_HOST}/xrpc/com.bad-example.identity.resolveMiniDoc?identifier=${agent.did}`,
125+
{ headers: { 'User-Agent': 'npmx' } },
126+
)
128127

129-
let avatar: string | undefined = await getAvatar(authSession.did, miniDoc.pds)
128+
const avatar: string | undefined = await getAvatar(authSession.did, miniDoc.pds)
130129

131130
await session.update({
132131
public: {
133132
...miniDoc,
134133
avatar,
135134
},
136135
})
137-
} else {
136+
} catch {
138137
//If slingshot fails we still want to set some key info we need.
139138
const pdsBase = (await authSession.getTokenInfo()).aud
140-
let avatar: string | undefined = await getAvatar(authSession.did, pdsBase)
139+
const avatar: string | undefined = await getAvatar(authSession.did, pdsBase)
141140
await session.update({
142141
public: {
143142
did: authSession.did,

server/api/contributors.get.ts

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -13,25 +13,25 @@ export default defineCachedEventHandler(
1313
const perPage = 100
1414

1515
while (true) {
16-
const response = await fetch(
17-
`https://api.github.com/repos/npmx-dev/npmx.dev/contributors?per_page=${perPage}&page=${page}`,
18-
{
19-
headers: {
20-
'Accept': 'application/vnd.github.v3+json',
21-
'User-Agent': 'npmx',
16+
let contributors: GitHubContributor[]
17+
try {
18+
contributors = await $fetch<GitHubContributor[]>(
19+
`https://api.github.com/repos/npmx-dev/npmx.dev/contributors?per_page=${perPage}&page=${page}`,
20+
{
21+
headers: {
22+
'Accept': 'application/vnd.github.v3+json',
23+
'User-Agent': 'npmx',
24+
},
2225
},
23-
},
24-
)
25-
26-
if (!response.ok) {
26+
)
27+
} catch (error: unknown) {
28+
const fetchError = error as { response?: { status?: number } }
2729
throw createError({
28-
statusCode: response.status,
30+
statusCode: fetchError.response?.status ?? 502,
2931
message: 'Failed to fetch contributors',
3032
})
3133
}
3234

33-
const contributors = (await response.json()) as GitHubContributor[]
34-
3535
if (contributors.length === 0) {
3636
break
3737
}

server/api/registry/badge/[type]/[...pkg].get.ts

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,9 @@ async function fetchDownloads(
7474
period: 'last-day' | 'last-week' | 'last-month' | 'last-year',
7575
): Promise<number> {
7676
try {
77-
const response = await fetch(`${NPM_DOWNLOADS_API}/${period}/${packageName}`)
78-
const data = await response.json()
77+
const data = await $fetch<{ downloads?: number }>(
78+
`${NPM_DOWNLOADS_API}/${period}/${packageName}`,
79+
)
7980
return data.downloads ?? 0
8081
} catch {
8182
return 0
@@ -84,8 +85,7 @@ async function fetchDownloads(
8485

8586
async function fetchNpmsScore(packageName: string) {
8687
try {
87-
const response = await fetch(`${NPMS_API}/${encodeURIComponent(packageName)}`)
88-
const data = await response.json()
88+
const data = await $fetch<{ score: any }>(`${NPMS_API}/${encodeURIComponent(packageName)}`)
8989
return data.score
9090
} catch {
9191
return null
@@ -94,14 +94,13 @@ async function fetchNpmsScore(packageName: string) {
9494

9595
async function fetchVulnerabilities(packageName: string, version: string): Promise<number> {
9696
try {
97-
const response = await fetch(OSV_QUERY_API, {
97+
const data = await $fetch<{ vulns?: unknown[] }>(OSV_QUERY_API, {
9898
method: 'POST',
99-
body: JSON.stringify({
99+
body: {
100100
version,
101101
package: { name: packageName, ecosystem: 'npm' },
102-
}),
102+
},
103103
})
104-
const data = await response.json()
105104
return data.vulns?.length ?? 0
106105
} catch {
107106
return 0
@@ -110,8 +109,9 @@ async function fetchVulnerabilities(packageName: string, version: string): Promi
110109

111110
async function fetchInstallSize(packageName: string, version: string): Promise<number | null> {
112111
try {
113-
const response = await fetch(`${BUNDLEPHOBIA_API}?package=${packageName}@${version}`)
114-
const data = await response.json()
112+
const data = await $fetch<{ size?: number }>(
113+
`${BUNDLEPHOBIA_API}?package=${packageName}@${version}`,
114+
)
115115
return data.size ?? null
116116
} catch {
117117
return null

server/api/registry/file/[...pkg].get.ts

Lines changed: 32 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,7 @@ interface PackageJson {
3535
async function fetchPackageJson(packageName: string, version: string): Promise<PackageJson | null> {
3636
try {
3737
const url = `https://cdn.jsdelivr.net/npm/${packageName}@${version}/package.json`
38-
const response = await fetch(url)
39-
if (!response.ok) return null
40-
return (await response.json()) as PackageJson
38+
return await $fetch<PackageJson>(url)
4139
} catch {
4240
return null
4341
}
@@ -52,38 +50,45 @@ async function fetchFileContent(
5250
filePath: string,
5351
): Promise<string> {
5452
const url = `https://cdn.jsdelivr.net/npm/${packageName}@${version}/${filePath}`
55-
const response = await fetch(url)
5653

57-
if (!response.ok) {
58-
if (response.status === 404) {
54+
try {
55+
const content = await $fetch<string>(url, {
56+
responseType: 'text',
57+
onResponse({ response }) {
58+
const contentLength = response.headers.get('content-length')
59+
if (contentLength && parseInt(contentLength, 10) > MAX_FILE_SIZE) {
60+
throw createError({
61+
statusCode: 413,
62+
message: `File too large (${(parseInt(contentLength, 10) / 1024 / 1024).toFixed(1)}MB). Maximum size is ${MAX_FILE_SIZE / 1024}KB.`,
63+
})
64+
}
65+
},
66+
})
67+
68+
// Double-check size after fetching (in case content-length wasn't set)
69+
if (content.length > MAX_FILE_SIZE) {
70+
throw createError({
71+
statusCode: 413,
72+
message: `File too large (${(content.length / 1024 / 1024).toFixed(1)}MB). Maximum size is ${MAX_FILE_SIZE / 1024}KB.`,
73+
})
74+
}
75+
76+
return content
77+
} catch (error: unknown) {
78+
// Re-throw H3 errors (including our 413 from above)
79+
if (error && typeof error === 'object' && 'statusCode' in error) {
80+
throw error
81+
}
82+
// ofetch throws FetchError for non-2xx responses
83+
const fetchError = error as { response?: { status?: number } }
84+
if (fetchError.response?.status === 404) {
5985
throw createError({ statusCode: 404, message: 'File not found' })
6086
}
6187
throw createError({
6288
statusCode: 502,
6389
message: 'Failed to fetch file from jsDelivr',
6490
})
6591
}
66-
67-
// Check content-length header if available
68-
const contentLength = response.headers.get('content-length')
69-
if (contentLength && parseInt(contentLength, 10) > MAX_FILE_SIZE) {
70-
throw createError({
71-
statusCode: 413,
72-
message: `File too large (${(parseInt(contentLength, 10) / 1024 / 1024).toFixed(1)}MB). Maximum size is ${MAX_FILE_SIZE / 1024}KB.`,
73-
})
74-
}
75-
76-
const content = await response.text()
77-
78-
// Double-check size after fetching (in case content-length wasn't set)
79-
if (content.length > MAX_FILE_SIZE) {
80-
throw createError({
81-
statusCode: 413,
82-
message: `File too large (${(content.length / 1024 / 1024).toFixed(1)}MB). Maximum size is ${MAX_FILE_SIZE / 1024}KB.`,
83-
})
84-
}
85-
86-
return content
8792
}
8893

8994
/**

server/api/registry/readme/[...pkg].get.ts

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,12 +34,9 @@ async function fetchReadmeFromJsdelivr(
3434
for (const filename of readmeFilenames) {
3535
try {
3636
const url = `https://cdn.jsdelivr.net/npm/${packageName}${versionSuffix}/${filename}`
37-
const response = await fetch(url)
38-
if (response.ok) {
39-
return await response.text()
40-
}
37+
return await $fetch<string>(url, { responseType: 'text' })
4138
} catch {
42-
// Try next filename
39+
// Try next filename ($fetch throws on 404, so we continue to the next)
4340
}
4441
}
4542

server/utils/file-tree.ts

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,16 +14,15 @@ export async function fetchFileTree(
1414
version: string,
1515
): Promise<JsDelivrPackageResponse> {
1616
const url = `https://data.jsdelivr.com/v1/packages/npm/${packageName}@${version}`
17-
const response = await fetch(url)
18-
19-
if (!response.ok) {
20-
if (response.status === 404) {
17+
try {
18+
return await $fetch<JsDelivrPackageResponse>(url)
19+
} catch (error: unknown) {
20+
const fetchError = error as { response?: { status?: number } }
21+
if (fetchError.response?.status === 404) {
2122
throw createError({ statusCode: 404, message: 'Package or version not found' })
2223
}
2324
throw createError({ statusCode: 502, message: 'Failed to fetch file list from jsDelivr' })
2425
}
25-
26-
return response.json()
2726
}
2827

2928
/**

server/utils/skills.ts

Lines changed: 29 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -119,33 +119,40 @@ export async function fetchSkillFile(
119119
filePath: string,
120120
): Promise<string> {
121121
const url = `https://cdn.jsdelivr.net/npm/${packageName}@${version}/${filePath}`
122-
const response = await fetch(url)
123122

124-
if (!response.ok) {
125-
if (response.status === 404) {
126-
throw createError({ statusCode: 404, message: 'File not found' })
127-
}
128-
throw createError({ statusCode: 502, message: 'Failed to fetch file from jsDelivr' })
129-
}
130-
131-
const contentLength = response.headers.get('content-length')
132-
if (contentLength && parseInt(contentLength, 10) > MAX_SKILL_FILE_SIZE) {
133-
throw createError({
134-
statusCode: 413,
135-
message: `File too large (${(parseInt(contentLength, 10) / 1024 / 1024).toFixed(1)}MB). Maximum size is ${MAX_SKILL_FILE_SIZE / 1024}KB.`,
123+
try {
124+
const content = await $fetch<string>(url, {
125+
responseType: 'text',
126+
onResponse({ response }) {
127+
const contentLength = response.headers.get('content-length')
128+
if (contentLength && parseInt(contentLength, 10) > MAX_SKILL_FILE_SIZE) {
129+
throw createError({
130+
statusCode: 413,
131+
message: `File too large (${(parseInt(contentLength, 10) / 1024 / 1024).toFixed(1)}MB). Maximum size is ${MAX_SKILL_FILE_SIZE / 1024}KB.`,
132+
})
133+
}
134+
},
136135
})
137-
}
138136

139-
const content = await response.text()
137+
if (content.length > MAX_SKILL_FILE_SIZE) {
138+
throw createError({
139+
statusCode: 413,
140+
message: `File too large (${(content.length / 1024 / 1024).toFixed(1)}MB). Maximum size is ${MAX_SKILL_FILE_SIZE / 1024}KB.`,
141+
})
142+
}
140143

141-
if (content.length > MAX_SKILL_FILE_SIZE) {
142-
throw createError({
143-
statusCode: 413,
144-
message: `File too large (${(content.length / 1024 / 1024).toFixed(1)}MB). Maximum size is ${MAX_SKILL_FILE_SIZE / 1024}KB.`,
145-
})
144+
return content
145+
} catch (error: unknown) {
146+
// Re-throw H3 errors (including our 413 from above)
147+
if (error && typeof error === 'object' && 'statusCode' in error) {
148+
throw error
149+
}
150+
const fetchError = error as { response?: { status?: number } }
151+
if (fetchError.response?.status === 404) {
152+
throw createError({ statusCode: 404, message: 'File not found' })
153+
}
154+
throw createError({ statusCode: 502, message: 'Failed to fetch file from jsDelivr' })
146155
}
147-
148-
return content
149156
}
150157

151158
/**

0 commit comments

Comments
 (0)