Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[RRFC] Add "registryRules" to package.json to specify which registry to choose from #331

Closed
rafedramzi opened this issue Feb 24, 2021 · 2 comments

Comments

@rafedramzi
Copy link

Motivation ("The Why")

First, I want mention that I'm very glad for #275 RFC, I believe it can make the NPM ecosystem more open and safer, thank you! While I would agree with #275, but I think adding registry: to all my private packages can be a little tedious, especially if I have multiple packages that are in @myorg Scope and IMO can make package.json harder to read.

So my proposal is to add new key called registryRules in package.json, it is an object that its key acts like a prefix-pattern that will be matched against packages that are in dependencies or *Dependencies, if the package name match the pattern, it will look up the package to the registries that are defined in that particular pattern.

Example

{
  "name": "package-name",
  // ...
  "registryRules": { // <patterns>
    "<pattern>": [ // Arrray of <registry>
      {
        "url": "<registry_url>",
      },
      // ...
    ]
  }
}

A concrete example would be something like

{
  "name": "fabulous-package",
  // ...
  "registryRules": {
    "@myorg": [
      { "url":"https://registry.npmjs.org"}, 
      { "url":"https://registry.example.com"}, 
    ],
    "@myorg/legacy-app-*": [
      { "url":"https://legacy-registry.example.com" }, 
    ]
  }
}

Details:

  • <registry> object holds the details about the registry, with properties:

    • url :string - the url of the registry

    Why an object? This will make future extension easier. Let's say NPM decided to have v10 API, you can add version key to maintain backward compatibility with older API.

  • <patterns> is an object, that have a string as the key and <registry> object for the value

    • It will match the key to the prefix of the package name, so if the pattern is @myorg is will affect all the dependency that have prefix @myorg, the pattern not limited to Scope name but can also match full package name like @myorg/fabulous-package as well.
    • Additional support for wildcard *, to match the package name, example: @myorg/app-*-demo it will only match @myorg/app-super-demo and not @myorg/app-super

Alternatively, use regex instead of prefix + wildcard patterns.

Implementation details proposal:

  • <patterns> respect it's key ordering. If a package name match multiple patters it
    will search through the pattern that have lowest index, and if the package not found, continue the search to the second lowest index.
  • <registry> inside a <pattern> also respect it's ordering, so if the package found in multiple registry, it will use use registry that have the lowest index number as a tie breaker.
  • Authentication to the registry still being handled by npm login.
  • my suggestion is to match the pattern only for package that are explicitly stated in that package.json (dependencies and *Dependencies), it does not affect it's the dependencies of it's package. For example:

Dependency tree for @myorg/package-a

@myorg/package-a
├── @myorg/package-b
│   ├── @myorg/package-x
│   └── @myorg/package-y
└── @myorg/package-c

In this scenario, @myorg/package-a explicitly define the registryRules in it's package.json as

{
  "name": "@myorg/package-a",
  "registryRules": {
    "@myorg": [
      {
        "url": "https://registry.example.com",
      }
    ]
  }
}

Thus this explicit registryRules will only affect @myorg/package-b, @myorg/package-c not @myorg/package-x, @myorg/package-y

I have no concrete argument for this, but I think this behavior is easier to grasp compared to propagating the rules to the dependency tree.

Current Behaviour

AFAIK it will try to match given pattern specified in npm login --scope=@organization --registry=registry.organization.com and fall back to NPM public registry if the package is not found.

Related

And lastly, I just want to point out that something similar but slightly different has been done by other community, I want to point this out, maybe we can get some inspiration or concerns from their implementation:

@ljharb
Copy link
Contributor

ljharb commented Feb 24, 2021

To avoid a supply chain attack, you'd only want your internal packages to be under scopes (scopes that you publicly control), and you'd want your internal scopes to be different than the scopes you used for public packages to avoid accidentally publishing an internal package.

If one followed these best practices, what would be the remaining use cases for registryRules?

@rafedramzi
Copy link
Author

Hmm, I haven't think about that, my initial thought was just trying to address some of the concerns in #314. Yes, the differences are subtle, but I think the registryRules have some advantages:

  1. It's more explicit, you put the registry target in package.json instead of .npmrc.
  2. AFAIK you cannot define multiple registries .npmrc, registryRules try to solve the problem. Usually, you achieve this using something like verdaccio, registryRules try to eliminate that intermediary.
  3. It uses prefix+wildcare system instead of Scope, which gives you more flexibility to define the rule.

You can also argue this is making the process too strict and complex, and I agree. Now I have conflicting thoughts, I think I'm going to close this for now and think more thoroughly about this, thanks @ljharb .

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants