forked from
npmx.dev/npmx.dev
[READ-ONLY]
a fast, modern browser for the npm registry
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}