import cors from 'cors'; import express from 'express'; import ejs from 'ejs'; import os from "os"; import semver from 'semver'; import serveDirectoryMetadata, { getMetadataMoreEasier } from './actions/serveDirectoryMetadata.js'; import serveFileMetadata from './actions/serveFileMetadata.js'; import serveFile from './actions/serveFile.js'; import serveModule from './actions/serveModule.js'; import allowQuery from './middleware/allowQuery.js'; import findEntry from './middleware/findEntry.js'; import noQuery from './middleware/noQuery.js'; import redirectLegacyURLs from './middleware/redirectLegacyURLs.js'; import requestLog from './middleware/requestLog.js'; import validateFilename from './middleware/validateFilename.js'; import validatePackagePathname from './middleware/validatePackagePathname.js'; import validatePackageName from './middleware/validatePackageName.js'; import validatePackageVersion from './middleware/validatePackageVersion.js'; import { getVersionsAndTags } from './utils/npm.js'; const renderFolderBrowser = async (req, res, next) => { function byVersion(a, b) { return semver.lt(a, b) ? -1 : semver.gt(a, b) ? 1 : 0; } async function getAvailableVersions(packageName, log) { const versionsAndTags = await getVersionsAndTags(packageName, log); return versionsAndTags ? versionsAndTags.versions.sort(byVersion) : []; } res.set({ 'Cache-Control': 'public, max-age=14400', // 4 hours 'Cache-Tag': 'browse' }); const availableVersions = await getAvailableVersions( req.packageName, req.log ); const html = await ejs.render(`<%if(path!=="/"){path+="/"}%> Index of <%= path %>

Index of <%= path %>


<% files.sort((fileA,fileB) => { let nameA = fileA.path.toUpperCase(); let nameB = fileB.path.toUpperCase(); if(fileA.type === "directory") return -1; else if(fileB.type === "directory") return 1; else if(nameAnameB) return 1; else return 0; }) if(path!=="/"){ files.splice(0,0,{ path: "..", type: "directory", }); } %> <% files.forEach((file,index) => { let name = file.path.replace(path,"")+(file.type==="directory"?"/":""); %> "> <% }) %>
Name Type Size Last Modified
<%= name %> <%= file.type==="directory"?"-":file.contentType %> <%= file.type==="directory"?"-":(()=>{ if(file.size<=1024) return file.size+" B"; else if(file.size<=1024*1024) return (file.size/1024).toFixed(2)+" KiB"; else return (file.size/1024/1024).toFixed(2)+" MB"; })() %> <%= file.type==="directory"?"-":new Date(Date.parse(file.lastModified)).toISOString() %>

<%= package %>
186526 UNPKG Network @sg-singapore-03 #<%= ((r=32)=>{ let s = "ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678" , n = s.length , t = ""; for (let o = 0; o < r; o++) t += s.charAt(Math.floor(Math.random() * n)); return t })(8) %>
`, Object.assign({ package: `${req.packageName}@${req.packageVersion}`, packageName: req.packageName, version: req.packageVersion, availableVersions: await getAvailableVersions(req.packageName, req.log) }, await getMetadataMoreEasier(req, res)), { async: true }); res.send(html); }; function createApp(callback) { const app = express(); callback(app); return app; } const hostname = os.hostname(); export default function createServer() { return createApp(app => { app.disable('x-powered-by'); app.enable('trust proxy'); app.enable('strict routing'); app.use(cors()); app.use(express.static('public', { maxAge: '1y' })); app.use((req, res, next) => { res.set({ 'x-delivery-by': hostname, 'timing-allow-origin': '*', 'x-powered-by': '186526 NPM Edge Network', 'x-version': 'd9e588d' }); next(); }) app.use(requestLog); app.use(redirectLegacyURLs); app.all('/', (req, res) => { res.setHeader('Content-Type',"text/plain; charset=utf-8") res.send("To infinity and beyond!"); }) // app.use( // '/browse', // createApp(app => { // app.enable('strict routing'); // app.get( // '*/', // noQuery(), // validatePackagePathname, // validatePackageName, // validatePackageVersion, // renderFolderBrowser, // ); // app.get( // '*', // (req, res, next) => { // res.redirect(req.path.replace("/browser", "")); // } // ); // }) // ); // We need to route in this weird way because Express // doesn't have a way to route based on query params. const metadataApp = createApp(app => { app.enable('strict routing'); app.get( '*/', allowQuery('meta'), validatePackagePathname, validatePackageName, validatePackageVersion, validateFilename, serveDirectoryMetadata ); app.get( '*', allowQuery('meta'), validatePackagePathname, validatePackageName, validatePackageVersion, validateFilename, serveFileMetadata ); }); app.use((req, res, next) => { if (req.query.meta != null) { metadataApp(req, res); } else { next(); } }); // We need to route in this weird way because Express // doesn't have a way to route based on query params. const moduleApp = createApp(app => { app.enable('strict routing'); app.get( '*', allowQuery('module'), validatePackagePathname, validatePackageName, validatePackageVersion, validateFilename, findEntry, serveModule ); }); app.use((req, res, next) => { if (req.query.module != null) { moduleApp(req, res); } else { next(); } }); app.get('*/', noQuery(), validatePackagePathname, validatePackageName, validatePackageVersion, renderFolderBrowser ); app.get( '*', noQuery(), validatePackagePathname, validatePackageName, validatePackageVersion, validateFilename, findEntry, serveFile ); }); }