Skip to content

Commit 062f445

Browse files
committed
feat(mcmeta): Add Vercel proxy and optimize fetch order
- Add Vercel proxy configuration for raw.githubusercontent.com - Set Vercel proxy as first priority to avoid rate limits - Change fetch order: proxies first, GitHub API as last fallback - Add Vite dev server proxy for local testing
1 parent 0d3882e commit 062f445

File tree

3 files changed

+61
-21
lines changed

3 files changed

+61
-21
lines changed

src/utils/mcmeta.ts

Lines changed: 41 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,9 @@ export function isMcmetaFile(path: string): boolean {
128128
}
129129

130130
// Fallback proxy URLs (in order of preference)
131+
// Vercel proxy is first (self-hosted, no rate limits)
131132
const PROXY_URLS = [
133+
'/proxy/raw/',
132134
'https://corsproxy.io/?url=',
133135
'https://api.allorigins.win/raw?url=',
134136
'https://cors-anywhere.herokuapp.com/',
@@ -171,11 +173,11 @@ async function fetchViaGitHubApi(
171173
token?: string | null,
172174
): Promise<McmetaData | null> {
173175
const apiUrl = `https://api.github.com/repos/${owner}/${repo}/contents/${encodeURIComponent(path)}?ref=${encodeURIComponent(ref)}`
174-
176+
175177
const headers: HeadersInit = {
176178
Accept: 'application/vnd.github.v3+json',
177179
}
178-
180+
179181
if (token) {
180182
headers.Authorization = `Bearer ${token}`
181183
}
@@ -185,15 +187,15 @@ async function fetchViaGitHubApi(
185187
if (!response.ok) {
186188
return null
187189
}
188-
190+
189191
const data = await response.json()
190-
192+
191193
// GitHub API returns base64 encoded content
192194
if (data.content && data.encoding === 'base64') {
193195
const decodedContent = atob(data.content.replace(/\s/g, ''))
194196
return JSON.parse(decodedContent) as McmetaData
195197
}
196-
198+
197199
return null
198200
} catch {
199201
return null
@@ -212,17 +214,34 @@ async function fetchViaProxy(
212214
}
213215

214216
try {
215-
const proxyUrl = PROXY_URLS[proxyIndex] + encodeURIComponent(url)
217+
const proxyBase = PROXY_URLS[proxyIndex]
218+
let proxyUrl: string
219+
220+
// Vercel proxy uses relative path, extract path from full URL
221+
if (proxyBase.startsWith('/')) {
222+
const parsed = parseGithubRawUrl(url)
223+
if (parsed) {
224+
// Build relative path: /proxy/raw/owner/repo/ref/path
225+
proxyUrl = `${proxyBase}${parsed.owner}/${parsed.repo}/${parsed.ref}/${parsed.path}`
226+
} else {
227+
// If URL parsing fails, try next proxy
228+
return fetchViaProxy(url, proxyIndex + 1)
229+
}
230+
} else {
231+
// External proxy services use full URL encoding
232+
proxyUrl = proxyBase + encodeURIComponent(url)
233+
}
234+
216235
const response = await fetch(proxyUrl, {cache: 'no-store'})
217-
236+
218237
if (!response.ok) {
219238
// Try next proxy if this one fails
220239
if (response.status === 403 || response.status === 429) {
221240
return fetchViaProxy(url, proxyIndex + 1)
222241
}
223242
return null
224243
}
225-
244+
226245
const data = (await response.json()) as McmetaData
227246
return data
228247
} catch {
@@ -233,7 +252,8 @@ async function fetchViaProxy(
233252

234253
/**
235254
* Fetch and parse mcmeta data from a URL
236-
* Tries GitHub API first, then falls back to proxy services
255+
* Tries proxy services first to avoid GitHub API rate limits,
256+
* then falls back to GitHub API if all proxies fail
237257
*/
238258
export async function fetchMcmetaData(
239259
url: string,
@@ -244,7 +264,18 @@ export async function fetchMcmetaData(
244264
return mcmetaCache.get(url) ?? null
245265
}
246266

247-
// Try GitHub API first (CORS-friendly, no proxy needed)
267+
// Try proxy services first to avoid GitHub API rate limits
268+
try {
269+
const proxyData = await fetchViaProxy(url)
270+
if (proxyData) {
271+
mcmetaCache.set(url, proxyData)
272+
return proxyData
273+
}
274+
} catch {
275+
// Ignore proxy errors, will try GitHub API as fallback
276+
}
277+
278+
// Fallback to GitHub API if all proxies failed
248279
const parsed = parseGithubRawUrl(url)
249280
if (parsed) {
250281
const apiData = await fetchViaGitHubApi(
@@ -260,17 +291,6 @@ export async function fetchMcmetaData(
260291
}
261292
}
262293

263-
// Fallback to proxy services
264-
try {
265-
const proxyData = await fetchViaProxy(url)
266-
if (proxyData) {
267-
mcmetaCache.set(url, proxyData)
268-
return proxyData
269-
}
270-
} catch {
271-
// Ignore proxy errors
272-
}
273-
274294
// Cache null result to avoid retrying immediately
275295
mcmetaCache.set(url, null)
276296
return null

vercel.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@
44
"source": "/proxy/github/:path*",
55
"destination": "https://github.com/:path*"
66
},
7+
{
8+
"source": "/proxy/raw/:path*",
9+
"destination": "https://raw.githubusercontent.com/:path*"
10+
},
711
{
812
"source": "/(.*)",
913
"destination": "/index.html"

vite.config.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,22 @@ export default defineConfig(({mode}) => {
1414
'@': path.resolve(__dirname, 'src'),
1515
},
1616
},
17+
server: {
18+
proxy: {
19+
// Proxy for GitHub raw files (matches Vercel rewrites)
20+
'/proxy/raw': {
21+
target: 'https://raw.githubusercontent.com',
22+
changeOrigin: true,
23+
rewrite: path => path.replace(/^\/proxy\/raw/, ''),
24+
},
25+
// Proxy for GitHub pages (matches Vercel rewrites)
26+
'/proxy/github': {
27+
target: 'https://github.com',
28+
changeOrigin: true,
29+
rewrite: path => path.replace(/^\/proxy\/github/, ''),
30+
},
31+
},
32+
},
1733
worker: {
1834
format: 'es',
1935
},

0 commit comments

Comments
 (0)