[READ-ONLY] a fast, modern browser for the npm registry
at main 86 lines 2.2 kB view raw
1import type { 2 JsDelivrPackageResponse, 3 JsDelivrFileNode, 4 PackageFileTree, 5 PackageFileTreeResponse, 6} from '#shared/types' 7 8/** 9 * Fetch the file tree from jsDelivr API. 10 * Returns a nested tree structure of all files in the package. 11 */ 12export async function fetchFileTree( 13 packageName: string, 14 version: string, 15): Promise<JsDelivrPackageResponse> { 16 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) { 21 throw createError({ statusCode: 404, message: 'Package or version not found' }) 22 } 23 throw createError({ statusCode: 502, message: 'Failed to fetch file list from jsDelivr' }) 24 } 25 26 return response.json() 27} 28 29/** 30 * Convert jsDelivr nested structure to our PackageFileTree format 31 */ 32export function convertToFileTree( 33 nodes: JsDelivrFileNode[], 34 parentPath: string = '', 35): PackageFileTree[] { 36 const result: PackageFileTree[] = [] 37 38 for (const node of nodes) { 39 const path = parentPath ? `${parentPath}/${node.name}` : node.name 40 41 if (node.type === 'directory') { 42 result.push({ 43 name: node.name, 44 path, 45 type: 'directory', 46 children: node.files ? convertToFileTree(node.files, path) : [], 47 }) 48 } else { 49 result.push({ 50 name: node.name, 51 path, 52 type: 'file', 53 size: node.size, 54 }) 55 } 56 } 57 58 // Sort: directories first, then files, alphabetically within each group 59 result.sort((a, b) => { 60 if (a.type !== b.type) { 61 return a.type === 'directory' ? -1 : 1 62 } 63 return a.name.localeCompare(b.name) 64 }) 65 66 return result 67} 68 69/** 70 * Fetch and convert file tree for a package version. 71 * Returns the full response including tree and metadata. 72 */ 73export async function getPackageFileTree( 74 packageName: string, 75 version: string, 76): Promise<PackageFileTreeResponse> { 77 const jsDelivrData = await fetchFileTree(packageName, version) 78 const tree = convertToFileTree(jsDelivrData.files) 79 80 return { 81 package: packageName, 82 version, 83 default: jsDelivrData.default ?? undefined, 84 tree, 85 } 86}