Get tests passing again

This commit is contained in:
Michael Jackson 2019-07-09 17:21:25 -07:00
parent 2e3c9ff526
commit f3ecddea47
42 changed files with 309 additions and 305 deletions

View File

@ -1,9 +1,9 @@
module.exports = {
moduleNameMapper: {
"\\.css$": "<rootDir>/modules/__mocks__/styleMock.js"
'entry-manifest': '<rootDir>/modules/__mocks__/entryManifest.js',
'\\.png$': '<rootDir>/modules/__mocks__/imageMock.js',
'\\.css$': '<rootDir>/modules/__mocks__/styleMock.js'
},
setupTestFrameworkScriptFile:
"<rootDir>/modules/__tests__/setupTestFramework.js",
testMatch: ["**/__tests__/*-test.js"],
testURL: "http://localhost/"
testMatch: ['**/__tests__/*-test.js'],
testURL: 'http://localhost/'
};

3
modules/.babelrc Normal file
View File

@ -0,0 +1,3 @@
{
"presets": [["@babel/preset-env", { "loose": true, "targets": "node 8" }]]
}

View File

@ -0,0 +1 @@
export default [];

View File

@ -0,0 +1 @@
export default '';

View File

@ -0,0 +1,19 @@
import request from 'supertest';
import createServer from '../createServer';
describe('Invalid package names', () => {
let server;
beforeEach(() => {
server = createServer();
});
it('are rejected', done => {
request(server)
.get('/_invalid/index.js')
.end((err, res) => {
expect(res.statusCode).toBe(403);
done();
});
});
});

View File

@ -0,0 +1,20 @@
import request from 'supertest';
import createServer from '../createServer';
describe('Invalid query params', () => {
let server;
beforeEach(() => {
server = createServer();
});
it('redirect to the same path w/out those params', done => {
request(server)
.get('/d3?module&invalid-param')
.end((err, res) => {
expect(res.statusCode).toBe(302);
expect(res.headers.location).toBe('/d3?module');
done();
});
});
});

View File

@ -0,0 +1,30 @@
import request from 'supertest';
import createServer from '../createServer';
describe('Legacy URLs', () => {
let server;
beforeEach(() => {
server = createServer();
});
it('redirect /_meta to ?meta', done => {
request(server)
.get('/_meta/react')
.end((err, res) => {
expect(res.statusCode).toBe(301);
expect(res.headers.location).toBe('/react?meta');
done();
});
});
it('redirect ?json to ?meta', done => {
request(server)
.get('/react?json')
.end((err, res) => {
expect(res.statusCode).toBe(301);
expect(res.headers.location).toBe('/react?meta');
done();
});
});
});

View File

@ -1,49 +0,0 @@
import request from 'supertest';
import createServer from '../createServer';
describe('The server', () => {
let server;
beforeEach(() => {
server = createServer();
});
it('redirects /_meta to ?meta', done => {
request(server)
.get('/_meta/react')
.end((err, res) => {
expect(res.statusCode).toBe(301);
expect(res.headers.location).toBe('/react?meta');
done();
});
});
it('redirects ?json to ?meta', done => {
request(server)
.get('/react?json')
.end((err, res) => {
expect(res.statusCode).toBe(301);
expect(res.headers.location).toBe('/react?meta');
done();
});
});
it('redirects invalid query params', done => {
request(server)
.get('/react?main=index&invalid')
.end((err, res) => {
expect(res.statusCode).toBe(302);
expect(res.headers.location).toBe('/react?main=index');
done();
});
});
it('rejects invalid package names', done => {
request(server)
.get('/_invalid/index.js')
.end((err, res) => {
expect(res.statusCode).toBe(403);
done();
});
});
});

View File

@ -1,14 +1,14 @@
import { renderToString, renderToStaticMarkup } from 'react-dom/server';
import semver from 'semver';
import AutoIndexApp from '../client/autoIndex/App';
import AutoIndexApp from '../client/autoIndex/App.js';
import createElement from './utils/createElement';
import createHTML from './utils/createHTML';
import createScript from './utils/createScript';
import getEntryPoint from './utils/getEntryPoint';
import getGlobalScripts from './utils/getGlobalScripts';
import MainTemplate from './utils/MainTemplate';
import MainTemplate from './utils/MainTemplate.js';
import createElement from './utils/createElement.js';
import createHTML from './utils/createHTML.js';
import createScript from './utils/createScript.js';
import getEntryPoint from './utils/getEntryPoint.js';
import getGlobalScripts from './utils/getGlobalScripts.js';
const doctype = '<!DOCTYPE html>';
const globalURLs =

View File

@ -1,7 +1,7 @@
import serveAutoIndexPage from './serveAutoIndexPage';
import serveMetadata from './serveMetadata';
import serveModule from './serveModule';
import serveStaticFile from './serveStaticFile';
import serveAutoIndexPage from './serveAutoIndexPage.js';
import serveMetadata from './serveMetadata.js';
import serveModule from './serveModule.js';
import serveStaticFile from './serveStaticFile.js';
/**
* Send the file, JSON metadata, or HTML directory listing.

View File

@ -1,8 +1,8 @@
import etag from 'etag';
import cheerio from 'cheerio';
import getContentTypeHeader from '../utils/getContentTypeHeader';
import rewriteBareModuleIdentifiers from '../utils/rewriteBareModuleIdentifiers';
import getContentTypeHeader from '../utils/getContentTypeHeader.js';
import rewriteBareModuleIdentifiers from '../utils/rewriteBareModuleIdentifiers.js';
export default function serveHTMLModule(req, res) {
try {
@ -40,9 +40,7 @@ export default function serveHTMLModule(req, res) {
.status(500)
.type('text')
.send(
`Cannot generate module for ${req.packageSpec}${
req.filename
}\n\n${debugInfo}`
`Cannot generate module for ${req.packageSpec}${req.filename}\n\n${debugInfo}`
);
}
}

View File

@ -1,7 +1,7 @@
import etag from 'etag';
import getContentTypeHeader from '../utils/getContentTypeHeader';
import rewriteBareModuleIdentifiers from '../utils/rewriteBareModuleIdentifiers';
import getContentTypeHeader from '../utils/getContentTypeHeader.js';
import rewriteBareModuleIdentifiers from '../utils/rewriteBareModuleIdentifiers.js';
export default function serveJavaScriptModule(req, res) {
try {
@ -34,9 +34,7 @@ export default function serveJavaScriptModule(req, res) {
.status(500)
.type('text')
.send(
`Cannot generate module for ${req.packageSpec}${
req.filename
}\n\n${debugInfo}`
`Cannot generate module for ${req.packageSpec}${req.filename}\n\n${debugInfo}`
);
}
}

View File

@ -1,13 +1,13 @@
import { renderToString, renderToStaticMarkup } from 'react-dom/server';
import MainApp from '../client/main/App';
import MainApp from '../client/main/App.js';
import createElement from './utils/createElement';
import createHTML from './utils/createHTML';
import createScript from './utils/createScript';
import getEntryPoint from './utils/getEntryPoint';
import getGlobalScripts from './utils/getGlobalScripts';
import MainTemplate from './utils/MainTemplate';
import MainTemplate from './utils/MainTemplate.js';
import createElement from './utils/createElement.js';
import createHTML from './utils/createHTML.js';
import createScript from './utils/createScript.js';
import getEntryPoint from './utils/getEntryPoint.js';
import getGlobalScripts from './utils/getGlobalScripts.js';
const doctype = '<!DOCTYPE html>';
const globalURLs =

View File

@ -1,6 +1,6 @@
import path from 'path';
import addLeadingSlash from '../utils/addLeadingSlash';
import addLeadingSlash from '../utils/addLeadingSlash.js';
function getMatchingEntries(entry, entries) {
const dirname = entry.name || '.';

View File

@ -1,5 +1,5 @@
import serveHTMLModule from './serveHTMLModule';
import serveJavaScriptModule from './serveJavaScriptModule';
import serveHTMLModule from './serveHTMLModule.js';
import serveJavaScriptModule from './serveJavaScriptModule.js';
export default function serveModule(req, res) {
if (req.entry.contentType === 'application/javascript') {

View File

@ -1,7 +1,7 @@
import path from 'path';
import etag from 'etag';
import getContentTypeHeader from '../utils/getContentTypeHeader';
import getContentTypeHeader from '../utils/getContentTypeHeader.js';
export default function serveStaticFile(req, res) {
const tags = ['file'];

View File

@ -1,8 +1,8 @@
import PropTypes from 'prop-types';
import e from './createElement';
import h from './createHTML';
import x from './createScript';
import e from './createElement.js';
import h from './createHTML.js';
import x from './createScript.js';
const promiseShim =
'window.Promise || document.write(\'\\x3Cscript src="/es6-promise@4.2.5/dist/es6-promise.min.js">\\x3C/script>\\x3Cscript>ES6Promise.polyfill()\\x3C/script>\')';
@ -11,12 +11,12 @@ const fetchShim =
'window.fetch || document.write(\'\\x3Cscript src="/whatwg-fetch@3.0.0/dist/fetch.umd.js">\\x3C/script>\')';
export default function MainTemplate({
title,
description,
favicon,
title = 'UNPKG',
description = 'The CDN for everything on npm',
favicon = '/favicon.ico',
data,
content,
elements
content = h(''),
elements = []
}) {
return e(
'html',
@ -47,14 +47,6 @@ export default function MainTemplate({
);
}
MainTemplate.defaultProps = {
title: 'UNPKG',
description: 'The CDN for everything on npm',
favicon: '/favicon.ico',
content: h(''),
elements: []
};
if (process.env.NODE_ENV !== 'production') {
const htmlType = PropTypes.shape({
__html: PropTypes.string

View File

@ -1,16 +1,18 @@
import fetch from 'isomorphic-fetch';
import invariant from 'invariant';
const cloudflareURL = 'https://api.cloudflare.com/client/v4';
const cloudflareEmail = process.env.CLOUDFLARE_EMAIL;
const cloudflareKey = process.env.CLOUDFLARE_KEY;
invariant(
cloudflareEmail,
'Missing the $CLOUDFLARE_EMAIL environment variable'
);
if (process.env.NODE_ENV !== 'production' && process.env.NODE_ENV !== 'test') {
if (!cloudflareEmail) {
throw new Error('Missing the $CLOUDFLARE_EMAIL environment variable');
}
invariant(cloudflareKey, 'Missing the $CLOUDFLARE_KEY environment variable');
if (!cloudflareKey) {
throw new Error('Missing the $CLOUDFLARE_KEY environment variable');
}
}
function get(path, headers) {
return fetch(`${cloudflareURL}${path}`, {

View File

@ -1,5 +1,5 @@
import createElement from './createElement';
import createHTML from './createHTML';
import createElement from './createElement.js';
import createHTML from './createHTML.js';
export default function createScript(script) {
return createElement('script', {

View File

@ -1,4 +1,5 @@
// Virtual module id; see rollup.config.js
// eslint-disable-next-line import/no-unresolved
import entryManifest from 'entry-manifest';
export default function getEntryPoint(name, format) {

View File

@ -1,10 +1,13 @@
import invariant from 'invariant';
import createElement from './createElement';
import createElement from './createElement.js';
export default function getGlobalScripts(entryPoint, globalURLs) {
return entryPoint.globalImports.map(id => {
invariant(globalURLs[id], 'Missing global URL for id "%s"', id);
if (process.env.NODE_ENV !== 'production') {
if (!globalURLs[id]) {
throw new Error('Missing global URL for id "%s"', id);
}
}
return createElement('script', { src: globalURLs[id] });
});
}

View File

@ -1,4 +1,4 @@
import * as cloudflare from './cloudflare.js';
import { getZones, getZoneAnalyticsDashboard } from './cloudflare.js';
function extractPublicInfo(data) {
return {
@ -28,12 +28,8 @@ function extractPublicInfo(data) {
const DomainNames = ['unpkg.com', 'npmcdn.com'];
export default async function getStats(since, until) {
const zones = await cloudflare.getZones(DomainNames);
const dashboard = await cloudflare.getZoneAnalyticsDashboard(
zones,
since,
until
);
const zones = await getZones(DomainNames);
const dashboard = await getZoneAnalyticsDashboard(zones, since, until);
return {
timeseries: dashboard.timeseries.map(extractPublicInfo),

View File

@ -1,9 +1,7 @@
{
"presets": [
["@babel/preset-env", { "loose": true }],
["@babel/preset-env", { "loose": true, "targets": "> 0.25%, not dead" }],
"@babel/preset-react"
],
"plugins": [
["@babel/plugin-proposal-class-properties", { "loose": true }]
]
"plugins": [["@babel/plugin-proposal-class-properties", { "loose": true }]]
}

View File

@ -1,4 +1,7 @@
{
"env": {
"browser": true
},
"plugins": [
"react"
],
@ -10,8 +13,5 @@
"react": {
"version": "16"
}
},
"env": {
"browser": true
}
}

49
modules/createServer.js Normal file
View File

@ -0,0 +1,49 @@
import express from 'express';
import serveFile from './actions/serveFile.js';
import serveMainPage from './actions/serveMainPage.js';
import serveStats from './actions/serveStats.js';
import cors from './middleware/cors.js';
import fetchPackage from './middleware/fetchPackage.js';
import findFile from './middleware/findFile.js';
import logger from './middleware/logger.js';
import redirectLegacyURLs from './middleware/redirectLegacyURLs.js';
import staticFiles from './middleware/staticFiles.js';
import validatePackageURL from './middleware/validatePackageURL.js';
import validatePackageName from './middleware/validatePackageName.js';
import validateQuery from './middleware/validateQuery.js';
export default function createServer() {
const app = express();
app.disable('x-powered-by');
app.enable('trust proxy');
app.use(logger);
app.use(cors);
app.use(staticFiles);
// Special startup request from App Engine
// https://cloud.google.com/appengine/docs/standard/nodejs/how-instances-are-managed
app.get('/_ah/start', (req, res) => {
res.status(200).end();
});
app.get('/', serveMainPage);
app.get('/api/stats', serveStats);
app.use(redirectLegacyURLs);
app.get(
'*',
validatePackageURL,
validatePackageName,
validateQuery,
fetchPackage,
findFile,
serveFile
);
return app;
}

View File

@ -1,9 +1,9 @@
import semver from 'semver';
import addLeadingSlash from '../utils/addLeadingSlash';
import createPackageURL from '../utils/createPackageURL';
import createSearch from '../utils/createSearch';
import { getPackageInfo as getNpmPackageInfo } from '../utils/npm';
import addLeadingSlash from '../utils/addLeadingSlash.js';
import createPackageURL from '../utils/createPackageURL.js';
import createSearch from '../utils/createSearch.js';
import { getPackageInfo as getNpmPackageInfo } from '../utils/npm.js';
function tagRedirect(req, res) {
const version = req.packageInfo['dist-tags'][req.packageVersion];
@ -114,41 +114,41 @@ function filenameRedirect(req, res) {
* version if the request targets a tag or uses a semver version, or to the
* exact filename if the request omits the filename.
*/
export default function fetchPackage(req, res, next) {
getNpmPackageInfo(req.packageName).then(
packageInfo => {
if (packageInfo == null || packageInfo.versions == null) {
return res
.status(404)
.type('text')
.send(`Cannot find package "${req.packageName}"`);
}
export default async function fetchPackage(req, res, next) {
let packageInfo;
try {
packageInfo = await getNpmPackageInfo(req.packageName);
} catch (error) {
console.error(error);
req.packageInfo = packageInfo;
req.packageConfig = req.packageInfo.versions[req.packageVersion];
return res
.status(500)
.type('text')
.send(`Cannot get info for package "${req.packageName}"`);
}
if (!req.packageConfig) {
// Redirect to a fully-resolved version.
if (req.packageVersion in req.packageInfo['dist-tags']) {
return tagRedirect(req, res);
} else {
return semverRedirect(req, res);
}
}
if (packageInfo == null || packageInfo.versions == null) {
return res
.status(404)
.type('text')
.send(`Cannot find package "${req.packageName}"`);
}
if (!req.filename) {
return filenameRedirect(req, res);
}
req.packageInfo = packageInfo;
req.packageConfig = req.packageInfo.versions[req.packageVersion];
next();
},
error => {
console.error(error);
return res
.status(500)
.type('text')
.send(`Cannot get info for package "${req.packageName}"`);
if (!req.packageConfig) {
// Redirect to a fully-resolved version.
if (req.packageVersion in req.packageInfo['dist-tags']) {
return tagRedirect(req, res);
} else {
return semverRedirect(req, res);
}
);
}
if (!req.filename) {
return filenameRedirect(req, res);
}
next();
}

View File

@ -1,11 +1,11 @@
import path from 'path';
import addLeadingSlash from '../utils/addLeadingSlash';
import createPackageURL from '../utils/createPackageURL';
import createSearch from '../utils/createSearch';
import { fetchPackage as fetchNpmPackage } from '../utils/npm';
import getIntegrity from '../utils/getIntegrity';
import getContentType from '../utils/getContentType';
import addLeadingSlash from '../utils/addLeadingSlash.js';
import createPackageURL from '../utils/createPackageURL.js';
import createSearch from '../utils/createSearch.js';
import { fetchPackage as fetchNpmPackage } from '../utils/npm.js';
import getIntegrity from '../utils/getIntegrity.js';
import getContentType from '../utils/getContentType.js';
function indexRedirect(req, res, entry) {
// Redirect to the index file so relative imports
@ -143,62 +143,59 @@ const trailingSlash = /\/$/;
* Fetch and search the archive to try and find the requested file.
* Redirect to the "index" file if a directory was requested.
*/
export default function findFile(req, res, next) {
fetchNpmPackage(req.packageConfig).then(tarballStream => {
const wantsIndex = trailingSlash.test(req.filename);
export default async function findFile(req, res, next) {
const wantsIndex = trailingSlash.test(req.filename);
// The name of the file/directory we're looking for.
const entryName = req.filename
.replace(multipleSlash, '/')
.replace(trailingSlash, '')
.replace(leadingSlash, '');
// The name of the file/directory we're looking for.
const entryName = req.filename
.replace(multipleSlash, '/')
.replace(trailingSlash, '')
.replace(leadingSlash, '');
searchEntries(tarballStream, entryName, wantsIndex).then(
({ entries, foundEntry }) => {
if (!foundEntry) {
return res
.status(404)
.set({
'Cache-Control': 'public, max-age=31536000', // 1 year
'Cache-Tag': 'missing, missing-entry'
})
.type('text')
.send(`Cannot find "${req.filename}" in ${req.packageSpec}`);
}
const tarballStream = await fetchNpmPackage(req.packageConfig);
const { entries, foundEntry } = await searchEntries(
tarballStream,
entryName,
wantsIndex
);
// If the foundEntry is a directory and there is no trailing slash
// on the request path, we need to redirect to some "index" file
// inside that directory. This is so our URLs work in a similar way
// to require("lib") in node where it searches for `lib/index.js`
// and `lib/index.json` when `lib` is a directory.
if (foundEntry.type === 'directory' && !wantsIndex) {
const indexEntry =
entries[path.join(entryName, 'index.js')] ||
entries[path.join(entryName, 'index.json')];
if (!foundEntry) {
return res
.status(404)
.set({
'Cache-Control': 'public, max-age=31536000', // 1 year
'Cache-Tag': 'missing, missing-entry'
})
.type('text')
.send(`Cannot find "${req.filename}" in ${req.packageSpec}`);
}
if (indexEntry && indexEntry.type === 'file') {
return indexRedirect(req, res, indexEntry);
} else {
return res
.status(404)
.set({
'Cache-Control': 'public, max-age=31536000', // 1 year
'Cache-Tag': 'missing, missing-index'
})
.type('text')
.send(
`Cannot find an index in "${req.filename}" in ${
req.packageSpec
}`
);
}
}
// If the foundEntry is a directory and there is no trailing slash
// on the request path, we need to redirect to some "index" file
// inside that directory. This is so our URLs work in a similar way
// to require("lib") in node where it searches for `lib/index.js`
// and `lib/index.json` when `lib` is a directory.
if (foundEntry.type === 'directory' && !wantsIndex) {
const indexEntry =
entries[path.join(entryName, 'index.js')] ||
entries[path.join(entryName, 'index.json')];
req.entries = entries;
req.entry = foundEntry;
if (indexEntry && indexEntry.type === 'file') {
return indexRedirect(req, res, indexEntry);
}
next();
}
);
});
return res
.status(404)
.set({
'Cache-Control': 'public, max-age=31536000', // 1 year
'Cache-Tag': 'missing, missing-index'
})
.type('text')
.send(`Cannot find an index in "${req.filename}" in ${req.packageSpec}`);
}
req.entries = entries;
req.entry = foundEntry;
next();
}

View File

@ -1,15 +1,20 @@
import createSearch from '../utils/createSearch.js';
/**
* Redirect old URLs that we no longer support.
*/
export default function redirectLegacyURLs(req, res, next) {
// Permanently redirect /_meta/path to /_metadata/path
// Permanently redirect /_meta/path to /path?meta
if (req.path.match(/^\/_meta\//)) {
return res.redirect(301, '/_metadata' + req.path.substr(6));
req.query.meta = '';
return res.redirect(301, req.path.substr(6) + createSearch(req.query));
}
// Permanently redirect /path?json => /path?meta
if (req.query.json != null) {
return res.redirect(301, '/_metadata' + req.path);
delete req.query.json;
req.query.meta = '';
return res.redirect(301, req.path + createSearch(req.query));
}
next();

View File

@ -1,4 +1,4 @@
import parsePackageURL from '../utils/parsePackageURL';
import parsePackageURL from '../utils/parsePackageURL.js';
/**
* Parse the URL and add various properties to the request object to

View File

@ -1,4 +1,4 @@
import createSearch from '../utils/createSearch';
import createSearch from '../utils/createSearch.js';
const knownQueryParams = {
main: true, // Deprecated, see #63

View File

@ -1,6 +1,6 @@
import babel from 'babel-core';
import * as babel from '@babel/core';
import unpkgRewrite from '../unpkgRewrite';
import unpkgRewrite from '../unpkgRewrite.js';
const testCases = [
{
@ -66,6 +66,7 @@ const testCases = [
}
];
const origin = 'https://unpkg.com';
const dependencies = {
react: '15.6.1',
'@angular/router': '4.3.5',
@ -75,9 +76,9 @@ const dependencies = {
describe('Rewriting imports/exports', () => {
testCases.forEach(testCase => {
it(`successfully rewrites '${testCase.before}'`, () => {
it(`rewrites '${testCase.before}' => '${testCase.after}'`, () => {
const result = babel.transform(testCase.before, {
plugins: [unpkgRewrite(dependencies)]
plugins: [unpkgRewrite(origin, dependencies)]
});
expect(result.code).toEqual(testCase.after);

View File

@ -1,59 +1,8 @@
import express from 'express';
import serveFile from './actions/serveFile';
import serveMainPage from './actions/serveMainPage';
import serveStats from './actions/serveStats';
import cors from './middleware/cors';
import fetchPackage from './middleware/fetchPackage';
import findFile from './middleware/findFile';
import logger from './middleware/logger';
import redirectLegacyURLs from './middleware/redirectLegacyURLs';
import staticFiles from './middleware/staticFiles';
import validatePackageURL from './middleware/validatePackageURL';
import validatePackageName from './middleware/validatePackageName';
import validateQuery from './middleware/validateQuery';
import createRouter from './utils/createRouter';
import createServer from './createServer.js';
const server = createServer();
const port = process.env.PORT || '8080';
const app = express();
app.disable('x-powered-by');
app.enable('trust proxy');
app.use(logger);
app.use(cors);
app.use(staticFiles);
// Special startup request from App Engine
// https://cloud.google.com/appengine/docs/standard/nodejs/how-instances-are-managed
app.get('/_ah/start', (req, res) => {
res.status(200).end();
});
app.get('/', serveMainPage);
app.use(redirectLegacyURLs);
app.use(
'/api',
createRouter(app => {
app.get('/stats', serveStats);
})
);
app.get(
'*',
validatePackageURL,
validatePackageName,
validateQuery,
fetchPackage,
findFile,
serveFile
);
app.listen(port, () => {
server.listen(port, () => {
console.log('Server listening on port %s, Ctrl+C to quit', port);
});

View File

@ -1,4 +1,4 @@
import createSearch from '../createSearch';
import createSearch from '../createSearch.js';
describe('createSearch', () => {
it('omits the trailing = for empty string values', () => {

View File

@ -1,4 +1,4 @@
import getContentType from '../getContentType';
import getContentType from '../getContentType.js';
it('gets a content type of text/plain for LICENSE|README|CHANGES|AUTHORS|Makefile', () => {
expect(getContentType('AUTHORS')).toBe('text/plain');

View File

@ -1,4 +1,4 @@
import parsePackageURL from '../parsePackageURL';
import parsePackageURL from '../parsePackageURL.js';
describe('parsePackageURL', () => {
it('parses plain packages', () => {

View File

@ -1,10 +1,10 @@
export default function bufferStream(stream) {
return new Promise((resolve, reject) => {
return new Promise((accept, reject) => {
const chunks = [];
stream
.on('error', reject)
.on('data', chunk => chunks.push(chunk))
.on('end', () => resolve(Buffer.concat(chunks)));
.on('end', () => accept(Buffer.concat(chunks)));
});
}

View File

@ -1,7 +0,0 @@
import express from 'express';
export default function createRouter(configureRouter) {
const router = express.Router();
configureRouter(router);
return router;
}

View File

@ -3,9 +3,7 @@ export default function createSearch(query) {
const params = keys.reduce(
(memo, key) =>
memo.concat(
query[key] === ''
? key // Omit the trailing "=" from key=
: `${key}=${encodeURIComponent(query[key])}`
query[key] ? `${key}=${encodeURIComponent(query[key])}` : key
),
[]
);

View File

@ -4,8 +4,8 @@ import gunzip from 'gunzip-maybe';
import tar from 'tar-stream';
import LRUCache from 'lru-cache';
import debug from './debug';
import bufferStream from './bufferStream';
import debug from './debug.js';
import bufferStream from './bufferStream.js';
const npmRegistryURL =
process.env.NPM_REGISTRY_URL || 'https://registry.npmjs.org';

View File

@ -1,6 +1,6 @@
import babel from '@babel/core';
import unpkgRewrite from '../plugins/unpkgRewrite';
import unpkgRewrite from '../plugins/unpkgRewrite.js';
const origin = process.env.ORIGIN || 'https://unpkg.com';

View File

@ -23,7 +23,6 @@
"etag": "^1.8.1",
"express": "^4.16.4",
"gunzip-maybe": "^1.4.1",
"invariant": "^2.2.4",
"isomorphic-fetch": "^2.2.1",
"lru-cache": "^5.1.1",
"mime": "^2.4.0",

View File

@ -3142,7 +3142,7 @@ inquirer@^3.0.6:
strip-ansi "^4.0.0"
through "^2.3.6"
invariant@^2.2.0, invariant@^2.2.2, invariant@^2.2.4:
invariant@^2.2.0, invariant@^2.2.2:
version "2.2.4"
resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6"
integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==