diff --git a/server/middleware/fetchFile.js b/server/middleware/fetchFile.js index e3ad572..e72a744 100644 --- a/server/middleware/fetchFile.js +++ b/server/middleware/fetchFile.js @@ -1,6 +1,7 @@ const fs = require("fs"); const path = require("path"); const semver = require("semver"); + const createPackageURL = require("../utils/createPackageURL"); const createSearch = require("./utils/createSearch"); const getPackageInfo = require("./utils/getPackageInfo"); @@ -69,11 +70,12 @@ function fetchFile(req, res, next) { .send(`Cannot get info for package "${req.packageName}"`); } - if (packageInfo == null || packageInfo.versions == null) + if (packageInfo == null || packageInfo.versions == null) { return res .status(404) .type("text") .send(`Cannot find package "${req.packageName}"`); + } req.packageInfo = packageInfo; @@ -84,6 +86,7 @@ function fetchFile(req, res, next) { getPackage(req.packageConfig, (error, outputDir) => { if (error) { console.error(error); + res .status(500) .type("text") @@ -95,9 +98,9 @@ function fetchFile(req, res, next) { let useIndex = true; if (req.query.module != null) { - // They want an ES module. Try "module", "jsnext:main", and "/" - // https://github.com/rollup/rollup/wiki/pkg.module + // They want an ES module. if (!filename) { + // See https://github.com/rollup/rollup/wiki/pkg.module filename = req.packageConfig.module || req.packageConfig["jsnext:main"] || @@ -105,15 +108,18 @@ function fetchFile(req, res, next) { } } else if (filename) { // They are requesting an explicit filename. Only try to find an - // index file if they are NOT requesting an HTML directory listing. - useIndex = filename[filename.length - 1] !== "/"; + // index.js if they are NOT requesting an HTML directory listing. + useIndex = filename.charAt(filename.length - 1) !== "/"; } else if ( req.query.main && typeof req.packageConfig[req.query.main] === "string" ) { // They specified a custom ?main field. + // Deprecated, see https://github.com/unpkg/unpkg/issues/63 filename = req.packageConfig[req.query.main]; + // Count which packages are using this so we can warn them when we + // remove this functionality. incrementCounter( "package-json-custom-main", req.packageSpec + "?main=" + req.query.main, @@ -121,15 +127,15 @@ function fetchFile(req, res, next) { ); } else if (typeof req.packageConfig.unpkg === "string") { // The "unpkg" field allows packages to explicitly declare the - // file to serve at the bare URL (see #59). + // file to serve at the bare URL. filename = req.packageConfig.unpkg; } else if (typeof req.packageConfig.browser === "string") { // Fall back to the "browser" field if declared (only support strings). + // Deprecated, see https://github.com/unpkg/unpkg/issues/63 filename = req.packageConfig.browser; // Count which packages + versions are actually using this fallback // so we can warn them when we deprecate this functionality. - // See https://github.com/unpkg/unpkg/issues/63 incrementCounter( "package-json-browser-fallback", req.packageSpec, @@ -166,6 +172,7 @@ function fetchFile(req, res, next) { // Need to redirect to the module file so relative imports resolve // correctly. Cache module redirects for 1 minute. delete req.query.main; + res .set({ "Cache-Control": "public, max-age=60", diff --git a/server/middleware/utils/createMutex.js b/server/middleware/utils/createMutex.js index 106276a..9be3687 100644 --- a/server/middleware/utils/createMutex.js +++ b/server/middleware/utils/createMutex.js @@ -1,21 +1,18 @@ function createMutex(doWork) { const mutex = {}; - return function(key, payload, callback) { + return (key, payload, callback) => { if (mutex[key]) { mutex[key].push(callback); } else { - mutex[key] = [ - function() { - delete mutex[key]; - }, - callback - ]; + mutex[key] = [callback]; - doWork(payload, function(error, value) { + doWork(payload, (error, value) => { mutex[key].forEach(callback => { callback(error, value); }); + + delete mutex[key]; }); } }; diff --git a/server/middleware/utils/getPackageInfo.js b/server/middleware/utils/getPackageInfo.js index 7d2e177..a595568 100644 --- a/server/middleware/utils/getPackageInfo.js +++ b/server/middleware/utils/getPackageInfo.js @@ -1,11 +1,12 @@ require("isomorphic-fetch"); + const createCache = require("./createCache"); const createMutex = require("./createMutex"); -const RegistryURL = +const registryURL = process.env.NPM_REGISTRY_URL || "https://registry.npmjs.org"; -const PackageInfoCache = createCache("packageInfo"); +const packageInfoCache = createCache("packageInfo"); function fetchPackageInfo(packageName) { console.log(`info: Fetching package info for ${packageName}`); @@ -17,7 +18,7 @@ function fetchPackageInfo(packageName) { encodedPackageName = encodeURIComponent(packageName); } - const url = `${RegistryURL}/${encodedPackageName}`; + const url = `${registryURL}/${encodedPackageName}`; return fetch(url, { headers: { @@ -34,25 +35,25 @@ const PackageNotFound = "PackageNotFound"; // the registry for the same package info. const fetchMutex = createMutex((packageName, callback) => { fetchPackageInfo(packageName).then( - function(value) { + value => { if (value == null) { // Cache 404s for 5 minutes. This prevents us from making // unnecessary requests to the registry for bad package names. // In the worst case, a brand new package's info will be // available within 5 minutes. - PackageInfoCache.set(packageName, PackageNotFound, 300, function() { + packageInfoCache.set(packageName, PackageNotFound, 300, () => { callback(null, value); }); } else { // Cache valid package info for 1 minute. - PackageInfoCache.set(packageName, value, 60, function() { + packageInfoCache.set(packageName, value, 60, () => { callback(null, value); }); } }, - function(error) { + error => { // Do not cache errors. - PackageInfoCache.del(packageName, function() { + packageInfoCache.del(packageName, () => { callback(error); }); } @@ -60,7 +61,7 @@ const fetchMutex = createMutex((packageName, callback) => { }); function getPackageInfo(packageName, callback) { - PackageInfoCache.get(packageName, function(error, value) { + packageInfoCache.get(packageName, (error, value) => { if (error || value != null) { callback(error, value === PackageNotFound ? null : value); } else { diff --git a/server/utils/parsePackageURL.js b/server/utils/parsePackageURL.js index 6019786..4a47694 100644 --- a/server/utils/parsePackageURL.js +++ b/server/utils/parsePackageURL.js @@ -1,7 +1,8 @@ const url = require("url"); + const isValidPackageName = require("./isValidPackageName"); -const URLFormat = /^\/((?:@[^/@]+\/)?[^/@]+)(?:@([^/]+))?(\/.*)?$/; +const packageURLFormat = /^\/((?:@[^/@]+\/)?[^/@]+)(?:@([^/]+))?(\/.*)?$/; function decodeParam(param) { if (param) { @@ -18,7 +19,7 @@ function decodeParam(param) { function parsePackageURL(originalURL) { const { pathname, search, query } = url.parse(originalURL, true); - const match = URLFormat.exec(pathname); + const match = packageURLFormat.exec(pathname); // Disallow invalid URL formats. if (match == null) {