UNPKG

@reliverse/rse

Version:

@reliverse/rse is your all-in-one companion for bootstrapping and improving any kind of projects (especially web apps built with frameworks like Next.js) — whether you're kicking off something new or upgrading an existing app. It is also a little AI-power

166 lines (165 loc) 5 kB
import path from "@reliverse/pathkit"; import fs from "@reliverse/relifso"; import { setHiddenAttribute } from "@reliverse/relifso"; import { relinka } from "@reliverse/relinka"; import { confirmPrompt, selectPrompt } from "@reliverse/rempts"; import { ofetch } from "ofetch"; import { cliHomeRepos, UNKNOWN_VALUE } from "../../constants.js"; import { downloadRepo } from "./downloadRepo.js"; import { REPO_TEMPLATES, saveRepoToDevice, getRepoInfo } from "../projectRepository.js"; async function checkRepoVersion(repo) { const [owner, repoName] = repo.id.split("/"); if (!owner || !repoName) return null; const url = `https://ungh.cc/repos/${owner}/${repoName}`; try { const data = await ofetch(url); return data.repo?.pushedAt ?? null; } catch (error) { console.error("Fetch error:", error); return null; } } export async function handleDownload({ cwd, isDev, skipPrompts, projectPath, projectName, selectedRepo, githubToken, config, preserveGit = true, install = false, isCustom = false, isTemplateDownload, cache = false }) { if (isTemplateDownload) { relinka("verbose", "Handling template downloading..."); } let repo; const foundRepo = REPO_TEMPLATES.find((t) => t.id === selectedRepo); if (foundRepo && !isCustom) { repo = foundRepo; } else { const [author, name] = selectedRepo.split("/"); if (!author || !name) { throw new Error( `Invalid repo format: ${selectedRepo}. Expected format: owner/repo` ); } repo = { id: selectedRepo, // We trust the user input for custom repos author, name, description: "Custom repository", category: UNKNOWN_VALUE }; } const localRepoPath = path.join(cliHomeRepos, repo.author, repo.name); let useLocalRepo = false; if (await fs.pathExists(localRepoPath)) { const localInfo = await getRepoInfo(repo.id); const currentPushedAt = await checkRepoVersion(repo); if (skipPrompts) { useLocalRepo = true; relinka("info", "Using local repo copy (auto)."); } else if (localInfo && currentPushedAt) { const localDate = new Date(localInfo.github.pushedAt); const currentDate = new Date(currentPushedAt); if (currentDate > localDate) { const choice = await selectPrompt({ title: "A newer version of the repo is available", options: [ { label: "Download latest version", value: "download", hint: `Last updated ${currentDate.toLocaleDateString()}` }, { label: "Use local copy", value: "local", hint: `Downloaded ${localDate.toLocaleDateString()}` } ] }); useLocalRepo = choice === "local"; } else { useLocalRepo = true; relinka("info", "Using local repo copy (up to date)..."); } } else { useLocalRepo = await confirmPrompt({ title: "Local copy found. Use it?", content: "If no, I'll download a fresh version.", defaultValue: true }); } if (useLocalRepo) { projectPath = isDev ? path.join(cwd, "tests-runtime", projectName) : path.join(cwd, projectName); await fs.copy(localRepoPath, projectPath); await setHiddenAttribute(path.join(projectPath, ".git")); } } let result; const term = isTemplateDownload ? "template" : "repo"; if (!projectPath) { try { relinka( "info", `Now I'm downloading the '${selectedRepo}' ${term}...`, "The download speed depends on your internet connection and GitHub limits." ); result = await downloadRepo({ repoURL: selectedRepo, projectName, isDev, cwd, ...githubToken ? { githubToken } : {}, preserveGit, ...config ? { config } : {}, install, returnTime: true, returnSize: true, isTemplateDownload, cache }); projectPath = result.dir; if (result.time) { const includesGit = preserveGit ? " (size includes the preserved .git folder)." : "."; relinka( "success", `Successfully downloaded ${term} to ${projectPath}`, `It took ${result.time} seconds to download ${result.sizePretty}${includesGit}` ); } } catch (error) { relinka("error", `Failed to download ${term}:`, String(error)); throw error; } } else { result = { source: selectedRepo, dir: projectPath }; } let shouldSaveRepo = !useLocalRepo; if (!skipPrompts && !useLocalRepo) { shouldSaveRepo = await confirmPrompt({ title: `Save a copy of the ${term} to your device?`, content: `This is useful if you have limited internet data or plan to reuse the ${term} soon.`, defaultValue: true }); } if (shouldSaveRepo) { await saveRepoToDevice(repo, projectPath); } return result; }