@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
JavaScript
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;
}