Permalink
Browse files

Add npm-registry-client dep

  • Loading branch information...
1 parent c7b2241 commit b194c5e2aeffb8d328d0d668a3f70e9f16781383 @isaacs isaacs committed Jun 7, 2012
View
1 node_modules/npm-registry-client/.npmignore
@@ -0,0 +1 @@
+test/fixtures/cache
View
132 node_modules/npm-registry-client/README.md
@@ -0,0 +1,132 @@
+# npm-registry-client
+
+The code that npm uses to talk to the registry.
+
+It handles all the caching and HTTP calls.
+
+## Usage
+
+```javascript
+var RegClient = require('npm-registry-client')
+var client = new RegClient(options)
+
+client.get("npm", "latest", 1000, function (er, data, raw, res) {
+ // error is an error if there was a problem.
+ // data is the parsed data object
+ // raw is the json string
+ // res is the response from couch
+})
+```
+
+# Options
+
+* `registry` **Required** {String} URL to the registry
+* `cache` **Required** {String} Path to the cache folder
+* `alwaysAuth` {Boolean} Auth even for GET requests.
+* `auth` {String} A base64-encoded `username:password`
+* `email` {String} User's email address
+* `tag` {String} The default tag to use when publishing new packages.
+ Default = `"latest"`
+* `ca` {String} Cerficate signing authority certificates to trust.
+* `strictSSL` {Boolean} Whether or not to be strict with SSL
+ certificates. Default = `true`
+* `userAgent` {String} User agent header to send. Default =
+ `"node/{process.version}"`
+* `E404` {Object} Error indicator to use when a 404 is encountered.
+* `EPUBLISHCONFLICT` {Object} Error indicator to use when a publish
+ conflict occurs.
+* `log` {Object} The logger to use. Defaults to `require("npmlog")` if
+ that works, otherwise logs are disabled.
+
+# client.request(method, where, [what], [etag], [nofollow], cb)
+
+* `method` {String} HTTP method
+* `where` {String} Path to request on the server
+* `what` {Stream | Buffer | String | Object} The request body. Objects
+ that are not Buffers or Streams are encoded as JSON.
+* `etag` {String} The cached ETag
+* `nofollow` {Boolean} Prevent following 302/301 responses
+* `cb` {Function}
+ * `error` {Error | null}
+ * `data` {Object} the parsed data object
+ * `raw` {String} the json
+ * `res` {Response Object} response from couch
+
+Make a request to the registry. All the other methods are wrappers
+around this. one.
+
+# client.adduser(username, password, email, cb)
+
+* `username` {String}
+* `password` {String}
+* `email` {String}
+* `cb` {Function}
+
+Add a user account to the registry, or verify the credentials.
+
+# client.get(url, [timeout], [nofollow], [staleOk], cb)
+
+* `url` {String} The url path to fetch
+* `timeout` {Number} Number of seconds old that a cached copy must be
+ before a new request will be made.
+* `nofollow` {Boolean} Do not follow 301/302 responses
+* `staleOk` {Boolean} If there's cached data available, then return that
+ to the callback quickly, and update the cache the background.
+
+Fetches data from the registry via a GET request, saving it in
+the cache folder with the ETag.
+
+# client.publish(data, tarball, [readme], cb)
+
+* `data` {Object} Package data
+* `tarball` {String | Stream} Filename or stream of the package tarball
+* `readme` {String} Contents of the README markdown file
+* `cb` {Function}
+
+Publish a package to the registry.
+
+Note that this does not create the tarball from a folder. However, it
+can accept a gzipped tar stream or a filename to a tarball.
+
+# client.star(package, starred, cb)
+
+* `package` {String} Name of the package to star
+* `starred` {Boolean} True to star the package, false to unstar it.
+* `cb` {Function}
+
+Star or unstar a package.
+
+Note that the user does not have to be the package owner to star or
+unstar a package, though other writes do require that the user be the
+package owner.
+
+# client.tag(project, version, tag, cb)
+
+* `project` {String} Project name
+* `version` {String} Version to tag
+* `tag` {String} Tag name to apply
+* `cb` {Function}
+
+Mark a version in the `dist-tags` hash, so that `pkg@tag`
+will fetch the specified version.
+
+# client.unpublish(name, [ver], cb)
+
+* `name` {String} package name
+* `ver` {String} version to unpublish. Leave blank to unpublish all
+ versions.
+* `cb` {Function}
+
+Remove a version of a package (or all versions) from the registry. When
+the last version us unpublished, the entire document is removed from the
+database.
+
+# client.upload(where, file, [etag], [nofollow], cb)
+
+* `where` {String} URL path to upload to
+* `file` {String | Stream} Either the filename or a readable stream
+* `etag` {String} Cache ETag
+* `nofollow` {Boolean} Do not follow 301/302 responses
+* `cb` {Function}
+
+Upload an attachment. Mostly used by `client.publish()`.
View
68 node_modules/npm-registry-client/index.js
@@ -0,0 +1,68 @@
+
+// utilities for working with the js-registry site.
+
+module.exports = RegClient
+
+var fs = require('fs')
+, url = require('url')
+, path = require('path')
+, npmlog
+
+try {
+ npmlog = require("npmlog")
+} catch (er) {
+ npmlog = { error: noop, warn: noop, info: noop,
+ verbose: noop, silly: noop, http: silly,
+ pause: noop, resume: noop }
+}
+
+function noop () {}
+
+function RegClient (options) {
+ // a registry url must be provided.
+ var registry = url.parse(options.registry)
+ if (!registry.protocol) throw new Error(
+ 'Invalid registry: ' + registry.url)
+ this.registry = registry.href
+
+ this.cache = options.cache
+ if (!this.cache) throw new Error("Cache dir is required")
+
+ this.alwaysAuth = options.alwaysAuth || false
+
+ this.auth = options.auth || null
+ if (this.auth) {
+ var a = new Buffer(this.auth, "base64").toString()
+ a = a.split(":")
+ this.username = a.shift()
+ this.password = a.join(":")
+ }
+ this.email = options.email || null
+ this.tag = options.tag || "latest"
+
+ this.ca = options.ca || null
+
+ this.strictSSL = options.strictSSL
+ if (this.strictSSL === undefined) this.strictSSL = true
+
+ this.userAgent = options.userAgent
+ if (this.userAgent === undefined) {
+ this.userAgent = 'node/' + process.version
+ }
+
+ this.cacheMin = options.cacheMin || 0
+ this.cacheMax = options.cacheMax || Infinity
+
+ this.proxy = options.proxy
+ this.httpsProxy = options.httpsProxy || options.proxy
+
+ this.E404 = options.E404 || {}
+ this.EPUBLISHCONFLICT = options.EPUBLISHCONFLICT || {}
+
+ this.log = options.log || npmlog
+}
+
+require('fs').readdirSync(__dirname + "/lib").forEach(function (f) {
+ if (!f.match(/\.js$/)) return
+ RegClient.prototype[f.replace(/\.js$/, '')] = require('./lib/' + f)
+})
View
99 node_modules/npm-registry-client/lib/adduser.js
@@ -0,0 +1,99 @@
+
+module.exports = adduser
+
+var uuid = require("node-uuid")
+ , crypto
+
+try {
+} catch (ex) {}
+
+function sha (s) {
+ return crypto.createHash("sha1").update(s).digest("hex")
+}
+
+function adduser (username, password, email, cb) {
+ if (!crypto) crypto = require("crypto")
+
+ password = ("" + (password || "")).trim()
+ if (!password) return cb(new Error("No password supplied."))
+
+ email = ("" + (email || "")).trim()
+ if (!email) return cb(new Error("No email address supplied."))
+ if (!email.match(/^[^@]+@[^\.]+\.[^\.]+/)) {
+ return cb(new Error("Please use a real email address."))
+ }
+
+ if (password.indexOf(":") !== -1) return cb(new Error(
+ "Sorry, ':' chars are not allowed in passwords.\n"+
+ "See <https://issues.apache.org/jira/browse/COUCHDB-969> for why."))
+
+ var salt = uuid()
+ , userobj =
+ { name : username
+ , salt : salt
+ , password_sha : sha(password + salt)
+ , email : email
+ , _id : 'org.couchdb.user:'+username
+ , type : "user"
+ , roles : []
+ , date: new Date().toISOString()
+ }
+
+ cb = done.call(this, cb)
+
+ this.log.verbose("adduser", "before first PUT", userobj)
+ this.request('PUT'
+ , '/-/user/org.couchdb.user:'+encodeURIComponent(username)
+ , userobj
+ , function (error, data, json, response) {
+ // if it worked, then we just created a new user, and all is well.
+ // but if we're updating a current record, then it'll 409 first
+ if (error && !this.auth) {
+ // must be trying to re-auth on a new machine.
+ // use this info as auth
+ var b = new Buffer(username + ":" + password)
+ this.auth = b.toString("base64")
+ }
+
+ if (!error || !response || response.statusCode !== 409) {
+ return cb(error, data, json, response)
+ }
+
+ this.log.verbose("adduser", "update existing user")
+ return this.request('GET'
+ , '/-/user/org.couchdb.user:'+encodeURIComponent(username)
+ , function (er, data, json, response) {
+ Object.keys(data).forEach(function (k) {
+ userobj[k] = data[k]
+ })
+ this.log.verbose("adduser", "userobj", userobj)
+ this.request('PUT'
+ , '/-/user/org.couchdb.user:'+encodeURIComponent(username)
+ + "/-rev/" + userobj._rev
+ , userobj
+ , cb )
+ }.bind(this))
+ }.bind(this))
+}
+
+function done (cb) {
+ return function (error, data, json, response) {
+ if (!error && (!response || response.statusCode === 201)) {
+ return cb(error, data, json, response)
+ }
+ this.log.verbose("adduser", "back", [error, data, json])
+ if (!error) {
+ error = new Error( (response && response.statusCode || "") + " "+
+ "Could not create user\n"+JSON.stringify(data))
+ }
+ if (response
+ && (response.statusCode === 401 || response.statusCode === 403)) {
+ this.log.warn("adduser", "Incorrect username or password\n"
+ +"You can reset your account by visiting:\n"
+ +"\n"
+ +" http://admin.npmjs.org/reset\n")
+ }
+
+ return cb(error)
+ }.bind(this)
+}
View
172 node_modules/npm-registry-client/lib/get.js
@@ -0,0 +1,172 @@
+
+module.exports = get
+
+var fs = require("graceful-fs")
+ , path = require("path")
+ , mkdir = require("mkdirp")
+ , chownr = require("chownr")
+
+function get (uri, timeout, nofollow, staleOk, cb) {
+ if (typeof cb !== "function") cb = staleOk, staleOk = false
+ if (typeof cb !== "function") cb = nofollow, nofollow = false
+ if (typeof cb !== "function") cb = timeout, timeout = -1
+ if (typeof cb !== "function") cb = version, version = null
+
+ timeout = Math.min(timeout, this.cacheMax)
+ timeout = Math.max(timeout, this.cacheMin)
+
+ if ( process.env.COMP_CWORD !== undefined
+ && process.env.COMP_LINE !== undefined
+ && process.env.COMP_POINT !== undefined
+ ) timeout = Math.max(timeout, 60000)
+
+ // /-/all is special.
+ // It uses timestamp-based caching and partial updates,
+ // because it is a monster.
+ if (uri === "/-/all") {
+ return requestAll.call(this, cb)
+ }
+
+ var cache = path.join(this.cache, uri, ".cache.json")
+ fs.stat(cache, function (er, stat) {
+ if (!er) fs.readFile(cache, function (er, data) {
+ try { data = JSON.parse(data) }
+ catch (ex) { data = null }
+ get_.call(this, uri, timeout, cache, stat, data, nofollow, staleOk, cb)
+ }.bind(this))
+ else get_.call(this, uri, timeout, cache, null, null, nofollow, staleOk, cb)
+ }.bind(this))
+}
+
+function requestAll (cb) {
+ var cache = path.join(this.cache, "/-/all", ".cache.json")
+
+ mkdir(path.join(this.cache, "-", "all"), function (er) {
+ fs.readFile(cache, function (er, data) {
+ if (er) return requestAll_(0, {}, cb)
+ try {
+ data = JSON.parse(data)
+ } catch (ex) {
+ fs.writeFile(cache, "{}", function (er) {
+ if (er) return cb(new Error("Broken cache."))
+ return requestAll_.call(this, 0, {}, cb)
+ })
+ }
+ var t = +data._updated || 0
+ requestAll_.call(this, t, data, cb)
+ }.bind(this))
+ }.bind(this))
+}
+
+function requestAll_ (c, data, cb) {
+ // use the cache and update in the background if it's not too old
+ if (Date.now() - c < 60000) {
+ cb(null, data)
+ cb = function () {}
+ }
+
+ var uri = "/-/all/since?stale=update_after&startkey=" + c
+
+ if (c === 0) {
+ this.log.warn("", "Building the local index for the first time, please be patient")
+ uri = "/-/all"
+ }
+
+ var cache = path.join(this.cache, "-/all", ".cache.json")
+ this.request('GET', uri, function (er, updates, _, res) {
+ if (er) return cb(er, data)
+ var headers = res.headers
+ , updated = Date.parse(headers.date)
+ Object.keys(updates).forEach(function (p) {
+ data[p] = updates[p]
+ })
+ data._updated = updated
+ fs.writeFile( cache, JSON.stringify(data)
+ , function (er) {
+ delete data._updated
+ return cb(er, data)
+ })
+ })
+}
+
+function get_ (uri, timeout, cache, stat, data, nofollow, staleOk, cb) {
+ var etag
+ if (data && data._etag) etag = data._etag
+ if (timeout && timeout > 0 && stat && data) {
+ if ((Date.now() - stat.mtime.getTime())/1000 < timeout) {
+ this.log.verbose("registry.get", uri, "not expired, no request")
+ delete data._etag
+ return cb(null, data, JSON.stringify(data), {statusCode:304})
+ }
+ if (staleOk) {
+ this.log.verbose("registry.get", uri, "staleOk, background update")
+ delete data._etag
+ process.nextTick(cb.bind( null, null, data, JSON.stringify(data)
+ , {statusCode: 304} ))
+ cb = function () {}
+ }
+ }
+
+ this.request('GET', uri, etag, nofollow, function (er, remoteData, raw, response) {
+ // if we get an error talking to the registry, but we have it
+ // from the cache, then just pretend we got it.
+ if (er && cache && data && !data.error) {
+ er = null
+ response = {statusCode: 304}
+ }
+
+ if (response) {
+ this.log.silly("registry.get", "cb", [response.statusCode, response.headers])
+ if (response.statusCode === 304 && etag) {
+ remoteData = data
+ this.log.verbose("etag", uri+" from cache")
+ }
+ }
+
+ data = remoteData
+ if (!data) {
+ er = er || new Error("failed to fetch from registry: " + uri)
+ }
+
+ if (er) return cb(er, data, raw, response)
+
+ // just give the write the old college try. if it fails, whatever.
+ function saved () {
+ delete data._etag
+ cb(er, data, raw, response)
+ }
+
+ saveToCache.call(this, cache, data, saved)
+ }.bind(this))
+}
+
+function saveToCache (cache, data, saved) {
+ if (this.cacheStat) {
+ var cs = this.cacheStat
+ return saveToCache_.call(this, cache, data, cs.uid, cs.gid, saved)
+ }
+ fs.stat(this.cache, function (er, st) {
+ if (er) {
+ return fs.stat(process.env.HOME || "", function (er, st) {
+ // if this fails, oh well.
+ if (er) return saved()
+ this.cacheStat = st
+ return saveToCache.call(this, cache, data, saved)
+ }.bind(this))
+ }
+ this.cacheStat = st || { uid: null, gid: null }
+ return saveToCache.call(this, cache, data, saved)
+ }.bind(this))
+}
+
+function saveToCache_ (cache, data, uid, gid, saved) {
+ mkdir(path.dirname(cache), function (er, made) {
+ if (er) return saved()
+ fs.writeFile(cache, JSON.stringify(data), function (er) {
+ if (er || uid === null || gid === null) {
+ return saved()
+ }
+ chownr(made || cache, uid, gid, saved)
+ })
+ })
+}
View
120 node_modules/npm-registry-client/lib/publish.js
@@ -0,0 +1,120 @@
+
+module.exports = publish
+
+var path = require("path")
+ , url = require("url")
+
+function publish (data, tarball, readme, cb) {
+ if (typeof cb !== "function") cb = readme, readme = ""
+
+ if (!this.email || !this.auth || !this.username) {
+ return cb(new Error("auth and email required for publishing"))
+ }
+
+ // add the dist-url to the data, pointing at the tarball.
+ // if the {name} isn't there, then create it.
+ // if the {version} is already there, then fail.
+ // then:
+ // PUT the data to {config.registry}/{data.name}/{data.version}
+ var registry = this.registry
+
+ readme = readme ? "" + readme : ""
+
+ var fullData =
+ { _id : data.name
+ , name : data.name
+ , description : data.description
+ , "dist-tags" : {}
+ , versions : {}
+ , readme: readme
+ , maintainers :
+ [ { name : this.username
+ , email : this.email
+ }
+ ]
+ }
+
+ var tbName = data.name + "-" + data.version + ".tgz"
+ , tbURI = data.name + "/-/" + tbName
+
+ data._id = data.name+"@"+data.version
+ data.dist = data.dist || {}
+ data.dist.tarball = url.resolve(registry, tbURI)
+ .replace(/^https:\/\//, "http://")
+
+
+ // first try to just PUT the whole fullData, and this will fail if it's
+ // already there, because it'll be lacking a _rev, so couch'll bounce it.
+ this.request("PUT", encodeURIComponent(data.name), fullData,
+ function (er, parsed, json, response) {
+ // get the rev and then upload the attachment
+ // a 409 is expected here, if this is a new version of an existing package.
+ if (er
+ && !(response && response.statusCode === 409)
+ && !( parsed
+ && parsed.reason ===
+ "must supply latest _rev to update existing package" )) {
+ this.log.error("publish", "Failed PUT response "
+ +(response && response.statusCode))
+ return cb(er)
+ }
+ var dataURI = encodeURIComponent(data.name)
+ + "/" + encodeURIComponent(data.version)
+
+ var tag = data.tag || this.tag || "latest"
+ dataURI += "/-tag/" + tag
+
+ // let's see what versions are already published.
+ // could be that we just need to update the bin dist values.
+ this.request("GET", data.name, function (er, fullData) {
+ if (er) return cb(er)
+
+ var exists = fullData.versions && fullData.versions[data.version]
+ if (exists) return cb(conflictError(data._id))
+
+ // this way, it'll also get attached to packages that were previously
+ // published with a version of npm that lacked this feature.
+ if (!fullData.readme) {
+ data.readme = readme
+ }
+
+ this.request("PUT", dataURI, data, function (er) {
+ if (er) {
+ if (er.message.indexOf("conflict Document update conflict.") === 0) {
+ return cb(conflictError(data._id))
+ }
+ this.log.error("publish", "Error sending version data")
+ return cb(er)
+ }
+
+ this.log.verbose("publish", "attach 2", [data.name, tarball, tbName])
+ attach.call(this, data.name, tarball, tbName, function (er) {
+ this.log.verbose("publish", "attach 3"
+ ,[er, data.name])
+ return cb(er)
+ }.bind(this))
+ }.bind(this))
+ }.bind(this))
+ }.bind(this)) // pining for fat arrows.
+}
+
+function conflictError (pkgid) {
+ var e = new Error("publish fail")
+ e.errno = this.EPUBLISHCONFLICT
+ e.code = "EPUBLISHCONFLICT"
+ e.pkgid = pkgid
+ return e
+}
+
+function attach (doc, file, filename, cb) {
+ doc = encodeURIComponent(doc)
+ this.request("GET", doc, function (er, d) {
+ if (er) return cb(er)
+ if (!d) return cb(new Error(
+ "Attempting to upload to invalid doc "+doc))
+ var rev = "-rev/"+d._rev
+ , attURI = doc + "/-/" + encodeURIComponent(filename) + "/" + rev
+ this.log.verbose("uploading", [attURI, file])
+ this.upload(attURI, file, cb)
+ }.bind(this))
+}
View
202 node_modules/npm-registry-client/lib/request.js
@@ -0,0 +1,202 @@
+module.exports = regRequest
+
+var url = require("url")
+ , fs = require("graceful-fs")
+ , rm = require("rimraf")
+ , asyncMap = require("slide").asyncMap
+ , Stream = require("stream").Stream
+ , request = require("request")
+
+function regRequest (method, where, what, etag, nofollow, cb_) {
+ if (typeof cb_ !== "function") cb_ = nofollow, nofollow = false
+ if (typeof cb_ !== "function") cb_ = etag, etag = null
+ if (typeof cb_ !== "function") cb_ = what, what = null
+
+ // Since there are multiple places where an error could occur,
+ // don't let the cb be called more than once.
+ var errState = null
+ function cb (er) {
+ if (errState) return
+ if (er) errState = er
+ cb_.apply(null, arguments)
+ }
+
+ if (where.match(/^\/?favicon.ico/)) {
+ return cb(new Error("favicon.ico isn't a package, it's a picture."))
+ }
+
+ var registry = this.registry
+
+ var adduserChange = /^\/?-\/user\/org\.couchdb\.user:([^\/]+)\/-rev/
+ , adduserNew = /^\/?-\/user\/org\.couchdb\.user:([^\/]+)/
+ , authRequired = (what || this.alwaysAuth)
+ && !where.match(adduserNew)
+ || where.match(adduserChange)
+ || method === "DELETE"
+
+ // resolve to a full url on the registry
+ if (!where.match(/^https?:\/\//)) {
+ this.log.verbose("url raw", where)
+
+ var q = where.split("?")
+ where = q.shift()
+ q = q.join("?")
+
+ if (where.charAt(0) !== "/") where = "/" + where
+ where = "." + where.split("/").map(function (p) {
+ p = p.trim()
+ if (p.match(/^org.couchdb.user/)) {
+ return p.replace(/\//g, encodeURIComponent("/"))
+ }
+ return encodeURIComponent(p)
+ }).join("/")
+ if (q) where += "?" + q
+ this.log.verbose("url resolving", [registry, where])
+ where = url.resolve(registry, where)
+ this.log.verbose("url resolved", where)
+ }
+
+ var remote = url.parse(where)
+ , auth = authRequired && this.auth
+
+ if (authRequired && !auth) {
+ return cb(new Error(
+ "Cannot insert data into the registry without auth"))
+ }
+
+ if (auth) {
+ remote.auth = new Buffer(auth, "base64").toString("utf8")
+ }
+
+ makeRequest.call(this, method, remote, where, what, etag, nofollow, cb)
+}
+
+function makeRequest (method, remote, where, what, etag, nofollow, cb) {
+ var opts = { url: remote
+ , method: method
+ , ca: this.ca
+ , strictSSL: this.strictSSL }
+ , headers = opts.headers = {}
+ if (etag) {
+ this.log.verbose("etag", etag)
+ headers[method === "GET" ? "if-none-match" : "if-match"] = etag
+ }
+
+ headers.accept = "application/json"
+
+ headers["user-agent"] = this.userAgent
+
+ opts.proxy = remote.protocol === "https:"
+ ? this.httpsProxy : this.proxy
+
+ // figure out wth 'what' is
+ if (what) {
+ if (Buffer.isBuffer(what) || typeof what === "string") {
+ opts.body = what
+ headers["content-type"] = "application/json"
+ headers["content-length"] = Buffer.byteLength(what)
+ } else if (what instanceof Stream) {
+ headers["content-type"] = "application/octet-stream"
+ if (what.size) headers["content-length"] = what.size
+ } else {
+ delete what._etag
+ opts.json = what
+ }
+ }
+
+ if (nofollow) {
+ opts.followRedirect = false
+ }
+
+ this.log.http(method, remote.href || "/")
+
+ var done = requestDone.call(this, method, where, cb)
+ var req = request(opts, done)
+
+ req.on("error", cb)
+
+ if (what && (what instanceof Stream)) {
+ what.pipe(req)
+ }
+}
+
+// cb(er, parsed, raw, response)
+function requestDone (method, where, cb) {
+ return function (er, response, data) {
+ if (er) return cb(er)
+
+ this.log.http(response.statusCode, url.parse(where).href)
+
+ var parsed
+
+ if (Buffer.isBuffer(data)) {
+ data = data.toString()
+ }
+
+ if (data && typeof data === "string" && response.statusCode !== 304) {
+ try {
+ parsed = JSON.parse(data)
+ } catch (ex) {
+ ex.message += "\n" + data
+ this.log.verbose("bad json", data)
+ this.log.error("registry", "error parsing json")
+ return cb(ex, null, data, response)
+ }
+ } else if (data) {
+ parsed = data
+ data = JSON.stringify(parsed)
+ }
+
+ // expect data with any error codes
+ if (!data && response.statusCode >= 400) {
+ return cb( response.statusCode + " "
+ + require("http").STATUS_CODES[response.statusCode]
+ , null, data, response )
+ }
+
+ var er = null
+ if (parsed && response.headers.etag) {
+ parsed._etag = response.headers.etag
+ }
+
+ if (parsed && parsed.error && response.statusCode >= 400) {
+ var w = url.parse(where).pathname.substr(1)
+ if (!w.match(/^-/) && parsed.error === "not_found") {
+ w = w.split("/")
+ name = w[w.indexOf("_rewrite") + 1]
+ er = new Error("404 Not Found: "+name)
+ er.errno = this.E404
+ er.pkgid = name
+ } else {
+ er = new Error(
+ parsed.error + " " + (parsed.reason || "") + ": " + w)
+ }
+ } else if (method !== "HEAD" && method !== "GET") {
+ // invalidate cache
+ // This is irrelevant for commands that do etag caching, but
+ // ls and view also have a timed cache, so this keeps the user
+ // from thinking that it didn't work when it did.
+ // Note that failure is an acceptable option here, since the
+ // only result will be a stale cache for some helper commands.
+ var path = require("path")
+ , p = url.parse(where).pathname.split("/")
+ , _ = "/"
+ , caches = p.map(function (part) {
+ return _ = path.join(_, part)
+ }).map(function (cache) {
+ return path.join(this.cache, cache, ".cache.json")
+ }, this)
+
+ // if the method is DELETE, then also remove the thing itself.
+ // Note that the search index is probably invalid. Whatever.
+ // That's what you get for deleting stuff. Don't do that.
+ if (method === "DELETE") {
+ p = p.slice(0, p.indexOf("-rev"))
+ caches.push(path.join(this.cache, p.join("/")))
+ }
+
+ asyncMap(caches, rm, function () {})
+ }
+ return cb(er, parsed, data, response)
+ }.bind(this)
+}
View
29 node_modules/npm-registry-client/lib/star.js
@@ -0,0 +1,29 @@
+
+module.exports = star
+
+function star (package, starred, cb) {
+ if (!this.username) return cb(new Error(
+ "Must be logged in to star/unstar packages"))
+
+ var users = {}
+
+ this.request("GET", package, function (er, fullData) {
+ if (er) return cb(er)
+
+ fullData = { _id: fullData._id
+ , _rev: fullData._rev
+ , users: fullData.users || {} }
+
+ if (starred) {
+ this.log.info("starring", fullData._id)
+ fullData.users[this.username] = true
+ this.log.verbose("starring", fullData)
+ } else {
+ delete fullData.users[this.username]
+ this.log.info("unstarring", fullData._id)
+ this.log.verbose("unstarring", fullData)
+ }
+
+ return this.request("PUT", package, fullData, cb)
+ }.bind(this))
+}
View
6 node_modules/npm-registry-client/lib/tag.js
@@ -0,0 +1,6 @@
+
+module.exports = tag
+
+function tag (project, version, tag, cb) {
+ this.request("PUT", project+"/"+tag, JSON.stringify(version), cb)
+}
View
103 node_modules/npm-registry-client/lib/unpublish.js
@@ -0,0 +1,103 @@
+
+// fetch the data
+// modify to remove the version in question
+// If no versions remaining, then DELETE
+// else, PUT the modified data
+// delete the tarball
+
+module.exports = unpublish
+
+var semver = require("semver")
+ , url = require("url")
+ , chain = require("slide").chain
+
+function unpublish (name, ver, cb) {
+ if (typeof cb !== "function") cb = ver, ver = null
+
+ this.get(name, null, -1, true, function (er, data) {
+ if (er) {
+ this.log.info("unpublish", name+" not published")
+ return cb()
+ }
+ // remove all if no version specified
+ if (!ver) {
+ this.log.info("unpublish", "No version specified, removing all")
+ return this.request("DELETE", name+'/-rev/'+data._rev, cb)
+ }
+
+ var versions = data.versions || {}
+ , versionPublic = versions.hasOwnProperty(ver)
+
+ if (!versionPublic) {
+ this.log.info("unpublish", name+"@"+ver+" not published")
+ } else {
+ var dist = versions[ver].dist
+ this.log.verbose("unpublish", "removing attachments", dist)
+ }
+
+ delete versions[ver]
+ // if it was the only version, then delete the whole package.
+ if (!Object.keys(versions).length) {
+ this.log.info("unpublish", "No versions remain, removing entire package")
+ return this.request("DELETE", name+"/-rev/"+data._rev, cb)
+ }
+
+ if (!versionPublic) return cb()
+
+ var latestVer = data["dist-tags"].latest
+ for (var tag in data["dist-tags"]) {
+ if (data["dist-tags"][tag] === ver) delete data["dist-tags"][tag]
+ }
+
+ if (latestVer === ver) {
+ data["dist-tags"].latest =
+ Object.getOwnPropertyNames(versions).sort(semver.compare).pop()
+ }
+
+ var rev = data._rev
+ delete data._revisions
+ delete data._attachments
+ var cb_ = detacher.call(this, data, dist, cb)
+ this.request("PUT", name+"/-rev/"+rev, data, function (er) {
+ if (er) {
+ this.log.error("unpublish", "Failed to update data")
+ }
+ cb_(er)
+ }.bind(this))
+ }.bind(this))
+}
+
+function detacher (data, dist, cb) {
+ return function (er) {
+ if (er) return cb(er)
+ this.get(data.name, function (er, data) {
+ if (er) return cb(er)
+
+ var tb = url.parse(dist.tarball)
+
+ detach.call(this, data, tb.pathname, data._rev, function (er) {
+ if (er || !dist.bin) return cb(er)
+ chain(Object.keys(dist.bin).map(function (bt) {
+ return function (cb) {
+ var d = dist.bin[bt]
+ detach.call(this, data, url.parse(d.tarball).pathname, null, cb)
+ }.bind(this)
+ }, this), cb)
+ }.bind(this))
+ }.bind(this))
+ }.bind(this)
+}
+
+function detach (data, path, rev, cb) {
+ if (rev) {
+ path += "/-rev/" + rev
+ this.log.info("detach", path)
+ return this.request("DELETE", path, cb)
+ }
+ this.get(data.name, function (er, data) {
+ rev = data._rev
+ if (!rev) return cb(new Error(
+ "No _rev found in "+data._id))
+ detach.call(this, data, path, rev, cb)
+ }.bind(this))
+}
View
22 node_modules/npm-registry-client/lib/upload.js
@@ -0,0 +1,22 @@
+module.exports = upload
+
+var fs = require('fs')
+, Stream = require("stream").Stream
+
+function upload (where, file, etag, nofollow, cb) {
+ if (typeof nofollow === "function") cb = nofollow, nofollow = false
+ if (typeof etag === "function") cb = etag, etag = null
+
+ if (file instanceof Stream) {
+ return this.request("PUT", where, file, etag, nofollow, cb)
+ }
+
+ fs.stat(file, function (er, stat) {
+ if (er) return cb(er)
+ var s = fs.createReadStream(file)
+ s.size = stat.size
+ s.on("error", cb)
+
+ this.request("PUT", where, s, etag, nofollow, cb)
+ }.bind(this))
+}
View
47 node_modules/npm-registry-client/package.json
@@ -0,0 +1,47 @@
+{
+ "author": {
+ "name": "Isaac Z. Schlueter",
+ "email": "i@izs.me",
+ "url": "http://blog.izs.me/"
+ },
+ "name": "npm-registry-client",
+ "description": "Client for the npm registry",
+ "version": "0.0.2",
+ "repository": {
+ "url": "git://github.com/isaacs/npm-registry-client"
+ },
+ "main": "index.js",
+ "scripts": {
+ "test": "tap test/*.js"
+ },
+ "dependencies": {
+ "node-uuid": "~1.3.3",
+ "request": "~2.9.202",
+ "graceful-fs": "~1.1.8",
+ "semver": "~1.0.14",
+ "slide": "~1.1.3",
+ "chownr": "0",
+ "mkdirp": "~0.3.3",
+ "rimraf": "~2.0.1",
+ "npmlog": ""
+ },
+ "devDependencies": {
+ "tap": ""
+ },
+ "optionalDependencies": {
+ "npmlog": ""
+ },
+ "engines": {
+ "node": "*"
+ },
+ "_npmUser": {
+ "name": "isaacs",
+ "email": "i@izs.me"
+ },
+ "_id": "npm-registry-client@0.0.2",
+ "_engineSupported": true,
+ "_npmVersion": "1.1.24",
+ "_nodeVersion": "v0.7.10-pre",
+ "_defaultsLoaded": true,
+ "_from": "npm-registry-client@0"
+}
View
10 node_modules/npm-registry-client/test/00-setup.js
@@ -0,0 +1,10 @@
+var tap = require('tap')
+var rimraf = require('rimraf')
+
+tap.test('setup', function (t) {
+ rimraf(__dirname + '/fixtures/cache', function (er) {
+ if (er) throw er
+ t.pass('cache cleaned')
+ t.end()
+ })
+})
View
51 node_modules/npm-registry-client/test/adduser-new.js
@@ -0,0 +1,51 @@
+var tap = require('tap')
+var server = require('./fixtures/server.js')
+var RC = require('../')
+var client = new RC({
+ cache: __dirname + '/fixtures/cache'
+ , registry: 'http://localhost:' + server.port })
+
+var userdata =
+{ name: 'username',
+ email: 'i@izs.me',
+ _id: 'org.couchdb.user:username',
+ type: 'user',
+ roles: [],
+ date: '2012-06-07T04:11:21.591Z' }
+, password = "password"
+, username = "username"
+, crypto = require("crypto")
+, SD = require('string_decoder').StringDecoder
+, decoder = new SD
+
+function sha (s) {
+ return crypto.createHash("sha1").update(s).digest("hex")
+}
+
+tap.test("create new user account", function (t) {
+ server.expect("/-/user/org.couchdb.user:username", function (req, res) {
+ t.equal(req.method, "PUT")
+ var b = ""
+ req.on("data", function (d) {
+ b += decoder.write(d)
+ })
+
+ req.on("end", function () {
+ var o = JSON.parse(b)
+ var salt = o.salt
+ userdata.salt = salt
+ userdata.password_sha = sha(password + salt)
+ userdata.date = o.date
+ t.deepEqual(o, userdata)
+
+ res.statusCode = 201
+ res.json({created:true})
+ })
+ })
+
+ client.adduser(username, password, "i@izs.me", function (er, data, raw, res) {
+ if (er) throw er
+ t.deepEqual(data, { created: true })
+ t.end()
+ })
+})
View
68 node_modules/npm-registry-client/test/adduser-update.js
@@ -0,0 +1,68 @@
+var tap = require('tap')
+var server = require('./fixtures/server.js')
+var RC = require('../')
+var client = new RC({
+ cache: __dirname + '/fixtures/cache'
+ , registry: 'http://localhost:' + server.port })
+
+var userdata =
+{ name: 'username',
+ email: 'i@izs.me',
+ _id: 'org.couchdb.user:username',
+ type: 'user',
+ roles: [],
+ _rev: "1-15aac515ac515aac515aac515aac5125"
+}
+
+, password = "password"
+, username = "username"
+, crypto = require("crypto")
+, SD = require('string_decoder').StringDecoder
+, decoder = new SD
+
+
+function sha (s) {
+ return crypto.createHash("sha1").update(s).digest("hex")
+}
+
+tap.test("update a user acct", function (t) {
+ server.expect("PUT", "/-/user/org.couchdb.user:username", function (req, res) {
+ t.equal(req.method, "PUT")
+ res.statusCode = 409
+ res.json({error: "conflict"})
+ })
+
+ server.expect("GET", "/-/user/org.couchdb.user:username", function (req, res) {
+ t.equal(req.method, "GET")
+ res.json(userdata)
+ })
+
+ server.expect("PUT", "/-/user/org.couchdb.user:username/-rev/" + userdata._rev, function (req, res) {
+ t.equal(req.method, "PUT")
+
+ var b = ""
+ req.on("data", function (d) {
+ b += decoder.write(d)
+ })
+
+ req.on("end", function () {
+ var o = JSON.parse(b)
+ var salt = o.salt
+ userdata.salt = salt
+ userdata.password_sha = sha(password + salt)
+ userdata.date = o.date
+ t.deepEqual(o, userdata)
+
+ res.statusCode = 201
+ res.json({created:true})
+ })
+ })
+
+
+
+ client.adduser(username, password, "i@izs.me", function (er, data, raw, res) {
+ if (er) throw er
+ t.deepEqual(data, { created: true })
+ t.end()
+ })
+})
View
32 node_modules/npm-registry-client/test/basic.js
@@ -0,0 +1,32 @@
+var tap = require('tap')
+var server = require('./fixtures/server.js')
+var RC = require('../')
+var rimraf = require("rimraf")
+var client = new RC({
+ cache: __dirname + '/fixtures/cache'
+ , registry: 'http://localhost:' + server.port })
+var us = require('./fixtures/underscore/1.3.3/cache.json')
+var usroot = require("./fixtures/underscore/cache.json")
+
+tap.test("basic request", function (t) {
+ server.expect("/underscore/1.3.3", function (req, res) {
+ console.error('got a request')
+ res.json(us)
+ })
+
+ server.expect("/underscore", function (req, res) {
+ console.error('got a request')
+ res.json(usroot)
+ })
+
+ t.plan(2)
+ client.get("/underscore/1.3.3", function (er, data, raw, res) {
+ console.error("got response")
+ t.deepEqual(data, us)
+ })
+
+ client.get("/underscore", function (er, data, raw, res) {
+ console.error("got response")
+ t.deepEqual(data, usroot)
+ })
+})
View
44 node_modules/npm-registry-client/test/fixtures/server.js
@@ -0,0 +1,44 @@
+// a fake registry server.
+
+var http = require('http')
+var server = http.createServer(handler)
+var port = server.port = process.env.PORT || 1337
+server.listen(port)
+
+module.exports = server
+
+server._expect = {}
+
+var expect = {}
+function handler (req, res) {
+ var u = "* " + req.url
+ , mu = req.method + " " + req.url
+ , k = expect[mu] ? mu : expect[u] ? u : null
+
+ if (!k) throw Error("unexpected request", req.method, req.url)
+ expect[k] --
+
+ if (Object.keys(expect).reduce(function (s, k) {
+ return s + expect[k]
+ }, 0) === 0) server.close()
+
+ res.json = json
+ server._expect[k](req, res)
+}
+
+function json (o) {
+ this.setHeader('content-type', 'application/json')
+ this.end(JSON.stringify(o))
+}
+
+server.expect = function (method, u, fn) {
+ if (typeof u === "function") {
+ fn = u
+ u = method
+ method = "*"
+ }
+ u = method + " " + u
+ server._expect[u] = fn
+ expect[u] = expect[u] || 0
+ expect[u] ++
+}
View
1 node_modules/npm-registry-client/test/fixtures/underscore/1.3.3/cache.json
@@ -0,0 +1 @@
+{"name":"underscore","description":"JavaScript's functional programming helper library.","homepage":"http://documentcloud.github.com/underscore/","keywords":["util","functional","server","client","browser"],"author":{"name":"Jeremy Ashkenas","email":"jeremy@documentcloud.org"},"repository":{"type":"git","url":"git://github.com/documentcloud/underscore.git"},"main":"underscore.js","version":"1.3.3","_npmUser":{"name":"jashkenas","email":"jashkenas@gmail.com"},"_id":"underscore@1.3.3","dependencies":{},"devDependencies":{},"optionalDependencies":{},"engines":{"node":"*"},"_engineSupported":true,"_npmVersion":"1.1.1","_nodeVersion":"v0.6.11","_defaultsLoaded":true,"dist":{"shasum":"47ac53683daf832bfa952e1774417da47817ae42","tarball":"http://registry.npmjs.org/underscore/-/underscore-1.3.3.tgz"},"readme":" __ \n /\\ \\ __ \n __ __ ___ \\_\\ \\ __ _ __ ____ ___ ___ _ __ __ /\\_\\ ____ \n /\\ \\/\\ \\ /' _ `\\ /'_ \\ /'__`\\/\\ __\\/ ,__\\ / ___\\ / __`\\/\\ __\\/'__`\\ \\/\\ \\ /',__\\ \n \\ \\ \\_\\ \\/\\ \\/\\ \\/\\ \\ \\ \\/\\ __/\\ \\ \\//\\__, `\\/\\ \\__//\\ \\ \\ \\ \\ \\//\\ __/ __ \\ \\ \\/\\__, `\\\n \\ \\____/\\ \\_\\ \\_\\ \\___,_\\ \\____\\\\ \\_\\\\/\\____/\\ \\____\\ \\____/\\ \\_\\\\ \\____\\/\\_\\ _\\ \\ \\/\\____/\n \\/___/ \\/_/\\/_/\\/__,_ /\\/____/ \\/_/ \\/___/ \\/____/\\/___/ \\/_/ \\/____/\\/_//\\ \\_\\ \\/___/ \n \\ \\____/ \n \\/___/\n \nUnderscore.js is a utility-belt library for JavaScript that provides \nsupport for the usual functional suspects (each, map, reduce, filter...) \nwithout extending any core JavaScript objects.\n\nFor Docs, License, Tests, and pre-packed downloads, see:\nhttp://documentcloud.github.com/underscore/\n\nMany thanks to our contributors:\nhttps://github.com/documentcloud/underscore/contributors\n","maintainers":[{"name":"documentcloud","email":"jeremy@documentcloud.org"},{"name":"jashkenas","email":"jashkenas@gmail.com"}],"directories":{}}
View
1 node_modules/npm-registry-client/test/fixtures/underscore/cache.json
@@ -0,0 +1 @@
+{"_id":"underscore","_rev":"72-47f2986bfd8e8b55068b204588bbf484","name":"underscore","description":"JavaScript's functional programming helper library.","dist-tags":{"latest":"1.3.3","stable":"1.3.3"},"versions":{"1.0.3":{"name":"underscore","description":"Functional programming aid for JavaScript. Works well with jQuery.","url":"http://documentcloud.github.com/underscore/","keywords":["util","functional","server","client","browser"],"author":{"name":"Jeremy Ashkenas","email":"jeremy@documentcloud.org"},"contributors":[],"dependencies":{},"lib":".","main":"underscore","version":"1.0.3","_id":"underscore@1.0.3","engines":{"node":"*"},"_nodeSupported":true,"_npmVersion":"0.2.7-2","_nodeVersion":"v0.3.1-pre","dist":{"tarball":"http://registry.npmjs.org/underscore/-/underscore-1.0.3.tgz"},"directories":{},"_npmUser":{"name":"jashkenas","email":"jashkenas@gmail.com"},"maintainers":[{"name":"documentcloud","email":"jeremy@documentcloud.org"},{"name":"jashkenas","email":"jashkenas@gmail.com"}]},"1.0.4":{"name":"underscore","description":"Functional programming aid for JavaScript. Works well with jQuery.","url":"http://documentcloud.github.com/underscore/","keywords":["util","functional","server","client","browser"],"author":{"name":"Jeremy Ashkenas","email":"jeremy@documentcloud.org"},"contributors":[],"dependencies":{},"lib":".","main":"underscore","version":"1.0.4","_id":"underscore@1.0.4","engines":{"node":"*"},"_nodeSupported":true,"_npmVersion":"0.2.7-2","_nodeVersion":"v0.3.1-pre","dist":{"tarball":"http://registry.npmjs.org/underscore/-/underscore-1.0.4.tgz"},"directories":{},"_npmUser":{"name":"jashkenas","email":"jashkenas@gmail.com"},"maintainers":[{"name":"documentcloud","email":"jeremy@documentcloud.org"},{"name":"jashkenas","email":"jashkenas@gmail.com"}]},"1.1.0":{"name":"underscore","description":"Functional programming aid for JavaScript. Works well with jQuery.","url":"http://documentcloud.github.com/underscore/","keywords":["util","functional","server","client","browser"],"author":{"name":"Jeremy Ashkenas","email":"jeremy@documentcloud.org"},"contributors":[],"dependencies":{},"lib":".","main":"underscore","version":"1.1.0","_id":"underscore@1.1.0","engines":{"node":"*"},"_nodeSupported":true,"_npmVersion":"0.2.7-2","_nodeVersion":"v0.3.1-pre","dist":{"tarball":"http://registry.npmjs.org/underscore/-/underscore-1.1.0.tgz"},"directories":{},"_npmUser":{"name":"jashkenas","email":"jashkenas@gmail.com"},"maintainers":[{"name":"documentcloud","email":"jeremy@documentcloud.org"},{"name":"jashkenas","email":"jashkenas@gmail.com"}]},"1.1.1":{"name":"underscore","description":"Functional programming aid for JavaScript. Works well with jQuery.","url":"http://documentcloud.github.com/underscore/","keywords":["util","functional","server","client","browser"],"author":{"name":"Jeremy Ashkenas","email":"jeremy@documentcloud.org"},"contributors":[],"dependencies":{},"lib":".","main":"underscore","version":"1.1.1","_id":"underscore@1.1.1","engines":{"node":"*"},"_nodeSupported":true,"_npmVersion":"0.2.7-2","_nodeVersion":"v0.3.1-pre","dist":{"tarball":"http://registry.npmjs.org/underscore/-/underscore-1.1.1.tgz"},"directories":{},"_npmUser":{"name":"jashkenas","email":"jashkenas@gmail.com"},"maintainers":[{"name":"documentcloud","email":"jeremy@documentcloud.org"},{"name":"jashkenas","email":"jashkenas@gmail.com"}]},"1.1.2":{"name":"underscore","description":"Functional programming aid for JavaScript. Works well with jQuery.","url":"http://documentcloud.github.com/underscore/","keywords":["util","functional","server","client","browser"],"author":{"name":"Jeremy Ashkenas","email":"jeremy@documentcloud.org"},"contributors":[],"dependencies":{},"lib":".","main":"underscore","version":"1.1.2","_id":"underscore@1.1.2","engines":{"node":"*"},"_nodeSupported":true,"_npmVersion":"0.2.7-2","_nodeVersion":"v0.3.1-pre","dist":{"tarball":"http://registry.npmjs.org/underscore/-/underscore-1.1.2.tgz"},"directories":{},"_npmUser":{"name":"jashkenas","email":"jashkenas@gmail.com"},"maintainers":[{"name":"documentcloud","email":"jeremy@documentcloud.org"},{"name":"jashkenas","email":"jashkenas@gmail.com"}]},"1.1.3":{"name":"underscore","description":"Functional programming aid for JavaScript. Works well with jQuery.","url":"http://documentcloud.github.com/underscore/","keywords":["util","functional","server","client","browser"],"author":{"name":"Jeremy Ashkenas","email":"jeremy@documentcloud.org"},"contributors":[],"dependencies":{},"lib":".","main":"underscore","version":"1.1.3","_id":"underscore@1.1.3","engines":{"node":"*"},"_nodeSupported":true,"_npmVersion":"0.2.8-1","_nodeVersion":"v0.2.5","dist":{"tarball":"http://registry.npmjs.org/underscore/-/underscore-1.1.3.tgz"},"directories":{},"_npmUser":{"name":"jashkenas","email":"jashkenas@gmail.com"},"maintainers":[{"name":"documentcloud","email":"jeremy@documentcloud.org"},{"name":"jashkenas","email":"jashkenas@gmail.com"}]},"1.1.4":{"name":"underscore","description":"Functional programming aid for JavaScript. Works well with jQuery.","url":"http://documentcloud.github.com/underscore/","keywords":["util","functional","server","client","browser"],"author":{"name":"Jeremy Ashkenas","email":"jeremy@documentcloud.org"},"contributors":[],"dependencies":{},"lib":".","main":"underscore.js","version":"1.1.4","_id":"underscore@1.1.4","engines":{"node":"*"},"_engineSupported":true,"_npmVersion":"0.3.9","_nodeVersion":"v0.5.0-pre","dist":{"shasum":"9e82274902865625b3a6d4c315a38ffd80047dae","tarball":"http://registry.npmjs.org/underscore/-/underscore-1.1.4.tgz"},"_npmUser":{"name":"jashkenas","email":"jashkenas@gmail.com"},"maintainers":[{"name":"documentcloud","email":"jeremy@documentcloud.org"},{"name":"jashkenas","email":"jashkenas@gmail.com"}],"directories":{}},"1.1.5":{"name":"underscore","description":"JavaScript's functional programming helper library.","homepage":"http://documentcloud.github.com/underscore/","keywords":["util","functional","server","client","browser"],"author":{"name":"Jeremy Ashkenas","email":"jeremy@documentcloud.org"},"contributors":[],"dependencies":{},"repository":{"type":"git","url":"git://github.com/documentcloud/underscore.git"},"main":"underscore.js","version":"1.1.5","_id":"underscore@1.1.5","engines":{"node":"*"},"_engineSupported":true,"_npmVersion":"0.3.16","_nodeVersion":"v0.4.2","directories":{},"files":[""],"_defaultsLoaded":true,"dist":{"shasum":"23601d62c75619998b2f0db24938102793336a56","tarball":"http://registry.npmjs.org/underscore/-/underscore-1.1.5.tgz"},"_npmUser":{"name":"jashkenas","email":"jashkenas@gmail.com"},"maintainers":[{"name":"documentcloud","email":"jeremy@documentcloud.org"},{"name":"jashkenas","email":"jashkenas@gmail.com"}]},"1.1.6":{"name":"underscore","description":"JavaScript's functional programming helper library.","homepage":"http://documentcloud.github.com/underscore/","keywords":["util","functional","server","client","browser"],"author":{"name":"Jeremy Ashkenas","email":"jeremy@documentcloud.org"},"contributors":[],"dependencies":{},"repository":{"type":"git","url":"git://github.com/documentcloud/underscore.git"},"main":"underscore.js","version":"1.1.6","_id":"underscore@1.1.6","engines":{"node":"*"},"_engineSupported":true,"_npmVersion":"0.3.18","_nodeVersion":"v0.4.2","directories":{},"files":[""],"_defaultsLoaded":true,"dist":{"shasum":"6868da1bdd72d75285be0b4e50f228e70d001a2c","tarball":"http://registry.npmjs.org/underscore/-/underscore-1.1.6.tgz"},"_npmUser":{"name":"jashkenas","email":"jashkenas@gmail.com"},"maintainers":[{"name":"documentcloud","email":"jeremy@documentcloud.org"},{"name":"jashkenas","email":"jashkenas@gmail.com"}]},"1.1.7":{"name":"underscore","description":"JavaScript's functional programming helper library.","homepage":"http://documentcloud.github.com/underscore/","keywords":["util","functional","server","client","browser"],"author":{"name":"Jeremy Ashkenas","email":"jeremy@documentcloud.org"},"contributors":[],"dependencies":{},"repository":{"type":"git","url":"git://github.com/documentcloud/underscore.git"},"main":"underscore.js","version":"1.1.7","devDependencies":{},"_id":"underscore@1.1.7","engines":{"node":"*"},"_engineSupported":true,"_npmVersion":"1.0.3","_nodeVersion":"v0.4.7","_defaultsLoaded":true,"dist":{"shasum":"40bab84bad19d230096e8d6ef628bff055d83db0","tarball":"http://registry.npmjs.org/underscore/-/underscore-1.1.7.tgz"},"scripts":{},"_npmUser":{"name":"jashkenas","email":"jashkenas@gmail.com"},"maintainers":[{"name":"documentcloud","email":"jeremy@documentcloud.org"},{"name":"jashkenas","email":"jashkenas@gmail.com"}],"directories":{}},"1.2.0":{"name":"underscore","description":"JavaScript's functional programming helper library.","homepage":"http://documentcloud.github.com/underscore/","keywords":["util","functional","server","client","browser"],"author":{"name":"Jeremy Ashkenas","email":"jeremy@documentcloud.org"},"contributors":[],"dependencies":{},"repository":{"type":"git","url":"git://github.com/documentcloud/underscore.git"},"main":"underscore.js","version":"1.2.0","_npmJsonOpts":{"file":"/Users/jashkenas/.npm/underscore/1.2.0/package/package.json","wscript":false,"contributors":false,"serverjs":false},"_id":"underscore@1.2.0","devDependencies":{},"engines":{"node":"*"},"_engineSupported":true,"_npmVersion":"1.0.22","_nodeVersion":"v0.4.10","_defaultsLoaded":true,"dist":{"shasum":"b32ce32c8c118caa8031c10b54c7f65ab3b557fd","tarball":"http://registry.npmjs.org/underscore/-/underscore-1.2.0.tgz"},"scripts":{},"maintainers":[{"name":"documentcloud","email":"jeremy@documentcloud.org"},{"name":"jashkenas","email":"jashkenas@gmail.com"}],"_npmUser":{"name":"jashkenas","email":"jashkenas@gmail.com"},"directories":{}},"1.2.1":{"name":"underscore","description":"JavaScript's functional programming helper library.","homepage":"http://documentcloud.github.com/underscore/","keywords":["util","functional","server","client","browser"],"author":{"name":"Jeremy Ashkenas","email":"jeremy@documentcloud.org"},"contributors":[],"dependencies":{},"repository":{"type":"git","url":"git://github.com/documentcloud/underscore.git"},"main":"underscore.js","version":"1.2.1","_npmJsonOpts":{"file":"/Users/jashkenas/.npm/underscore/1.2.1/package/package.json","wscript":false,"contributors":false,"serverjs":false},"_id":"underscore@1.2.1","devDependencies":{},"engines":{"node":"*"},"_engineSupported":true,"_npmVersion":"1.0.22","_nodeVersion":"v0.4.10","_defaultsLoaded":true,"dist":{"shasum":"fc5c6b0765673d92a2d4ac8b4dc0aa88702e2bd4","tarball":"http://registry.npmjs.org/underscore/-/underscore-1.2.1.tgz"},"scripts":{},"maintainers":[{"name":"documentcloud","email":"jeremy@documentcloud.org"},{"name":"jashkenas","email":"jashkenas@gmail.com"}],"_npmUser":{"name":"jashkenas","email":"jashkenas@gmail.com"},"directories":{}},"1.2.2":{"name":"underscore","description":"JavaScript's functional programming helper library.","homepage":"http://documentcloud.github.com/underscore/","keywords":["util","functional","server","client","browser"],"author":{"name":"Jeremy Ashkenas","email":"jeremy@documentcloud.org"},"contributors":[],"dependencies":{},"repository":{"type":"git","url":"git://github.com/documentcloud/underscore.git"},"main":"underscore.js","version":"1.2.2","_npmUser":{"name":"jashkenas","email":"jashkenas@gmail.com"},"_id":"underscore@1.2.2","devDependencies":{},"engines":{"node":"*"},"_engineSupported":true,"_npmVersion":"1.0.104","_nodeVersion":"v0.6.0","_defaultsLoaded":true,"dist":{"shasum":"74dd40e9face84e724eb2edae945b8aedc233ba3","tarball":"http://registry.npmjs.org/underscore/-/underscore-1.2.2.tgz"},"maintainers":[{"name":"documentcloud","email":"jeremy@documentcloud.org"},{"name":"jashkenas","email":"jashkenas@gmail.com"}],"directories":{}},"1.2.3":{"name":"underscore","description":"JavaScript's functional programming helper library.","homepage":"http://documentcloud.github.com/underscore/","keywords":["util","functional","server","client","browser"],"author":{"name":"Jeremy Ashkenas","email":"jeremy@documentcloud.org"},"contributors":[],"dependencies":{},"repository":{"type":"git","url":"git://github.com/documentcloud/underscore.git"},"main":"underscore.js","version":"1.2.3","_npmUser":{"name":"jashkenas","email":"jashkenas@gmail.com"},"_id":"underscore@1.2.3","devDependencies":{},"engines":{"node":"*"},"_engineSupported":true,"_npmVersion":"1.0.104","_nodeVersion":"v0.6.0","_defaultsLoaded":true,"dist":{"shasum":"11b874da70f4683d7d48bba2b44be1e600d2f6cf","tarball":"http://registry.npmjs.org/underscore/-/underscore-1.2.3.tgz"},"maintainers":[{"name":"documentcloud","email":"jeremy@documentcloud.org"},{"name":"jashkenas","email":"jashkenas@gmail.com"}],"directories":{}},"1.2.4":{"name":"underscore","description":"JavaScript's functional programming helper library.","homepage":"http://documentcloud.github.com/underscore/","keywords":["util","functional","server","client","browser"],"author":{"name":"Jeremy Ashkenas","email":"jeremy@documentcloud.org"},"contributors":[],"repository":{"type":"git","url":"git://github.com/documentcloud/underscore.git"},"main":"underscore.js","version":"1.2.4","_npmUser":{"name":"jashkenas","email":"jashkenas@gmail.com"},"_id":"underscore@1.2.4","dependencies":{},"devDependencies":{},"engines":{"node":"*"},"_engineSupported":true,"_npmVersion":"1.0.104","_nodeVersion":"v0.6.6","_defaultsLoaded":true,"dist":{"shasum":"e8da6241aa06f64df2473bb2590b8c17c84c3c7e","tarball":"http://registry.npmjs.org/underscore/-/underscore-1.2.4.tgz"},"maintainers":[{"name":"documentcloud","email":"jeremy@documentcloud.org"},{"name":"jashkenas","email":"jashkenas@gmail.com"}],"directories":{}},"1.3.0":{"name":"underscore","description":"JavaScript's functional programming helper library.","homepage":"http://documentcloud.github.com/underscore/","keywords":["util","functional","server","client","browser"],"author":{"name":"Jeremy Ashkenas","email":"jeremy@documentcloud.org"},"contributors":[],"repository":{"type":"git","url":"git://github.com/documentcloud/underscore.git"},"main":"underscore.js","version":"1.3.0","_npmUser":{"name":"jashkenas","email":"jashkenas@gmail.com"},"_id":"underscore@1.3.0","dependencies":{},"devDependencies":{},"engines":{"node":"*"},"_engineSupported":true,"_npmVersion":"1.0.104","_nodeVersion":"v0.6.6","_defaultsLoaded":true,"dist":{"shasum":"253b2d79b7bb67943ced0fc744eb18267963ede8","tarball":"http://registry.npmjs.org/underscore/-/underscore-1.3.0.tgz"},"maintainers":[{"name":"documentcloud","email":"jeremy@documentcloud.org"},{"name":"jashkenas","email":"jashkenas@gmail.com"}],"directories":{}},"1.3.1":{"name":"underscore","description":"JavaScript's functional programming helper library.","homepage":"http://documentcloud.github.com/underscore/","keywords":["util","functional","server","client","browser"],"author":{"name":"Jeremy Ashkenas","email":"jeremy@documentcloud.org"},"repository":{"type":"git","url":"git://github.com/documentcloud/underscore.git"},"main":"underscore.js","version":"1.3.1","_npmUser":{"name":"jashkenas","email":"jashkenas@gmail.com"},"_id":"underscore@1.3.1","dependencies":{},"devDependencies":{},"engines":{"node":"*"},"_engineSupported":true,"_npmVersion":"1.0.104","_nodeVersion":"v0.6.6","_defaultsLoaded":true,"dist":{"shasum":"6cb8aad0e77eb5dbbfb54b22bcd8697309cf9641","tarball":"http://registry.npmjs.org/underscore/-/underscore-1.3.1.tgz"},"maintainers":[{"name":"documentcloud","email":"jeremy@documentcloud.org"},{"name":"jashkenas","email":"jashkenas@gmail.com"}],"directories":{}},"1.3.2":{"name":"underscore","description":"JavaScript's functional programming helper library.","homepage":"http://documentcloud.github.com/underscore/","keywords":["util","functional","server","client","browser"],"author":{"name":"Jeremy Ashkenas","email":"jeremy@documentcloud.org"},"repository":{"type":"git","url":"git://github.com/documentcloud/underscore.git"},"main":"underscore.js","version":"1.3.2","_npmUser":{"name":"jashkenas","email":"jashkenas@gmail.com"},"_id":"underscore@1.3.2","dependencies":{},"devDependencies":{},"optionalDependencies":{},"engines":{"node":"*"},"_engineSupported":true,"_npmVersion":"1.1.1","_nodeVersion":"v0.6.11","_defaultsLoaded":true,"dist":{"shasum":"1b4e455089ab1d1d38ab6794ffe6cf08f764394a","tarball":"http://registry.npmjs.org/underscore/-/underscore-1.3.2.tgz"},"readme":" __ \n /\\ \\ __ \n __ __ ___ \\_\\ \\ __ _ __ ____ ___ ___ _ __ __ /\\_\\ ____ \n /\\ \\/\\ \\ /' _ `\\ /'_ \\ /'__`\\/\\ __\\/ ,__\\ / ___\\ / __`\\/\\ __\\/'__`\\ \\/\\ \\ /',__\\ \n \\ \\ \\_\\ \\/\\ \\/\\ \\/\\ \\ \\ \\/\\ __/\\ \\ \\//\\__, `\\/\\ \\__//\\ \\ \\ \\ \\ \\//\\ __/ __ \\ \\ \\/\\__, `\\\n \\ \\____/\\ \\_\\ \\_\\ \\___,_\\ \\____\\\\ \\_\\\\/\\____/\\ \\____\\ \\____/\\ \\_\\\\ \\____\\/\\_\\ _\\ \\ \\/\\____/\n \\/___/ \\/_/\\/_/\\/__,_ /\\/____/ \\/_/ \\/___/ \\/____/\\/___/ \\/_/ \\/____/\\/_//\\ \\_\\ \\/___/ \n \\ \\____/ \n \\/___/\n \nUnderscore.js is a utility-belt library for JavaScript that provides \nsupport for the usual functional suspects (each, map, reduce, filter...) \nwithout extending any core JavaScript objects.\n\nFor Docs, License, Tests, and pre-packed downloads, see:\nhttp://documentcloud.github.com/underscore/\n\nMany thanks to our contributors:\nhttps://github.com/documentcloud/underscore/contributors\n","maintainers":[{"name":"documentcloud","email":"jeremy@documentcloud.org"},{"name":"jashkenas","email":"jashkenas@gmail.com"}],"directories":{}},"1.3.3":{"name":"underscore","description":"JavaScript's functional programming helper library.","homepage":"http://documentcloud.github.com/underscore/","keywords":["util","functional","server","client","browser"],"author":{"name":"Jeremy Ashkenas","email":"jeremy@documentcloud.org"},"repository":{"type":"git","url":"git://github.com/documentcloud/underscore.git"},"main":"underscore.js","version":"1.3.3","_npmUser":{"name":"jashkenas","email":"jashkenas@gmail.com"},"_id":"underscore@1.3.3","dependencies":{},"devDependencies":{},"optionalDependencies":{},"engines":{"node":"*"},"_engineSupported":true,"_npmVersion":"1.1.1","_nodeVersion":"v0.6.11","_defaultsLoaded":true,"dist":{"shasum":"47ac53683daf832bfa952e1774417da47817ae42","tarball":"http://registry.npmjs.org/underscore/-/underscore-1.3.3.tgz"},"readme":" __ \n /\\ \\ __ \n __ __ ___ \\_\\ \\ __ _ __ ____ ___ ___ _ __ __ /\\_\\ ____ \n /\\ \\/\\ \\ /' _ `\\ /'_ \\ /'__`\\/\\ __\\/ ,__\\ / ___\\ / __`\\/\\ __\\/'__`\\ \\/\\ \\ /',__\\ \n \\ \\ \\_\\ \\/\\ \\/\\ \\/\\ \\ \\ \\/\\ __/\\ \\ \\//\\__, `\\/\\ \\__//\\ \\ \\ \\ \\ \\//\\ __/ __ \\ \\ \\/\\__, `\\\n \\ \\____/\\ \\_\\ \\_\\ \\___,_\\ \\____\\\\ \\_\\\\/\\____/\\ \\____\\ \\____/\\ \\_\\\\ \\____\\/\\_\\ _\\ \\ \\/\\____/\n \\/___/ \\/_/\\/_/\\/__,_ /\\/____/ \\/_/ \\/___/ \\/____/\\/___/ \\/_/ \\/____/\\/_//\\ \\_\\ \\/___/ \n \\ \\____/ \n \\/___/\n \nUnderscore.js is a utility-belt library for JavaScript that provides \nsupport for the usual functional suspects (each, map, reduce, filter...) \nwithout extending any core JavaScript objects.\n\nFor Docs, License, Tests, and pre-packed downloads, see:\nhttp://documentcloud.github.com/underscore/\n\nMany thanks to our contributors:\nhttps://github.com/documentcloud/underscore/contributors\n","maintainers":[{"name":"documentcloud","email":"jeremy@documentcloud.org"},{"name":"jashkenas","email":"jashkenas@gmail.com"}],"directories":{}}},"maintainers":[{"name":"documentcloud","email":"jeremy@documentcloud.org"},{"name":"jashkenas","email":"jashkenas@gmail.com"}],"author":{"name":"Jeremy Ashkenas","email":"jeremy@documentcloud.org"},"time":{"1.0.3":"2011-12-07T15:12:18.045Z","1.0.4":"2011-12-07T15:12:18.045Z","1.1.0":"2011-12-07T15:12:18.045Z","1.1.1":"2011-12-07T15:12:18.045Z","1.1.2":"2011-12-07T15:12:18.045Z","1.1.3":"2011-12-07T15:12:18.045Z","1.1.4":"2011-12-07T15:12:18.045Z","1.1.5":"2011-12-07T15:12:18.045Z","1.1.6":"2011-12-07T15:12:18.045Z","1.1.7":"2011-12-07T15:12:18.045Z","1.2.0":"2011-12-07T15:12:18.045Z","1.2.1":"2011-12-07T15:12:18.045Z","1.2.2":"2011-11-14T20:28:47.115Z","1.2.3":"2011-12-07T15:12:18.045Z","1.2.4":"2012-01-09T17:23:14.818Z","1.3.0":"2012-01-11T16:41:38.459Z","1.3.1":"2012-01-23T22:57:36.474Z","1.3.2":"2012-04-09T18:38:14.345Z","1.3.3":"2012-04-10T14:43:48.089Z"},"repository":{"type":"git","url":"git://github.com/documentcloud/underscore.git"},"users":{"vesln":true,"mvolkmann":true,"lancehunt":true,"mikl":true,"linus":true,"vasc":true,"bat":true,"dmalam":true,"mbrevoort":true,"danielr":true,"rsimoes":true,"thlorenz":true}}
View
10 node_modules/npm-registry-client/test/zz-cleanup.js
@@ -0,0 +1,10 @@
+var tap = require('tap')
+var rimraf = require('rimraf')
+
+tap.test('teardown', function (t) {
+ rimraf(__dirname + '/fixtures/cache', function (er) {
+ if (er) throw er
+ t.pass('cache cleaned')
+ t.end()
+ })
+})
View
3 package.json
@@ -59,7 +59,8 @@
"archy": "0",
"chownr": "0",
"npmlog": "0",
- "ansi": "~0.1.2"
+ "ansi": "~0.1.2",
+ "npm-registry-client": "0"
},
"bundleDependencies": [
"slide",

0 comments on commit b194c5e

Please sign in to comment.