diff --git a/app.js b/app.js new file mode 100644 index 0000000..28a1056 --- /dev/null +++ b/app.js @@ -0,0 +1,65 @@ +var express = require('express'); +var fs = require('fs'); + +var NPM_PATH = process.env.HOME + '/.npm'; +var REGISTRY_NAME = 'registry.npmjs.org'; +var LOCAL_REGISTRY = 'localhost:8080'; + + +var app = express(); + +function patchData( data ){ + Object.keys(data.versions).forEach( function( v ){ + var val = data.versions[v]; + val.dist.tarball = val.dist.tarball.replace( REGISTRY_NAME, LOCAL_REGISTRY ); + }); +} + + +app.use( function(req, res, next ){ + console.log(req.method, req.path ); + next(); +}); + +app.get( '/:package', function( req, res ){ + var packageName = req.params.package; + var cacheFile = [ NPM_PATH, REGISTRY_NAME, packageName, '.cache.json' ].join( '/' ); + var cacheData = fs.readFileSync( cacheFile, 'utf-8' ); + cacheData = JSON.parse( cacheData ); + + patchData( cacheData ); + return res.send( cacheData ); +}); + +app.get( '/:package/-/:packageName-:version.tgz', function( req, res ){ + var packageName = req.params.package; + var version = req.params.version.split('-').pop(); + var packagePath = [ NPM_PATH , packageName, version, 'package.tgz'].join( '/' ); + return fs.createReadStream( packagePath ).pipe( res ); +}); + + +// catch 404 and forward to error handler +app.use(function(req, res, next) { + var err = new Error('Not Found'); + err.status = 404; + next(err); +}); + +// error handlers + +// development error handler +// will print stacktrace +if (app.get('env') === 'development') { + app.use(function(err, req, res, next) { + res.status(err.status || 500); + res.send({ + message: err.message, + error: err + }); + }); +} + + + +module.exports = app; diff --git a/bin/www b/bin/www new file mode 100755 index 0000000..3aea8e8 --- /dev/null +++ b/bin/www @@ -0,0 +1,90 @@ +#!/usr/bin/env node + +/** + * Module dependencies. + */ + +var app = require('../app'); +var debug = require('debug')('npm-proxy:server'); +var http = require('http'); + +/** + * Get port from environment and store in Express. + */ + +var port = normalizePort(process.env.PORT || '8080'); +app.set('port', port); + +/** + * Create HTTP server. + */ + +var server = http.createServer(app); + +/** + * Listen on provided port, on all network interfaces. + */ + +server.listen(port); +server.on('error', onError); +server.on('listening', onListening); + +/** + * Normalize a port into a number, string, or false. + */ + +function normalizePort(val) { + var port = parseInt(val, 10); + + if (isNaN(port)) { + // named pipe + return val; + } + + if (port >= 0) { + // port number + return port; + } + + return false; +} + +/** + * Event listener for HTTP server "error" event. + */ + +function onError(error) { + if (error.syscall !== 'listen') { + throw error; + } + + var bind = typeof port === 'string' + ? 'Pipe ' + port + : 'Port ' + port; + + // handle specific listen errors with friendly messages + switch (error.code) { + case 'EACCES': + console.error(bind + ' requires elevated privileges'); + process.exit(1); + break; + case 'EADDRINUSE': + console.error(bind + ' is already in use'); + process.exit(1); + break; + default: + throw error; + } +} + +/** + * Event listener for HTTP server "listening" event. + */ + +function onListening() { + var addr = server.address(); + var bind = typeof addr === 'string' + ? 'pipe ' + addr + : 'port ' + addr.port; + debug('Listening on ' + bind); +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..28df467 --- /dev/null +++ b/package.json @@ -0,0 +1,11 @@ +{ + "name": "npm-offline-registry", + "version": "0.0.1", + "private": true, + "scripts": { + "start": "node ./bin/www" + }, + "dependencies": { + "express": "~4.13.1" + } +}