@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
177 lines (176 loc) • 5.66 kB
JavaScript
import { dirname, join } from "@reliverse/pathkit";
import { ensuredir } from "@reliverse/relifso";
import fs from "@reliverse/relifso";
import { relinka } from "@reliverse/relinka";
import { installDependencies } from "nypm";
import { ofetch } from "ofetch";
import pLimit from "p-limit";
import semver from "semver";
import { glob } from "tinyglobby";
import { fileURLToPath } from "url";
const verbose = false;
const BASE_URL = "https://jsr.io";
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
async function fetchJson(url) {
try {
return await ofetch(url, {
headers: { Accept: "application/json" }
});
} catch (error) {
throw new Error(`Failed to fetch JSON from "${url}" (error: ${error})`);
}
}
async function getPackageMeta(scope, packageName) {
const url = `${BASE_URL}/@${scope}/${packageName}/meta.json`;
return fetchJson(url);
}
function pickVersionFromMeta(meta, userVersion) {
if (userVersion) {
const info = meta.versions[userVersion];
if (!info) {
throw new Error(
`Version "${userVersion}" not found in package metadata.`
);
}
if (info.yanked) {
throw new Error(
`Version "${userVersion}" is yanked and cannot be downloaded.`
);
}
return userVersion;
}
const versions = Object.keys(meta.versions).filter((v) => {
const versionInfo = meta.versions[v];
return versionInfo && !versionInfo.yanked && semver.valid(v);
});
if (versions.length === 0) {
throw new Error(
"No valid (non-yanked, semver) versions found for this package."
);
}
versions.sort((a, b) => semver.rcompare(a, b));
return versions[0];
}
async function getVersionMeta(scope, packageName, version) {
const url = `${BASE_URL}/@${scope}/${packageName}/${version}_meta.json`;
return fetchJson(url);
}
async function downloadFile(scope, packageName, version, filePath, outputDir, useSinglePath) {
const trimmedFilePath = filePath.replace(/^\//, "");
const url = `${BASE_URL}/@${scope}/${packageName}/${version}/${trimmedFilePath}`;
const buffer = Buffer.from(
await ofetch(url, {
headers: { Accept: "*/*" },
responseType: "arrayBuffer"
})
);
const targetFilePath = useSinglePath ? join(outputDir, trimmedFilePath) : join(outputDir, scope, packageName, version, trimmedFilePath);
await ensuredir(dirname(targetFilePath));
await fs.writeFile(targetFilePath, buffer);
relinka("verbose", `Downloaded: ${url} -> ${targetFilePath}`);
}
async function isPackageDownloaded(filePaths, outputDir, useSinglePath, scope, packageName, version) {
try {
for (const filePath of filePaths) {
const trimmedFilePath = filePath.replace(/^\//, "");
const targetFilePath = useSinglePath ? join(outputDir, trimmedFilePath) : join(outputDir, scope, packageName, version, trimmedFilePath);
if (!await fs.pathExists(targetFilePath)) {
return false;
}
}
return true;
} catch {
return false;
}
}
async function renameTxtToTsx(dir) {
try {
const files = await glob("**/*-tsx.txt", {
cwd: dir,
absolute: true
});
for (const filePath of files) {
const newPath = filePath.replace(/-tsx\.txt$/, ".tsx");
await fs.rename(filePath, newPath);
if (verbose) {
relinka("verbose", `Renamed: ${filePath} -> ${newPath}`);
}
}
} catch (error) {
relinka(
"error",
"Error renaming -tsx.txt files:",
error instanceof Error ? error.message : String(error)
);
}
}
export async function downloadJsrDist(scope, packageName, version, outputDir = join(__dirname, "output"), useSinglePath = true, concurrency = 5, pkgIsCLI = true, msgDownloadStarted, revertTsxFiles = false, cliInstallDeps = true) {
try {
const meta = await getPackageMeta(scope, packageName);
const resolvedVersion = version || pickVersionFromMeta(meta);
const versionMeta = await getVersionMeta(
scope,
packageName,
resolvedVersion
);
const filePaths = Object.keys(versionMeta.manifest);
const isDownloaded = await isPackageDownloaded(
filePaths,
outputDir,
useSinglePath,
scope,
packageName,
resolvedVersion
);
if (isDownloaded) {
relinka(
"success",
`@${scope}/${packageName}@${resolvedVersion} is already downloaded.`,
pkgIsCLI ? `Use "bun ${outputDir}/bin/mod.ts" to run it (short command coming soon).` : void 0
);
return;
}
relinka(
"info",
msgDownloadStarted ?? `Downloading ${scope}/${packageName}@${resolvedVersion} from JSR...`
);
const limit = pLimit(concurrency);
const tasks = filePaths.map(
(filePath) => limit(
() => downloadFile(
scope,
packageName,
resolvedVersion,
filePath,
outputDir,
useSinglePath
)
)
);
await Promise.all(tasks);
if (pkgIsCLI && revertTsxFiles) {
relinka("verbose", "Reverting .tsx files...");
await renameTxtToTsx(outputDir);
}
if (pkgIsCLI && cliInstallDeps) {
relinka("info", "Installing dependencies...");
await installDependencies({
cwd: outputDir,
silent: false
});
}
relinka(
"success",
`All files for @${scope}/${packageName} downloaded successfully.`,
pkgIsCLI ? `Use "bun ${outputDir}/bin/mod.ts" to run it (short command coming soon).` : void 0
);
} catch (error) {
relinka(
"error",
`Something went wrong while downloading ${scope}/${packageName}:`,
`${error}`
);
throw error;
}
}