unpkg/modules/actions/serveFileMetadata.js

69 lines
2.0 KiB
JavaScript
Raw Normal View History

import gunzip from 'gunzip-maybe';
import tar from 'tar-stream';
2019-07-31 00:06:27 +00:00
import asyncHandler from '../utils/asyncHandler.js';
import bufferStream from '../utils/bufferStream.js';
import getContentType from '../utils/getContentType.js';
import getIntegrity from '../utils/getIntegrity.js';
import { getPackage } from '../utils/npm.js';
async function findEntry(stream, filename) {
// filename = /some/file/name.js
return new Promise((accept, reject) => {
let foundEntry = null;
stream
.pipe(gunzip())
.pipe(tar.extract())
.on('error', reject)
.on('entry', async (header, stream, next) => {
const entry = {
// Most packages have header names that look like `package/index.js`
// so we shorten that to just `/index.js` here. A few packages use a
// prefix other than `package/`. e.g. the firebase package uses the
// `firebase_npm/` prefix. So we just strip the first dir name.
path: header.name.replace(/^[^/]+/, ''),
type: header.type
};
// Ignore non-files and files that don't match the name.
if (entry.type !== 'file' || entry.path !== filename) {
stream.resume();
stream.on('end', next);
return;
}
2019-07-31 00:06:27 +00:00
try {
const content = await bufferStream(stream);
2019-07-31 00:06:27 +00:00
entry.contentType = getContentType(entry.path);
entry.integrity = getIntegrity(content);
entry.lastModified = header.mtime.toUTCString();
entry.size = content.length;
2019-07-31 00:06:27 +00:00
foundEntry = entry;
2019-07-31 00:06:27 +00:00
next();
} catch (error) {
next(error);
}
})
.on('finish', () => {
accept(foundEntry);
});
});
}
2019-07-31 00:06:27 +00:00
async function serveFileMetadata(req, res) {
const stream = await getPackage(req.packageName, req.packageVersion);
const entry = await findEntry(stream, req.filename);
if (!entry) {
// TODO: 404
}
res.send(entry);
}
2019-07-31 00:06:27 +00:00
export default asyncHandler(serveFileMetadata);