smart-private-npm
Version:
An intelligent routing proxy for npm with support for: private, whitelisted, and blacklisted packaged
172 lines (140 loc) • 4.22 kB
JavaScript
;
var defaultConfig = require('../config/default'),
snpm = require('../lib'),
url = require('url'),
fs = require('fs'),
path = require('path'),
getPkgs = require('npm-registry-packages');
process.title = 'smart-private-npm';
var argv = require('minimist')(process.argv.slice(2), {
alias: {
help: 'h',
'private': 'P',
'public': 'p',
config: 'c',
exclude: 'e',
loglevel: 'l',
transparent: 't',
'ignore-private': 'i'
},
boolean: ['help', 'transparent', 'ignore-private'],
string: ['private', 'public', 'exclude', 'loglevel'],
default: {
loglevel: 'info',
transparent: false,
'ignore-private': false
}
});
if (argv.help) {
return fs.createReadStream(__dirname + '/usage.txt')
.pipe(process.stdout)
.on('close', function () { process.exit(1); });
}
// TODO: Replace with diagnostic
var winston = require('winston');
var log = new winston.Logger({
transports: [
new (winston.transports.Console)({ level: argv.loglevel, colorize: true })
]
});
var config = argv.config ? require(path.resolve(process.cwd(), argv.config)) : {};
config.ip = argv.i;
//
// TODO: A better way of merging the defaults with the cli flags
// taking precendence
//
config.private = argv.private || config.private || defaultConfig.private;
config.public = argv.public || config.public || defaultConfig.public;
config.http = config.http || defaultConfig.http;
config.https = config.https || null;
config.exclude = argv.exclude || config.exclude || defaultConfig.exclude;
config.rewrites = config.rewrites || require('../config/rewrites');
config.transparent = argv.transparent || config.transparent || false;
if (argv.config) {
log.verbose('config => %s', argv.config);
}
log.verbose('private registry => %s', config.private);
log.verbose('public registry => %s', config.public);
log.verbose('http => %s', ''+config.http);
log.verbose('https => '+(config.https ? config.https : 'null'));
log.verbose('excludes =>', config.exclude);
log.verbose('transparent =>', config.transparent);
log.verbose('ignore-private =>', config.ip);
if (typeof config.public === "string") {
config.public = url.parse(config.public);
}
if (typeof config.private === "string") {
config.private = url.parse(config.private);
}
var proxyOpts = {
rewrites: config.rewrites,
proxy: {
npm: config.public,
policy: {
npm: config.private,
private: {},
blacklist: {},
transparent: config.transparent
},
log: log
},
http: config.http,
https: config.https,
log: log
};
if (config.blacklist) {
proxyOpts.proxy.policy.blacklist = config.blacklist;
}
if (config.whitelist) {
proxyOpts.proxy.policy.whitelist = config.whitelist;
}
if (config.ip === true) {
getPkgs = function(a, cb) {
process.nextTick(function() {
cb(null, []);
});
};
}
getPkgs(config.private.href, function(err, pkgs) {
if (err) {
if (err.code && err.code === 'ECONNREFUSED') {
log.error('Error loading private packages', err.message);
log.error('Is your private registry running and accessible at [%s]?', config.private);
} else {
log.error('Error loading private packages', { err: err });
}
return process.exit(1);
}
if (!config.filter) {
pkgs = pkgs.filter(function(f) {
return (!(~config.exclude.indexOf(f)));
});
}
var privatePkgs = {},
len = pkgs.length;
if (!config.ip) {
for (var i=0; i<len; i++) {
var pkg = pkgs[i];
privatePkgs[pkg] = 1;
}
config.exclude.forEach(function(e) {
log.verbose('excluding package: '+e);
if (privatePkgs.hasOwnProperty(e)) {
delete privatePkgs[e];
}
});
log.verbose('loaded private packages', privatePkgs);
} else {
log.verbose('ignoring packages from private registry');
}
proxyOpts.proxy.policy.private = privatePkgs;
snpm.createServer(proxyOpts, function(err, servers) {
if (err) {
log.error('error starting private npm', { err: err });
log.error('servers: %j', Object.keys(servers));
return process.exit(1);
}
log.info('private npm running on: %j', Object.keys(servers));
});
});