-
Notifications
You must be signed in to change notification settings - Fork 239
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
RFC:
registry:
dependency specifiers
- Loading branch information
Showing
1 changed file
with
160 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,160 @@ | ||
# The `registry:` Dependency Specifier | ||
|
||
## Summary | ||
|
||
Add a dependency specifier which defines a registry base url, package name, | ||
and optionally SemVer range or dist-tag. | ||
|
||
## Motivation | ||
|
||
Occasionally, users wish to use multiple npm registries. For example, they | ||
may have some packages hosted on the public npm registry, and others within | ||
a private registry on their company's intranet, or provided by a company | ||
like GitHub, Jfrog, Sonatype, or others. | ||
|
||
Currently, it is possible to map a scope to a given registry, and all | ||
packages starting with that scope will be published to and installed from | ||
the defined registry: | ||
|
||
```ini | ||
; .npmrc file | ||
@company:registry = https://npm-registry.my-company.com | ||
``` | ||
|
||
However, this does not address the following use cases: | ||
|
||
- Users publish a package to one registry as a "staging" area, and then | ||
later wish to "upgrade" it to the public npm registry for broader | ||
distribution. Some code should fetch from the internal registry (for | ||
example, for testing and validation prior to promotion), but this is | ||
challenging unless the private registry also can serve _any_ public npm | ||
package. | ||
|
||
- Users have a set of unscoped package dependencies, some of which come | ||
from the public registry, and others which have patches applied to them | ||
(either to the code, or to the packument to add warnings via the | ||
`deprecated` field for example). Again, this is only feasible right now | ||
by making the internal registry capable of proxying the entire set of npm | ||
packages. | ||
|
||
- Alias package specifiers cannot point to any registries other than the | ||
primary `--registry` configuration. It would be useful in many scenarios | ||
to be able to alias a package to a copy found on a different registry. | ||
|
||
- Migrating packages from one registry to another is particularly | ||
challenging, requiring downloading the tarball locally and then | ||
re-uploading it. It would be much simpler to script such migrations by | ||
being able to do `npm publish <pkg from src registry> --registry=<dest | ||
registry>`. | ||
|
||
- Using multiple different registries in the best of cases always requires | ||
using a `.npmrc` file for configuration, which is a challenge in some | ||
environments, and always adds a layer of indirection. It would be more | ||
straightforward at times to specify the registry right in the | ||
package.json file or command line. | ||
|
||
## Detailed Explanation | ||
|
||
A new dependency specifier is added: | ||
|
||
``` | ||
registry:<registry url>#<package name>[@<specifier>] | ||
``` | ||
|
||
Where: | ||
|
||
- `<registry>` is a fully qualified URL to an npm registry, which may not | ||
contain a `hash` portion, | ||
- `<package name>` is the (scoped or unscoped) name of the package to | ||
resolve on the registry, and | ||
- `<specifier>` is an optional dist-tag, version, or range. | ||
|
||
If `<specifier>` is omitted, then it defaults to the `tag` config (or | ||
`defaultTag` internal optional), which defaults to `latest`. | ||
|
||
### Saving | ||
|
||
When a package is installed using a registry specifier, it *must* be saved | ||
using a registry specifier. | ||
|
||
### Alias Specifiers | ||
|
||
Alias specifiers desugar into registry specifiers with the default | ||
configured registry url. | ||
|
||
For example, the alias dependency spec `npm:foo@latest` will be equivalent | ||
to `registry:https://registry.npmjs.org#foo@latest`. | ||
|
||
### Deduping | ||
|
||
Two packages with the same name and version which come from different | ||
registries *must not* be deduped against one another unless: | ||
|
||
- If either has a defined `integrity` value, then their `integrity` values | ||
must match. | ||
- If neither has a defined `integrity` value, they will be considered | ||
dedupable if their `resolved` values match (for example, `registry-a` | ||
lists the tarball in `registry-b` as its `dist.tarball` url.) | ||
|
||
### Specifying Package Name | ||
|
||
The `<package name>` portion is always required, even when it would match | ||
the `name` portion of a complete named specifier. | ||
|
||
For example, `foo@registry:https://url.com#[email protected]` is acceptable. | ||
`foo@registry:https://url.com#1.x` is not valid, and will attempt to alias | ||
`foo` to the `1.x` package. | ||
|
||
This avoids the hazards of attempting to infer whether the `hash` portion | ||
of the url is a SemVer, dist-tag, or package name. | ||
|
||
### Examples: | ||
|
||
- on the command line: | ||
|
||
```bash | ||
# the name may be specified | ||
npm install forked@registry:https://internal.local#forked | ||
# but is not required | ||
npm install registry:https://internal.local#[email protected] | ||
``` | ||
|
||
- in a `package.json` file | ||
|
||
```json | ||
{ | ||
"dependencies": { | ||
"aliased": "registry:https://internal.com#[email protected]", | ||
"forked": "registry:https://other-internal.com#[email protected]", | ||
"patched": "registry:https://security-provider.com#patched@^1.4 || 2" | ||
} | ||
} | ||
``` | ||
|
||
## Rationale and Alternatives | ||
|
||
Use cases described are challenging to address in any other way. | ||
|
||
Initial proposal used a `:` character to delimit the url from the package | ||
specifier, but this is a poor choice, since `:` appears in registry urls. | ||
|
||
[RFC PR #217](https://github.com/npm/rfcs/pull/217) addressed some of the | ||
use cases described by defining a registry per _package_ underneath a | ||
scope. However, analysis and discussion uncovered security concerns that | ||
would make that approach unwise to implement. Packages with `registry:` | ||
specifiers in their dependencies will fail to install on older npm versions | ||
that do not support the new spec type, so there is no chance of fetching | ||
from the _wrong_ registry. | ||
|
||
## Implementation | ||
|
||
- Add support for `registry:` specifiers in `npm-package-arg` module. **This | ||
is a breaking change**, but adding `registry:` specifier support to | ||
npm/cli is SemVer-minor. | ||
- Upgrade all modules depending on `npm-package-arg` to ensure that they | ||
will behave properly with `registry:` specifiers. (Note: this is most of | ||
npm.) | ||
|
||
## Prior Art | ||
|
||
Alias specifiers already present in npm. |