Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

initial

  • Loading branch information...
commit e4e15f2fe034d7d991ddbfb5f8f21f25ef6b12a6 0 parents
@jden authored
Showing with 211 additions and 0 deletions.
  1. +1 −0  .gitignore
  2. +62 −0 README.md
  3. +134 −0 npm-delegate.js
  4. +14 −0 package.json
1  .gitignore
@@ -0,0 +1 @@
+node_modules
62 README.md
@@ -0,0 +1,62 @@
+# npm-delegate
+a hierarchical npm-registry proxy to make private registries easier
+
+npm registries all the way down.
+
+## wherefore?
+
+say you want to set up a local, private npm registry for certain modules, but you still want to be able to install public modules. Sure, thanks to couchdb, you could replicate the entire public registry down - but that's tens of gigabytes of extra disk space you'd need.
+
+
+ +--+
+ +------------+ |p |
+ | client | 'foo'? |r | +------------+
+ | | --------> |o | 'foo'? | |
+ | | |x | ------> | private |
+ | | |y | <------ | registry |
+ | | | | 404 +------------+
+ | | | | 'foo'? +---------------+
+ | | | | -----------------> | |
+ | | | | <----------------- | public |
+ | | <-------- | | 'foo' | registry |
+ +------------+ 'foo' +--+ +---------------+
+
+
+## usage
+
+run `npm-registry` somewhere - possibly on the server where you're running couchdb for your registry.
+
+ node npm-registry registry1 registry2 registry3
+
+eg
+
+ node npm-registry -p 1337 http://localhost:5984/registry https://registry.npmjs.org
+
+setup your npm client:
+
+ npm do-some-stuff
+
+List as many registries as you want in fall-back order as command line arguments when startingnpm-registry.
+
+## note: proxy is read-onlys
+
+Only GET requests are allowed. Strange things happens when you send state-changing requests around willy-nilly, and that's probably not what you want. For example, to publish a module, you probably want to specify which registry you're publishing it to, eg
+
+ $ npm publish --registry http://mysweetregistry.com
+
+See also: [how to specify a registry to publish to in your package.json](https://npmjs.org/doc/registry.html#I-don-t-want-my-package-published-in-the-official-registry-It-s-private)
+
+Options
+
+## faqs
+
+*does this run a registry for me?*
+no
+
+*how do I set up my own private registry?*
+read this: [https://github.com/isaacs/npmjs.org](https://github.com/isaacs/npmjs.org)
+
+## license
+MIT
+(c) 2012 jden - Jason Denizac <jason@denizac.org>
+http://jden.mit-license.org/2012
134 npm-delegate.js
@@ -0,0 +1,134 @@
+var optimist = require('optimist')
+var fallback = require('fallback')
+var http = require('http')
+var https = require('https')
+var url = require('url2')
+
+var argv = optimist
+ .usage('Compose multiple npm registries in fallback order.\nUsage: $0 [opts] host1/registry host2/registry ... hostN/registry')
+ .alias('p','port')
+ .default('p',5983)
+ .describe('p', 'port to listen on')
+ .alias('s','secure')
+ .default(false)
+ .boolean('s')
+ .describe('s', 'run the proxy using https?')
+ .check(function (argv) {
+ if (!argv._.length)
+ throw new Error('you must specify at least one registry (two to be useful)')
+ })
+ .argv;
+
+var registries = argv._.map(parseRegistry)
+
+function parseRegistry(string) {
+ var parsed = url.parse(string)
+ if (!/http(s?):/.test(parsed.protocol))
+ die('invalid registry address: specify a protocol (eg https://): ' + string)
+
+ parsed.port || (parsed.port = 80)
+
+ return parsed
+}
+
+(argv.secure ? https : http).createServer(delegate).listen(argv.port)
+console.log('proxy started')
+console.dir(registries.map(url.format))
+
+
+function delegate(req, resOut) {
+
+ if (req.method !== 'GET') {
+ console.log('invalid method')
+ resOut.statusCode = 405
+ resOut.write(JSON.stringify({error: 'invalid method'}))
+ resOut.end()
+ return
+ }
+
+ fallback(registries, function (registry, cb) {
+ console.log('forwarding to ' + registry.hostname)
+ forward(req, registry, function (err, res) {
+ if (!err) {
+ return cb(null, res)
+ }
+ console.log('err calling ' + registry.hostname + '. ' + err)
+ return cb()
+ })
+
+ }, function (err, resIn, registry) {
+ if (err) {
+ resOut.write(JSON.stringify({error: 'There was an error resolving your request:\n' + JSON.stringify(err, null, 2)}))
+ return resOut.end()
+ }
+ else if (!resIn) {
+ resOut.statusCode = 400
+ resOut.write(JSON.stringify({error: 'request could not be fulfilled by any of the registries on this proxy.'
+ + 'perhaps the module you\'re looking for does not exist'}))
+ resOut.end()
+ } else {
+ console.log('proxying response from registry' + url.format(registry))
+ resOut.setHeader('x-registry', url.format(registry))
+ pipeRes(resIn, resOut)
+ }
+ });
+
+
+}
+
+function forward(reqIn, registry, cb) {
+ var reqOut = {
+ hostname: registry.hostname
+ , port: registry.port
+ , path: rebase(registry.path, reqIn.url)
+ , headers: reqIn.headers
+ , method: reqIn.method
+ , auth: registry.auth
+ }
+ delete reqOut.headers.host
+ delete reqOut.headers.authorization
+
+
+ console.log('fwd req', reqOut)
+ reqOut = (/https/.test(reqOut.protocol) ? https : http).request(reqOut, function (res) {
+ console.log('res received')
+ if (res.statusCode >= 400) {
+ console.log('bad response from ' + registry.hostname + ' ' + res.statusCode)
+ res.pipe(process.stdout)
+ return cb(new Error('Response from ' + registry.hostname + ': ' + res.statusCode))
+ }
+ return cb(null, res);
+ }).on('error', cb);
+ reqOut.end();
+}
+
+function pipeRes(resFrom, resTo) {
+ copyHeaders(resFrom, resTo)
+ resFrom.pipe(resTo)
+}
+
+function copyHeaders(resFrom, resTo) {
+ resTo.statusCode = resFrom.statusCode;
+ for (var header in resFrom.headers) {
+ resTo.setHeader(header, resFrom.headers[header])
+ }
+}
+
+
+function rebase(pathBase, path) {
+ console.log(pathBase, path)
+
+ if (pathBase != '/registry') {
+ return path.replace('/registry','')
+ }
+
+ if (path.indexOf('/registry') != 0) {
+ return '/registry' + path;
+ }
+}
+
+
+function die(msg) {
+ console.error(msg)
+ process.exit(1)
+}
14 package.json
@@ -0,0 +1,14 @@
+{
+ "name": "npm-delegate",
+ "version": "0.1.0",
+ "description": "a hierarchical npm-registry proxy",
+ "main": "npm-delegate.js",
+ "repository": "",
+ "author": "jden <jason@denizac.org>",
+ "license": "MIT",
+ "dependencies": {
+ "optimist": "~0.3.5",
+ "fallback": "~1.0.0",
+ "url2": "0.0.0"
+ }
+}
Please sign in to comment.
Something went wrong with that request. Please try again.