const semver = require("semver"); const createPackageURL = require("../utils/createPackageURL"); const getPackageInfo = require("../utils/getPackageInfo"); const getPackage = require("../utils/getPackage"); function tagRedirect(req, res) { // Cache tag redirects for 1 minute. res .set({ "Cache-Control": "public, max-age=60", "Cache-Tag": "redirect,tag-redirect" }) .redirect( 302, createPackageURL( req.packageName, req.packageInfo["dist-tags"][req.packageVersion], req.filename, req.search ) ); } function semverRedirect(req, res) { const maxVersion = semver.maxSatisfying( Object.keys(req.packageInfo.versions), req.packageVersion ); if (maxVersion) { // Cache semver redirects for 1 minute. res .set({ "Cache-Control": "public, max-age=60", "Cache-Tag": "redirect,semver-redirect" }) .redirect( 302, createPackageURL(req.packageName, maxVersion, req.filename, req.search) ); } else { res .status(404) .type("text") .send(`Cannot find package ${req.packageSpec}`); } } /** * Fetch the package metadata and tarball from npm. Redirect to the exact * version if the request targets a tag or uses a semver version. */ function fetchPackage(req, res, next) { getPackageInfo(req.packageName, (error, packageInfo) => { if (error) { console.error(error); return res .status(500) .type("text") .send(`Cannot get info for package "${req.packageName}"`); } if (packageInfo == null || packageInfo.versions == null) { return res .status(404) .type("text") .send(`Cannot find package "${req.packageName}"`); } req.packageInfo = packageInfo; if (req.packageVersion in req.packageInfo.versions) { // A valid request for a package we haven't downloaded yet. req.packageConfig = req.packageInfo.versions[req.packageVersion]; getPackage(req.packageConfig, (error, outputDir) => { if (error) { console.error(error); res .status(500) .type("text") .send(`Cannot fetch package ${req.packageSpec}`); } else { req.packageDir = outputDir; next(); } }); } else if (req.packageVersion in req.packageInfo["dist-tags"]) { tagRedirect(req, res); } else { semverRedirect(req, res); } }); } module.exports = fetchPackage;