* Fetch file content from jsDelivr CDN.
( packageName: string, version: string, filePath: string, )
| 47 | * Fetch file content from jsDelivr CDN. |
| 48 | */ |
| 49 | async function fetchFileContent( |
| 50 | packageName: string, |
| 51 | version: string, |
| 52 | filePath: string, |
| 53 | ): Promise<{ content: string; contentType: string | null }> { |
| 54 | const url = `https://cdn.jsdelivr.net/npm/${packageName}@${version}/${filePath}` |
| 55 | const response = await fetch(url) |
| 56 | |
| 57 | if (!response.ok) { |
| 58 | if (response.status === 404) { |
| 59 | throw createError({ statusCode: 404, message: 'File not found' }) |
| 60 | } |
| 61 | throw createError({ |
| 62 | statusCode: 502, |
| 63 | message: 'Failed to fetch file from jsDelivr', |
| 64 | }) |
| 65 | } |
| 66 | |
| 67 | const contentType = response.headers.get('content-type') |
| 68 | |
| 69 | // Check content-length header if available |
| 70 | const contentLength = response.headers.get('content-length') |
| 71 | if (contentLength && parseInt(contentLength, 10) > MAX_FILE_SIZE) { |
| 72 | throw createError({ |
| 73 | statusCode: 413, |
| 74 | message: `File too large (${(parseInt(contentLength, 10) / 1024 / 1024).toFixed(1)}MB). Maximum size is ${MAX_FILE_SIZE / 1024}KB.`, |
| 75 | }) |
| 76 | } |
| 77 | |
| 78 | const content = await response.text() |
| 79 | |
| 80 | // Double-check size after fetching (in case content-length wasn't set) |
| 81 | if (content.length > MAX_FILE_SIZE) { |
| 82 | throw createError({ |
| 83 | statusCode: 413, |
| 84 | message: `File too large (${(content.length / 1024 / 1024).toFixed(1)}MB). Maximum size is ${MAX_FILE_SIZE / 1024}KB.`, |
| 85 | }) |
| 86 | } |
| 87 | |
| 88 | return { content, contentType } |
| 89 | } |
| 90 | |
| 91 | /** |
| 92 | * Returns syntax-highlighted HTML for a file in a package. |