unpkg/modules/middleware/validatePackageVersion.js

78 lines
1.8 KiB
JavaScript

import semver from 'semver';
import asyncHandler from '../utils/asyncHandler.js';
import createPackageURL from '../utils/createPackageURL.js';
import { getPackageConfig, getVersionsAndTags } from '../utils/npm.js';
function semverRedirect(req, res, newVersion) {
res
.set({
'Cache-Control': 'public, s-maxage=600, max-age=60', // 10 mins on CDN, 1 min on clients
'Cache-Tag': 'redirect, semver-redirect'
})
.redirect(
302,
req.baseUrl +
createPackageURL(req.packageName, newVersion, req.filename, req.query)
);
}
async function resolveVersion(packageName, range, log) {
const versionsAndTags = await getVersionsAndTags(packageName, log);
if (versionsAndTags) {
const { versions, tags } = versionsAndTags;
if (range in tags) {
range = tags[range];
}
return versions.includes(range)
? range
: semver.maxSatisfying(versions, range);
}
return null;
}
/**
* Check the package version/tag in the URL and make sure it's good. Also
* fetch the package config and add it to req.packageConfig. Redirect to
* the resolved version number if necessary.
*/
async function validateVersion(req, res, next) {
const version = await resolveVersion(
req.packageName,
req.packageVersion,
req.log
);
if (!version) {
return res
.status(404)
.type('text')
.send(`Cannot find package ${req.packageSpec}`);
}
if (version !== req.packageVersion) {
return semverRedirect(req, res, version);
}
req.packageConfig = await getPackageConfig(
req.packageName,
req.packageVersion,
req.log
);
if (!req.packageConfig) {
return res
.status(500)
.type('text')
.send(`Cannot get config for package ${req.packageSpec}`);
}
next();
}
export default asyncHandler(validateVersion);