Better async error handling
This commit is contained in:
parent
7582c641fb
commit
7f90203a66
|
@ -2,9 +2,10 @@ import { renderToString, renderToStaticMarkup } from 'react-dom/server';
|
||||||
|
|
||||||
import BrowseApp from '../client/browse/App.js';
|
import BrowseApp from '../client/browse/App.js';
|
||||||
import MainTemplate from '../templates/MainTemplate.js';
|
import MainTemplate from '../templates/MainTemplate.js';
|
||||||
import { getAvailableVersions } from '../utils/npm.js';
|
import asyncHandler from '../utils/asyncHandler.js';
|
||||||
import getScripts from '../utils/getScripts.js';
|
import getScripts from '../utils/getScripts.js';
|
||||||
import { createElement, createHTML } from '../utils/markup.js';
|
import { createElement, createHTML } from '../utils/markup.js';
|
||||||
|
import { getAvailableVersions } from '../utils/npm.js';
|
||||||
|
|
||||||
const doctype = '<!DOCTYPE html>';
|
const doctype = '<!DOCTYPE html>';
|
||||||
const globalURLs =
|
const globalURLs =
|
||||||
|
@ -20,7 +21,7 @@ const globalURLs =
|
||||||
'react-dom': '/react-dom@16.8.6/umd/react-dom.development.js'
|
'react-dom': '/react-dom@16.8.6/umd/react-dom.development.js'
|
||||||
};
|
};
|
||||||
|
|
||||||
export default async function serveBrowsePage(req, res) {
|
async function serveBrowsePage(req, res) {
|
||||||
const availableVersions = await getAvailableVersions(req.packageName);
|
const availableVersions = await getAvailableVersions(req.packageName);
|
||||||
const data = {
|
const data = {
|
||||||
packageName: req.packageName,
|
packageName: req.packageName,
|
||||||
|
@ -51,3 +52,5 @@ export default async function serveBrowsePage(req, res) {
|
||||||
})
|
})
|
||||||
.send(html);
|
.send(html);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default asyncHandler(serveBrowsePage);
|
||||||
|
|
|
@ -2,6 +2,7 @@ import path from 'path';
|
||||||
import gunzip from 'gunzip-maybe';
|
import gunzip from 'gunzip-maybe';
|
||||||
import tar from 'tar-stream';
|
import tar from 'tar-stream';
|
||||||
|
|
||||||
|
import asyncHandler from '../utils/asyncHandler.js';
|
||||||
import bufferStream from '../utils/bufferStream.js';
|
import bufferStream from '../utils/bufferStream.js';
|
||||||
import getContentType from '../utils/getContentType.js';
|
import getContentType from '../utils/getContentType.js';
|
||||||
import getIntegrity from '../utils/getIntegrity.js';
|
import getIntegrity from '../utils/getIntegrity.js';
|
||||||
|
@ -45,15 +46,19 @@ async function findMatchingEntries(stream, filename) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const content = await bufferStream(stream);
|
try {
|
||||||
|
const content = await bufferStream(stream);
|
||||||
|
|
||||||
entry.contentType = getContentType(entry.path);
|
entry.contentType = getContentType(entry.path);
|
||||||
entry.integrity = getIntegrity(content);
|
entry.integrity = getIntegrity(content);
|
||||||
entry.size = content.length;
|
entry.size = content.length;
|
||||||
|
|
||||||
entries[entry.path] = entry;
|
entries[entry.path] = entry;
|
||||||
|
|
||||||
next();
|
next();
|
||||||
|
} catch (error) {
|
||||||
|
next(error);
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.on('finish', () => {
|
.on('finish', () => {
|
||||||
accept(entries);
|
accept(entries);
|
||||||
|
@ -61,7 +66,7 @@ async function findMatchingEntries(stream, filename) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export default async function serveDirectoryBrowser(req, res) {
|
async function serveDirectoryBrowser(req, res) {
|
||||||
const stream = await getPackage(req.packageName, req.packageVersion);
|
const stream = await getPackage(req.packageName, req.packageVersion);
|
||||||
|
|
||||||
const filename = req.filename.slice(0, -1) || '/';
|
const filename = req.filename.slice(0, -1) || '/';
|
||||||
|
@ -79,3 +84,5 @@ export default async function serveDirectoryBrowser(req, res) {
|
||||||
|
|
||||||
serveBrowsePage(req, res);
|
serveBrowsePage(req, res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default asyncHandler(serveDirectoryBrowser);
|
||||||
|
|
|
@ -2,6 +2,7 @@ import path from 'path';
|
||||||
import gunzip from 'gunzip-maybe';
|
import gunzip from 'gunzip-maybe';
|
||||||
import tar from 'tar-stream';
|
import tar from 'tar-stream';
|
||||||
|
|
||||||
|
import asyncHandler from '../utils/asyncHandler.js';
|
||||||
import bufferStream from '../utils/bufferStream.js';
|
import bufferStream from '../utils/bufferStream.js';
|
||||||
import getContentType from '../utils/getContentType.js';
|
import getContentType from '../utils/getContentType.js';
|
||||||
import getIntegrity from '../utils/getIntegrity.js';
|
import getIntegrity from '../utils/getIntegrity.js';
|
||||||
|
@ -46,16 +47,20 @@ async function findMatchingEntries(stream, filename) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const content = await bufferStream(stream);
|
try {
|
||||||
|
const content = await bufferStream(stream);
|
||||||
|
|
||||||
entry.contentType = getContentType(entry.path);
|
entry.contentType = getContentType(entry.path);
|
||||||
entry.integrity = getIntegrity(content);
|
entry.integrity = getIntegrity(content);
|
||||||
entry.lastModified = header.mtime.toUTCString();
|
entry.lastModified = header.mtime.toUTCString();
|
||||||
entry.size = content.length;
|
entry.size = content.length;
|
||||||
|
|
||||||
entries[entry.path] = entry;
|
entries[entry.path] = entry;
|
||||||
|
|
||||||
next();
|
next();
|
||||||
|
} catch (error) {
|
||||||
|
next(error);
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.on('finish', () => {
|
.on('finish', () => {
|
||||||
accept(entries);
|
accept(entries);
|
||||||
|
@ -86,7 +91,7 @@ function getMetadata(entry, entries) {
|
||||||
return metadata;
|
return metadata;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default async function serveDirectoryMetadata(req, res) {
|
async function serveDirectoryMetadata(req, res) {
|
||||||
const stream = await getPackage(req.packageName, req.packageVersion);
|
const stream = await getPackage(req.packageName, req.packageVersion);
|
||||||
|
|
||||||
const filename = req.filename.slice(0, -1) || '/';
|
const filename = req.filename.slice(0, -1) || '/';
|
||||||
|
@ -95,3 +100,5 @@ export default async function serveDirectoryMetadata(req, res) {
|
||||||
|
|
||||||
res.send(metadata);
|
res.send(metadata);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default asyncHandler(serveDirectoryMetadata);
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import gunzip from 'gunzip-maybe';
|
import gunzip from 'gunzip-maybe';
|
||||||
import tar from 'tar-stream';
|
import tar from 'tar-stream';
|
||||||
|
|
||||||
|
import asyncHandler from '../utils/asyncHandler.js';
|
||||||
import bufferStream from '../utils/bufferStream.js';
|
import bufferStream from '../utils/bufferStream.js';
|
||||||
import createDataURI from '../utils/createDataURI.js';
|
import createDataURI from '../utils/createDataURI.js';
|
||||||
import getContentType from '../utils/getContentType.js';
|
import getContentType from '../utils/getContentType.js';
|
||||||
|
@ -37,10 +38,15 @@ async function findEntry(stream, filename) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
entry.content = await bufferStream(stream);
|
try {
|
||||||
foundEntry = entry;
|
entry.content = await bufferStream(stream);
|
||||||
|
|
||||||
next();
|
foundEntry = entry;
|
||||||
|
|
||||||
|
next();
|
||||||
|
} catch (error) {
|
||||||
|
next(error);
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.on('finish', () => {
|
.on('finish', () => {
|
||||||
accept(foundEntry);
|
accept(foundEntry);
|
||||||
|
@ -48,7 +54,7 @@ async function findEntry(stream, filename) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export default async function serveFileBrowser(req, res) {
|
async function serveFileBrowser(req, res) {
|
||||||
const stream = await getPackage(req.packageName, req.packageVersion);
|
const stream = await getPackage(req.packageName, req.packageVersion);
|
||||||
const entry = await findEntry(stream, req.filename);
|
const entry = await findEntry(stream, req.filename);
|
||||||
|
|
||||||
|
@ -82,3 +88,5 @@ export default async function serveFileBrowser(req, res) {
|
||||||
|
|
||||||
serveBrowsePage(req, res);
|
serveBrowsePage(req, res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default asyncHandler(serveFileBrowser);
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import gunzip from 'gunzip-maybe';
|
import gunzip from 'gunzip-maybe';
|
||||||
import tar from 'tar-stream';
|
import tar from 'tar-stream';
|
||||||
|
|
||||||
|
import asyncHandler from '../utils/asyncHandler.js';
|
||||||
import bufferStream from '../utils/bufferStream.js';
|
import bufferStream from '../utils/bufferStream.js';
|
||||||
import getContentType from '../utils/getContentType.js';
|
import getContentType from '../utils/getContentType.js';
|
||||||
import getIntegrity from '../utils/getIntegrity.js';
|
import getIntegrity from '../utils/getIntegrity.js';
|
||||||
|
@ -32,16 +33,20 @@ async function findEntry(stream, filename) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const content = await bufferStream(stream);
|
try {
|
||||||
|
const content = await bufferStream(stream);
|
||||||
|
|
||||||
entry.contentType = getContentType(entry.path);
|
entry.contentType = getContentType(entry.path);
|
||||||
entry.integrity = getIntegrity(content);
|
entry.integrity = getIntegrity(content);
|
||||||
entry.lastModified = header.mtime.toUTCString();
|
entry.lastModified = header.mtime.toUTCString();
|
||||||
entry.size = content.length;
|
entry.size = content.length;
|
||||||
|
|
||||||
foundEntry = entry;
|
foundEntry = entry;
|
||||||
|
|
||||||
next();
|
next();
|
||||||
|
} catch (error) {
|
||||||
|
next(error);
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.on('finish', () => {
|
.on('finish', () => {
|
||||||
accept(foundEntry);
|
accept(foundEntry);
|
||||||
|
@ -49,7 +54,7 @@ async function findEntry(stream, filename) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export default async function serveFileMetadata(req, res) {
|
async function serveFileMetadata(req, res) {
|
||||||
const stream = await getPackage(req.packageName, req.packageVersion);
|
const stream = await getPackage(req.packageName, req.packageVersion);
|
||||||
const entry = await findEntry(stream, req.filename);
|
const entry = await findEntry(stream, req.filename);
|
||||||
|
|
||||||
|
@ -59,3 +64,5 @@ export default async function serveFileMetadata(req, res) {
|
||||||
|
|
||||||
res.send(entry);
|
res.send(entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default asyncHandler(serveFileMetadata);
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import serveHTMLModule from './serveHTMLModule.js';
|
import serveHTMLModule from './serveHTMLModule.js';
|
||||||
import serveJavaScriptModule from './serveJavaScriptModule.js';
|
import serveJavaScriptModule from './serveJavaScriptModule.js';
|
||||||
|
|
||||||
export default async function serveModule(req, res) {
|
export default function serveModule(req, res) {
|
||||||
if (req.entry.contentType === 'application/javascript') {
|
if (req.entry.contentType === 'application/javascript') {
|
||||||
return serveJavaScriptModule(req, res);
|
return serveJavaScriptModule(req, res);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,12 +2,13 @@ import path from 'path';
|
||||||
import gunzip from 'gunzip-maybe';
|
import gunzip from 'gunzip-maybe';
|
||||||
import tar from 'tar-stream';
|
import tar from 'tar-stream';
|
||||||
|
|
||||||
|
import asyncHandler from '../utils/asyncHandler.js';
|
||||||
|
import bufferStream from '../utils/bufferStream.js';
|
||||||
import createPackageURL from '../utils/createPackageURL.js';
|
import createPackageURL from '../utils/createPackageURL.js';
|
||||||
import createSearch from '../utils/createSearch.js';
|
import createSearch from '../utils/createSearch.js';
|
||||||
import { getPackage } from '../utils/npm.js';
|
|
||||||
import getIntegrity from '../utils/getIntegrity.js';
|
|
||||||
import getContentType from '../utils/getContentType.js';
|
import getContentType from '../utils/getContentType.js';
|
||||||
import bufferStream from '../utils/bufferStream.js';
|
import getIntegrity from '../utils/getIntegrity.js';
|
||||||
|
import { getPackage } from '../utils/npm.js';
|
||||||
|
|
||||||
function fileRedirect(req, res, entry) {
|
function fileRedirect(req, res, entry) {
|
||||||
// Redirect to the file with the extension so it's
|
// Redirect to the file with the extension so it's
|
||||||
|
@ -123,20 +124,24 @@ function searchEntries(stream, filename) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const content = await bufferStream(stream);
|
try {
|
||||||
|
const content = await bufferStream(stream);
|
||||||
|
|
||||||
entry.contentType = getContentType(entry.path);
|
entry.contentType = getContentType(entry.path);
|
||||||
entry.integrity = getIntegrity(content);
|
entry.integrity = getIntegrity(content);
|
||||||
entry.lastModified = header.mtime.toUTCString();
|
entry.lastModified = header.mtime.toUTCString();
|
||||||
entry.size = content.length;
|
entry.size = content.length;
|
||||||
|
|
||||||
// Set the content only for the foundEntry and
|
// Set the content only for the foundEntry and
|
||||||
// discard the buffer for all others.
|
// discard the buffer for all others.
|
||||||
if (entry === foundEntry) {
|
if (entry === foundEntry) {
|
||||||
entry.content = content;
|
entry.content = content;
|
||||||
|
}
|
||||||
|
|
||||||
|
next();
|
||||||
|
} catch (error) {
|
||||||
|
next(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
next();
|
|
||||||
})
|
})
|
||||||
.on('finish', () => {
|
.on('finish', () => {
|
||||||
accept({
|
accept({
|
||||||
|
@ -153,7 +158,7 @@ function searchEntries(stream, filename) {
|
||||||
* Fetch and search the archive to try and find the requested file.
|
* Fetch and search the archive to try and find the requested file.
|
||||||
* Redirect to the "index" file if a directory was requested.
|
* Redirect to the "index" file if a directory was requested.
|
||||||
*/
|
*/
|
||||||
export default async function findEntry(req, res, next) {
|
async function findEntry(req, res, next) {
|
||||||
const stream = await getPackage(req.packageName, req.packageVersion);
|
const stream = await getPackage(req.packageName, req.packageVersion);
|
||||||
const { foundEntry: entry, matchingEntries: entries } = await searchEntries(
|
const { foundEntry: entry, matchingEntries: entries } = await searchEntries(
|
||||||
stream,
|
stream,
|
||||||
|
@ -201,3 +206,5 @@ export default async function findEntry(req, res, next) {
|
||||||
|
|
||||||
next();
|
next();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default asyncHandler(findEntry);
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import asyncHandler from '../utils/asyncHandler.js';
|
||||||
import createPackageURL from '../utils/createPackageURL.js';
|
import createPackageURL from '../utils/createPackageURL.js';
|
||||||
import { getPackageConfig, resolveVersion } from '../utils/npm.js';
|
import { getPackageConfig, resolveVersion } from '../utils/npm.js';
|
||||||
|
|
||||||
|
@ -18,7 +19,7 @@ function semverRedirect(req, res, newVersion) {
|
||||||
* fetch the package config and add it to req.packageConfig. Redirect to
|
* fetch the package config and add it to req.packageConfig. Redirect to
|
||||||
* the resolved version number if necessary.
|
* the resolved version number if necessary.
|
||||||
*/
|
*/
|
||||||
export default async function validateVersion(req, res, next) {
|
async function validateVersion(req, res, next) {
|
||||||
const version = await resolveVersion(req.packageName, req.packageVersion);
|
const version = await resolveVersion(req.packageName, req.packageVersion);
|
||||||
|
|
||||||
if (!version) {
|
if (!version) {
|
||||||
|
@ -47,3 +48,5 @@ export default async function validateVersion(req, res, next) {
|
||||||
|
|
||||||
next();
|
next();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default asyncHandler(validateVersion);
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
/**
|
||||||
|
* Useful for wrapping `async` request handlers so they
|
||||||
|
* automatically propagate errors.
|
||||||
|
*/
|
||||||
|
export default function asyncHandler(handler) {
|
||||||
|
return (req, res, next) => {
|
||||||
|
Promise.resolve(handler(req, res, next)).catch(error => {
|
||||||
|
console.error(`Unexpected error in ${handler.name}!`);
|
||||||
|
console.error(error);
|
||||||
|
|
||||||
|
next(error);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
Loading…
Reference in New Issue