Spaces:
Sleeping
Sleeping
| import { json } from '@remix-run/cloudflare'; | |
| import JSZip from 'jszip'; | |
| export async function loader({ request }: { request: Request }) { | |
| const url = new URL(request.url); | |
| const repo = url.searchParams.get('repo'); | |
| if (!repo) { | |
| return json({ error: 'Repository name is required' }, { status: 400 }); | |
| } | |
| try { | |
| const baseUrl = 'https://api.github.com'; | |
| // Get the latest release | |
| const releaseResponse = await fetch(`${baseUrl}/repos/${repo}/releases/latest`, { | |
| headers: { | |
| Accept: 'application/vnd.github.v3+json', | |
| // Add GitHub token if available in environment variables | |
| ...(process.env.GITHUB_TOKEN ? { Authorization: `Bearer ${process.env.GITHUB_TOKEN}` } : {}), | |
| }, | |
| }); | |
| if (!releaseResponse.ok) { | |
| throw new Error(`GitHub API error: ${releaseResponse.status}`); | |
| } | |
| const releaseData = (await releaseResponse.json()) as any; | |
| const zipballUrl = releaseData.zipball_url; | |
| // Fetch the zipball | |
| const zipResponse = await fetch(zipballUrl, { | |
| headers: { | |
| ...(process.env.GITHUB_TOKEN ? { Authorization: `Bearer ${process.env.GITHUB_TOKEN}` } : {}), | |
| }, | |
| }); | |
| if (!zipResponse.ok) { | |
| throw new Error(`Failed to fetch release zipball: ${zipResponse.status}`); | |
| } | |
| // Get the zip content as ArrayBuffer | |
| const zipArrayBuffer = await zipResponse.arrayBuffer(); | |
| // Use JSZip to extract the contents | |
| const zip = await JSZip.loadAsync(zipArrayBuffer); | |
| // Find the root folder name | |
| let rootFolderName = ''; | |
| zip.forEach((relativePath) => { | |
| if (!rootFolderName && relativePath.includes('/')) { | |
| rootFolderName = relativePath.split('/')[0]; | |
| } | |
| }); | |
| // Extract all files | |
| const promises = Object.keys(zip.files).map(async (filename) => { | |
| const zipEntry = zip.files[filename]; | |
| // Skip directories | |
| if (zipEntry.dir) { | |
| return null; | |
| } | |
| // Skip the root folder itself | |
| if (filename === rootFolderName) { | |
| return null; | |
| } | |
| // Remove the root folder from the path | |
| let normalizedPath = filename; | |
| if (rootFolderName && filename.startsWith(rootFolderName + '/')) { | |
| normalizedPath = filename.substring(rootFolderName.length + 1); | |
| } | |
| // Get the file content | |
| const content = await zipEntry.async('string'); | |
| return { | |
| name: normalizedPath.split('/').pop() || '', | |
| path: normalizedPath, | |
| content, | |
| }; | |
| }); | |
| const results = await Promise.all(promises); | |
| const fileList = results.filter(Boolean) as { name: string; path: string; content: string }[]; | |
| return json(fileList); | |
| } catch (error) { | |
| console.error('Error processing GitHub template:', error); | |
| return json({ error: 'Failed to fetch template files' }, { status: 500 }); | |
| } | |
| } | |