--- /dev/null
+## Before you submit a new issue
+
+* Check if there's a simple solution in the [Troubleshooting](https://github.com/npm/npm/wiki/Troubleshooting) wiki.
+* [Search for similar issues](https://github.com/npm/npm/search?q=Similar%20issues&type=Issues).
+* Ensure your new issue conforms to the [Contributing Guidelines](https://github.com/npm/npm/wiki/Contributing-Guidelines).
-Copyright (c) Isaac Z. Schlueter
+Copyright (c) npm, Inc. and Contributors
All rights reserved.
npm is released under the Artistic License 2.0.
--------
-"Node.js" and "node" trademark Joyent, Inc. npm is not officially
+"Node.js" and "node" trademark Joyent, Inc. npm is not officially
part of the Node.js project, and is neither owned by nor
officially affiliated with Joyent, Inc.
When you find issues, please report them:
* web:
- <https://github.com/isaacs/npm/issues>
+ <https://github.com/npm/npm/issues>
* email:
<npm-@googlegroups.com>
Examples:
- git+ssh://git@github.com:isaacs/npm.git#v1.0.27
- git+https://isaacs@github.com/isaacs/npm.git
- git://github.com/isaacs/npm.git#v1.0.27
+ git+ssh://git@github.com:npm/npm.git#v1.0.27
+ git+https://isaacs@github.com/npm/npm.git
+ git://github.com/npm/npm.git#v1.0.27
You may combine multiple arguments, and even multiple types of arguments.
For example:
List packages in the global install prefix instead of in the current
project.
+### depth
+
+* Type: Int
+
+Max display depth of the dependency tree.
+
## SEE ALSO
* npm-config(1)
version specified in the package.json, the field 'latest' the very latest
version of the package.
+## CONFIGURATION
+
+### json
+
+* Default: false
+* Type: Boolean
+
+Show information in JSON format.
+
+### long
+
+* Default: false
+* Type: Boolean
+
+Show extended information.
+
+### parseable
+
+* Default: false
+* Type: Boolean
+
+Show parseable output instead of tree view.
+
+### global
+
+* Default: false
+* Type: Boolean
+
+Check packages in the global install prefix instead of in the current
+project.
+
+### depth
+
+* Type: Int
+
+Max depth for checking dependency tree.
+
## SEE ALSO
* npm-update(1)
If you would like to contribute, but don't know what to work on, check
the issues list or ask on the mailing list.
-* <http://github.com/isaacs/npm/issues>
+* <http://github.com/npm/npm/issues>
* <npm-@googlegroups.com>
## BUGS
When you find issues, please report them:
* web:
- <http://github.com/isaacs/npm/issues>
+ <http://github.com/npm/npm/issues>
* email:
<npm-@googlegroups.com>
"repository" :
{ "type" : "git"
- , "url" : "http://github.com/isaacs/npm.git"
+ , "url" : "http://github.com/npm/npm.git"
}
"repository" :
## Logging
-Logging is done using the [npmlog](https://github.com/isaacs/npmlog)
+Logging is done using the [npmlog](https://github.com/npm/npmlog)
utility.
Please clean up logs when they are no longer helpful. In particular,
### init.license
-* Default: "BSD-2-Clause"
+* Default: "ISC"
* Type: String
The value `npm init` should use by default for the package license.
* Type: Stream
This is the stream that is passed to the
-[npmlog](https://github.com/isaacs/npmlog) module at run time.
+[npmlog](https://github.com/npm/npmlog) module at run time.
It cannot be set from the command line, but if you are using npm
programmatically, you may wish to send logs to somewhere other than
access the internet for some reason.
If the registry IS down, let me know by emailing <i@izs.me> or posting
-an issue at <https://github.com/isaacs/npm/issues>. We'll have
+an issue at <https://github.com/npm/npm/issues>. We'll have
someone kick it or something.
## Why no namespaces?
-Please see this discussion: <https://github.com/isaacs/npm/issues/798>
+Please see this discussion: <https://github.com/npm/npm/issues/798>
tl;dr - It doesn't actually make things better, and can make them worse.
Post an issue on the github project:
-* <https://github.com/isaacs/npm/issues>
+* <https://github.com/npm/npm/issues>
## Why does npm hate me?
The official public npm registry is at <http://registry.npmjs.org/>. It
is powered by a CouchDB database at
<http://isaacs.iriscouch.com/registry>. The code for the couchapp is
-available at <http://github.com/isaacs/npmjs.org>. npm user accounts
+available at <http://github.com/npm/npmjs.org>. npm user accounts
are CouchDB users, stored in the <http://isaacs.iriscouch.com/_users>
database.
<p>When you find issues, please report them:</p>
<ul><li>web:
-<a href="https://github.com/isaacs/npm/issues">https://github.com/isaacs/npm/issues</a></li><li>email:
+<a href="https://github.com/npm/npm/issues">https://github.com/npm/npm/issues</a></li><li>email:
<a href="mailto:npm-@googlegroups.com">npm-@googlegroups.com</a></li></ul>
<p>Be sure to include <em>all</em> of the output from the npm command that didn't work
<ul><li><a href="cli/npm.html">npm(1)</a></li><li><a href="misc/npm-faq.html">npm-faq(7)</a></li><li><a href="cli/npm-help.html">npm-help(1)</a></li><li><a href="misc/npm-index.html">npm-index(7)</a></li></ul>
</div>
-<p id="footer"><a href="../doc/README.html">README</a> — npm@1.3.26</p>
+<p id="footer"><a href="../doc/README.html">README</a> — npm@1.4.0</p>
<script>
;(function () {
var wrapper = document.getElementById("wrapper")
<p>This function should not be used programmatically. Instead, just refer
to the <code>npm.bin</code> member.</p>
</div>
-<p id="footer">npm-bin — npm@1.3.26</p>
+<p id="footer">npm-bin — npm@1.4.0</p>
<script>
;(function () {
var wrapper = document.getElementById("wrapper")
<p>This command will launch a browser, so this command may not be the most
friendly for programmatic use.</p>
</div>
-<p id="footer">npm-bugs — npm@1.3.26</p>
+<p id="footer">npm-bugs — npm@1.4.0</p>
<script>
;(function () {
var wrapper = document.getElementById("wrapper")
<ul><li><a href="../misc/npm-index.html">npm-index(7)</a></li></ul>
</div>
-<p id="footer">npm-commands — npm@1.3.26</p>
+<p id="footer">npm-commands — npm@1.4.0</p>
<script>
;(function () {
var wrapper = document.getElementById("wrapper")
<ul><li><a href="../api/npm.html">npm(3)</a></li></ul>
</div>
-<p id="footer">npm-config — npm@1.3.26</p>
+<p id="footer">npm-config — npm@1.4.0</p>
<script>
;(function () {
var wrapper = document.getElementById("wrapper")
<ul><li><a href="../api/npm-publish.html">npm-publish(3)</a></li><li><a href="../api/npm-unpublish.html">npm-unpublish(3)</a></li><li><a href="../misc/npm-registry.html">npm-registry(7)</a></li></ul>
</div>
-<p id="footer">npm-deprecate — npm@1.3.26</p>
+<p id="footer">npm-deprecate — npm@1.4.0</p>
<script>
;(function () {
var wrapper = document.getElementById("wrapper")
<p>This command will launch a browser, so this command may not be the most
friendly for programmatic use.</p>
</div>
-<p id="footer">npm-docs — npm@1.3.26</p>
+<p id="footer">npm-docs — npm@1.4.0</p>
<script>
;(function () {
var wrapper = document.getElementById("wrapper")
<p>Since this command opens an editor in a new process, be careful about where
and how this is used.</p>
</div>
-<p id="footer">npm-edit — npm@1.3.26</p>
+<p id="footer">npm-edit — npm@1.4.0</p>
<script>
;(function () {
var wrapper = document.getElementById("wrapper")
<p>The first element in the 'args' parameter must be a package name. After that is the optional command, which can be any number of strings. All of the strings will be combined into one, space-delimited command.</p>
</div>
-<p id="footer">npm-explore — npm@1.3.26</p>
+<p id="footer">npm-explore — npm@1.4.0</p>
<script>
;(function () {
var wrapper = document.getElementById("wrapper")
<p>The silent parameter is not neccessary not used, but it may in the future.</p>
</div>
-<p id="footer">npm-help-search — npm@1.3.26</p>
+<p id="footer">npm-help-search — npm@1.4.0</p>
<script>
;(function () {
var wrapper = document.getElementById("wrapper")
<p><a href="../files/package.json.html">package.json(5)</a></p>
</div>
-<p id="footer">npm-init — npm@1.3.26</p>
+<p id="footer">npm-init — npm@1.4.0</p>
<script>
;(function () {
var wrapper = document.getElementById("wrapper")
<p>Finally, 'callback' is a function that will be called when all packages have been
installed or when an error has been encountered.</p>
</div>
-<p id="footer">npm-install — npm@1.3.26</p>
+<p id="footer">npm-install — npm@1.4.0</p>
<script>
;(function () {
var wrapper = document.getElementById("wrapper")
<p>Now, any changes to the redis package will be reflected in
the package in the current working directory</p>
</div>
-<p id="footer">npm-link — npm@1.3.26</p>
+<p id="footer">npm-link — npm@1.4.0</p>
<script>
;(function () {
var wrapper = document.getElementById("wrapper")
<p>For a list of all the available command-line configs, see <code>npm help config</code></p>
</div>
-<p id="footer">npm-load — npm@1.3.26</p>
+<p id="footer">npm-load — npm@1.4.0</p>
<script>
;(function () {
var wrapper = document.getElementById("wrapper")
This means that if a submodule a same dependency as a parent module, then the
dependency will only be output once.</p>
</div>
-<p id="footer">npm-ls — npm@1.3.26</p>
+<p id="footer">npm-ls — npm@1.4.0</p>
<script>
;(function () {
var wrapper = document.getElementById("wrapper")
<p>If the 'packages' parameter is left out, npm will check all packages.</p>
</div>
-<p id="footer">npm-outdated — npm@1.3.26</p>
+<p id="footer">npm-outdated — npm@1.4.0</p>
<script>
;(function () {
var wrapper = document.getElementById("wrapper")
<ul><li><a href="../api/npm-publish.html">npm-publish(3)</a></li><li><a href="../misc/npm-registry.html">npm-registry(7)</a></li></ul>
</div>
-<p id="footer">npm-owner — npm@1.3.26</p>
+<p id="footer">npm-owner — npm@1.4.0</p>
<script>
;(function () {
var wrapper = document.getElementById("wrapper")
<p>If no arguments are supplied, then npm packs the current package folder.</p>
</div>
-<p id="footer">npm-pack — npm@1.3.26</p>
+<p id="footer">npm-pack — npm@1.4.0</p>
<script>
;(function () {
var wrapper = document.getElementById("wrapper")
<p>This function is not useful programmatically</p>
</div>
-<p id="footer">npm-prefix — npm@1.3.26</p>
+<p id="footer">npm-prefix — npm@1.4.0</p>
<script>
;(function () {
var wrapper = document.getElementById("wrapper")
<p>Extraneous packages are packages that are not listed on the parent
package's dependencies list.</p>
</div>
-<p id="footer">npm-prune — npm@1.3.26</p>
+<p id="footer">npm-prune — npm@1.4.0</p>
<script>
;(function () {
var wrapper = document.getElementById("wrapper")
<ul><li><a href="../misc/npm-registry.html">npm-registry(7)</a></li><li><a href="../cli/npm-adduser.html">npm-adduser(1)</a></li><li><a href="../api/npm-owner.html">npm-owner(3)</a></li></ul>
</div>
-<p id="footer">npm-publish — npm@1.3.26</p>
+<p id="footer">npm-publish — npm@1.4.0</p>
<script>
;(function () {
var wrapper = document.getElementById("wrapper")
<p>See <code>npm help build</code></p>
</div>
-<p id="footer">npm-rebuild — npm@1.3.26</p>
+<p id="footer">npm-rebuild — npm@1.4.0</p>
<script>
;(function () {
var wrapper = document.getElementById("wrapper")
<p>This command will launch a browser, so this command may not be the most
friendly for programmatic use.</p>
</div>
-<p id="footer">npm-repo — npm@1.3.26</p>
+<p id="footer">npm-repo — npm@1.4.0</p>
<script>
;(function () {
var wrapper = document.getElementById("wrapper")
<ul><li><a href="../api/npm-start.html">npm-start(3)</a></li><li><a href="../api/npm-stop.html">npm-stop(3)</a></li></ul>
</div>
-<p id="footer">npm-restart — npm@1.3.26</p>
+<p id="footer">npm-restart — npm@1.4.0</p>
<script>
;(function () {
var wrapper = document.getElementById("wrapper")
<p>This function is not useful programmatically.</p>
</div>
-<p id="footer">npm-root — npm@1.3.26</p>
+<p id="footer">npm-root — npm@1.4.0</p>
<script>
;(function () {
var wrapper = document.getElementById("wrapper")
<ul><li><a href="../misc/npm-scripts.html">npm-scripts(7)</a></li><li><a href="../api/npm-test.html">npm-test(3)</a></li><li><a href="../api/npm-start.html">npm-start(3)</a></li><li><a href="../api/npm-restart.html">npm-restart(3)</a></li><li><a href="../api/npm-stop.html">npm-stop(3)</a></li></ul>
</div>
-<p id="footer">npm-run-script — npm@1.3.26</p>
+<p id="footer">npm-run-script — npm@1.4.0</p>
<script>
;(function () {
var wrapper = document.getElementById("wrapper")
and doesn't try to read your mind (it doesn't do any verb tense matching or the
like).</p>
</div>
-<p id="footer">npm-search — npm@1.3.26</p>
+<p id="footer">npm-search — npm@1.4.0</p>
<script>
;(function () {
var wrapper = document.getElementById("wrapper")
<p>Finally, 'callback' is a function that will be called when the shrinkwrap has
been saved.</p>
</div>
-<p id="footer">npm-shrinkwrap — npm@1.3.26</p>
+<p id="footer">npm-shrinkwrap — npm@1.4.0</p>
<script>
;(function () {
var wrapper = document.getElementById("wrapper")
<p>npm can run tests on multiple packages. Just specify multiple packages
in the <code>packages</code> parameter.</p>
</div>
-<p id="footer">npm-start — npm@1.3.26</p>
+<p id="footer">npm-start — npm@1.4.0</p>
<script>
;(function () {
var wrapper = document.getElementById("wrapper")
<p>npm can run stop on multiple packages. Just specify multiple packages
in the <code>packages</code> parameter.</p>
</div>
-<p id="footer">npm-stop — npm@1.3.26</p>
+<p id="footer">npm-stop — npm@1.4.0</p>
<script>
;(function () {
var wrapper = document.getElementById("wrapper")
<ul><li>npm help json</li><li>git help submodule</li></ul>
</div>
-<p id="footer">npm-submodule — npm@1.3.26</p>
+<p id="footer">npm-submodule — npm@1.4.0</p>
<script>
;(function () {
var wrapper = document.getElementById("wrapper")
used. For more information about how to set this config, check
<code>man 3 npm-config</code> for programmatic usage or <code>man npm-config</code> for cli usage.</p>
</div>
-<p id="footer">npm-tag — npm@1.3.26</p>
+<p id="footer">npm-tag — npm@1.4.0</p>
<script>
;(function () {
var wrapper = document.getElementById("wrapper")
<p>npm can run tests on multiple packages. Just specify multiple packages
in the <code>packages</code> parameter.</p>
</div>
-<p id="footer">npm-test — npm@1.3.26</p>
+<p id="footer">npm-test — npm@1.4.0</p>
<script>
;(function () {
var wrapper = document.getElementById("wrapper")
<p>Finally, 'callback' is a function that will be called when all packages have been
uninstalled or when an error has been encountered.</p>
</div>
-<p id="footer">npm-uninstall — npm@1.3.26</p>
+<p id="footer">npm-uninstall — npm@1.4.0</p>
<script>
;(function () {
var wrapper = document.getElementById("wrapper")
<p>If no version is specified, or if all versions are removed then
the root package entry is removed from the registry entirely.</p>
</div>
-<p id="footer">npm-unpublish — npm@1.3.26</p>
+<p id="footer">npm-unpublish — npm@1.4.0</p>
<script>
;(function () {
var wrapper = document.getElementById("wrapper")
<p>The 'packages' argument is an array of packages to update. The 'callback' parameter will be called when done or when an error occurs.</p>
</div>
-<p id="footer">npm-update — npm@1.3.26</p>
+<p id="footer">npm-update — npm@1.4.0</p>
<script>
;(function () {
var wrapper = document.getElementById("wrapper")
parameter. The difference, however, is this function will fail if it does
not have exactly one element. The only element should be a version number.</p>
</div>
-<p id="footer">npm-version — npm@1.3.26</p>
+<p id="footer">npm-version — npm@1.4.0</p>
<script>
;(function () {
var wrapper = document.getElementById("wrapper")
<p>corresponding to the list of fields selected.</p>
</div>
-<p id="footer">npm-view — npm@1.3.26</p>
+<p id="footer">npm-view — npm@1.4.0</p>
<script>
;(function () {
var wrapper = document.getElementById("wrapper")
<p>This function is not useful programmatically</p>
</div>
-<p id="footer">npm-whoami — npm@1.3.26</p>
+<p id="footer">npm-whoami — npm@1.4.0</p>
<script>
;(function () {
var wrapper = document.getElementById("wrapper")
<h2 id="VERSION">VERSION</h2>
-<p>1.3.26</p>
+<p>1.4.0</p>
<h2 id="DESCRIPTION">DESCRIPTION</h2>
<pre><code>var cmd = npm.deref("unp") // cmd === "unpublish"</code></pre>
</div>
-<p id="footer">npm — npm@1.3.26</p>
+<p id="footer">npm — npm@1.4.0</p>
<script>
;(function () {
var wrapper = document.getElementById("wrapper")
<ul><li><a href="../misc/npm-registry.html">npm-registry(7)</a></li><li><a href="../cli/npm-config.html">npm-config(1)</a></li><li><a href="../misc/npm-config.html">npm-config(7)</a></li><li><a href="../files/npmrc.html">npmrc(5)</a></li><li><a href="../cli/npm-owner.html">npm-owner(1)</a></li><li><a href="../cli/npm-whoami.html">npm-whoami(1)</a></li></ul>
</div>
-<p id="footer">npm-adduser — npm@1.3.26</p>
+<p id="footer">npm-adduser — npm@1.4.0</p>
<script>
;(function () {
var wrapper = document.getElementById("wrapper")
<ul><li><a href="../cli/npm-prefix.html">npm-prefix(1)</a></li><li><a href="../cli/npm-root.html">npm-root(1)</a></li><li><a href="../files/npm-folders.html">npm-folders(5)</a></li><li><a href="../cli/npm-config.html">npm-config(1)</a></li><li><a href="../misc/npm-config.html">npm-config(7)</a></li><li><a href="../files/npmrc.html">npmrc(5)</a></li></ul>
</div>
-<p id="footer">npm-bin — npm@1.3.26</p>
+<p id="footer">npm-bin — npm@1.4.0</p>
<script>
;(function () {
var wrapper = document.getElementById("wrapper")
<ul><li><a href="../cli/npm-docs.html">npm-docs(1)</a></li><li><a href="../cli/npm-view.html">npm-view(1)</a></li><li><a href="../cli/npm-publish.html">npm-publish(1)</a></li><li><a href="../misc/npm-registry.html">npm-registry(7)</a></li><li><a href="../cli/npm-config.html">npm-config(1)</a></li><li><a href="../misc/npm-config.html">npm-config(7)</a></li><li><a href="../files/npmrc.html">npmrc(5)</a></li><li><a href="../files/package.json.html">package.json(5)</a></li></ul>
</div>
-<p id="footer">npm-bugs — npm@1.3.26</p>
+<p id="footer">npm-bugs — npm@1.4.0</p>
<script>
;(function () {
var wrapper = document.getElementById("wrapper")
<ul><li><a href="../cli/npm-install.html">npm-install(1)</a></li><li><a href="../cli/npm-link.html">npm-link(1)</a></li><li><a href="../misc/npm-scripts.html">npm-scripts(7)</a></li><li><a href="../files/package.json.html">package.json(5)</a></li></ul>
</div>
-<p id="footer">npm-build — npm@1.3.26</p>
+<p id="footer">npm-build — npm@1.4.0</p>
<script>
;(function () {
var wrapper = document.getElementById("wrapper")
<ul><li><a href="../cli/npm-install.html">npm-install(1)</a></li></ul>
</div>
-<p id="footer">npm-bundle — npm@1.3.26</p>
+<p id="footer">npm-bundle — npm@1.4.0</p>
<script>
;(function () {
var wrapper = document.getElementById("wrapper")
<ul><li><a href="../files/npm-folders.html">npm-folders(5)</a></li><li><a href="../cli/npm-config.html">npm-config(1)</a></li><li><a href="../misc/npm-config.html">npm-config(7)</a></li><li><a href="../files/npmrc.html">npmrc(5)</a></li><li><a href="../cli/npm-install.html">npm-install(1)</a></li><li><a href="../cli/npm-publish.html">npm-publish(1)</a></li><li><a href="../cli/npm-pack.html">npm-pack(1)</a></li></ul>
</div>
-<p id="footer">npm-cache — npm@1.3.26</p>
+<p id="footer">npm-cache — npm@1.4.0</p>
<script>
;(function () {
var wrapper = document.getElementById("wrapper")
<ul><li><a href="../misc/npm-developers.html">npm-developers(7)</a></li><li><a href="../misc/npm-faq.html">npm-faq(7)</a></li><li><a href="../cli/npm.html">npm(1)</a></li></ul>
</div>
-<p id="footer">npm-completion — npm@1.3.26</p>
+<p id="footer">npm-completion — npm@1.4.0</p>
<script>
;(function () {
var wrapper = document.getElementById("wrapper")
<ul><li><a href="../files/npm-folders.html">npm-folders(5)</a></li><li><a href="../misc/npm-config.html">npm-config(7)</a></li><li><a href="../files/package.json.html">package.json(5)</a></li><li><a href="../files/npmrc.html">npmrc(5)</a></li><li><a href="../cli/npm.html">npm(1)</a></li></ul>
</div>
-<p id="footer">npm-config — npm@1.3.26</p>
+<p id="footer">npm-config — npm@1.4.0</p>
<script>
;(function () {
var wrapper = document.getElementById("wrapper")
<ul><li><a href="../cli/npm-ls.html">npm-ls(1)</a></li><li><a href="../cli/npm-update.html">npm-update(1)</a></li><li><a href="../cli/npm-install.html">npm-install(1)</a></li></ul>
</div>
-<p id="footer">npm-dedupe — npm@1.3.26</p>
+<p id="footer">npm-dedupe — npm@1.4.0</p>
<script>
;(function () {
var wrapper = document.getElementById("wrapper")
<ul><li><a href="../cli/npm-publish.html">npm-publish(1)</a></li><li><a href="../misc/npm-registry.html">npm-registry(7)</a></li></ul>
</div>
-<p id="footer">npm-deprecate — npm@1.3.26</p>
+<p id="footer">npm-deprecate — npm@1.4.0</p>
<script>
;(function () {
var wrapper = document.getElementById("wrapper")
<ul><li><a href="../cli/npm-view.html">npm-view(1)</a></li><li><a href="../cli/npm-publish.html">npm-publish(1)</a></li><li><a href="../misc/npm-registry.html">npm-registry(7)</a></li><li><a href="../cli/npm-config.html">npm-config(1)</a></li><li><a href="../misc/npm-config.html">npm-config(7)</a></li><li><a href="../files/npmrc.html">npmrc(5)</a></li><li><a href="../files/package.json.html">package.json(5)</a></li></ul>
</div>
-<p id="footer">npm-docs — npm@1.3.26</p>
+<p id="footer">npm-docs — npm@1.4.0</p>
<script>
;(function () {
var wrapper = document.getElementById("wrapper")
<ul><li><a href="../files/npm-folders.html">npm-folders(5)</a></li><li><a href="../cli/npm-explore.html">npm-explore(1)</a></li><li><a href="../cli/npm-install.html">npm-install(1)</a></li><li><a href="../cli/npm-config.html">npm-config(1)</a></li><li><a href="../misc/npm-config.html">npm-config(7)</a></li><li><a href="../files/npmrc.html">npmrc(5)</a></li></ul>
</div>
-<p id="footer">npm-edit — npm@1.3.26</p>
+<p id="footer">npm-edit — npm@1.4.0</p>
<script>
;(function () {
var wrapper = document.getElementById("wrapper")
<ul><li><a href="../cli/npm-submodule.html">npm-submodule(1)</a></li><li><a href="../files/npm-folders.html">npm-folders(5)</a></li><li><a href="../cli/npm-edit.html">npm-edit(1)</a></li><li><a href="../cli/npm-rebuild.html">npm-rebuild(1)</a></li><li><a href="../cli/npm-build.html">npm-build(1)</a></li><li><a href="../cli/npm-install.html">npm-install(1)</a></li></ul>
</div>
-<p id="footer">npm-explore — npm@1.3.26</p>
+<p id="footer">npm-explore — npm@1.4.0</p>
<script>
;(function () {
var wrapper = document.getElementById("wrapper")
<ul><li><a href="../cli/npm.html">npm(1)</a></li><li><a href="../misc/npm-faq.html">npm-faq(7)</a></li><li><a href="../cli/npm-help.html">npm-help(1)</a></li></ul>
</div>
-<p id="footer">npm-help-search — npm@1.3.26</p>
+<p id="footer">npm-help-search — npm@1.4.0</p>
<script>
;(function () {
var wrapper = document.getElementById("wrapper")
<ul><li><a href="../cli/npm.html">npm(1)</a></li><li><a href="../../doc/README.html">README</a></li><li><a href="../misc/npm-faq.html">npm-faq(7)</a></li><li><a href="../files/npm-folders.html">npm-folders(5)</a></li><li><a href="../cli/npm-config.html">npm-config(1)</a></li><li><a href="../misc/npm-config.html">npm-config(7)</a></li><li><a href="../files/npmrc.html">npmrc(5)</a></li><li><a href="../files/package.json.html">package.json(5)</a></li><li><a href="../cli/npm-help-search.html">npm-help-search(1)</a></li><li><a href="../misc/npm-index.html">npm-index(7)</a></li></ul>
</div>
-<p id="footer">npm-help — npm@1.3.26</p>
+<p id="footer">npm-help — npm@1.4.0</p>
<script>
;(function () {
var wrapper = document.getElementById("wrapper")
<ul><li><a href="https://github.com/isaacs/init-package-json">https://github.com/isaacs/init-package-json</a></li><li><a href="../files/package.json.html">package.json(5)</a></li><li><a href="../cli/npm-version.html">npm-version(1)</a></li></ul>
</div>
-<p id="footer">npm-init — npm@1.3.26</p>
+<p id="footer">npm-init — npm@1.4.0</p>
<script>
;(function () {
var wrapper = document.getElementById("wrapper")
treat it as a single argument.</p><p>Example:</p><p> npm install sax@">=0.1.0 <0.2.0"</p></li><li><p><code>npm install <git remote url></code>:</p><p>Install a package by cloning a git remote url. The format of the git
url is:</p><p> <protocol>://[<user>@]<hostname><separator><path>[#<commit-ish>]</p><p><code><protocol></code> is one of <code>git</code>, <code>git+ssh</code>, <code>git+http</code>, or
<code>git+https</code>. If no <code><commit-ish></code> is specified, then <code>master</code> is
-used.</p><p>Examples:</p><pre><code> git+ssh://git@github.com:isaacs/npm.git#v1.0.27
- git+https://isaacs@github.com/isaacs/npm.git
- git://github.com/isaacs/npm.git#v1.0.27</code></pre></li></ul>
+used.</p><p>Examples:</p><pre><code> git+ssh://git@github.com:npm/npm.git#v1.0.27
+ git+https://isaacs@github.com/npm/npm.git
+ git://github.com/npm/npm.git#v1.0.27</code></pre></li></ul>
<p>You may combine multiple arguments, and even multiple types of arguments.
For example:</p>
<ul><li><a href="../files/npm-folders.html">npm-folders(5)</a></li><li><a href="../cli/npm-update.html">npm-update(1)</a></li><li><a href="../cli/npm-link.html">npm-link(1)</a></li><li><a href="../cli/npm-rebuild.html">npm-rebuild(1)</a></li><li><a href="../misc/npm-scripts.html">npm-scripts(7)</a></li><li><a href="../cli/npm-build.html">npm-build(1)</a></li><li><a href="../cli/npm-config.html">npm-config(1)</a></li><li><a href="../misc/npm-config.html">npm-config(7)</a></li><li><a href="../files/npmrc.html">npmrc(5)</a></li><li><a href="../misc/npm-registry.html">npm-registry(7)</a></li><li><a href="../files/npm-folders.html">npm-folders(5)</a></li><li><a href="../cli/npm-tag.html">npm-tag(1)</a></li><li><a href="../cli/npm-rm.html">npm-rm(1)</a></li><li><a href="../cli/npm-shrinkwrap.html">npm-shrinkwrap(1)</a></li></ul>
</div>
-<p id="footer">npm-install — npm@1.3.26</p>
+<p id="footer">npm-install — npm@1.4.0</p>
<script>
;(function () {
var wrapper = document.getElementById("wrapper")
<ul><li><a href="../misc/npm-developers.html">npm-developers(7)</a></li><li><a href="../misc/npm-faq.html">npm-faq(7)</a></li><li><a href="../files/package.json.html">package.json(5)</a></li><li><a href="../cli/npm-install.html">npm-install(1)</a></li><li><a href="../files/npm-folders.html">npm-folders(5)</a></li><li><a href="../cli/npm-config.html">npm-config(1)</a></li><li><a href="../misc/npm-config.html">npm-config(7)</a></li><li><a href="../files/npmrc.html">npmrc(5)</a></li></ul>
</div>
-<p id="footer">npm-link — npm@1.3.26</p>
+<p id="footer">npm-link — npm@1.4.0</p>
<script>
;(function () {
var wrapper = document.getElementById("wrapper")
nested packages will <em>also</em> show the paths to the specified packages.
For example, running <code>npm ls promzard</code> in npm's source tree will show:</p>
-<pre><code>npm@1.3.26 /path/to/npm
+<pre><code>npm@1.4.0 /path/to/npm
└─┬ init-package-json@0.0.4
└── promzard@0.1.5</code></pre>
<p>List packages in the global install prefix instead of in the current
project.</p>
+<h3 id="depth">depth</h3>
+
+<ul><li>Type: Int</li></ul>
+
+<p>Max display depth of the dependency tree.</p>
+
<h2 id="SEE-ALSO">SEE ALSO</h2>
<ul><li><a href="../cli/npm-config.html">npm-config(1)</a></li><li><a href="../misc/npm-config.html">npm-config(7)</a></li><li><a href="../files/npmrc.html">npmrc(5)</a></li><li><a href="../files/npm-folders.html">npm-folders(5)</a></li><li><a href="../cli/npm-install.html">npm-install(1)</a></li><li><a href="../cli/npm-link.html">npm-link(1)</a></li><li><a href="../cli/npm-prune.html">npm-prune(1)</a></li><li><a href="../cli/npm-outdated.html">npm-outdated(1)</a></li><li><a href="../cli/npm-update.html">npm-update(1)</a></li></ul>
</div>
-<p id="footer">npm-ls — npm@1.3.26</p>
+<p id="footer">npm-ls — npm@1.4.0</p>
<script>
;(function () {
var wrapper = document.getElementById("wrapper")
version specified in the package.json, the field 'latest' the very latest
version of the package.</p>
+<h2 id="CONFIGURATION">CONFIGURATION</h2>
+
+<h3 id="json">json</h3>
+
+<ul><li>Default: false</li><li>Type: Boolean</li></ul>
+
+<p>Show information in JSON format.</p>
+
+<h3 id="long">long</h3>
+
+<ul><li>Default: false</li><li>Type: Boolean</li></ul>
+
+<p>Show extended information.</p>
+
+<h3 id="parseable">parseable</h3>
+
+<ul><li>Default: false</li><li>Type: Boolean</li></ul>
+
+<p>Show parseable output instead of tree view.</p>
+
+<h3 id="global">global</h3>
+
+<ul><li>Default: false</li><li>Type: Boolean</li></ul>
+
+<p>Check packages in the global install prefix instead of in the current
+project.</p>
+
+<h3 id="depth">depth</h3>
+
+<ul><li>Type: Int</li></ul>
+
+<p>Max depth for checking dependency tree.</p>
+
<h2 id="SEE-ALSO">SEE ALSO</h2>
<ul><li><a href="../cli/npm-update.html">npm-update(1)</a></li><li><a href="../misc/npm-registry.html">npm-registry(7)</a></li><li><a href="../files/npm-folders.html">npm-folders(5)</a></li></ul>
</div>
-<p id="footer">npm-outdated — npm@1.3.26</p>
+<p id="footer">npm-outdated — npm@1.4.0</p>
<script>
;(function () {
var wrapper = document.getElementById("wrapper")
<ul><li><a href="../cli/npm-publish.html">npm-publish(1)</a></li><li><a href="../misc/npm-registry.html">npm-registry(7)</a></li><li><a href="../cli/npm-adduser.html">npm-adduser(1)</a></li><li><a href="../misc/npm-disputes.html">npm-disputes(7)</a></li></ul>
</div>
-<p id="footer">npm-owner — npm@1.3.26</p>
+<p id="footer">npm-owner — npm@1.4.0</p>
<script>
;(function () {
var wrapper = document.getElementById("wrapper")
<ul><li><a href="../cli/npm-cache.html">npm-cache(1)</a></li><li><a href="../cli/npm-publish.html">npm-publish(1)</a></li><li><a href="../cli/npm-config.html">npm-config(1)</a></li><li><a href="../misc/npm-config.html">npm-config(7)</a></li><li><a href="../files/npmrc.html">npmrc(5)</a></li></ul>
</div>
-<p id="footer">npm-pack — npm@1.3.26</p>
+<p id="footer">npm-pack — npm@1.4.0</p>
<script>
;(function () {
var wrapper = document.getElementById("wrapper")
<ul><li><a href="../cli/npm-root.html">npm-root(1)</a></li><li><a href="../cli/npm-bin.html">npm-bin(1)</a></li><li><a href="../files/npm-folders.html">npm-folders(5)</a></li><li><a href="../cli/npm-config.html">npm-config(1)</a></li><li><a href="../misc/npm-config.html">npm-config(7)</a></li><li><a href="../files/npmrc.html">npmrc(5)</a></li></ul>
</div>
-<p id="footer">npm-prefix — npm@1.3.26</p>
+<p id="footer">npm-prefix — npm@1.4.0</p>
<script>
;(function () {
var wrapper = document.getElementById("wrapper")
<ul><li><a href="../cli/npm-rm.html">npm-rm(1)</a></li><li><a href="../files/npm-folders.html">npm-folders(5)</a></li><li><a href="../cli/npm-ls.html">npm-ls(1)</a></li></ul>
</div>
-<p id="footer">npm-prune — npm@1.3.26</p>
+<p id="footer">npm-prune — npm@1.4.0</p>
<script>
;(function () {
var wrapper = document.getElementById("wrapper")
<ul><li><a href="../misc/npm-registry.html">npm-registry(7)</a></li><li><a href="../cli/npm-adduser.html">npm-adduser(1)</a></li><li><a href="../cli/npm-owner.html">npm-owner(1)</a></li><li><a href="../cli/npm-deprecate.html">npm-deprecate(1)</a></li><li><a href="../cli/npm-tag.html">npm-tag(1)</a></li></ul>
</div>
-<p id="footer">npm-publish — npm@1.3.26</p>
+<p id="footer">npm-publish — npm@1.4.0</p>
<script>
;(function () {
var wrapper = document.getElementById("wrapper")
<ul><li><a href="../cli/npm-build.html">npm-build(1)</a></li><li><a href="../cli/npm-install.html">npm-install(1)</a></li></ul>
</div>
-<p id="footer">npm-rebuild — npm@1.3.26</p>
+<p id="footer">npm-rebuild — npm@1.4.0</p>
<script>
;(function () {
var wrapper = document.getElementById("wrapper")
<ul><li><a href="../cli/npm-docs.html">npm-docs(1)</a></li><li><a href="../cli/npm-config.html">npm-config(1)</a></li></ul>
</div>
-<p id="footer">npm-repo — npm@1.3.26</p>
+<p id="footer">npm-repo — npm@1.4.0</p>
<script>
;(function () {
var wrapper = document.getElementById("wrapper")
<ul><li><a href="../cli/npm-run-script.html">npm-run-script(1)</a></li><li><a href="../misc/npm-scripts.html">npm-scripts(7)</a></li><li><a href="../cli/npm-test.html">npm-test(1)</a></li><li><a href="../cli/npm-start.html">npm-start(1)</a></li><li><a href="../cli/npm-stop.html">npm-stop(1)</a></li></ul>
</div>
-<p id="footer">npm-restart — npm@1.3.26</p>
+<p id="footer">npm-restart — npm@1.4.0</p>
<script>
;(function () {
var wrapper = document.getElementById("wrapper")
<ul><li><a href="../cli/npm-prune.html">npm-prune(1)</a></li><li><a href="../cli/npm-install.html">npm-install(1)</a></li><li><a href="../files/npm-folders.html">npm-folders(5)</a></li><li><a href="../cli/npm-config.html">npm-config(1)</a></li><li><a href="../misc/npm-config.html">npm-config(7)</a></li><li><a href="../files/npmrc.html">npmrc(5)</a></li></ul>
</div>
-<p id="footer">npm-rm — npm@1.3.26</p>
+<p id="footer">npm-rm — npm@1.4.0</p>
<script>
;(function () {
var wrapper = document.getElementById("wrapper")
<ul><li><a href="../cli/npm-prefix.html">npm-prefix(1)</a></li><li><a href="../cli/npm-bin.html">npm-bin(1)</a></li><li><a href="../files/npm-folders.html">npm-folders(5)</a></li><li><a href="../cli/npm-config.html">npm-config(1)</a></li><li><a href="../misc/npm-config.html">npm-config(7)</a></li><li><a href="../files/npmrc.html">npmrc(5)</a></li></ul>
</div>
-<p id="footer">npm-root — npm@1.3.26</p>
+<p id="footer">npm-root — npm@1.4.0</p>
<script>
;(function () {
var wrapper = document.getElementById("wrapper")
<ul><li><a href="../misc/npm-scripts.html">npm-scripts(7)</a></li><li><a href="../cli/npm-test.html">npm-test(1)</a></li><li><a href="../cli/npm-start.html">npm-start(1)</a></li><li><a href="../cli/npm-restart.html">npm-restart(1)</a></li><li><a href="../cli/npm-stop.html">npm-stop(1)</a></li></ul>
</div>
-<p id="footer">npm-run-script — npm@1.3.26</p>
+<p id="footer">npm-run-script — npm@1.4.0</p>
<script>
;(function () {
var wrapper = document.getElementById("wrapper")
<ul><li><a href="../misc/npm-registry.html">npm-registry(7)</a></li><li><a href="../cli/npm-config.html">npm-config(1)</a></li><li><a href="../misc/npm-config.html">npm-config(7)</a></li><li><a href="../files/npmrc.html">npmrc(5)</a></li><li><a href="../cli/npm-view.html">npm-view(1)</a></li></ul>
</div>
-<p id="footer">npm-search — npm@1.3.26</p>
+<p id="footer">npm-search — npm@1.4.0</p>
<script>
;(function () {
var wrapper = document.getElementById("wrapper")
<ul><li><a href="../cli/npm-install.html">npm-install(1)</a></li><li><a href="../files/package.json.html">package.json(5)</a></li><li><a href="../cli/npm-ls.html">npm-ls(1)</a></li></ul>
</div>
-<p id="footer">npm-shrinkwrap — npm@1.3.26</p>
+<p id="footer">npm-shrinkwrap — npm@1.4.0</p>
<script>
;(function () {
var wrapper = document.getElementById("wrapper")
<ul><li><a href="../cli/npm-view.html">npm-view(1)</a></li><li><a href="../cli/npm-whoami.html">npm-whoami(1)</a></li><li><a href="../cli/npm-adduser.html">npm-adduser(1)</a></li></ul>
</div>
-<p id="footer">npm-star — npm@1.3.26</p>
+<p id="footer">npm-star — npm@1.4.0</p>
<script>
;(function () {
var wrapper = document.getElementById("wrapper")
<ul><li><a href="../cli/npm-star.html">npm-star(1)</a></li><li><a href="../cli/npm-view.html">npm-view(1)</a></li><li><a href="../cli/npm-whoami.html">npm-whoami(1)</a></li><li><a href="../cli/npm-adduser.html">npm-adduser(1)</a></li></ul>
</div>
-<p id="footer">npm-stars — npm@1.3.26</p>
+<p id="footer">npm-stars — npm@1.4.0</p>
<script>
;(function () {
var wrapper = document.getElementById("wrapper")
<ul><li><a href="../cli/npm-run-script.html">npm-run-script(1)</a></li><li><a href="../misc/npm-scripts.html">npm-scripts(7)</a></li><li><a href="../cli/npm-test.html">npm-test(1)</a></li><li><a href="../cli/npm-restart.html">npm-restart(1)</a></li><li><a href="../cli/npm-stop.html">npm-stop(1)</a></li></ul>
</div>
-<p id="footer">npm-start — npm@1.3.26</p>
+<p id="footer">npm-start — npm@1.4.0</p>
<script>
;(function () {
var wrapper = document.getElementById("wrapper")
<ul><li><a href="../cli/npm-run-script.html">npm-run-script(1)</a></li><li><a href="../misc/npm-scripts.html">npm-scripts(7)</a></li><li><a href="../cli/npm-test.html">npm-test(1)</a></li><li><a href="../cli/npm-start.html">npm-start(1)</a></li><li><a href="../cli/npm-restart.html">npm-restart(1)</a></li></ul>
</div>
-<p id="footer">npm-stop — npm@1.3.26</p>
+<p id="footer">npm-stop — npm@1.4.0</p>
<script>
;(function () {
var wrapper = document.getElementById("wrapper")
<ul><li><a href="../files/package.json.html">package.json(5)</a></li><li>git help submodule</li></ul>
</div>
-<p id="footer">npm-submodule — npm@1.3.26</p>
+<p id="footer">npm-submodule — npm@1.4.0</p>
<script>
;(function () {
var wrapper = document.getElementById("wrapper")
<ul><li><a href="../cli/npm-publish.html">npm-publish(1)</a></li><li><a href="../cli/npm-install.html">npm-install(1)</a></li><li><a href="../cli/npm-dedupe.html">npm-dedupe(1)</a></li><li><a href="../misc/npm-registry.html">npm-registry(7)</a></li><li><a href="../cli/npm-config.html">npm-config(1)</a></li><li><a href="../misc/npm-config.html">npm-config(7)</a></li><li><a href="../files/npmrc.html">npmrc(5)</a></li></ul>
</div>
-<p id="footer">npm-tag — npm@1.3.26</p>
+<p id="footer">npm-tag — npm@1.4.0</p>
<script>
;(function () {
var wrapper = document.getElementById("wrapper")
<ul><li><a href="../cli/npm-run-script.html">npm-run-script(1)</a></li><li><a href="../misc/npm-scripts.html">npm-scripts(7)</a></li><li><a href="../cli/npm-start.html">npm-start(1)</a></li><li><a href="../cli/npm-restart.html">npm-restart(1)</a></li><li><a href="../cli/npm-stop.html">npm-stop(1)</a></li></ul>
</div>
-<p id="footer">npm-test — npm@1.3.26</p>
+<p id="footer">npm-test — npm@1.4.0</p>
<script>
;(function () {
var wrapper = document.getElementById("wrapper")
<ul><li><a href="../cli/npm-prune.html">npm-prune(1)</a></li><li><a href="../cli/npm-install.html">npm-install(1)</a></li><li><a href="../files/npm-folders.html">npm-folders(5)</a></li><li><a href="../cli/npm-config.html">npm-config(1)</a></li><li><a href="../misc/npm-config.html">npm-config(7)</a></li><li><a href="../files/npmrc.html">npmrc(5)</a></li></ul>
</div>
-<p id="footer">npm-uninstall — npm@1.3.26</p>
+<p id="footer">npm-uninstall — npm@1.4.0</p>
<script>
;(function () {
var wrapper = document.getElementById("wrapper")
<ul><li><a href="../cli/npm-deprecate.html">npm-deprecate(1)</a></li><li><a href="../cli/npm-publish.html">npm-publish(1)</a></li><li><a href="../misc/npm-registry.html">npm-registry(7)</a></li><li><a href="../cli/npm-adduser.html">npm-adduser(1)</a></li><li><a href="../cli/npm-owner.html">npm-owner(1)</a></li></ul>
</div>
-<p id="footer">npm-unpublish — npm@1.3.26</p>
+<p id="footer">npm-unpublish — npm@1.4.0</p>
<script>
;(function () {
var wrapper = document.getElementById("wrapper")
<ul><li><a href="../cli/npm-install.html">npm-install(1)</a></li><li><a href="../cli/npm-outdated.html">npm-outdated(1)</a></li><li><a href="../misc/npm-registry.html">npm-registry(7)</a></li><li><a href="../files/npm-folders.html">npm-folders(5)</a></li><li><a href="../cli/npm-ls.html">npm-ls(1)</a></li></ul>
</div>
-<p id="footer">npm-update — npm@1.3.26</p>
+<p id="footer">npm-update — npm@1.4.0</p>
<script>
;(function () {
var wrapper = document.getElementById("wrapper")
<ul><li><a href="../cli/npm-init.html">npm-init(1)</a></li><li><a href="../files/package.json.html">package.json(5)</a></li><li><a href="../misc/semver.html">semver(7)</a></li></ul>
</div>
-<p id="footer">npm-version — npm@1.3.26</p>
+<p id="footer">npm-version — npm@1.4.0</p>
<script>
;(function () {
var wrapper = document.getElementById("wrapper")
<ul><li><a href="../cli/npm-search.html">npm-search(1)</a></li><li><a href="../misc/npm-registry.html">npm-registry(7)</a></li><li><a href="../cli/npm-config.html">npm-config(1)</a></li><li><a href="../misc/npm-config.html">npm-config(7)</a></li><li><a href="../files/npmrc.html">npmrc(5)</a></li><li><a href="../cli/npm-docs.html">npm-docs(1)</a></li></ul>
</div>
-<p id="footer">npm-view — npm@1.3.26</p>
+<p id="footer">npm-view — npm@1.4.0</p>
<script>
;(function () {
var wrapper = document.getElementById("wrapper")
<ul><li><a href="../cli/npm-config.html">npm-config(1)</a></li><li><a href="../misc/npm-config.html">npm-config(7)</a></li><li><a href="../files/npmrc.html">npmrc(5)</a></li><li><a href="../cli/npm-adduser.html">npm-adduser(1)</a></li></ul>
</div>
-<p id="footer">npm-whoami — npm@1.3.26</p>
+<p id="footer">npm-whoami — npm@1.4.0</p>
<script>
;(function () {
var wrapper = document.getElementById("wrapper")
<h2 id="VERSION">VERSION</h2>
-<p>1.3.26</p>
+<p>1.4.0</p>
<h2 id="DESCRIPTION">DESCRIPTION</h2>
<p>If you would like to contribute, but don't know what to work on, check
the issues list or ask on the mailing list.</p>
-<ul><li><a href="http://github.com/isaacs/npm/issues">http://github.com/isaacs/npm/issues</a></li><li><a href="mailto:npm-@googlegroups.com">npm-@googlegroups.com</a></li></ul>
+<ul><li><a href="http://github.com/npm/npm/issues">http://github.com/npm/npm/issues</a></li><li><a href="mailto:npm-@googlegroups.com">npm-@googlegroups.com</a></li></ul>
<h2 id="BUGS">BUGS</h2>
<p>When you find issues, please report them:</p>
<ul><li>web:
-<a href="http://github.com/isaacs/npm/issues">http://github.com/isaacs/npm/issues</a></li><li>email:
+<a href="http://github.com/npm/npm/issues">http://github.com/npm/npm/issues</a></li><li>email:
<a href="mailto:npm-@googlegroups.com">npm-@googlegroups.com</a></li></ul>
<p>Be sure to include <em>all</em> of the output from the npm command that didn't work
<ul><li><a href="../cli/npm-help.html">npm-help(1)</a></li><li><a href="../misc/npm-faq.html">npm-faq(7)</a></li><li><a href="../../doc/README.html">README</a></li><li><a href="../files/package.json.html">package.json(5)</a></li><li><a href="../cli/npm-install.html">npm-install(1)</a></li><li><a href="../cli/npm-config.html">npm-config(1)</a></li><li><a href="../misc/npm-config.html">npm-config(7)</a></li><li><a href="../files/npmrc.html">npmrc(5)</a></li><li><a href="../misc/npm-index.html">npm-index(7)</a></li><li><a href="../api/npm.html">npm(3)</a></li></ul>
</div>
-<p id="footer">npm — npm@1.3.26</p>
+<p id="footer">npm — npm@1.4.0</p>
<script>
;(function () {
var wrapper = document.getElementById("wrapper")
<ul><li><a href="../misc/npm-faq.html">npm-faq(7)</a></li><li><a href="../files/package.json.html">package.json(5)</a></li><li><a href="../cli/npm-install.html">npm-install(1)</a></li><li><a href="../cli/npm-pack.html">npm-pack(1)</a></li><li><a href="../cli/npm-cache.html">npm-cache(1)</a></li><li><a href="../cli/npm-config.html">npm-config(1)</a></li><li><a href="../files/npmrc.html">npmrc(5)</a></li><li><a href="../misc/npm-config.html">npm-config(7)</a></li><li><a href="../cli/npm-publish.html">npm-publish(1)</a></li></ul>
</div>
-<p id="footer">npm-folders — npm@1.3.26</p>
+<p id="footer">npm-folders — npm@1.4.0</p>
<script>
;(function () {
var wrapper = document.getElementById("wrapper")
<ul><li><a href="../misc/npm-faq.html">npm-faq(7)</a></li><li><a href="../files/package.json.html">package.json(5)</a></li><li><a href="../cli/npm-install.html">npm-install(1)</a></li><li><a href="../cli/npm-pack.html">npm-pack(1)</a></li><li><a href="../cli/npm-cache.html">npm-cache(1)</a></li><li><a href="../cli/npm-config.html">npm-config(1)</a></li><li><a href="../files/npmrc.html">npmrc(5)</a></li><li><a href="../misc/npm-config.html">npm-config(7)</a></li><li><a href="../cli/npm-publish.html">npm-publish(1)</a></li></ul>
</div>
-<p id="footer">npm-folders — npm@1.3.26</p>
+<p id="footer">npm-folders — npm@1.4.0</p>
<script>
;(function () {
var wrapper = document.getElementById("wrapper")
<pre><code>"repository" :
{ "type" : "git"
- , "url" : "http://github.com/isaacs/npm.git"
+ , "url" : "http://github.com/npm/npm.git"
}
"repository" :
<ul><li><a href="../misc/semver.html">semver(7)</a></li><li><a href="../cli/npm-init.html">npm-init(1)</a></li><li><a href="../cli/npm-version.html">npm-version(1)</a></li><li><a href="../cli/npm-config.html">npm-config(1)</a></li><li><a href="../misc/npm-config.html">npm-config(7)</a></li><li><a href="../cli/npm-help.html">npm-help(1)</a></li><li><a href="../misc/npm-faq.html">npm-faq(7)</a></li><li><a href="../cli/npm-install.html">npm-install(1)</a></li><li><a href="../cli/npm-publish.html">npm-publish(1)</a></li><li><a href="../cli/npm-rm.html">npm-rm(1)</a></li></ul>
</div>
-<p id="footer">package.json — npm@1.3.26</p>
+<p id="footer">package.json — npm@1.4.0</p>
<script>
;(function () {
var wrapper = document.getElementById("wrapper")
<ul><li><a href="../files/npm-folders.html">npm-folders(5)</a></li><li><a href="../cli/npm-config.html">npm-config(1)</a></li><li><a href="../misc/npm-config.html">npm-config(7)</a></li><li><a href="../files/package.json.html">package.json(5)</a></li><li><a href="../cli/npm.html">npm(1)</a></li></ul>
</div>
-<p id="footer">npmrc — npm@1.3.26</p>
+<p id="footer">npmrc — npm@1.4.0</p>
<script>
;(function () {
var wrapper = document.getElementById("wrapper")
<pre><code>"repository" :
{ "type" : "git"
- , "url" : "http://github.com/isaacs/npm.git"
+ , "url" : "http://github.com/npm/npm.git"
}
"repository" :
<ul><li><a href="../misc/semver.html">semver(7)</a></li><li><a href="../cli/npm-init.html">npm-init(1)</a></li><li><a href="../cli/npm-version.html">npm-version(1)</a></li><li><a href="../cli/npm-config.html">npm-config(1)</a></li><li><a href="../misc/npm-config.html">npm-config(7)</a></li><li><a href="../cli/npm-help.html">npm-help(1)</a></li><li><a href="../misc/npm-faq.html">npm-faq(7)</a></li><li><a href="../cli/npm-install.html">npm-install(1)</a></li><li><a href="../cli/npm-publish.html">npm-publish(1)</a></li><li><a href="../cli/npm-rm.html">npm-rm(1)</a></li></ul>
</div>
-<p id="footer">package.json — npm@1.3.26</p>
+<p id="footer">package.json — npm@1.4.0</p>
<script>
;(function () {
var wrapper = document.getElementById("wrapper")
<p>The semantic versioner for npm</p>
</div>
-<p id="footer">npm-index — npm@1.3.26</p>
+<p id="footer">npm-index — npm@1.4.0</p>
<script>
;(function () {
var wrapper = document.getElementById("wrapper")
<h2 id="Logging">Logging</h2>
-<p>Logging is done using the <a href="https://github.com/isaacs/npmlog">npmlog</a>
+<p>Logging is done using the <a href="https://github.com/npm/npmlog">npmlog</a>
utility.</p>
<p>Please clean up logs when they are no longer helpful. In particular,
<ul><li><a href="../misc/npm-developers.html">npm-developers(7)</a></li><li><a href="../misc/npm-faq.html">npm-faq(7)</a></li><li><a href="../cli/npm.html">npm(1)</a></li></ul>
</div>
-<p id="footer">npm-coding-style — npm@1.3.26</p>
+<p id="footer">npm-coding-style — npm@1.4.0</p>
<script>
;(function () {
var wrapper = document.getElementById("wrapper")
<h3 id="init-license">init.license</h3>
-<ul><li>Default: "BSD-2-Clause"</li><li>Type: String</li></ul>
+<ul><li>Default: "ISC"</li><li>Type: String</li></ul>
<p>The value <code>npm init</code> should use by default for the package license.</p>
<ul><li>Default: process.stderr</li><li>Type: Stream</li></ul>
<p>This is the stream that is passed to the
-<a href="https://github.com/isaacs/npmlog">npmlog</a> module at run time.</p>
+<a href="https://github.com/npm/npmlog">npmlog</a> module at run time.</p>
<p>It cannot be set from the command line, but if you are using npm
programmatically, you may wish to send logs to somewhere other than
<ul><li><a href="../cli/npm-config.html">npm-config(1)</a></li><li><a href="../misc/npm-config.html">npm-config(7)</a></li><li><a href="../files/npmrc.html">npmrc(5)</a></li><li><a href="../misc/npm-scripts.html">npm-scripts(7)</a></li><li><a href="../files/npm-folders.html">npm-folders(5)</a></li><li><a href="../cli/npm.html">npm(1)</a></li></ul>
</div>
-<p id="footer">npm-config — npm@1.3.26</p>
+<p id="footer">npm-config — npm@1.4.0</p>
<script>
;(function () {
var wrapper = document.getElementById("wrapper")
<ul><li><a href="../misc/npm-faq.html">npm-faq(7)</a></li><li><a href="../cli/npm.html">npm(1)</a></li><li><a href="../cli/npm-init.html">npm-init(1)</a></li><li><a href="../files/package.json.html">package.json(5)</a></li><li><a href="../misc/npm-scripts.html">npm-scripts(7)</a></li><li><a href="../cli/npm-publish.html">npm-publish(1)</a></li><li><a href="../cli/npm-adduser.html">npm-adduser(1)</a></li><li><a href="../misc/npm-registry.html">npm-registry(7)</a></li></ul>
</div>
-<p id="footer">npm-developers — npm@1.3.26</p>
+<p id="footer">npm-developers — npm@1.4.0</p>
<script>
;(function () {
var wrapper = document.getElementById("wrapper")
<ul><li><a href="../misc/npm-registry.html">npm-registry(7)</a></li><li><a href="../cli/npm-owner.html">npm-owner(1)</a></li></ul>
</div>
-<p id="footer">npm-disputes — npm@1.3.26</p>
+<p id="footer">npm-disputes — npm@1.4.0</p>
<script>
;(function () {
var wrapper = document.getElementById("wrapper")
access the internet for some reason.</p>
<p>If the registry IS down, let me know by emailing <a href="mailto:i@izs.me">i@izs.me</a> or posting
-an issue at <a href="https://github.com/isaacs/npm/issues">https://github.com/isaacs/npm/issues</a>. We'll have
+an issue at <a href="https://github.com/npm/npm/issues">https://github.com/npm/npm/issues</a>. We'll have
someone kick it or something.</p>
<h2 id="Why-no-namespaces">Why no namespaces?</h2>
-<p>Please see this discussion: <a href="https://github.com/isaacs/npm/issues/798">https://github.com/isaacs/npm/issues/798</a></p>
+<p>Please see this discussion: <a href="https://github.com/npm/npm/issues/798">https://github.com/npm/npm/issues/798</a></p>
<p>tl;dr - It doesn't actually make things better, and can make them worse.</p>
<p>Post an issue on the github project:</p>
-<ul><li><a href="https://github.com/isaacs/npm/issues">https://github.com/isaacs/npm/issues</a></li></ul>
+<ul><li><a href="https://github.com/npm/npm/issues">https://github.com/npm/npm/issues</a></li></ul>
<h2 id="Why-does-npm-hate-me">Why does npm hate me?</h2>
<ul><li><a href="../cli/npm.html">npm(1)</a></li><li><a href="../misc/npm-developers.html">npm-developers(7)</a></li><li><a href="../files/package.json.html">package.json(5)</a></li><li><a href="../cli/npm-config.html">npm-config(1)</a></li><li><a href="../misc/npm-config.html">npm-config(7)</a></li><li><a href="../files/npmrc.html">npmrc(5)</a></li><li><a href="../misc/npm-config.html">npm-config(7)</a></li><li><a href="../files/npm-folders.html">npm-folders(5)</a></li></ul>
</div>
-<p id="footer">npm-faq — npm@1.3.26</p>
+<p id="footer">npm-faq — npm@1.4.0</p>
<script>
;(function () {
var wrapper = document.getElementById("wrapper")
<p>The semantic versioner for npm</p>
</div>
-<p id="footer">npm-index — npm@1.3.26</p>
+<p id="footer">npm-index — npm@1.4.0</p>
<script>
;(function () {
var wrapper = document.getElementById("wrapper")
<p>The official public npm registry is at <a href="http://registry.npmjs.org/">http://registry.npmjs.org/</a>. It
is powered by a CouchDB database at
<a href="http://isaacs.iriscouch.com/registry">http://isaacs.iriscouch.com/registry</a>. The code for the couchapp is
-available at <a href="http://github.com/isaacs/npmjs.org">http://github.com/isaacs/npmjs.org</a>. npm user accounts
+available at <a href="http://github.com/npm/npmjs.org">http://github.com/npm/npmjs.org</a>. npm user accounts
are CouchDB users, stored in the <a href="http://isaacs.iriscouch.com/_users">http://isaacs.iriscouch.com/_users</a>
database.</p>
<ul><li><a href="../cli/npm-config.html">npm-config(1)</a></li><li><a href="../misc/npm-config.html">npm-config(7)</a></li><li><a href="../files/npmrc.html">npmrc(5)</a></li><li><a href="../misc/npm-developers.html">npm-developers(7)</a></li><li><a href="../misc/npm-disputes.html">npm-disputes(7)</a></li></ul>
</div>
-<p id="footer">npm-registry — npm@1.3.26</p>
+<p id="footer">npm-registry — npm@1.4.0</p>
<script>
;(function () {
var wrapper = document.getElementById("wrapper")
<ul><li><a href="../cli/npm-run-script.html">npm-run-script(1)</a></li><li><a href="../files/package.json.html">package.json(5)</a></li><li><a href="../misc/npm-developers.html">npm-developers(7)</a></li><li><a href="../cli/npm-install.html">npm-install(1)</a></li></ul>
</div>
-<p id="footer">npm-scripts — npm@1.3.26</p>
+<p id="footer">npm-scripts — npm@1.4.0</p>
<script>
;(function () {
var wrapper = document.getElementById("wrapper")
<ul><li><a href="../../doc/README.html">README</a></li><li><a href="../cli/npm-rm.html">npm-rm(1)</a></li><li><a href="../cli/npm-prune.html">npm-prune(1)</a></li></ul>
</div>
-<p id="footer">removing-npm — npm@1.3.26</p>
+<p id="footer">removing-npm — npm@1.4.0</p>
<script>
;(function () {
var wrapper = document.getElementById("wrapper")
range.</li><li>maxSatisfying(versions, range): Return the highest version in the list
that satisfies the range, or null if none of them do.</li></ul>
</div>
-<p id="footer">semver — npm@1.3.26</p>
+<p id="footer">semver — npm@1.4.0</p>
<script>
;(function () {
var wrapper = document.getElementById("wrapper")
<h2>Fancy Install</h2>
<ol>
- <li><a href="https://github.com/isaacs/npm">Get the code.</a>
+ <li><a href="https://github.com/npm/npm">Get the code.</a>
<li>Do what <a href="https://npmjs.org/doc/README.html">the README</a>
says to do.
</ol>
<li><a href="doc/faq.html">FAQ</a>
<li><a href="https://search.npmjs.org/">Search for Packages</a>
<li><a href="https://groups.google.com/group/npm-">Mailing List</a>
- <li><a href="https://github.com/isaacs/npm/issues">Bugs</a>
+ <li><a href="https://github.com/npm/npm/issues">Bugs</a>
</ul>
</body>
1. urls: http!/server.com/path/to/thing
2. c:\path\to\thing: file!/c!/path/to/thing
3. /path/to/thing: file!/path/to/thing
-4. git@ private: git_github.com!isaacs/npm
-5. git://public: git!/github.com/isaacs/npm
+4. git@ private: git_github.com!npm/npm
+5. git://public: git!/github.com/npm/npm
6. git+blah:// git-blah!/server.com/foo/bar
adding a folder:
}
log.verbose("git fetch -a origin ("+u+")", stdout)
tmp = path.join(npm.tmp, Date.now()+"-"+Math.random(), "tmp.tgz")
- resolveHead()
+ verifyOwnership()
})
+ function verifyOwnership() {
+ if (process.platform === "win32") {
+ log.silly("verifyOwnership", "skipping for windows")
+ resolveHead()
+ } else {
+ getCacheStat(function(er, cs) {
+ if (er) {
+ log.error("Could not get cache stat")
+ return cb(er)
+ }
+ chownr(p, cs.uid, cs.gid, function(er) {
+ if (er) {
+ log.error("Failed to change folder ownership under npm cache for %s", p)
+ return cb(er)
+ }
+ resolveHead()
+ })
+ })
+ }
+ }
+
function resolveHead () {
exec(git, resolve, {cwd: p, env: env}, function (er, stdout, stderr) {
stdout = (stdout + "\n" + stderr).trim()
parsed.hash = stdout
resolved = url.format(parsed)
- // https://github.com/isaacs/npm/issues/3224
+ // https://github.com/npm/npm/issues/3224
// node incorrectly sticks a / at the start of the path
// We know that the host won't change, so split and detect this
var spo = origUrl.split(parsed.host)
, lifecycle = require("./utils/lifecycle.js")
, archy = require("archy")
, isGitUrl = require("./utils/is-git-url.js")
+ , npmInstallChecks = require("npm-install-checks")
function install (args, cb_) {
var hasArguments = !!args.length
}
installOnesInProgress[target.name].push(where)
var indexOfIOIP = installOnesInProgress[target.name].length - 1
+ , force = npm.config.get("force")
+ , nodeVersion = npm.config.get("node-version")
+ , strict = npm.config.get("engine-strict")
+ , c = npmInstallChecks
chain
- ( [ [checkEngine, target]
- , [checkPlatform, target]
- , [checkCycle, target, context.ancestors]
- , [checkGit, targetFolder]
+ ( [ [c.checkEngine, target, npm.version, nodeVersion, force, strict]
+ , [c.checkPlatform, target, force]
+ , [c.checkCycle, target, context.ancestors]
+ , [c.checkGit, targetFolder]
, [write, target, targetFolder, context] ]
, function (er, d) {
installOnesInProgress[target.name].splice(indexOfIOIP, 1)
)
}
-function checkEngine (target, cb) {
- var npmv = npm.version
- , force = npm.config.get("force")
- , nodev = force ? null : npm.config.get("node-version")
- , strict = npm.config.get("engine-strict") || target.engineStrict
- , eng = target.engines
- if (!eng) return cb()
- if (nodev && eng.node && !semver.satisfies(nodev, eng.node)
- || eng.npm && !semver.satisfies(npmv, eng.npm)) {
- if (strict) {
- var er = new Error("Unsupported")
- er.code = "ENOTSUP"
- er.required = eng
- er.pkgid = target._id
- return cb(er)
- } else {
- log.warn( "engine", "%s: wanted: %j (current: %j)"
- , target._id, eng, {node: nodev, npm: npm.version} )
- }
- }
- return cb()
-}
-
-function checkPlatform (target, cb) {
- var platform = process.platform
- , arch = process.arch
- , osOk = true
- , cpuOk = true
- , force = npm.config.get("force")
-
- if (force) {
- return cb()
- }
-
- if (target.os) {
- osOk = checkList(platform, target.os)
- }
- if (target.cpu) {
- cpuOk = checkList(arch, target.cpu)
- }
- if (!osOk || !cpuOk) {
- var er = new Error("Unsupported")
- er.code = "EBADPLATFORM"
- er.os = target.os || ['any']
- er.cpu = target.cpu || ['any']
- er.pkgid = target._id
- return cb(er)
- }
- return cb()
-}
-
-function checkList (value, list) {
- var tmp
- , match = false
- , blc = 0
- if (typeof list === "string") {
- list = [list]
- }
- if (list.length === 1 && list[0] === "any") {
- return true
- }
- for (var i = 0; i < list.length; ++i) {
- tmp = list[i]
- if (tmp[0] === '!') {
- tmp = tmp.slice(1)
- if (tmp === value) {
- return false
- }
- ++blc
- } else {
- match = match || tmp === value
- }
- }
- return match || blc === list.length
-}
-
-function checkCycle (target, ancestors, cb) {
- // there are some very rare and pathological edge-cases where
- // a cycle can cause npm to try to install a never-ending tree
- // of stuff.
- // Simplest:
- //
- // A -> B -> A' -> B' -> A -> B -> A' -> B' -> A -> ...
- //
- // Solution: Simply flat-out refuse to install any name@version
- // that is already in the prototype tree of the ancestors object.
- // A more correct, but more complex, solution would be to symlink
- // the deeper thing into the new location.
- // Will do that if anyone whines about this irl.
- //
- // Note: `npm install foo` inside of the `foo` package will abort
- // earlier if `--force` is not set. However, if it IS set, then
- // we need to still fail here, but just skip the first level. Of
- // course, it'll still fail eventually if it's a true cycle, and
- // leave things in an undefined state, but that's what is to be
- // expected when `--force` is used. That is why getPrototypeOf
- // is used *twice* here: to skip the first level of repetition.
-
- var p = Object.getPrototypeOf(Object.getPrototypeOf(ancestors))
- , name = target.name
- , version = target.version
- while (p && p !== Object.prototype && p[name] !== version) {
- p = Object.getPrototypeOf(p)
- }
- if (p[name] !== version) return cb()
-
- var er = new Error("Unresolvable cycle detected")
- var tree = [target._id, JSON.parse(JSON.stringify(ancestors))]
- , t = Object.getPrototypeOf(ancestors)
- while (t && t !== Object.prototype) {
- if (t === p) t.THIS_IS_P = true
- tree.push(JSON.parse(JSON.stringify(t)))
- t = Object.getPrototypeOf(t)
- }
- log.verbose("unresolvable dependency tree", tree)
- er.pkgid = target._id
- er.code = "ECYCLE"
- return cb(er)
-}
-
-function checkGit (folder, cb) {
- // if it's a git repo then don't touch it!
- fs.lstat(folder, function (er, s) {
- if (er || !s.isDirectory()) return cb()
- else checkGit_(folder, cb)
- })
-}
-
-function checkGit_ (folder, cb) {
- fs.stat(path.resolve(folder, ".git"), function (er, s) {
- if (!er && s.isDirectory()) {
- var e = new Error("Appears to be a git repo or submodule.")
- e.path = folder
- e.code = "EISGIT"
- return cb(e)
- }
- cb()
- })
-}
-
function write (target, targetFolder, context, cb_) {
var up = npm.config.get("unsafe-perm")
, user = up ? null : npm.config.get("user")
// { version: , from: }
var curr = has[dep]
- function skip () {
+ function skip (er) {
+ // show user that no viable version can be found
+ if (er) return cb(er)
outdated_( args
, path.resolve(dir, "node_modules", dep)
, has
cache.add(dep, req, function (er, d) {
// if this fails, then it means we can't update this thing.
// it's probably a thing that isn't published.
- if (er) return skip()
+ if (er) {
+ if (er.code && er.code === 'ETARGET') {
+ // no viable version found
+ return skip(er)
+ }
+ return skip()
+ }
// check that the url origin hasn't changed (#1727) and that
// there is no newer version available
var r = d.repository;
if (!r) return cb(new Error('no repository'));
// XXX remove this when npm@v1.3.10 from node 0.10 is deprecated
- // from https://github.com/isaacs/npm-www/issues/418
+ // from https://github.com/npm/npm-www/issues/418
if (githubUserRepo(r.url))
r.url = githubUserRepo(r.url)
var url = github(r.url)
log.error("", er.stack || er.message || er)
log.error("", ["If you need help, you may report this *entire* log,"
,"including the npm and node versions, at:"
- ," <http://github.com/isaacs/npm/issues>"
+ ," <http://github.com/npm/npm/issues>"
].join("\n"))
printStack = false
break
When you find issues, please report them:
.
.IP "\(bu" 4
-web: \fIhttps://github\.com/isaacs/npm/issues\fR
+web: \fIhttps://github\.com/npm/npm/issues\fR
.
.IP "\(bu" 4
email: \fInpm\-@googlegroups\.com\fR
.IP "" 4
.
.nf
- git+ssh://git@github\.com:isaacs/npm\.git#v1\.0\.27
- git+https://isaacs@github\.com/isaacs/npm\.git
- git://github\.com/isaacs/npm\.git#v1\.0\.27
+ git+ssh://git@github\.com:npm/npm\.git#v1\.0\.27
+ git+https://isaacs@github\.com/npm/npm\.git
+ git://github\.com/npm/npm\.git#v1\.0\.27
.
.fi
.
.IP "" 4
.
.nf
-npm@1.3.26 /path/to/npm
+npm@1.4.0 /path/to/npm
└─┬ init\-package\-json@0\.0\.4
└── promzard@0\.1\.5
.
List packages in the global install prefix instead of in the current
project\.
.
+.SS "depth"
+.
+.IP "\(bu" 4
+Type: Int
+.
+.IP "" 0
+.
+.P
+Max display depth of the dependency tree\.
+.
.SH "SEE ALSO"
.
.IP "\(bu" 4
version specified in the package\.json, the field \'latest\' the very latest
version of the package\.
.
+.SH "CONFIGURATION"
+.
+.SS "json"
+.
+.IP "\(bu" 4
+Default: false
+.
+.IP "\(bu" 4
+Type: Boolean
+.
+.IP "" 0
+.
+.P
+Show information in JSON format\.
+.
+.SS "long"
+.
+.IP "\(bu" 4
+Default: false
+.
+.IP "\(bu" 4
+Type: Boolean
+.
+.IP "" 0
+.
+.P
+Show extended information\.
+.
+.SS "parseable"
+.
+.IP "\(bu" 4
+Default: false
+.
+.IP "\(bu" 4
+Type: Boolean
+.
+.IP "" 0
+.
+.P
+Show parseable output instead of tree view\.
+.
+.SS "global"
+.
+.IP "\(bu" 4
+Default: false
+.
+.IP "\(bu" 4
+Type: Boolean
+.
+.IP "" 0
+.
+.P
+Check packages in the global install prefix instead of in the current
+project\.
+.
+.SS "depth"
+.
+.IP "\(bu" 4
+Type: Int
+.
+.IP "" 0
+.
+.P
+Max depth for checking dependency tree\.
+.
.SH "SEE ALSO"
.
.IP "\(bu" 4
.fi
.
.SH "VERSION"
-1.3.26
+1.4.0
.
.SH "DESCRIPTION"
npm is the package manager for the Node JavaScript platform\. It puts
the issues list or ask on the mailing list\.
.
.IP "\(bu" 4
-\fIhttp://github\.com/isaacs/npm/issues\fR
+\fIhttp://github\.com/npm/npm/issues\fR
.
.IP "\(bu" 4
\fInpm\-@googlegroups\.com\fR
When you find issues, please report them:
.
.IP "\(bu" 4
-web: \fIhttp://github\.com/isaacs/npm/issues\fR
+web: \fIhttp://github\.com/npm/npm/issues\fR
.
.IP "\(bu" 4
email: \fInpm\-@googlegroups\.com\fR
.fi
.
.SH "VERSION"
-1.3.26
+1.4.0
.
.SH "DESCRIPTION"
This is the API documentation for npm\.
.nf
"repository" :
{ "type" : "git"
- , "url" : "http://github\.com/isaacs/npm\.git"
+ , "url" : "http://github\.com/npm/npm\.git"
}
"repository" :
{ "type" : "svn"
.nf
"repository" :
{ "type" : "git"
- , "url" : "http://github\.com/isaacs/npm\.git"
+ , "url" : "http://github\.com/npm/npm\.git"
}
"repository" :
{ "type" : "svn"
string message to the callback\. Stack traces are handy\.
.
.SH "Logging"
-Logging is done using the npmlog \fIhttps://github\.com/isaacs/npmlog\fR
+Logging is done using the npmlog \fIhttps://github\.com/npm/npmlog\fR
utility\.
.
.P
.SS "init\.license"
.
.IP "\(bu" 4
-Default: "BSD\-2\-Clause"
+Default: "ISC"
.
.IP "\(bu" 4
Type: String
.IP "" 0
.
.P
-This is the stream that is passed to the npmlog \fIhttps://github\.com/isaacs/npmlog\fR module at run time\.
+This is the stream that is passed to the npmlog \fIhttps://github\.com/npm/npmlog\fR module at run time\.
.
.P
It cannot be set from the command line, but if you are using npm
.
.P
If the registry IS down, let me know by emailing \fIi@izs\.me\fR or posting
-an issue at \fIhttps://github\.com/isaacs/npm/issues\fR\|\. We\'ll have
+an issue at \fIhttps://github\.com/npm/npm/issues\fR\|\. We\'ll have
someone kick it or something\.
.
.SH "Why no namespaces?"
-Please see this discussion: \fIhttps://github\.com/isaacs/npm/issues/798\fR
+Please see this discussion: \fIhttps://github\.com/npm/npm/issues/798\fR
.
.P
tl;dr \- It doesn\'t actually make things better, and can make them worse\.
Post an issue on the github project:
.
.IP "\(bu" 4
-\fIhttps://github\.com/isaacs/npm/issues\fR
+\fIhttps://github\.com/npm/npm/issues\fR
.
.IP "" 0
.
.P
The official public npm registry is at \fIhttp://registry\.npmjs\.org/\fR\|\. It
is powered by a CouchDB database at \fIhttp://isaacs\.iriscouch\.com/registry\fR\|\. The code for the couchapp is
-available at \fIhttp://github\.com/isaacs/npmjs\.org\fR\|\. npm user accounts
+available at \fIhttp://github\.com/npm/npmjs\.org\fR\|\. npm user accounts
are CouchDB users, stored in the \fIhttp://isaacs\.iriscouch\.com/_users\fR
database\.
.
--- /dev/null
+Copyright (c) Robert Kowalski ("Author")
+All rights reserved.
+
+
+The BSD License
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+This uses parts of npm, (c) Isaac Z. Schlueter, under the following license:
+
+
+The Artistic License 2.0
+
+Copyright (c) 2000-2006, The Perl Foundation.
+
+Everyone is permitted to copy and distribute verbatim copies
+of this license document, but changing it is not allowed.
+
+Preamble
+
+This license establishes the terms under which a given free software
+Package may be copied, modified, distributed, and/or redistributed.
+The intent is that the Copyright Holder maintains some artistic
+control over the development of that Package while still keeping the
+Package available as open source and free software.
+
+You are always permitted to make arrangements wholly outside of this
+license directly with the Copyright Holder of a given Package. If the
+terms of this license do not permit the full use that you propose to
+make of the Package, you should contact the Copyright Holder and seek
+a different licensing arrangement.
+
+Definitions
+
+ "Copyright Holder" means the individual(s) or organization(s)
+ named in the copyright notice for the entire Package.
+
+ "Contributor" means any party that has contributed code or other
+ material to the Package, in accordance with the Copyright Holder's
+ procedures.
+
+ "You" and "your" means any person who would like to copy,
+ distribute, or modify the Package.
+
+ "Package" means the collection of files distributed by the
+ Copyright Holder, and derivatives of that collection and/or of
+ those files. A given Package may consist of either the Standard
+ Version, or a Modified Version.
+
+ "Distribute" means providing a copy of the Package or making it
+ accessible to anyone else, or in the case of a company or
+ organization, to others outside of your company or organization.
+
+ "Distributor Fee" means any fee that you charge for Distributing
+ this Package or providing support for this Package to another
+ party. It does not mean licensing fees.
+
+ "Standard Version" refers to the Package if it has not been
+ modified, or has been modified only in ways explicitly requested
+ by the Copyright Holder.
+
+ "Modified Version" means the Package, if it has been changed, and
+ such changes were not explicitly requested by the Copyright
+ Holder.
+
+ "Original License" means this Artistic License as Distributed with
+ the Standard Version of the Package, in its current version or as
+ it may be modified by The Perl Foundation in the future.
+
+ "Source" form means the source code, documentation source, and
+ configuration files for the Package.
+
+ "Compiled" form means the compiled bytecode, object code, binary,
+ or any other form resulting from mechanical transformation or
+ translation of the Source form.
+
+
+Permission for Use and Modification Without Distribution
+
+(1) You are permitted to use the Standard Version and create and use
+Modified Versions for any purpose without restriction, provided that
+you do not Distribute the Modified Version.
+
+
+Permissions for Redistribution of the Standard Version
+
+(2) You may Distribute verbatim copies of the Source form of the
+Standard Version of this Package in any medium without restriction,
+either gratis or for a Distributor Fee, provided that you duplicate
+all of the original copyright notices and associated disclaimers. At
+your discretion, such verbatim copies may or may not include a
+Compiled form of the Package.
+
+(3) You may apply any bug fixes, portability changes, and other
+modifications made available from the Copyright Holder. The resulting
+Package will still be considered the Standard Version, and as such
+will be subject to the Original License.
+
+
+Distribution of Modified Versions of the Package as Source
+
+(4) You may Distribute your Modified Version as Source (either gratis
+or for a Distributor Fee, and with or without a Compiled form of the
+Modified Version) provided that you clearly document how it differs
+from the Standard Version, including, but not limited to, documenting
+any non-standard features, executables, or modules, and provided that
+you do at least ONE of the following:
+
+ (a) make the Modified Version available to the Copyright Holder
+ of the Standard Version, under the Original License, so that the
+ Copyright Holder may include your modifications in the Standard
+ Version.
+
+ (b) ensure that installation of your Modified Version does not
+ prevent the user installing or running the Standard Version. In
+ addition, the Modified Version must bear a name that is different
+ from the name of the Standard Version.
+
+ (c) allow anyone who receives a copy of the Modified Version to
+ make the Source form of the Modified Version available to others
+ under
+
+ (i) the Original License or
+
+ (ii) a license that permits the licensee to freely copy,
+ modify and redistribute the Modified Version using the same
+ licensing terms that apply to the copy that the licensee
+ received, and requires that the Source form of the Modified
+ Version, and of any works derived from it, be made freely
+ available in that license fees are prohibited but Distributor
+ Fees are allowed.
+
+
+Distribution of Compiled Forms of the Standard Version
+or Modified Versions without the Source
+
+(5) You may Distribute Compiled forms of the Standard Version without
+the Source, provided that you include complete instructions on how to
+get the Source of the Standard Version. Such instructions must be
+valid at the time of your distribution. If these instructions, at any
+time while you are carrying out such distribution, become invalid, you
+must provide new instructions on demand or cease further distribution.
+If you provide valid instructions or cease distribution within thirty
+days after you become aware that the instructions are invalid, then
+you do not forfeit any of your rights under this license.
+
+(6) You may Distribute a Modified Version in Compiled form without
+the Source, provided that you comply with Section 4 with respect to
+the Source of the Modified Version.
+
+
+Aggregating or Linking the Package
+
+(7) You may aggregate the Package (either the Standard Version or
+Modified Version) with other packages and Distribute the resulting
+aggregation provided that you do not charge a licensing fee for the
+Package. Distributor Fees are permitted, and licensing fees for other
+components in the aggregation are permitted. The terms of this license
+apply to the use and Distribution of the Standard or Modified Versions
+as included in the aggregation.
+
+(8) You are permitted to link Modified and Standard Versions with
+other works, to embed the Package in a larger work of your own, or to
+build stand-alone binary or bytecode versions of applications that
+include the Package, and Distribute the result without restriction,
+provided the result does not expose a direct interface to the Package.
+
+
+Items That are Not Considered Part of a Modified Version
+
+(9) Works (including, but not limited to, modules and scripts) that
+merely extend or make use of the Package, do not, by themselves, cause
+the Package to be a Modified Version. In addition, such works are not
+considered parts of the Package itself, and are not subject to the
+terms of this license.
+
+
+General Provisions
+
+(10) Any use, modification, and distribution of the Standard or
+Modified Versions is governed by this Artistic License. By using,
+modifying or distributing the Package, you accept this license. Do not
+use, modify, or distribute the Package, if you do not accept this
+license.
+
+(11) If your Modified Version has been derived from a Modified
+Version made by someone other than you, you are nevertheless required
+to ensure that your Modified Version complies with the requirements of
+this license.
+
+(12) This license does not grant you the right to use any trademark,
+service mark, tradename, or logo of the Copyright Holder.
+
+(13) This license includes the non-exclusive, worldwide,
+free-of-charge patent license to make, have made, use, offer to sell,
+sell, import and otherwise transfer the Package with respect to any
+patent claims licensable by the Copyright Holder that are necessarily
+infringed by the Package. If you institute patent litigation
+(including a cross-claim or counterclaim) against any party alleging
+that the Package constitutes direct or contributory patent
+infringement, then this Artistic License to you shall terminate on the
+date that such litigation is filed.
+
+(14) Disclaimer of Warranty:
+THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS
+IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES. THE IMPLIED
+WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
+NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY YOUR LOCAL
+LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR CONTRIBUTOR WILL
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
+DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE, EVEN IF
+ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--- /dev/null
+# npm-install-checks
+
+A package that contains checks that npm runs during the installation.
+
+## API
+
+### .checkEngine(target, npmVer, nodeVer, force, strict, cb)
+Check if node/npm version is supported by the package.
+
+Error type: `ENOTSUP`
+
+### .checkPlatform(target, force, cb)
+Check if OS/Arch is supported by the package.
+
+Error type: `EBADPLATFORM`
+
+### .checkCycle(target, ancestors, cb)
+Check for cyclic dependencies.
+
+Error type: `ECYCLE`
+
+### .checkGit(folder, cb)
+Check if a folder is a .git folder.
+
+Error type: `EISGIT`
--- /dev/null
+var fs = require("fs")
+var path = require("path")
+var log = require("npmlog")
+var semver = require("semver")
+
+exports.checkEngine = checkEngine
+function checkEngine (target, npmVer, nodeVer, force, strict, cb) {
+ var nodev = force ? null : nodeVer
+ , strict = strict || target.engineStrict
+ , eng = target.engines
+ if (!eng) return cb()
+ if (nodev && eng.node && !semver.satisfies(nodev, eng.node)
+ || eng.npm && !semver.satisfies(npmVer, eng.npm)) {
+
+ if (strict) {
+ var er = new Error("Unsupported")
+ er.code = "ENOTSUP"
+ er.required = eng
+ er.pkgid = target._id
+ return cb(er)
+ } else {
+ log.warn( "engine", "%s: wanted: %j (current: %j)"
+ , target._id, eng, {node: nodev, npm: npmVer} )
+ }
+ }
+ return cb()
+}
+
+exports.checkPlatform = checkPlatform
+function checkPlatform (target, force, cb) {
+ var platform = process.platform
+ , arch = process.arch
+ , osOk = true
+ , cpuOk = true
+
+ if (force) {
+ return cb()
+ }
+
+ if (target.os) {
+ osOk = checkList(platform, target.os)
+ }
+ if (target.cpu) {
+ cpuOk = checkList(arch, target.cpu)
+ }
+ if (!osOk || !cpuOk) {
+ var er = new Error("Unsupported")
+ er.code = "EBADPLATFORM"
+ er.os = target.os || ['any']
+ er.cpu = target.cpu || ['any']
+ er.pkgid = target._id
+ return cb(er)
+ }
+ return cb()
+}
+
+function checkList (value, list) {
+ var tmp
+ , match = false
+ , blc = 0
+ if (typeof list === "string") {
+ list = [list]
+ }
+ if (list.length === 1 && list[0] === "any") {
+ return true
+ }
+ for (var i = 0; i < list.length; ++i) {
+ tmp = list[i]
+ if (tmp[0] === '!') {
+ tmp = tmp.slice(1)
+ if (tmp === value) {
+ return false
+ }
+ ++blc
+ } else {
+ match = match || tmp === value
+ }
+ }
+ return match || blc === list.length
+}
+
+exports.checkCycle = checkCycle
+function checkCycle (target, ancestors, cb) {
+ // there are some very rare and pathological edge-cases where
+ // a cycle can cause npm to try to install a never-ending tree
+ // of stuff.
+ // Simplest:
+ //
+ // A -> B -> A' -> B' -> A -> B -> A' -> B' -> A -> ...
+ //
+ // Solution: Simply flat-out refuse to install any name@version
+ // that is already in the prototype tree of the ancestors object.
+ // A more correct, but more complex, solution would be to symlink
+ // the deeper thing into the new location.
+ // Will do that if anyone whines about this irl.
+ //
+ // Note: `npm install foo` inside of the `foo` package will abort
+ // earlier if `--force` is not set. However, if it IS set, then
+ // we need to still fail here, but just skip the first level. Of
+ // course, it'll still fail eventually if it's a true cycle, and
+ // leave things in an undefined state, but that's what is to be
+ // expected when `--force` is used. That is why getPrototypeOf
+ // is used *twice* here: to skip the first level of repetition.
+
+ var p = Object.getPrototypeOf(Object.getPrototypeOf(ancestors))
+ , name = target.name
+ , version = target.version
+ while (p && p !== Object.prototype && p[name] !== version) {
+ p = Object.getPrototypeOf(p)
+ }
+ if (p[name] !== version) return cb()
+
+ var er = new Error("Unresolvable cycle detected")
+ var tree = [target._id, JSON.parse(JSON.stringify(ancestors))]
+ , t = Object.getPrototypeOf(ancestors)
+ while (t && t !== Object.prototype) {
+ if (t === p) t.THIS_IS_P = true
+ tree.push(JSON.parse(JSON.stringify(t)))
+ t = Object.getPrototypeOf(t)
+ }
+ log.verbose("unresolvable dependency tree", tree)
+ er.pkgid = target._id
+ er.code = "ECYCLE"
+ return cb(er)
+}
+
+exports.checkGit = checkGit
+function checkGit (folder, cb) {
+ // if it's a git repo then don't touch it!
+ fs.lstat(folder, function (er, s) {
+ if (er || !s.isDirectory()) return cb()
+ else checkGit_(folder, cb)
+ })
+}
+
+function checkGit_ (folder, cb) {
+ fs.stat(path.resolve(folder, ".git"), function (er, s) {
+ if (!er && s.isDirectory()) {
+ var e = new Error("Appears to be a git repo or submodule.")
+ e.path = folder
+ e.code = "EISGIT"
+ return cb(e)
+ }
+ cb()
+ })
+}
--- /dev/null
+{
+ "name": "npm-install-checks",
+ "version": "1.0.0",
+ "description": "checks that npm runs during the installation of a module",
+ "main": "index.js",
+ "dependencies": {
+ "npmlog": "0.0.6",
+ "semver": "~2.2.1"
+ },
+ "devDependencies": {
+ "tap": "~0.4.8",
+ "rimraf": "~2.2.5",
+ "mkdirp": "~0.3.5"
+ },
+ "scripts": {
+ "test": "tap test/*.js"
+ },
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/robertkowalski/npm-install-checks.git"
+ },
+ "homepage": "https://github.com/robertkowalski/npm-install-checks",
+ "keywords": [
+ "npm,",
+ "install"
+ ],
+ "author": {
+ "name": "Robert Kowalski",
+ "email": "rok@kowalski.gd"
+ },
+ "license": "BSD-2-Clause",
+ "bugs": {
+ "url": "https://github.com/robertkowalski/npm-install-checks/issues"
+ },
+ "readme": "# npm-install-checks\n\nA package that contains checks that npm runs during the installation.\n\n## API\n\n### .checkEngine(target, npmVer, nodeVer, force, strict, cb)\nCheck if node/npm version is supported by the package.\n\nError type: `ENOTSUP`\n\n### .checkPlatform(target, force, cb)\nCheck if OS/Arch is supported by the package.\n\nError type: `EBADPLATFORM`\n\n### .checkCycle(target, ancestors, cb)\nCheck for cyclic dependencies.\n\nError type: `ECYCLE`\n\n### .checkGit(folder, cb)\nCheck if a folder is a .git folder.\n\nError type: `EISGIT`\n",
+ "readmeFilename": "README.md",
+ "_id": "npm-install-checks@1.0.0",
+ "dist": {
+ "shasum": "7e1469b5e0c693b2ae2a8830b5fc4e7bf76c88fd"
+ },
+ "_from": "npm-install-checks@1.0.0",
+ "_resolved": "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-1.0.0.tgz"
+}
--- /dev/null
+var test = require("tap").test
+var c = require("../index.js").checkEngine
+
+test("no engine defined", function (t) {
+ c({ engines: {}}, "1.1.2", "0.2.1", false, true, function (err) {
+ t.notOk(err, "no error present")
+ t.end()
+ })
+})
+
+test("node version too old", function (t) {
+ var target = { engines: { node: "0.10.24" }}
+ c(target, "1.1.2", "0.10.18", false, true, function (err) {
+ t.ok(err, "returns an error")
+ t.equals(err.required.node, "0.10.24")
+ t.end()
+ })
+})
+
+test("npm version too old", function (t) {
+ var target = { engines: { npm: "1.3.6" }}
+ c(target, "1.4.2", "0.2.1", false, true, function (err) {
+ t.ok(err, "returns an error")
+ t.equals(err.required.npm, "1.3.6")
+ t.end()
+ })
+})
+
+test("strict=false does not return an error", function (t) {
+ var target = { engines: { npm: "1.3.6" }}
+ c(target, "1.4.2", "0.2.1", false, false, function (err) {
+ t.notOk(err, "returns no error")
+ t.end()
+ })
+})
--- /dev/null
+var test = require("tap").test
+var c = require("../index.js").checkGit
+var fs = require("fs")
+var rimraf = require("rimraf")
+var mkdirp = require("mkdirp")
+var path = require("path")
+var gitFixturePath = path.resolve(__dirname, "out")
+
+test("is .git repo", function (t) {
+ mkdirp(gitFixturePath + "/.git", function () {
+ c(gitFixturePath, function (err) {
+ t.ok(err, "error present")
+ t.equal(err.code, "EISGIT")
+ t.end()
+ })
+ })
+})
+
+test("is not a .git repo", function (t) {
+ c(__dirname, function (err) {
+ t.notOk(err, "error not present")
+ t.end()
+ })
+})
+
+test("cleanup", function (t) {
+ rimraf(gitFixturePath, function () {
+ t.pass("cleanup")
+ t.end()
+ })
+})
--- /dev/null
+var test = require("tap").test
+var c = require("../index.js").checkPlatform
+
+test("target cpu wrong", function (t) {
+ var target = {}
+ target.cpu = "enten-cpu"
+ target.os = "any"
+ c(target, false, function (err) {
+ t.ok(err, "error present")
+ t.equal(err.code, "EBADPLATFORM")
+ t.end()
+ })
+})
+
+test("os wrong", function (t) {
+ var target = {}
+ target.cpu = "any"
+ target.os = "enten-os"
+ c(target, false, function (err) {
+ t.ok(err, "error present")
+ t.equal(err.code, "EBADPLATFORM")
+ t.end()
+ })
+})
+
+test("nothing wrong", function (t) {
+ var target = {}
+ target.cpu = "any"
+ target.os = "any"
+ c(target, false, function (err) {
+ t.notOk(err, "no error present")
+ t.end()
+ })
+})
+
+test("force", function (t) {
+ var target = {}
+ target.cpu = "enten-cpu"
+ target.os = "any"
+ c(target, true, function (err) {
+ t.notOk(err, "no error present")
+ t.end()
+ })
+})
var fs = require('fs')
, url = require('url')
, path = require('path')
-, CouchLogin = require('couch-login')
, npmlog
try {
}
if (!conf.get('cache')) throw new Error("Cache dir is required")
-
- var auth = this.conf.get('_auth')
- var alwaysAuth = this.conf.get('always-auth')
- if (auth && !alwaysAuth && registry) {
- // if we're always authing, then we just send the
- // user/pass on every thing. otherwise, create a
- // session, and use that.
- var token = this.conf.get('_token')
- this.couchLogin = new CouchLogin(registry, token)
- this.couchLogin.proxy = this.conf.get('proxy')
- this.couchLogin.strictSSL = this.conf.get('strict-ssl')
- this.couchLogin.ca = this.conf.get('ca')
- this.couchLogin.cert = this.conf.get('cert')
- this.couchLogin.key = this.conf.get('key')
- }
-
this.log = conf.log || conf.get('log') || npmlog
}
function putNext(newVersion, root, current, cb) {
// already have the tardata on the root object
// just merge in existing stuff
- // if the version already exists, and not a --force, then raise error
- var force = this.conf.get('force')
var curVers = Object.keys(current.versions || {}).map(function (v) {
return semver.clean(v, true)
- })
-
- if (!force && curVers.indexOf(newVersion) !== -1) {
- return cb(conflictError(root.name))
+ }).concat(Object.keys(current.time || {}).map(function(v) {
+ if (semver.valid(v, true))
+ return semver.clean(v, true)
+ }).filter(function(v) {
+ return v
+ }))
+
+ if (curVers.indexOf(newVersion) !== -1) {
+ return cb(conflictError(root.name, newVersion))
}
current.versions[newVersion] = root.versions[newVersion]
this.request("PUT", root.name, current, cb)
}
-function conflictError (pkgid) {
- var e = new Error("cannot modify existing version")
+function conflictError (pkgid, version) {
+ var e = new Error("cannot modify pre-existing version")
e.code = "EPUBLISHCONFLICT"
e.pkgid = pkgid
+ e.version = version
return e
}
, request = require("request")
, retry = require("retry")
-function regRequest (method, where, what, etag, nofollow, reauthed, cb_) {
- if (typeof cb_ !== "function") cb_ = reauthed, reauthed = false
+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
, adduserNew = /^\/?-\/user\/org\.couchdb\.user:([^\/]+)/
, nu = where.match(adduserNew)
, uc = where.match(adduserChange)
- , isUpload = what || this.conf.get('always-auth')
+ , alwaysAuth = this.conf.get('always-auth')
, isDel = method === "DELETE"
- , authRequired = isUpload && !nu || uc || isDel
+ , isWrite = what || isDel
+ , authRequired = (alwaysAuth || isWrite) && !nu || uc || isDel
// resolve to a full url on the registry
if (!where.match(/^https?:\/\//)) {
var remote = url.parse(where)
, auth = this.conf.get('_auth')
- if (authRequired && !this.conf.get('always-auth')) {
- var couch = this.couchLogin
- , token = couch && (this.conf.get('_token') || couch.token)
- , validToken = token && couch.valid(token)
-
- if (!validToken) token = null
- else this.conf.set('_token', token)
-
- if (couch && !token) {
- // login to get a valid token
- var a = { name: this.conf.get('username'),
- password: this.conf.get('_password') }
- var args = arguments
- return this.couchLogin.login(a, function (er, cr, data) {
- if (er || !couch.valid(couch.token)) {
- er = er || new Error('login error')
- return cb(er, cr, data)
- }
- this.conf.set('_token', this.couchLogin.token)
- if (this.conf.save) this.conf.save('user')
- return regRequest.call(this,
- method, where, what,
- etag, nofollow, reauthed, cb_)
- }.bind(this))
- }
+ if (authRequired && !auth) {
+ var un = this.conf.get('username')
+ var pw = this.conf.get('_password')
+ if (un && pw)
+ auth = new Buffer(un + ':' + pw).toString('base64')
}
- // now we either have a valid token, or an auth.
-
- if (authRequired && !auth && !token) {
+ if (authRequired && !auth) {
return cb(new Error(
"Cannot insert data into the registry without auth"))
}
- if (auth && !token && authRequired) {
+ if (auth && authRequired) {
remote.auth = new Buffer(auth, "base64").toString("utf8")
}
operation.attempt(function (currentAttempt) {
self.log.info("trying", "registry request attempt " + currentAttempt
+ " at " + (new Date()).toLocaleTimeString())
- makeRequest.call(self, method, remote, where, what, etag, nofollow, token
+ makeRequest.call(self, method, remote, where, what, etag, nofollow
, function (er, parsed, raw, response) {
if (!er || er.message.match(/^SSL Error/)) {
if (er)
// Only retry on 408, 5xx or no `response`.
var statusCode = response && response.statusCode
- var reauth = !reauthed &&
- ( statusCode === 401 ||
- statusCode === 400 ||
- statusCode === 403 )
- if (reauth)
- reauthed = true
-
var timeout = statusCode === 408
var serverError = statusCode >= 500
var statusRetry = !statusCode || timeout || serverError
- if (reauth && this.conf.get('_auth') && this.conf.get('_token')) {
- this.conf.del('_token')
- this.couchLogin.token = null
- return regRequest.call(this, method, where, what,
- etag, nofollow, reauthed, cb_)
- }
if (er && statusRetry && operation.retry(er)) {
self.log.info("retry", "will retry, error on last attempt: " + er)
return
}.bind(this))
}
-function makeRequest (method, remote, where, what, etag, nofollow, tok, cb_) {
+function makeRequest (method, remote, where, what, etag, nofollow, cb_) {
var cbCalled = false
function cb () {
if (cbCalled) return
headers[method === "GET" ? "if-none-match" : "if-match"] = etag
}
- if (tok) {
- headers.cookie = 'AuthSession=' + tok.AuthSession
- }
-
headers.accept = "application/json"
headers["user-agent"] = this.conf.get('user-agent') ||
+++ /dev/null
-test/fixtures/couch.log
-test/fixtures/.delete
-test/fixtures/pid
-test/fixtures/_users.couch
+++ /dev/null
-The ISC License
-
-Copyright (c) Isaac Z. Schlueter
-
-Permission to use, copy, modify, and/or distribute this software for any
-purpose with or without fee is hereby granted, provided that the above
-copyright notice and this permission notice appear in all copies.
-
-THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
-IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+++ /dev/null
-# couch-login
-
-This module lets you log into couchdb to get a session token, then make
-requests using that session. It is basically just a thin wrapper around
-[@mikeal's request module](https://github.com/mikeal/request).
-
-This is handy if you want a user to take actions in a couchdb database
-on behalf of a user, without having to store their couchdb username and
-password anywhere. (You do need to store the AuthSession token
-somewhere, though.)
-
-## Usage
-
-```javascript
-var CouchLogin = require('couch-login')
-
-// Nothing about this module is http-server specific of course.
-// You could also use it to do authenticated requests against
-// a couchdb using sessions and storing the token somewhere else.
-
-http.createServer(function (req, res) {
- var couch = new CouchLogin('http://my-couch.iriscouch.com:5984/')
-
- // .. look up the token in the user's session or whatever ..
- // Look at couch.decorate(req, res) for more on doing that
- // automatically, below.
-
- if (sessionToken) {
- // this user already logged in.
- couch.token = sessionToken
-
- // now we can do things on their behalf, like:
- // 1. View their session info.
- // like doing request.get({ uri: couch + '/_session', ... })
- // but with the cookie and whatnot
-
- couch.get('/_session', function (er, resp, data) {
- // er = some kind of communication error.
- // resp = response object from the couchdb request.
- // data = parsed JSON response body.
- if (er || resp.statusCode !== 200) {
- res.statusCode = resp.statusCode || 403
- return res.end('Invalid login or something')
- }
-
- // now we have the session info, we know who this user is.
- // hitting couchdb for this on every request is kinda costly,
- // so maybe you should store the username wherever you're storing
- // the sessionToken. RedSess is a good util for this, if you're
- // into redis. And if you're not into redis, you're crazy,
- // because it is awesome.
-
- // now let's get the user record.
- // note that this will 404 for anyone other than the user,
- // unless they're a server admin.
- couch.get('/_users/org.couchdb.user:' + data.userCtx.name, etc)
-
- // PUTs and DELETEs will also use their session, of course, so
- // your validate_doc_update's will see their info in userCtx
- })
-
- } else {
- // don't have a sessionToken.
- // get a username and password from the post body or something.
- // maybe redirect to a /login page or something to ask for that.
- var login = { name: name, password: password }
- couch.login(login, function (er, resp, data) {
- // again, er is an error, resp is the response obj, data is the json
- if (er || resp.statusCode !== 200) {
- res.statusCode = resp.statusCode || 403
- return res.end('Invalid login or something')
- }
-
- // the data is something like
- // {"ok":true,"name":"testuser","roles":[]}
- // and couch.token is the token you'll need to save somewhere.
-
- // at this point, you can start making authenticated requests to
- // couchdb, or save data in their session, or do whatever it is
- // that you need to do.
-
- res.statusCode = 200
- res.write("Who's got two thumbs and just logged you into couch?\n")
- setTimeout(function () {
- res.end("THIS GUY!")
- }, 500)
- })
- }
-})
-```
-
-## Class: CouchLogin
-### new CouchLogin(couchdbUrl, token)
-
-Create a new CouchLogin object bound to the couchdb url.
-
-In addition to these, the `get`, `post`, `put`, and `del` methods all
-proxy to the associated method on [request](https://github.com/mikeal/request).
-
-However, as you'll note in the example above, only the pathname portion
-of the url is required. Urls will be appended to the couchdb url passed
-into the constructor.
-
-If you have to talk to more than one couchdb, then you'll need more than
-one CouchLogin object, for somewhat obvious reasons.
-
-All callbacks get called with the following arguments, which are exactly
-identical to the arguments passed to a `request` callback.
-
-* `er` {Error | null} Set if a communication error happens.
-* `resp` {HTTP Response} The response from the request to couchdb
-* `data` {Object} The parsed JSON data from couch
-
-If the token is the string "anonymous", then it will not attempt to log
-in before making requests. If the token is not "anonymous", then it
-must be an object with the appropriate fields.
-
-### couch.token
-
-* {Object}
-
-An object representing the couchdb session token. (Basically just a
-cookie and a timeout.)
-
-If the token has already timed out, then setting it will have no effect.
-
-### couch.tokenSet
-
-If set, this method is called whenever the token is saved.
-
-For example, you could assign a function to this method to save the
-token into a redis session, a cookie, or in some other database.
-
-Takes a callback which should be called when the token is saved.
-
-### couch.tokenGet
-
-If set, this method is called to look up the token on demand.
-
-The inverse of couch.tokenSet. Takes a callback which is called with
-the `cb(er || null, token)`.
-
-### couch.tokenDel
-
-If set, this method is called to delete the token when it should be
-discarded.
-
-Related to tokenGet and tokenSet. Takes a callback which should be
-called when the token is deleted.
-
-### couch.ca
-
-* {String | Array | null}
-
-A certificate authority string (PEM encoded), or an array of CA strings. Only
-relevant for HTTPS couches, of course.
-
-Leave as `null` to use the default ca settings built into node.
-
-### couch.cert
-
-* {String | null}
-
-A client certificate (PEM encoded) used to support secure access to servers that require client certificate. Only
-relevant for HTTPS couches, of course.
-
-Leave as `null` when not supporting client certificates.
-
-### couch.key
-
-* {String | null}
-
-A private key string (PEM encoded) used to validate a client certificate. Only
-relevant for HTTPS couches, of course.
-
-Leave as `null` when not supporting client certificates.
-
-### couch.strictSSL
-
-* {Boolean | null}
-
-Whether or not to be strict about SSL connections. If left as null,
-then use the default setting in node, which is true in node versions
-0.9.x and above, and false prior to 0.8.x.
-
-Only relevant for HTTPS couches, of course.
-
-### couch.anonymous()
-
-Return a new CouchLogin object that points at the same couchdb server,
-but doesn't try to log in before making requests.
-
-This is handy for situations where the user is not logged in at the
-moment, but a request needs to be made anyway, and does not require
-authorization.
-
-### couch.login(auth, callback)
-
-* `auth` {Object} The login details
- * `name` {String}
- * `password` {String}
-* `callback` {Function}
-
-When the callback is called, the `couch.token` will already have been
-set (assuming it worked!), so subsequent requests will be done as that
-user.
-
-### couch.get(path, callback)
-
-GET the supplied path from the couchdb using the credentials on the
-token.
-
-Fails if the token is invalid or expired.
-
-### couch.del(path, callback)
-
-DELETE the supplied path from the couchdb using the credentials on the
-token.
-
-Fails if the token is invalid or expired.
-
-### couch.post(path, data, callback)
-
-POST the data to the supplied path in the couchdb, using the credentials
-on the token.
-
-Fails if the token is invalid or expired.
-
-### couch.put(path, data, callback)
-
-PUT the data to the supplied path in the couchdb, using the credentials
-on the token.
-
-Fails if the token is invalid or expired.
-
-### couch.changePass(newAuth, callback)
-
-Must already be logged in. Updates the `_users` document with new salt
-and hash, and re-logs in with the new credentials. Callback is called
-with the same arguments as login, or the first step of the process that
-failed.
-
-### couch.signup(userData, callback)
-
-Create a new user account. The userData must contain at least a `name`
-and `password` field. Any additional data will be copied to the user
-record. The `_id`, `name`, `roles`, `type`, `password_sha`, `salt`, and
-`date` fields are generated.
-
-Also signs in as the newly created user, on successful account creation.
-
-### couch.deleteAccount(name, callback)
-
-Deletes a user account. If not logged in as the user, or a server
-admin, then the request will fail.
-
-Note that this immediately invalidates any session tokens for the
-deleted user account. If you are deleting the user's record, then you
-ought to follow this with `couch.logout(callback)` so that it won't try
-to re-use the invalid session.
-
-### couch.logout(callback)
-
-Delete the session out of couchdb. This makes the token permanently
-invalid, and deletes it.
-
-### couch.decorate(req, res)
-
-Set up `req.couch` and `res.couch` as references to this couch login
-instance.
-
-Additionall, if `req.session` or `res.session` is set, then it'll call
-`session.get('couch_token', cb)` as the tokenGet method,
-`session.set('couch_token', token, cb)` as the tokenSet method, and
-`session.del('couch_token', cb)` as the tokenDel method.
-
-This works really nice with
-[RedSess](https://github.com/isaacs/redsess).
+++ /dev/null
-var request = require('request')
-, url = require('url')
-, crypto = require('crypto')
-, YEAR = (1000 * 60 * 60 * 24 * 365)
-, BASIC = {}
-, assert = require('assert')
-
-module.exports = CouchLogin
-
-function CouchLogin (couch, tok) {
- if (!(this instanceof CouchLogin)) {
- return new CouchLogin(couch)
- }
-
- if (!couch) throw new Error(
- "Need to pass a couch url to CouchLogin constructor")
-
- if (couch instanceof CouchLogin)
- couch = couch.couch
-
- couch = url.parse(couch)
- if (couch.auth) {
- var a = couch.auth.split(':')
- var name = a.shift()
- var password = a.join(':')
- this.name = name
- if (password)
- this.auth = new Buffer(name + ':' + password).toString('base64')
- } else {
- this.auth = null
- this.name = null
- }
- delete couch.auth
-
- if (tok === 'anonymous')
- tok = NaN
- else if (tok === 'basic')
- tok = BASIC
-
- // ensure that couch url ends with a slash
- couch.pathname = couch.pathname.replace(/\/?$/, '/');
-
- this.token = tok
- this.couch = url.format(couch)
- this.proxy = null
-
- this.maxAge = YEAR
-
- // replace with a CA cert string, or an array, or leave as null
- // to use the defaults included in node. Only relevant for HTTPS
- // couches, of course.
- this.ca = null
-
- // replace these with client certificate and private key if required by
- // the server. Only relevant for HTTPS couches. These are passed to
- // the request and then on to https and tls as-is.
- this.cert = null
- this.key = null
-
- // set to boolean true or false to specify the strictSSL behavior.
- // if left as null, then it'll use whatever node defaults to, which
- // is false <=0.8.x, and true >=0.9.x
- //
- // Again, only relevant for https couches, of course.
- this.strictSSL = null
-}
-
-CouchLogin.prototype =
-{ get: makeReq('GET')
-, del: makeReq('DELETE')
-, put: makeReq('PUT', true)
-, post: makeReq('POST', true)
-, login: login
-, logout: logout
-, decorate: decorate
-, changePass: changePass
-, signup: signup
-, deleteAccount: deleteAccount
-, anon: anon
-, anonymous: anon
-, valid: valid
-}
-
-Object.defineProperty(CouchLogin.prototype, 'constructor',
- { value: CouchLogin, enumerable: false })
-
-function decorate (req, res) {
- assert(this instanceof CouchLogin)
- req.couch = res.couch = this
-
- // backed by some sort of set(k,v,cb), get(k,cb) session storage.
- var session = req.session || res.session || null
- if (session) {
- this.tokenGet = function (cb) {
- session.get('couch_token', cb)
- }
-
- // don't worry about it failing. it'll just mean a login next time.
- this.tokenSet = function (tok, cb) {
- session.set('couch_token', tok, cb || function () {})
- }
-
- this.tokenDel = function (cb) {
- session.del('couch_token', cb || function () {})
- }
- }
-
- return this
-}
-
-function anon () {
- assert(this instanceof CouchLogin)
- return new CouchLogin(this.couch, NaN)
-}
-
-function makeReq (meth, body, f) { return function madeReq (p, d, cb) {
- assert(this instanceof CouchLogin)
- f = f || (this.token !== this.token)
- if (!f && !valid(this.token)) {
- // lazily get the token.
- if (this.tokenGet) return this.tokenGet(function (er, tok) {
- if (er || !valid(tok)) {
- if (!body) cb = d, d = null
- return cb(new Error('auth token expired or invalid'))
- }
- this.token = tok
- return madeReq.call(this, p, d, cb)
- }.bind(this))
-
- // no getter, no token, no business.
- return process.nextTick(function () {
- if (!body) cb = d, d = null
- cb(new Error('auth token expired or invalid'))
- })
- }
-
- if (!body) cb = d, d = null
-
- var h = {}
- , u = url.resolve(this.couch, p.replace(/^\//, ''))
- , req = { uri: u, headers: h, json: true, body: d, method: meth }
-
- if (this.token === BASIC) {
- if (!this.auth)
- return process.nextTick(cb.bind(this, new Error(
- 'Using basic auth and no auth provided')))
- else
- h.authorization = 'Basic ' + this.auth
- } else if (this.token) {
- h.cookie = 'AuthSession=' + this.token.AuthSession
- }
-
- if (this.proxy) {
- req.proxy = this.proxy
- }
-
- // we're handling cookies, don't do it for us.
- req.jar = false
-
- if (this.ca)
- req.ca = this.ca
-
- if (this.cert)
- req.cert = this.cert
- if (this.key)
- req.key = this.key
-
- if (typeof this.strictSSL === 'boolean')
- req.strictSSL = req.rejectUnauthorized = this.strictSSL
-
- request(req, function (er, res, data) {
- // update cookie.
- if (er || res.statusCode !== 200) return cb(er, res, data)
- addToken.call(this, res)
- return cb.call(this, er, res, data)
- }.bind(this))
-}}
-
-function login (auth, cb) {
- assert(this instanceof CouchLogin)
- if (this.token === BASIC) {
- this.auth = new Buffer(auth.name + ':' + auth.password).toString('base64')
- this.name = auth.name
- cb = cb.bind(this, null, { statusCode: 200 }, { ok: true })
- return process.nextTick(cb)
- }
- var a = { name: auth.name, password: auth.password }
- var req = makeReq('post', true, true)
- req.call(this, '/_session', a, function (er, cr, data) {
- if (er || (cr && cr.statusCode >= 400))
- return cb(er, cr, data)
- this.name = auth.name
- cb(er, cr, data)
- }.bind(this))
-}
-
-function changePass (auth, cb) {
- assert(this instanceof CouchLogin)
- if (!auth.name || !auth.password) return cb(new Error('invalid auth'))
-
- var u = '/_users/org.couchdb.user:' + auth.name
- this.get(u, function (er, res, data) {
- if (er || res.statusCode !== 200) return cb(er, res, data)
-
- // copy any other keys we're setting here.
- // note that name, password_sha, salt, and date
- // are all set explicitly below.
- Object.keys(auth).filter(function (k) {
- return k.charAt(0) !== '_'
- && k !== 'password'
- && k !== 'password_sha'
- && k !== 'salt'
- }).forEach(function (k) {
- data[k] = auth[k]
- })
-
- var newSalt = crypto.randomBytes(30).toString('hex')
- , newPass = auth.password
- , newSha = sha(newPass + newSalt)
-
- data.password_sha = newSha
- data.salt = newSalt
- data.date = new Date().toISOString()
-
- this.put(u + '?rev=' + data._rev, data, function (er, res, data) {
- if (er || res.statusCode >= 400)
- return cb(er, res, data)
- if (this.name && this.name !== auth.name)
- return cb(er, res, data)
- return this.login(auth, cb)
- }.bind(this))
- }.bind(this))
-}
-
-// They said that there should probably be a warning before
-// deleting the user's whole account, so here it is:
-//
-// WATCH OUT!
-function deleteAccount (name, cb) {
- assert(this instanceof CouchLogin)
- var u = '/_users/org.couchdb.user:' + name
- this.get(u, thenPut.bind(this))
-
- function thenPut (er, res, data) {
- if (er || res.statusCode !== 200) {
- return cb(er, res, data)
- }
-
- // user accts can't be just DELETE'd by non-admins
- // so we take the existing doc and just slap a _deleted
- // flag on it to fake it. Works the same either way
- // in couch.
- data._deleted = true
- this.put(u + '?rev=' + data._rev, data, cb)
- }
-}
-
-
-
-function signup (auth, cb) {
- assert(this instanceof CouchLogin)
- if (this.token && this.token !== BASIC) {
-
- return this.logout(function (er, res, data) {
- if (er || res && res.statusCode !== 200) {
- return cb(er, res, data)
- }
-
- if (this.token) {
- return cb(new Error('failed to delete token'), res, data)
- }
-
- this.signup(auth, cb)
- }.bind(this))
- }
-
- // make a new user record.
- var newSalt = crypto.randomBytes(30).toString('hex')
- , newSha = sha(auth.password + newSalt)
- , user = { _id: 'org.couchdb.user:' + auth.name
- , name: auth.name
- , roles: []
- , type: 'user'
- , password_sha: newSha
- , salt: newSalt
- , date: new Date().toISOString() }
-
- Object.keys(auth).forEach(function (k) {
- if (k === 'name' || k === 'password') return
- user[k] = auth[k]
- })
-
- var u = '/_users/' + user._id
- makeReq('put', true, true).call(this, u, user, function (er, res, data) {
- if (er || res.statusCode >= 400) {
- return cb(er, res, data)
- }
-
- // it worked! log in as that user and get their record
- this.login(auth, function (er, res, data) {
- if (er || (res && res.statusCode >= 400) || data && data.error) {
- return cb(er, res, data)
- }
- this.get(u, cb)
- }.bind(this))
- }.bind(this))
-}
-
-function addToken (res) {
- assert(this instanceof CouchLogin)
- // not doing the whole login session cookie thing.
- if (this.token === BASIC)
- return
-
- // attach the token, if a new one was provided.
- var sc = res.headers['set-cookie']
- if (!sc) return
- if (!Array.isArray(sc)) sc = [sc]
-
- sc = sc.filter(function (c) {
- return c.match(/^AuthSession=/)
- })[0]
-
- if (!sc.length) return
-
- sc = sc.split(/\s*;\s*/).map(function (p) {
- return p.split('=')
- }).reduce(function (set, p) {
- var k = p[0] === 'AuthSession' ? p[0] : p[0].toLowerCase()
- , v = k === 'expires' ? Date.parse(p[1])
- : p[1] === '' || p[1] === undefined ? true // HttpOnly
- : p[1]
- set[k] = v
- return set
- }, {})
-
- if (sc.hasOwnProperty('max-age')) {
- var ma = sc['max-age']
- sc.expires = (ma <= 0) ? 0 : Date.now() + (ma * 1000)
- delete sc['max-age']
- }
-
- // expire the session after 1 year, even if couch won't.
- if (!sc.hasOwnProperty('expires')) {
- sc.expires = Date.now() + YEAR
- }
-
- if (!isNaN(this.maxAge)) {
- sc.expires = Math.min(sc.expires, Date.now() + this.maxAge)
- }
-
- this.token = sc
- if (this.tokenSet) this.tokenSet(this.token)
-}
-
-
-function logout (cb) {
- assert(this instanceof CouchLogin)
- if (!this.token && this.tokenGet) {
- return this.tokenGet(function (er, tok) {
- if (er || !tok)
- return cb(null, { statusCode: 200 }, {})
- this.token = tok
- this.logout(cb)
- }.bind(this))
- }
-
- if (!valid(this.token)) {
- this.token = null
- if (this.tokenDel) this.tokenDel()
- return process.nextTick(cb.bind(this, null, { statusCode: 200 }, {}))
- }
-
- var h = { cookie: 'AuthSession=' + this.token.AuthSession }
- , u = url.resolve(this.couch, '_session')
- , req = { uri: u, headers: h, json: true }
-
- request.del(req, function (er, res, data) {
- if (er || (res.statusCode !== 200 && res.statusCode !== 404)) {
- return cb(er, res, data)
- }
-
- this.token = null
- if (this.tokenDel)
- this.tokenDel()
- cb(er, res, data)
- }.bind(this))
-}
-
-function valid (token) {
- if (token === BASIC) return true
- if (!token) return false
- if (!token.hasOwnProperty('expires')) return true
- return token.expires > Date.now()
-}
-
-function sha (s) {
- return crypto.createHash("sha1").update(s).digest("hex")
-}
+++ /dev/null
-{
- "author": {
- "name": "Isaac Z. Schlueter",
- "email": "i@izs.me",
- "url": "http://blog.izs.me/"
- },
- "name": "couch-login",
- "description": "A module for doing logged-in requests to a couchdb server",
- "version": "0.1.20",
- "repository": {
- "type": "git",
- "url": "git://github.com/isaacs/couch-login.git"
- },
- "main": "couch-login.js",
- "scripts": {
- "test": "tap test/*.js"
- },
- "dependencies": {
- "request": "2 >=2.25.0"
- },
- "devDependencies": {
- "tap": "~0.2.4"
- },
- "license": "ISC",
- "readme": "# couch-login\n\nThis module lets you log into couchdb to get a session token, then make\nrequests using that session. It is basically just a thin wrapper around\n[@mikeal's request module](https://github.com/mikeal/request).\n\nThis is handy if you want a user to take actions in a couchdb database\non behalf of a user, without having to store their couchdb username and\npassword anywhere. (You do need to store the AuthSession token\nsomewhere, though.)\n\n## Usage\n\n```javascript\nvar CouchLogin = require('couch-login')\n\n// Nothing about this module is http-server specific of course.\n// You could also use it to do authenticated requests against\n// a couchdb using sessions and storing the token somewhere else.\n\nhttp.createServer(function (req, res) {\n var couch = new CouchLogin('http://my-couch.iriscouch.com:5984/')\n\n // .. look up the token in the user's session or whatever ..\n // Look at couch.decorate(req, res) for more on doing that\n // automatically, below.\n\n if (sessionToken) {\n // this user already logged in.\n couch.token = sessionToken\n\n // now we can do things on their behalf, like:\n // 1. View their session info.\n // like doing request.get({ uri: couch + '/_session', ... })\n // but with the cookie and whatnot\n\n couch.get('/_session', function (er, resp, data) {\n // er = some kind of communication error.\n // resp = response object from the couchdb request.\n // data = parsed JSON response body.\n if (er || resp.statusCode !== 200) {\n res.statusCode = resp.statusCode || 403\n return res.end('Invalid login or something')\n }\n\n // now we have the session info, we know who this user is.\n // hitting couchdb for this on every request is kinda costly,\n // so maybe you should store the username wherever you're storing\n // the sessionToken. RedSess is a good util for this, if you're\n // into redis. And if you're not into redis, you're crazy,\n // because it is awesome.\n\n // now let's get the user record.\n // note that this will 404 for anyone other than the user,\n // unless they're a server admin.\n couch.get('/_users/org.couchdb.user:' + data.userCtx.name, etc)\n\n // PUTs and DELETEs will also use their session, of course, so\n // your validate_doc_update's will see their info in userCtx\n })\n\n } else {\n // don't have a sessionToken.\n // get a username and password from the post body or something.\n // maybe redirect to a /login page or something to ask for that.\n var login = { name: name, password: password }\n couch.login(login, function (er, resp, data) {\n // again, er is an error, resp is the response obj, data is the json\n if (er || resp.statusCode !== 200) {\n res.statusCode = resp.statusCode || 403\n return res.end('Invalid login or something')\n }\n\n // the data is something like\n // {\"ok\":true,\"name\":\"testuser\",\"roles\":[]}\n // and couch.token is the token you'll need to save somewhere.\n\n // at this point, you can start making authenticated requests to\n // couchdb, or save data in their session, or do whatever it is\n // that you need to do.\n\n res.statusCode = 200\n res.write(\"Who's got two thumbs and just logged you into couch?\\n\")\n setTimeout(function () {\n res.end(\"THIS GUY!\")\n }, 500)\n })\n }\n})\n```\n\n## Class: CouchLogin\n### new CouchLogin(couchdbUrl, token)\n\nCreate a new CouchLogin object bound to the couchdb url.\n\nIn addition to these, the `get`, `post`, `put`, and `del` methods all\nproxy to the associated method on [request](https://github.com/mikeal/request).\n\nHowever, as you'll note in the example above, only the pathname portion\nof the url is required. Urls will be appended to the couchdb url passed\ninto the constructor.\n\nIf you have to talk to more than one couchdb, then you'll need more than\none CouchLogin object, for somewhat obvious reasons.\n\nAll callbacks get called with the following arguments, which are exactly\nidentical to the arguments passed to a `request` callback.\n\n* `er` {Error | null} Set if a communication error happens.\n* `resp` {HTTP Response} The response from the request to couchdb\n* `data` {Object} The parsed JSON data from couch\n\nIf the token is the string \"anonymous\", then it will not attempt to log\nin before making requests. If the token is not \"anonymous\", then it\nmust be an object with the appropriate fields.\n\n### couch.token\n\n* {Object}\n\nAn object representing the couchdb session token. (Basically just a\ncookie and a timeout.)\n\nIf the token has already timed out, then setting it will have no effect.\n\n### couch.tokenSet\n\nIf set, this method is called whenever the token is saved.\n\nFor example, you could assign a function to this method to save the\ntoken into a redis session, a cookie, or in some other database.\n\nTakes a callback which should be called when the token is saved.\n\n### couch.tokenGet\n\nIf set, this method is called to look up the token on demand.\n\nThe inverse of couch.tokenSet. Takes a callback which is called with\nthe `cb(er || null, token)`.\n\n### couch.tokenDel\n\nIf set, this method is called to delete the token when it should be\ndiscarded.\n\nRelated to tokenGet and tokenSet. Takes a callback which should be\ncalled when the token is deleted.\n\n### couch.ca\n\n* {String | Array | null}\n\nA certificate authority string (PEM encoded), or an array of CA strings. Only\nrelevant for HTTPS couches, of course.\n\nLeave as `null` to use the default ca settings built into node.\n\n### couch.cert\n\n* {String | null}\n\nA client certificate (PEM encoded) used to support secure access to servers that require client certificate. Only\nrelevant for HTTPS couches, of course.\n\nLeave as `null` when not supporting client certificates.\n\n### couch.key\n\n* {String | null}\n\nA private key string (PEM encoded) used to validate a client certificate. Only\nrelevant for HTTPS couches, of course.\n\nLeave as `null` when not supporting client certificates.\n\n### couch.strictSSL\n\n* {Boolean | null}\n\nWhether or not to be strict about SSL connections. If left as null,\nthen use the default setting in node, which is true in node versions\n0.9.x and above, and false prior to 0.8.x.\n\nOnly relevant for HTTPS couches, of course.\n\n### couch.anonymous()\n\nReturn a new CouchLogin object that points at the same couchdb server,\nbut doesn't try to log in before making requests.\n\nThis is handy for situations where the user is not logged in at the\nmoment, but a request needs to be made anyway, and does not require\nauthorization.\n\n### couch.login(auth, callback)\n\n* `auth` {Object} The login details\n * `name` {String}\n * `password` {String}\n* `callback` {Function}\n\nWhen the callback is called, the `couch.token` will already have been\nset (assuming it worked!), so subsequent requests will be done as that\nuser.\n\n### couch.get(path, callback)\n\nGET the supplied path from the couchdb using the credentials on the\ntoken.\n\nFails if the token is invalid or expired.\n\n### couch.del(path, callback)\n\nDELETE the supplied path from the couchdb using the credentials on the\ntoken.\n\nFails if the token is invalid or expired.\n\n### couch.post(path, data, callback)\n\nPOST the data to the supplied path in the couchdb, using the credentials\non the token.\n\nFails if the token is invalid or expired.\n\n### couch.put(path, data, callback)\n\nPUT the data to the supplied path in the couchdb, using the credentials\non the token.\n\nFails if the token is invalid or expired.\n\n### couch.changePass(newAuth, callback)\n\nMust already be logged in. Updates the `_users` document with new salt\nand hash, and re-logs in with the new credentials. Callback is called\nwith the same arguments as login, or the first step of the process that\nfailed.\n\n### couch.signup(userData, callback)\n\nCreate a new user account. The userData must contain at least a `name`\nand `password` field. Any additional data will be copied to the user\nrecord. The `_id`, `name`, `roles`, `type`, `password_sha`, `salt`, and\n`date` fields are generated.\n\nAlso signs in as the newly created user, on successful account creation.\n\n### couch.deleteAccount(name, callback)\n\nDeletes a user account. If not logged in as the user, or a server\nadmin, then the request will fail.\n\nNote that this immediately invalidates any session tokens for the\ndeleted user account. If you are deleting the user's record, then you\nought to follow this with `couch.logout(callback)` so that it won't try\nto re-use the invalid session.\n\n### couch.logout(callback)\n\nDelete the session out of couchdb. This makes the token permanently\ninvalid, and deletes it.\n\n### couch.decorate(req, res)\n\nSet up `req.couch` and `res.couch` as references to this couch login\ninstance.\n\nAdditionall, if `req.session` or `res.session` is set, then it'll call\n`session.get('couch_token', cb)` as the tokenGet method,\n`session.set('couch_token', token, cb)` as the tokenSet method, and\n`session.del('couch_token', cb)` as the tokenDel method.\n\nThis works really nice with\n[RedSess](https://github.com/isaacs/redsess).\n",
- "readmeFilename": "README.md",
- "bugs": {
- "url": "https://github.com/isaacs/couch-login/issues"
- },
- "homepage": "https://github.com/isaacs/couch-login",
- "_id": "couch-login@0.1.20",
- "_from": "couch-login@~0.1.18"
-}
+++ /dev/null
-// start the couchdb spinning as a detached child process.
-// the zz-teardown.js test kills it.
-//
-// localhost:15985 ==> couchdb
-// 127.0.0.1:15985 ==> npm registry
-
-var spawn = require('child_process').spawn
-var test = require('tap').test
-var path = require('path')
-var fs = require('fs')
-var request = require('request')
-
-// run with the cwd of the main program.
-var cwd = path.dirname(__dirname)
-
-var conf = path.resolve(__dirname, 'fixtures', 'couch.ini')
-var pidfile = path.resolve(__dirname, 'fixtures', 'pid')
-var logfile = path.resolve(__dirname, 'fixtures', 'couch.log')
-var started = /Apache CouchDB has started on http:\/\/127\.0\.0\.1:15985\/\n$/
-
-test('start couch as a zombie child', function (t) {
- var fd = fs.openSync(pidfile, 'wx')
-
- try { fs.unlinkSync(logfile) } catch (er) {}
-
- var child = spawn('couchdb', ['-a', conf], {
- detached: true,
- stdio: 'ignore',
- cwd: cwd
- })
- child.unref()
- t.ok(child.pid)
- fs.writeSync(fd, child.pid + '\n')
- fs.closeSync(fd)
-
- // wait for it to create a log, give it 5 seconds
- var start = Date.now()
- fs.readFile(logfile, function R (er, log) {
- log = log ? log.toString() : ''
- if (!er && !log.match(started))
- er = new Error('not started yet')
- if (er) {
- if (Date.now() - start < 5000)
- return setTimeout(function () {
- fs.readFile(logfile, R)
- }, 100)
- else
- throw er
- }
- t.pass('relax')
- t.end()
- })
-})
-
-// set up the testuser account that we'll be using everywhere.
-// first delete any existing one, so that we don't end up with
-// some newer copy taking over.
-test('create testuser', function (t) {
- var u = 'http://admin:admin@localhost:15985/_users/org.couchdb.user:testuser'
- var rev
-
- request.get({ url: u, json: true }, function (er, res, data) {
- if (er)
- throw er
- rev = data._rev
- if (res.statusCode === 404)
- put()
- else
- del()
- })
-
- function del () {
- request.del(u + '?rev=' + rev, function (er, res, data) {
- if (er)
- throw er
- put()
- })
- }
-
- function put () {
- request.put({
- url: u,
- body: {
- _id: 'org.couchdb.user:testuser',
- name: 'testuser',
- roles: [],
- type: 'user',
- password_sha: 'e23952b517695e6bb72ecf060e10bf1b35bf7e0b',
- salt: '83695c9b64d3b48b94c9dda0cd691e72',
- date: '2012-09-26T16:49:30.175Z'
- },
- json: true
- }, function (er, res, data) {
- if (er)
- throw er
- t.ok(data.ok, 'user created')
- t.end()
- })
- }
-})
+++ /dev/null
-var tap = require('tap')
-, CouchLogin = require('../couch-login.js')
-
-var auth = { name: 'testuser', password: 'test' }
-, newAuth = { name: 'testuser', password: 'asdfasdf' }
-, couch = new CouchLogin('http://localhost:15985/')
-, u = '/_users/org.couchdb.user:' + auth.name
-, userRecordMarker
-
-// simulate the 'must change password on next login' thing
-newAuth.mustChangePass = true
-auth.mustChangePass = false
-
-
-function okStatus (t, res) {
- var x = { found: res.statusCode, wanted: 'around 200' }
- var r = res.statusCode
- x.ok = (r >= 200 && r < 300)
- return t.ok(x.ok, 'Status code should be 200-ish', x)
-}
-
-tap.test('login', function (t) {
- couch.login(auth, function (er, res, data) {
- t.ifError(er)
- if (er) return t.end()
- okStatus(t, res)
- t.deepEqual(data, { ok: true, name: 'testuser', roles: [] })
- t.ok(couch.token)
- t.deepEqual(couch.token,
- { AuthSession: couch.token && couch.token.AuthSession,
- version: '1',
- expires: couch.token && couch.token.expires,
- path: '/',
- httponly: true })
- t.ok(couch.token, 'has token')
- t.end()
- })
-})
-
-var userRecord
-tap.test('get', function (t) {
- couch.get(u, function (er, res, data) {
- t.ifError(er)
- if (er) return t.end()
- t.ok(data, 'data')
- t.ok(couch.token, 'token')
- userRecord = data
- okStatus(t, res)
- t.end()
- })
-})
-
-var userRecordMarker = require('crypto').randomBytes(30).toString('base64')
-tap.test('add key to user record', function (t) {
- userRecord.testingCouchLogin = userRecordMarker
- var revved = u + '?rev=' + userRecord._rev
- couch.put(revved, userRecord, function (er, res, data) {
- t.ifError(er)
- if (er) return t.end()
- okStatus(t, res)
- t.ok(data, 'data')
- t.ok(couch.token, 'token')
- // get again so we have the current rev
- couch.get(u, function (er, res, data) {
- t.ifError(er)
- if (er) return t.end()
- okStatus(t, res)
- t.ok(data)
- t.ok(userRecord)
- t.equal(data.testingCouchLogin, userRecord.testingCouchLogin)
- userRecord = data
- t.end()
- })
- })
-})
-
-tap.test('remove key', function (t) {
- var revved = u + '?rev=' + userRecord._rev
- delete userRecord.testingCouchLogin
- couch.put(revved, userRecord, function (er, res, data) {
- t.ifError(er)
- if (er) return t.end()
- okStatus(t, res)
- t.ok(couch.token, 'token')
- couch.get(u, function (er, res, data) {
- t.ifError(er)
- if (er) return t.end()
- okStatus(t, res)
- t.ok(data, 'data')
- t.ok(couch.token, 'token')
- t.equal(data.testingCouchLogin, undefined)
- userRecord = data
- t.end()
- })
- })
-})
-
-var crypto = require('crypto')
-function sha (s) {
- return crypto.createHash("sha1").update(s).digest("hex")
-}
-
-tap.test('change password manually', function (t) {
- var revved = u + '?rev=' + userRecord._rev
- , newPass = newAuth.password
- , newSalt = 'test-salt-two'
- , newSha = sha(newPass + newSalt)
-
- userRecord.salt = newSalt
- userRecord.password_sha = newSha
- couch.put(revved, userRecord, function (er, res, data) {
- t.ifError(er)
- if (er) return t.end()
- okStatus(t, res)
-
- // changing password invalidates session.
- // need to re-login
- couch.login(newAuth, function (er, res, data) {
- t.ifError(er)
- if (er) return t.end()
- okStatus(t, res)
-
- couch.get(u, function (er, res, data) {
- t.ifError(er)
- if (er) return t.end()
- okStatus(t, res)
- t.ok(data, 'data')
- t.ok(couch.token, 'token')
- t.equal(data.testingCouchLogin, undefined)
- userRecord = data
- t.end()
- })
- })
- })
-})
-
-tap.test('change password back manually', function (t) {
- var revved = u + '?rev=' + userRecord._rev
- , newPass = auth.password
- , newSalt = 'test-salt'
- , newSha = sha(newPass + newSalt)
-
- userRecord.salt = newSalt
- userRecord.password_sha = newSha
- couch.put(revved, userRecord, function (er, res, data) {
- t.ifError(er)
- if (er) return t.end()
- okStatus(t, res)
- t.ok(data, 'data')
- t.ok(couch.token, 'token')
-
- couch.login(auth, function (er, res, data) {
- t.ifError(er)
- if (er) return t.end()
- okStatus(t, res)
-
- couch.get(u, function (er, res, data) {
- t.ifError(er)
- if (er) return t.end()
- okStatus(t, res)
- t.ok(data, 'data')
- t.ok(couch.token, 'token')
- userRecord = data
- t.end()
- })
- })
- })
-})
-
-tap.test('change password easy', function (t) {
- couch.changePass(newAuth, function (er, res, data) {
- t.ifError(er)
- if (er) return t.end()
- okStatus(t, res)
-
- couch.get(u, function (er, res, data) {
- t.ifError(er)
- if (er) return t.end()
- okStatus(t, res)
- t.ok(data, 'data')
- t.ok(couch.token, 'token')
- t.equal(data.testingCouchLogin, undefined)
- t.equal(data.mustChangePass, true)
- userRecord = data
- t.end()
- })
- })
-})
-
-tap.test('change password back easy', function (t) {
- couch.changePass(auth, function (er, res, data) {
- t.ifError(er)
- if (er) return t.end()
- okStatus(t, res)
-
- couch.get(u, function (er, res, data) {
- t.ifError(er)
- if (er) return t.end()
- okStatus(t, res)
- t.ok(data, 'data')
- t.ok(couch.token, 'token')
- t.equal(data.testingCouchLogin, undefined)
- t.equal(data.mustChangePass, false)
- userRecord = data
- t.end()
- })
- })
-})
-
-
-tap.test('logout', function (t) {
- couch.logout(function (er, res, data) {
- t.ifError(er)
- if (er) return t.end()
- okStatus(t, res)
- t.ok(data, 'data')
- t.notOk(couch.token, 'token')
- t.end()
- })
-})
-
-// now try some logged out monkey business!
-tap.test('logged out post', function (t) {
- couch.post('/yeah-right', {foo: 100}, function (er, res, data) {
- t.ok(er, 'should get an error')
- t.notOk(couch.token, 'token')
- t.end()
- })
-})
-
-tap.test('anonymous put', function (t) {
- var guy = couch.anonymous()
- guy.put('/remember', {november:5}, function (er, res, data) {
- t.ifError(er)
- if (er) return t.end()
- t.equal(res.statusCode, 401)
- t.deepEqual(data, { error: 'unauthorized'
- , reason: 'You are not a server admin.' })
- t.end()
- })
-})
-
-tap.test('anonymous get', function (t) {
- var guy = couch.anonymous()
- guy.get('/', function (er, res, data) {
- t.ifError(er)
- if (er) return t.end()
- t.equal(res.statusCode, 200)
- t.has(data, { couchdb: 'Welcome' })
- t.ok(data.version)
- t.end()
- })
-})
-
-
-
-var signupUser = { name: 'test-user-signup', password: 'signup-test' }
-
-tap.test('sign up as new user', function (t) {
- couch.signup(signupUser, function (er, res, data) {
- t.ifError(er)
- if (er) return t.end()
- okStatus(t, res)
- t.ok(data, 'data')
- t.has(data,
- { _id: 'org.couchdb.user:test-user-signup',
- name: 'test-user-signup',
- roles: [],
- type: 'user' })
- t.ok(data._rev, 'rev')
- t.ok(data.date, 'date')
- t.ok(data.password_sha, 'hash')
- t.ok(data.salt, 'salt')
- t.ok(couch.token, 'token')
- // now delete account
- var name = signupUser.name
- couch.deleteAccount(name, function (er, res, data) {
- t.ifError(er, 'should be no error deleting account')
- if (er) return t.end()
- okStatus(t, res)
- t.ok(data, 'data')
- t.end()
- })
- })
-})
-
-tap.test('using basic auth', function (t) {
- var c = new CouchLogin(couch.couch, 'basic')
- c.login(auth, function () {
- c.get('/_users/org.couchdb.user:testuser', function (er, res, data) {
- if (er)
- throw er
- okStatus(t, res)
- t.ok(data, 'data')
- t.end()
- })
- })
-})
+++ /dev/null
-[couchdb]
-database_dir = test/fixtures
-view_index_dir = test/fixtures
-uuid = 3ec49bc6c314484cb21d684dc3fc778e
-
-[httpd]
-port = 15985
-bind_address = 127.0.0.1
-secure_rewrites = false
-allow_jsonp = true
-config_whitelist = [{uuids,algorithm},{vhosts,"*"},{admins,"*"},{log,level},{httpd,allow_jsonp},{httpd,secure_rewrites},{httpd,mobile_futon},{httpd,sammy_futon},{httpd,cors},{httpd,x_forwarded_host},{httpd,'WWW-Authenticate'},{cors,"*"},{compactions,"*"},{replicator,db},{attachments,compression_level},{attachments,compressible_types},{couch_httpd_auth,authentication_db},{couch_httpd_auth,allow_persistent_cookies},{couch_httpd_auth,authentication_redirect},{couch_httpd_auth,require_valid_user},{couch_httpd_auth,timeout},{couch_httpd_auth,secret},{couchdb,os_process_timeout},{query_server_config,reduce_limit},{couch_httpd_oauth,"*"},{oauth_token_users,"*"},{oauth_token_secrets,"*"},{oauth_consumer_secrets,"*"},{browserid,enabled},{browserid,hash_secret},{fb,"*"}]
-
-[log]
-file = test/fixtures/couch.log
-
-[admins]
-admin = -hashed-b933598b0ade0e4c2a258d53c95990d5939461dd,a44895e5740b79d14b392ada8021d31d
-
-[couch_httpd_auth]
-secret = cafebad000deadbeef00000019790701
-timeout = 36000
-allow_persistent_cookies = true
-
-[vhosts]
-127.0.0.1:15985 = /registry/_design/ghost/_rewrite
+++ /dev/null
-// Should be able to use this module to log into the registry, as well.
-
-var tap = require('tap')
-, CouchLogin = require('../couch-login.js')
-
-var auth = { name: 'testuser', password: 'test' }
-, newAuth = { name: 'testuser', password: 'asdfasdf' }
-, couch = new CouchLogin('http://127.0.0.1:15985/')
-, u = '/_users/org.couchdb.user:' + auth.name
-, userRecordMarker
-
-// simulate the 'must change password on next login' thing
-newAuth.mustChangePass = true
-auth.mustChangePass = false
-
-
-function okStatus (t, res) {
- var x = { found: res.statusCode, wanted: 'around 200' }
- var r = res.statusCode
- x.ok = (r >= 200 && r < 300)
- return t.ok(x.ok, 'Status code should be 200-ish', x)
-}
-
-tap.test('login', function (t) {
- couch.login(auth, function (er, res, data) {
- t.ifError(er)
- if (er) return t.end()
- okStatus(t, res)
- t.deepEqual(data, { ok: true, name: 'testuser', roles: [] })
- t.ok(couch.token)
- t.deepEqual(couch.token,
- { AuthSession: couch.token && couch.token.AuthSession,
- version: '1',
- expires: couch.token && couch.token.expires,
- path: '/',
- httponly: true })
- t.ok(couch.token, 'has token')
- t.end()
- })
-})
-
-var userRecord
-tap.test('get', function (t) {
- couch.get(u, function (er, res, data) {
- t.ifError(er)
- if (er) return t.end()
- t.ok(data, 'data')
- t.ok(couch.token, 'token')
- userRecord = data
- okStatus(t, res)
- t.end()
- })
-})
-
-var userRecordMarker = require('crypto').randomBytes(30).toString('base64')
-tap.test('add key to user record', function (t) {
- userRecord.testingCouchLogin = userRecordMarker
- var revved = u + '?rev=' + userRecord._rev
- couch.put(revved, userRecord, function (er, res, data) {
- t.ifError(er)
- if (er) return t.end()
- okStatus(t, res)
- t.ok(data, 'data')
- t.ok(couch.token, 'token')
- // get again so we have the current rev
- couch.get(u, function (er, res, data) {
- t.ifError(er)
- if (er) return t.end()
- okStatus(t, res)
- t.ok(data)
- t.ok(userRecord)
- t.equal(data.testingCouchLogin, userRecord.testingCouchLogin)
- userRecord = data
- t.end()
- })
- })
-})
-
-tap.test('remove key', function (t) {
- var revved = u + '?rev=' + userRecord._rev
- delete userRecord.testingCouchLogin
- couch.put(revved, userRecord, function (er, res, data) {
- t.ifError(er)
- if (er) return t.end()
- okStatus(t, res)
- t.ok(couch.token, 'token')
- couch.get(u, function (er, res, data) {
- t.ifError(er)
- if (er) return t.end()
- okStatus(t, res)
- t.ok(data, 'data')
- t.ok(couch.token, 'token')
- t.equal(data.testingCouchLogin, undefined)
- userRecord = data
- t.end()
- })
- })
-})
-
-var crypto = require('crypto')
-function sha (s) {
- return crypto.createHash("sha1").update(s).digest("hex")
-}
-
-tap.test('change password manually', function (t) {
- var revved = u + '?rev=' + userRecord._rev
- , newPass = newAuth.password
- , newSalt = 'test-salt-two'
- , newSha = sha(newPass + newSalt)
-
- userRecord.salt = newSalt
- userRecord.password_sha = newSha
- couch.put(revved, userRecord, function (er, res, data) {
- t.ifError(er)
- if (er) return t.end()
- okStatus(t, res)
-
- // changing password invalidates session.
- // need to re-login
- couch.login(newAuth, function (er, res, data) {
- t.ifError(er)
- if (er) return t.end()
- okStatus(t, res)
-
- couch.get(u, function (er, res, data) {
- t.ifError(er)
- if (er) return t.end()
- okStatus(t, res)
- t.ok(data, 'data')
- t.ok(couch.token, 'token')
- t.equal(data.testingCouchLogin, undefined)
- userRecord = data
- t.end()
- })
- })
- })
-})
-
-tap.test('change password back manually', function (t) {
- var revved = u + '?rev=' + userRecord._rev
- , newPass = auth.password
- , newSalt = 'test-salt'
- , newSha = sha(newPass + newSalt)
-
- userRecord.salt = newSalt
- userRecord.password_sha = newSha
- couch.put(revved, userRecord, function (er, res, data) {
- t.ifError(er)
- if (er) return t.end()
- okStatus(t, res)
- t.ok(data, 'data')
- t.ok(couch.token, 'token')
-
- couch.login(auth, function (er, res, data) {
- t.ifError(er)
- if (er) return t.end()
- okStatus(t, res)
-
- couch.get(u, function (er, res, data) {
- t.ifError(er)
- if (er) return t.end()
- okStatus(t, res)
- t.ok(data, 'data')
- t.ok(couch.token, 'token')
- userRecord = data
- t.end()
- })
- })
- })
-})
-
-tap.test('change password easy', function (t) {
- couch.changePass(newAuth, function (er, res, data) {
- t.ifError(er)
- if (er) return t.end()
- okStatus(t, res)
-
- couch.get(u, function (er, res, data) {
- t.ifError(er)
- if (er) return t.end()
- okStatus(t, res)
- t.ok(data, 'data')
- t.ok(couch.token, 'token')
- t.equal(data.testingCouchLogin, undefined)
- t.equal(data.mustChangePass, true)
- userRecord = data
- t.end()
- })
- })
-})
-
-tap.test('change password back easy', function (t) {
- couch.changePass(auth, function (er, res, data) {
- t.ifError(er)
- if (er) return t.end()
- okStatus(t, res)
-
- couch.get(u, function (er, res, data) {
- t.ifError(er)
- if (er) return t.end()
- okStatus(t, res)
- t.ok(data, 'data')
- t.ok(couch.token, 'token')
- t.equal(data.testingCouchLogin, undefined)
- t.notOk(data.mustChangePass)
- userRecord = data
- t.end()
- })
- })
-})
-
-
-tap.test('logout', function (t) {
- couch.logout(function (er, res, data) {
- t.ifError(er)
- if (er) return t.end()
- okStatus(t, res)
- t.ok(data, 'data')
- t.notOk(couch.token, 'token')
- t.end()
- })
-})
-
-var signupUser = { name: 'test-user-signup', password: 'signup-test' }
-
-tap.test('sign up as new user', function (t) {
- couch.signup(signupUser, function (er, res, data) {
- t.ifError(er)
- if (er) return t.end()
- okStatus(t, res)
- t.ok(data, 'data')
- t.has(data,
- { _id: 'org.couchdb.user:test-user-signup',
- name: 'test-user-signup',
- roles: [],
- type: 'user' })
- t.ok(data._rev, 'rev')
- t.ok(data.date, 'date')
- t.ok(data.password_sha, 'hash')
- t.ok(data.salt, 'salt')
- t.ok(couch.token, 'token')
- // now delete account
- var name = signupUser.name
- couch.deleteAccount(name, function (er, res, data) {
- t.ifError(er, 'should be no error deleting account')
- if (er) return t.end()
- okStatus(t, res)
- t.ok(data, 'data')
- t.end()
- })
- })
-})
+++ /dev/null
-var test = require('tap').test
-var CouchLogin = require('../couch-login.js')
-
-var auth = { name: 'testuser', password: 'test' }
-, newAuth = { name: 'testuser', password: 'asdf', mustChangePass: true }
-, db = 'http://localhost:15985/'
-, couch = new CouchLogin(db)
-, u = '/_users/org.couchdb.user:' + auth.name
-, admin = { name: 'admin', password: 'admin' }
-, newUser = { name: 'testuser', password: 'test' }
-, newUserCouch = null
-, authToken = null
-
-newUser.name += Math.floor(Math.random() * 1E9)
-
-var okGlobal = Object.keys(global)
-
-var adminCouch = new CouchLogin(db, 'basic')
-
-function okStatus (t, res) {
- var x = { found: res.statusCode, wanted: 'around 200' }
- var r = res.statusCode
- x.ok = (r >= 200 && r < 300)
- return t.ok(x.ok, 'Status code should be 200-ish', x)
-}
-
-test('adminCouch login', function (t) {
- t.deepEqual(Object.keys(global), okGlobal)
- console.error('adminCouch login')
- adminCouch.login(admin, function (er, res, data) {
- if (er)
- throw er
- okStatus(t, res)
- t.ok(data)
- t.end()
- })
-})
-
-test('get the user data as admin', function (t) {
- t.deepEqual(Object.keys(global), okGlobal)
- console.error('2')
- adminCouch.get(u, function (er, res, data) {
- if (er)
- throw er
- okStatus(t, res)
- t.ok(data)
- t.end()
- })
-})
-
-test('admin user changes the password for non-admin user', function (t) {
- console.error(3)
- t.deepEqual(Object.keys(global), okGlobal)
- adminCouch.changePass(newAuth, function (er, res, data) {
- if (er)
- throw er
- okStatus(t, res)
- t.ok(data)
- t.end()
- })
-})
-
-test('testuser logs in', function (t) {
- console.error(4)
- t.deepEqual(Object.keys(global), okGlobal)
- couch.login(newAuth, function (er, res, data) {
- if (er)
- throw er
- okStatus(t, res)
- t.deepEqual(data, { ok: true, name: 'testuser', roles: [] })
- authToken = couch.token
- t.end()
- })
-})
-
-// test('testuser changes password', function (t) {
-// couch = new CouchLogin(db)
-// couch.token = authToken
-// couch.changePass(auth, function (er, res, data) {
-// if (er)
-// throw er
-// okStatus(t, res)
-// console.error(data)
-// t.ok(data)
-// t.end()
-// })
-// })
-
-test('new user signup', function (t) {
- t.deepEqual(Object.keys(global), okGlobal)
- newUserCouch = new CouchLogin(db)
- newUserCouch.signup(newUser, function (er, res, data) {
- if (er)
- throw er
- okStatus(t, res)
- console.error(data)
- t.ok(data)
- t.end()
- })
-})
-
-test('delete newUser account', function (t) {
- t.deepEqual(Object.keys(global), okGlobal)
- newUserCouch.deleteAccount(newUser.name, function (er, res, data) {
- if (er)
- throw er
- okStatus(t, res)
- console.error(data)
- t.ok(data)
- t.end()
- })
-})
+++ /dev/null
-// kill the couchdb process that's running as a detached child process
-// started by the 00-setup.js test
-
-var fs = require('fs')
-var test = require('tap').test
-var path = require('path')
-var pidfile = path.resolve(__dirname, 'fixtures', 'pid')
-var _users = path.resolve(__dirname, 'fixtures', '_users.couch')
-
-test('kill all the users', function (t) {
- fs.unlinkSync(_users)
- t.pass('_users db deleted')
- t.end()
-})
-
-test('craigslist (well, how do you get rid of YOUR couches?)', function (t) {
- var pid = fs.readFileSync(pidfile)
- fs.unlinkSync(pidfile)
- process.kill(pid)
- t.pass('couch is no more')
- t.end()
-})
-
},
"name": "npm-registry-client",
"description": "Client for the npm registry",
- "version": "0.3.5",
+ "version": "0.4.0",
"repository": {
"url": "git://github.com/isaacs/npm-registry-client"
},
"mkdirp": "~0.3.3",
"rimraf": "~2",
"retry": "0.6.0",
- "couch-login": "~0.1.18",
"npmlog": ""
},
"devDependencies": {
"url": "https://github.com/isaacs/npm-registry-client/issues"
},
"homepage": "https://github.com/isaacs/npm-registry-client",
- "_id": "npm-registry-client@0.3.5",
+ "_id": "npm-registry-client@0.4.0",
"dist": {
- "shasum": "98ba1ac851a3939a3fb9917c28fa8da522dc635f"
+ "shasum": "30d0c178b7f2e54183a6a3fc9fe4071eb10290bf"
},
- "_from": "npm-registry-client@0.3.5",
- "_resolved": "https://registry.npmjs.org/npm-registry-client/-/npm-registry-client-0.3.5.tgz"
+ "_from": "npm-registry-client@0.4.0",
+ "_resolved": "https://registry.npmjs.org/npm-registry-client/-/npm-registry-client-0.4.0.tgz"
}
--- /dev/null
+*.swp
+.*.swp
+
+.DS_Store
+*~
+.project
+.settings
+npm-debug.log
+coverage.html
+.idea
+lib-cov
+
+node_modules
var typos = require("./typos")
var coreModuleNames = require("./core_module_names")
var githubUserRepo = require("github-url-from-username-repo")
+var warningMessages = require('./warning_messages.json')
+var format = require('util').format
var fixer = module.exports = {
// default warning function
fixRepositoryField: function(data) {
if (data.repositories) {
- this.warn("'repositories' (plural) Not supported.\n" +
- "Please pick one as the 'repository' field");
+ this.warn(warningMessages.repositories);
data.repository = data.repositories[0]
}
- if (!data.repository) return this.warn('No repository field.')
+ if (!data.repository) return this.warn(warningMessages.missingRepository)
if (typeof data.repository === "string") {
data.repository = {
type: "git",
}
if (r.match(/github.com\/[^\/]+\/[^\/]+\.git\.git$/)) {
- this.warn("Probably broken git url: " + r)
+ this.warn(format(warningMessages.brokenGitUrl, r))
}
}
, fixScriptsField: function(data) {
if (!data.scripts) return
if (typeof data.scripts !== "object") {
- this.warn("scripts must be an object")
+ this.warn(warningMessages.nonObjectScripts)
delete data.scripts
}
Object.keys(data.scripts).forEach(function (k) {
if (typeof data.scripts[k] !== "string") {
- this.warn("script values must be string commands")
+ this.warn(warningMessages.nonStringScript)
delete data.scripts[k]
} else if (typos.script[k]) {
this.warn(makeTypoWarning(k, typos.script[k], "scripts"))
, fixFilesField: function(data) {
var files = data.files
if (files && !Array.isArray(files)) {
- this.warn("Invalid 'files' member")
+ this.warn(warningMessages.nonArrayFiles)
delete data.files
} else if (data.files) {
data.files = data.files.filter(function(file) {
if (!file || typeof file !== "string") {
- this.warn("Invalid filename in 'files' list: " + file)
+ this.warn(format(warningMessages.invalidFilename, file))
return false
} else {
return true
delete data[bdd]
}
if (data[bd] && !Array.isArray(data[bd])) {
- this.warn("Invalid 'bundleDependencies' list. " +
- "Must be array of package names")
+ this.warn(warningMessages.nonArrayBundleDependencies)
delete data[bd]
} else if (data[bd]) {
data[bd] = data[bd].filter(function(bd) {
if (!bd || typeof bd !== 'string') {
- this.warn("Invalid bundleDependencies member: " + bd)
+ this.warn(format(nonStringBundleDependency, bd))
return false
} else {
return true
;['dependencies','devDependencies'].forEach(function(deps) {
if (!(deps in data)) return
if (!data[deps] || typeof data[deps] !== "object") {
- this.warn(deps + " field must be an object")
+ this.warn(format(warningMessages.nonObjectDependencies, deps))
delete data[deps]
return
}
Object.keys(data[deps]).forEach(function (d) {
var r = data[deps][d]
if (typeof r !== 'string') {
- this.warn('Invalid dependency: ' + d + ' ' + JSON.stringify(r))
+ this.warn(format(nonStringDependency, d, JSON.stringify(r)))
delete data[deps][d]
}
+ // "/" is not allowed as packagename for publishing, but for git-urls
+ // normalize shorthand-urls
+ if (githubUserRepo(data[deps][d])) {
+ data[deps][d] = githubUserRepo(data[deps][d])
+ }
}, this)
}, this)
}
, fixModulesField: function (data) {
if (data.modules) {
- this.warn("modules field is deprecated")
+ this.warn(warningMessages.deprecatedModules)
delete data.modules
}
}
}
if (data.keywords && !Array.isArray(data.keywords)) {
delete data.keywords
- this.warn("keywords should be an array of strings")
+ this.warn(warningMessages.nonArrayKeywords)
} else if (data.keywords) {
data.keywords = data.keywords.filter(function(kw) {
if (typeof kw !== "string" || !kw) {
- this.warn("keywords should be an array of strings");
+ this.warn(warningMessages.nonStringKeyword);
return false
} else {
return true
data.name = data.name.trim()
ensureValidName(data.name, strict)
if (coreModuleNames.indexOf(data.name) !== -1)
- this.warn(data.name + " is also the name of a node core module.")
+ this.warn(format(warningMessages.conflictingName, data.name))
}
, fixDescriptionField: function (data) {
if (data.description && typeof data.description !== 'string') {
- this.warn("'description' field should be a string")
+ this.warn(warningMessages.nonStringDescription)
delete data.description
}
if (data.readme && !data.description)
data.description = extractDescription(data.readme)
if(data.description === undefined) delete data.description;
- if (!data.description) this.warn('No description')
+ if (!data.description) this.warn(warningMessages.missingDescription)
}
, fixReadmeField: function (data) {
if (!data.readme) {
- this.warn("No README data")
+ this.warn(warningMessages.missingReadme)
data.readme = "ERROR: No README data found!"
}
}
else if(url.parse(data.bugs).protocol)
data.bugs = {url: data.bugs}
else
- this.warn("Bug string field must be url, email, or {email,url}")
+ this.warn(warningMessages.nonEmailUrlBugsString)
}
else {
bugsTypos(data.bugs, this.warn)
if(typeof(oldBugs.url) == "string" && url.parse(oldBugs.url).protocol)
data.bugs.url = oldBugs.url
else
- this.warn("bugs.url field must be a string url. Deleted.")
+ this.warn(warningMessages.nonUrlBugsUrlField)
}
if(oldBugs.email) {
if(typeof(oldBugs.email) == "string" && emailRe.test(oldBugs.email))
data.bugs.email = oldBugs.email
else
- this.warn("bugs.email field must be a string email. Deleted.")
+ this.warn(warningMessages.nonEmailBugsEmailField)
}
}
if(!data.bugs.email && !data.bugs.url) {
delete data.bugs
- this.warn("Normalized value of bugs field is an empty object. Deleted.")
+ this.warn(warningMessages.emptyNormalizedBugs)
}
}
}
return true
if(typeof data.homepage !== "string") {
- this.warn("homepage field must be a string url. Deleted.")
+ this.warn(warningMessages.nonUrlHomepage)
return delete data.homepage
}
if(!url.parse(data.homepage).protocol) {
- this.warn("homepage field must start with a protocol.")
+ this.warn(warningMessages.missingProtocolHomepage)
data.homepage = "http://" + data.homepage
}
}
deps = deps.trim().split(/[\n\r\s\t ,]+/)
}
if (!Array.isArray(deps)) return deps
- warn("specifying " + type + " as array is deprecated")
+ warn(format(warningMessages.deprecatedArrayDependencies, type))
var o = {}
deps.filter(function (d) {
return typeof d === "string"
providedName = field + "['" + providedName + "']"
probableName = field + "['" + probableName + "']"
}
- return providedName + " should probably be " + probableName + "."
-}
+ return format(warningMessages.typo, providedName, probableName)
+}
\ No newline at end of file
--- /dev/null
+var util = require('util')
+
+module.exports = function() {
+ var args = Array.prototype.slice.call(arguments, 0)
+ args.forEach(function(arg) {
+ if (!arg) throw new TypeError('Bad arguments.')
+ })
+ return util.format.apply(null, arguments)
+}
\ No newline at end of file
--- /dev/null
+{
+ "repositories": "'repositories' (plural) Not supported. Please pick one as the 'repository' field"
+ ,"missingRepository": "No repository field."
+ ,"brokenGitUrl": "Probably broken git url: %s"
+ ,"nonObjectScripts": "scripts must be an object"
+ ,"nonStringScript": "script values must be string commands"
+ ,"nonArrayFiles": "Invalid 'files' member"
+ ,"invalidFilename": "Invalid filename in 'files' list: %s"
+ ,"nonArrayBundleDependencies": "Invalid 'bundleDependencies' list. Must be array of package names"
+ ,"nonStringBundleDependency": "Invalid bundleDependencies member: %s"
+ ,"nonObjectDependencies": "%s field must be an object"
+ ,"nonStringDependency": "Invalid dependency: %s %s"
+ ,"deprecatedArrayDependencies": "specifying %s as array is deprecated"
+ ,"deprecatedModules": "modules field is deprecated"
+ ,"nonArrayKeywords": "keywords should be an array of strings"
+ ,"nonStringKeyword": "keywords should be an array of strings"
+ ,"conflictingName": "%s is also the name of a node core module."
+ ,"nonStringDescription": "'description' field should be a string"
+ ,"missingDescription": "No description"
+ ,"missingReadme": "No README data"
+ ,"nonEmailUrlBugsString": "Bug string field must be url, email, or {email,url}"
+ ,"nonUrlBugsUrlField": "bugs.url field must be a string url. Deleted."
+ ,"nonEmailBugsEmailField": "bugs.email field must be a string email. Deleted."
+ ,"emptyNormalizedBugs": "Normalized value of bugs field is an empty object. Deleted."
+ ,"nonUrlHomepage": "homepage field must be a string url. Deleted."
+ ,"missingProtocolHomepage": "homepage field must start with a protocol."
+ ,"typo": "%s should probably be %s."
+}
\ No newline at end of file
{
"name": "normalize-package-data",
- "version": "0.2.8",
+ "version": "0.2.9",
"author": {
"name": "Meryn Stol",
"email": "merynstol@gmail.com"
"url": "https://github.com/meryn/normalize-package-data/issues"
},
"homepage": "https://github.com/meryn/normalize-package-data",
- "_id": "normalize-package-data@0.2.8",
- "_from": "normalize-package-data@~0.2.7"
+ "_id": "normalize-package-data@0.2.9",
+ "dist": {
+ "shasum": "73fff1f896ce6f95bd089c57037a96389ad5789e"
+ },
+ "_from": "normalize-package-data@~0.2.9",
+ "_resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-0.2.9.tgz"
}
var globals = Object.keys(global)
var normalize = require("../lib/normalize")
+var warningMessages = require("../lib/warning_messages.json")
+var safeFormat = require("../lib/safe_format")
var rpjPath = path.resolve(__dirname,"./fixtures/read-package-json.json")
tap.test("normalize some package data", function(t) {
normalize(packageData, warn)
t.same(packageData, expect)
t.same(warnings, [
- "No description",
- "No repository field.",
- "No README data"
+ warningMessages.missingDescription,
+ warningMessages.missingRepository,
+ warningMessages.missingReadme
])
t.end()
})
}, warn)
var expect = [
- "http is also the name of a node core module.",
- "Bug string field must be url, email, or {email,url}",
- "Normalized value of bugs field is an empty object. Deleted.",
- "homepage field must be a string url. Deleted."
+ safeFormat(warningMessages.conflictingName, 'http'),
+ warningMessages.nonEmailUrlBugsString,
+ warningMessages.emptyNormalizedBugs,
+ warningMessages.nonUrlHomepage
]
t.same(warnings, expect)
t.end()
console.error(a)
var expect =
- [ "No description",
- "No repository field.",
- "bugs.url field must be a string url. Deleted.",
- "bugs.email field must be a string email. Deleted.",
- "Normalized value of bugs field is an empty object. Deleted.",
- "No README data",
- "Bug string field must be url, email, or {email,url}",
- "Normalized value of bugs field is an empty object. Deleted.",
- "homepage field must be a string url. Deleted." ]
+ [ warningMessages.missingDescription,
+ warningMessages.missingRepository,
+ warningMessages.nonUrlBugsUrlField,
+ warningMessages.nonEmailBugsEmailField,
+ warningMessages.emptyNormalizedBugs,
+ warningMessages.missingReadme,
+ warningMessages.nonEmailUrlBugsString,
+ warningMessages.emptyNormalizedBugs,
+ warningMessages.nonUrlHomepage ]
t.same(warnings, expect)
t.end()
})
console.error(a)
var expect =
- [ "No description",
- "No repository field.",
- "No README data",
- "homepage field must start with a protocol." ]
+ [ warningMessages.missingDescription,
+ warningMessages.missingRepository,
+ warningMessages.missingReadme,
+ warningMessages.missingProtocolHomepage ]
t.same(warnings, expect)
t.same(a.homepage, 'http://example.org')
t.end()
t.end()
})
+tap.test("treat isaacs/node-graceful-fs as github repo in dependencies", function(t) {
+ var d = {dependencies: {"node-graceful-fs": "isaacs/node-graceful-fs"}}
+ normalize(d)
+ t.same(d.dependencies, {"node-graceful-fs": "git://github.com/isaacs/node-graceful-fs" })
+ t.end()
+});
+
tap.test("deprecation warning for array in dependencies fields", function(t) {
var a
var warnings = []
devDependencies: [],
optionalDependencies: []
}, warn)
- t.ok(~warnings.indexOf("specifying dependencies as array is deprecated"), "deprecation warning")
- t.ok(~warnings.indexOf("specifying devDependencies as array is deprecated"), "deprecation warning")
- t.ok(~warnings.indexOf("specifying optionalDependencies as array is deprecated"), "deprecation warning")
+ t.ok(~warnings.indexOf(safeFormat(warningMessages.deprecatedArrayDependencies, 'dependencies')), "deprecation warning")
+ t.ok(~warnings.indexOf(safeFormat(warningMessages.deprecatedArrayDependencies, 'devDependencies')), "deprecation warning")
+ t.ok(~warnings.indexOf(safeFormat(warningMessages.deprecatedArrayDependencies, 'optionalDependencies')), "deprecation warning")
t.end()
})
var test = require('tap').test
+
var normalize = require('../')
var typos = require('../lib/typos.json')
+var warningMessages = require("../lib/warning_messages.json")
+var safeFormat = require("../lib/safe_format")
test('typos', function(t) {
var warnings = []
function warn(m) {
warnings.push(m)
}
+
+ var typoMessage = safeFormat.bind(undefined, warningMessages.typo)
var expect =
- [ 'No repository field.',
- 'dependancies should probably be dependencies.',
- 'dependecies should probably be dependencies.',
- 'depdenencies should probably be dependencies.',
- 'devEependencies should probably be devDependencies.',
- 'depends should probably be dependencies.',
- 'dev-dependencies should probably be devDependencies.',
- 'devDependences should probably be devDependencies.',
- 'devDepenencies should probably be devDependencies.',
- 'devdependencies should probably be devDependencies.',
- 'repostitory should probably be repository.',
- 'repo should probably be repository.',
- 'prefereGlobal should probably be preferGlobal.',
- 'hompage should probably be homepage.',
- 'hampage should probably be homepage.',
- 'autohr should probably be author.',
- 'autor should probably be author.',
- 'contributers should probably be contributors.',
- 'publicationConfig should probably be publishConfig.' ]
+ [ warningMessages.missingRepository,
+ typoMessage('dependancies', 'dependencies'),
+ typoMessage('dependecies', 'dependencies'),
+ typoMessage('depdenencies', 'dependencies'),
+ typoMessage('devEependencies', 'devDependencies'),
+ typoMessage('depends', 'dependencies'),
+ typoMessage('dev-dependencies', 'devDependencies'),
+ typoMessage('devDependences', 'devDependencies'),
+ typoMessage('devDepenencies', 'devDependencies'),
+ typoMessage('devdependencies', 'devDependencies'),
+ typoMessage('repostitory', 'repository'),
+ typoMessage('repo', 'repository'),
+ typoMessage('prefereGlobal', 'preferGlobal'),
+ typoMessage('hompage', 'homepage'),
+ typoMessage('hampage', 'homepage'),
+ typoMessage('autohr', 'author'),
+ typoMessage('autor', 'author'),
+ typoMessage('contributers', 'contributors'),
+ typoMessage('publicationConfig', 'publishConfig') ]
normalize({"dependancies": "dependencies"
,"dependecies": "dependencies"
warnings.length = 0
var expect =
- [ 'No description',
- 'No repository field.',
- 'bugs[\'web\'] should probably be bugs[\'url\'].',
- 'bugs[\'name\'] should probably be bugs[\'url\'].',
- 'bugs.url field must be a string url. Deleted.',
- 'Normalized value of bugs field is an empty object. Deleted.',
- "No README data" ]
+ [ warningMessages.missingDescription,
+ warningMessages.missingRepository,
+ typoMessage("bugs['web']", "bugs['url']"),
+ typoMessage("bugs['name']", "bugs['url']"),
+ warningMessages.nonUrlBugsUrlField,
+ warningMessages.emptyNormalizedBugs,
+ warningMessages.missingReadme ]
normalize({name:"name"
,version:"1.2.5"
warnings.length = 0
var expect =
- [ 'No description',
- 'No repository field.',
- "No README data",
- 'script should probably be scripts.' ]
+ [ warningMessages.missingDescription,
+ warningMessages.missingRepository,
+ warningMessages.missingReadme,
+ typoMessage('script', 'scripts') ]
normalize({name:"name"
,version:"1.2.5"
warnings.length = 0
expect =
- [ 'No description',
- 'No repository field.',
- 'scripts[\'server\'] should probably be scripts[\'start\'].',
- 'scripts[\'tests\'] should probably be scripts[\'test\'].',
- "No README data" ]
+ [ warningMessages.missingDescription,
+ warningMessages.missingRepository,
+ typoMessage("scripts['server']", "scripts['start']"),
+ typoMessage("scripts['tests']", "scripts['test']"),
+ warningMessages.missingReadme ]
normalize({name:"name"
,version:"1.2.5"
{
"name": "read-package-json",
- "version": "1.1.6",
+ "version": "1.1.7",
"author": {
"name": "Isaac Z. Schlueter",
"email": "i@izs.me",
"dependencies": {
"glob": "~3.2.1",
"lru-cache": "2",
- "normalize-package-data": "~0.2.7",
+ "normalize-package-data": "~0.2.9",
"graceful-fs": "2"
},
"devDependencies": {
"url": "https://github.com/isaacs/read-package-json/issues"
},
"homepage": "https://github.com/isaacs/read-package-json",
- "_id": "read-package-json@1.1.6",
- "dist": {
- "shasum": "a851dbbaca48ff78a87f890f0a9fdf43b1759d5a"
- },
- "_from": "read-package-json@1.1.6",
- "_resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-1.1.6.tgz"
+ "_id": "read-package-json@1.1.7",
+ "_from": "read-package-json@~1.1.6"
}
{
- "version": "1.3.26",
+ "version": "1.4.0",
"name": "npm",
"publishConfig": {
"proprietary-attribs": false
"author": "Isaac Z. Schlueter <i@izs.me> (http://blog.izs.me)",
"repository": {
"type": "git",
- "url": "https://github.com/isaacs/npm"
+ "url": "https://github.com/npm/npm"
},
"bugs": {
"email": "npm-@googlegroups.com",
- "url": "http://github.com/isaacs/npm/issues"
+ "url": "http://github.com/npm/npm/issues"
},
"directories": {
"doc": "./doc",
"chownr": "0",
"npmlog": "0.0.6",
"ansi": "~0.2.1",
- "npm-registry-client": "~0.3.5",
- "read-package-json": "~1.1.6",
+ "npm-registry-client": "~0.4.0",
+ "read-package-json": "~1.1.7",
"read-installed": "~0.2.2",
"glob": "~3.2.6",
"init-package-json": "0.0.14",
"ansicolors": "~0.3.2",
"ansistyles": "~0.1.3",
"path-is-inside": "~1.0.0",
- "columnify": "0.1.2"
+ "columnify": "0.1.2",
+ "npm-install-checks": "~1.0.0"
},
"bundleDependencies": [
"semver",
"ansicolors",
"ansistyles",
"path-is-inside",
- "columnify"
+ "columnify",
+ "npm-install-checks"
],
"devDependencies": {
"ronn": "~0.3.6",
"tap": "~0.4.0",
- "npm-registry-mock": "~0.5.5"
+ "npm-registry-mock": "~0.5.8"
},
"engines": {
- "node": ">=0.6",
+ "node": ">=0.8",
"npm": "1"
},
"scripts": {
{ "name":"npm-test-blerg3"
-, "homepage": "https://github.com/isaacs/npm/issues/2658"
+, "homepage": "https://github.com/npm/npm/issues/2658"
, "version" : "0.0.0"
, "scripts" : { "test" : "node test.js" }
}
+++ /dev/null
-just an npm test
+++ /dev/null
-{
- "npm-test-peer-deps-file": {
- "version": "1.2.3",
- "from": "https://gist.github.com/domenic/3971128/raw/7472b26a013ceb174c2d726314e9fa97465729bb/index.js",
- "resolved": "https://gist.github.com/domenic/3971128/raw/7472b26a013ceb174c2d726314e9fa97465729bb/index.js",
- "dependencies": {
- "opener": {
- "version": "1.3.0",
- "from": "opener@1.3.0"
- }
- }
- },
- "dict": {
- "version": "1.1.0",
- "from": "dict@1.1.0"
- }
-}
+++ /dev/null
-{
- "author": "Domenic Denicola <domenic@domenicdenicola.com> (http://domenicdenicola.com/)",
- "name": "npm-test-peer-deps",
- "version": "0.0.0",
- "dependencies": {
- "npm-test-peer-deps-file": "https://gist.github.com/domenic/3971128/raw/7472b26a013ceb174c2d726314e9fa97465729bb/index.js"
- },
- "scripts": {
- "test": "node test.js"
- }
-}
+++ /dev/null
-var path = require("path")
-var assert = require("assert")
-
-process.env.npm_config_prefix = process.cwd()
-delete process.env.npm_config_global
-delete process.env.npm_config_depth
-
-var npm = process.env.npm_execpath
-
-require("child_process").execFile(process.execPath, [npm, "ls", "--json"], {
- env: process.env, cwd: process.cwd() },
- function (err, stdout, stderr) {
-
- if (err) throw err
-
- var actual = JSON.parse(stdout).dependencies
- var expected = require("./npm-ls.json")
-
- // resolved url doesn't matter
- clean(actual)
- clean(expected)
-
- console.error(JSON.stringify(actual, null, 2))
- console.error(JSON.stringify(expected, null, 2))
-
- assert.deepEqual(actual, expected)
-})
-
-function clean (obj) {
- for (var i in obj) {
- if (i === "from" || i === "resolved")
- delete obj[i]
- else if (typeof obj[i] === "object" && obj[i])
- clean(obj[i])
- }
-}
// Windows can't handle npm rm npm due to file-in-use issues.
thingsToChain.push([exec, "npm rm npm"])
}
- thingsToChain.push(publishTest)
chain(thingsToChain, cb)
}
-
- function publishTest (cb) {
- if (process.env.npm_package_config_publishtest !== "true") {
- console.error("To test publishing: "+
- "npm config set npm:publishtest true")
- return cb()
- }
-
- chain
- ( [ setup
- , [ execChain, packages.filter(function (p) {
- return !p.match(/private/)
- }).map(function (p) {
- return [ "npm publish packages/"+p
- , "npm install "+p
- , "npm unpublish "+p+" --force"
- ]
- }) ]
- , publishPrivateTest
- ], cb )
-
- }
-
- function publishPrivateTest (cb) {
- exec("npm publish packages/npm-test-private -s", true, function (er) {
- if (er) {
- exec( "npm unpublish npm-test-private --force"
- , function (e2) {
- cb(er || e2)
- })
- }
- cleanup(cb)
- })
- }
}
main(function (er) {
--- /dev/null
+// Fixes Issue #1770
+var common = require('../common-tap.js')
+var test = require('tap').test
+var npm = require('../../')
+var osenv = require('osenv')
+var path = require('path')
+var fs = require('fs')
+var rimraf = require('rimraf')
+var mkdirp = require('mkdirp')
+var pkg = path.resolve(__dirname, 'outdated-notarget')
+var cache = path.resolve(pkg, 'cache')
+var mr = require('npm-registry-mock')
+
+test('outdated-target: if no viable version is found, show error', function(t) {
+ t.plan(1)
+ setup()
+ mr({port: common.port}, function(s) {
+ npm.load({ cache: cache, registry: common.registry}, function() {
+ npm.commands.update(function(er, d) {
+ t.equal(er.code, 'ETARGET')
+ s.close()
+ t.end()
+ })
+ })
+ })
+})
+
+test('cleanup', function(t) {
+ process.chdir(osenv.tmpdir())
+ rimraf.sync(pkg)
+ t.end()
+})
+
+function setup() {
+ mkdirp.sync(pkg)
+ mkdirp.sync(cache)
+ fs.writeFileSync(path.resolve(pkg, 'package.json'), JSON.stringify({
+ author: 'Evan Lucas',
+ name: 'outdated-notarget',
+ version: '0.0.0',
+ description: 'Test for outdated-target',
+ dependencies: {
+ underscore: '~199.7.1'
+ }
+ }), 'utf8')
+ process.chdir(pkg)
+}
--- /dev/null
+var npm = npm = require("../../")
+var test = require("tap").test
+var path = require("path")
+var fs = require("fs")
+var osenv = require("osenv")
+var rimraf = require("rimraf")
+var mr = require("npm-registry-mock")
+var common = require("../common-tap.js")
+
+var pkg = path.resolve(__dirname, "peer-deps")
+var desiredResultsPath = path.resolve(pkg, "desired-ls-results.json")
+
+test("installs the peer dependency directory structure", function (t) {
+ t.plan(1)
+
+ mr(common.port, function (s) {
+ setup(function (err) {
+ if (err) return t.fail(err)
+
+ npm.install(".", function (err) {
+ if (err) return t.fail(err)
+
+ npm.commands.ls([], true, function (err, _, results) {
+ if (err) return t.fail(err)
+
+ fs.readFile(desiredResultsPath, function (err, desired) {
+ if (err) return t.fail(err)
+
+ t.deepEqual(results, JSON.parse(desired))
+ s.close()
+ t.end()
+ })
+ })
+ })
+ })
+ })
+})
+
+test("cleanup", function (t) {
+ cleanup()
+ t.end()
+})
+
+
+function setup (cb) {
+ cleanup()
+ process.chdir(pkg)
+
+ var opts = { cache: path.resolve(pkg, "cache"), registry: common.registry};
+ npm.load(opts, cb)
+}
+
+function cleanup () {
+ process.chdir(osenv.tmpdir())
+ rimraf.sync(path.resolve(pkg, "node_modules"))
+ rimraf.sync(path.resolve(pkg, "cache"))
+}
--- /dev/null
+{
+ "name": "npm-test-peer-deps-installer",
+ "version": "0.0.0",
+ "dependencies": {
+ "npm-test-peer-deps": {
+ "version": "0.0.0",
+ "dependencies": {
+ "underscore": {
+ "version": "1.3.1"
+ }
+ }
+ },
+ "request": {
+ "version": "0.9.5"
+ }
+ }
+}
--- /dev/null
+{
+ "author": "Domenic Denicola",
+ "name": "npm-test-peer-deps-installer",
+ "version": "0.0.0",
+ "dependencies": {
+ "npm-test-peer-deps": "*"
+ }
+}