silk.npm.config.

Read npm's configuration the way npm does: the built-in, global, user, and project .npmrc files, npm_config_* environment variables, and command-line values, with ${VAR} expansion, scoped registries, and registry credentials.

When to use#

Use NpmConfig.load in a tool that talks to an npm registry and must honor the user's .npmrc files, such as a package manager or a publish script. Read a key with NpmConfig.text, choose a registry for a package with NpmConfig.registryFor, and get the credentials for a request URL with NpmConfig.credentialsFor. To parse one ini text without layers, use silk.npm.ini.

Details#

A configuration is a list of layers. When two layers set a key, the one with the higher priority wins. From highest to lowest, the layers are:

  1. NpmConfigSource.CommandLine: values the caller passes, such as parsed --key=value options.

  2. NpmConfigSource.Environment: each variable npm_config_<name> (any case) with a non-empty value. In <name>, each _ after the first character becomes - and letters become lowercase, unless the name starts with //.

  3. NpmConfigSource.Project: .npmrc in the project directory. That is the prefix from the command line, or else the nearest directory, from the working directory up, that has a package.json file or a node_modules directory. If a directory above it has a package.json whose workspaces patterns include it, that workspace root is used instead. The project file is skipped in global mode (global is true or location is global) and when it is the same file as the user file.

  4. NpmConfigSource.User: the userconfig file, by default ~/.npmrc.

  5. NpmConfigSource.Global: the globalconfig file, by default <prefix>/etc/npmrc.

  6. NpmConfigSource.Builtin: the npmrc file in npm's own install directory, if the caller names it.

In every layer, ${NAME} in a key or a text value is replaced by the environment variable NAME. An unset variable leaves ${NAME} as it is. A \ before $ stops the expansion, and each pair of \ before it becomes one \. As in npm, the items of a key[] list are expanded only for npm's own list options: ca, cidr, diff, include, noproxy, omit, package, and workspace. A file that cannot be read is an empty layer, as in npm. Keys inside an ini [section] are ignored, as npm does not read them.

Errors#

  • HostInputError if the environment or the working directory cannot be read.

  • FileError if the working directory is not a valid absolute path.

  • OutOfMemoryError if the Allocator cannot supply the configuration.

Gotchas#

Values are not checked or converted with npm's table of option types: a value is text, a boolean, a null, or a list, as the ini text gives it. npm's default values are not included, except the default registry https://registry.npmjs.org/. npm finds its global prefix from the path of the node program; here it comes from NpmConfigOptions, the PREFIX environment variable, or a prefix key. Paths use the / form of silk.system.filesystem; on Windows pass the paths in NpmConfigOptions.

Examples#

Find the registry and the token for a scoped package#

silk
import silk.mem.allocator { Allocator, OutOfMemoryError }
import silk.core.effect { Effect }
import silk.core.option { Option }
import silk.collections.bytes { Bytes }
import silk.collections.list { List }
import silk.system.host_input { HostInput, HostInputError }
import silk.npm.config { NpmConfig, NpmConfigSource, NpmCredentials }
import silk.system.filesystem { Path }

struct NoEnvironment {}

effect fn argumentCount(self: &mut NoEnvironment) -> usize ! HostInputError { return 0 }

effect fn argument(self: &mut NoEnvironment, index: usize) -> Option<Bytes>
  ! HostInputError | OutOfMemoryError ? &mut Allocator {
  return Option<Bytes>.none()
}

effect fn variable(self: &mut NoEnvironment, name: &[u8]) -> Option<Bytes>
  ! HostInputError | OutOfMemoryError ? &mut Allocator {
  return Option<Bytes>.none()
}

effect fn variableNames(self: &mut NoEnvironment) -> List<Bytes>
  ! HostInputError | OutOfMemoryError ? &mut Allocator {
  return List<Bytes>.make()
}

effect fn workingDirectory(self: &mut NoEnvironment) -> Bytes
  ! HostInputError | OutOfMemoryError ? &mut Allocator {
  return run Bytes.copy(b"/")
}

impl HostInput for NoEnvironment {
  argumentCount: NoEnvironment.argumentCount
  argument: NoEnvironment.argument
  variable: NoEnvironment.variable
  variableNames: NoEnvironment.variableNames
  workingDirectory: NoEnvironment.workingDirectory
}

effect fn check() -> bool ! HostInputError | OutOfMemoryError ? &mut HostInput | &mut Allocator {
  let mut config = NpmConfig.make()
  let text = b"@acme:registry=https://npm.acme.test/\n//npm.acme.test/:_authToken=secret\n"
  let layer = run NpmConfig.parseLayer(NpmConfigSource.User, Option<Path>.none(), text)
  run NpmConfig.addLayer(&mut config, move layer)
  let registry = NpmConfig.registryFor(&config, "@acme/widgets")
  let credentials = run NpmConfig.credentialsFor(&config, "https://npm.acme.test/@acme%2fwidgets", registry)
  return match move credentials {
    Option<NpmCredentials>.Some { value } => registry == "https://npm.acme.test/"
      && &NpmCredentials.token(&value) == &Option<string>.some("secret")
    Option<NpmCredentials>.None => false
  }
}

pub effect fn main() -> i32 ! HostInputError | OutOfMemoryError {
  let mut allocator = Allocator.systemAllocatorProvider()
  let mut environment = NoEnvironment {}
  let found = run check() |> Effect.provideMut<HostInput>(&mut environment)
    |> Effect.provideMut<Allocator>(&mut allocator)
  if !found {
    return 1
  }
  return 0
}

Import as NpmConfig with import silk.npm.config { NpmConfig }.

Public declarations: 6.

DEFAULT_REGISTRY#

silk
pub const DEFAULT_REGISTRY: string<'static>

The registry npm uses when no registry key is set.

NpmConfigSource#

silk
pub enum NpmConfigSource

Where a layer of the configuration comes from. A later variant has a higher priority.

Builtin#

silk
Builtin

The npmrc file in npm's own install directory.

Global#

silk
Global

The global file, globalconfig, by default <prefix>/etc/npmrc.

User#

silk
User

The user file, userconfig, by default ~/.npmrc.

Project#

silk
Project

The .npmrc file in the project directory.

Environment#

silk
Environment

The npm_config_* environment variables.

CommandLine#

silk
CommandLine

Values the caller passes, such as options from the command line.

NpmConfigLayer#

silk
pub struct NpmConfigLayer

One layer of the configuration: the entries from one file, the environment, or the caller.

Field source#

silk
pub source: NpmConfigSource

Where the layer comes from.

Field file#

silk
pub file: Option<Path>

The file of the layer, or None for the environment and command-line layers.

Field error#

silk
pub error: Option<FileError>

The error that stopped the file from being read, such as NotFound. The layer then has no entries.

Field entries#

silk
pub entries: List<NpmEntry>

The entries, with ${NAME} expanded in keys and text values (for a list, only for npm's own list options). Keys inside an ini [section] are left out. A key appears once.

NpmConfigOptions#

silk
pub struct NpmConfigOptions

Paths and values for NpmConfig.load. Each field can be left out.

Field workingDirectory#

silk
pub workingDirectory: Option<Path>

The directory to start the project search from. By default, the working directory of HostInput.

Field home#

silk
pub home: Option<Path>

The home directory, for ~/ in paths and the default user file ~/.npmrc. By default, the HOME environment variable, or USERPROFILE if HOME is not set.

Field globalPrefix#

silk
pub globalPrefix: Option<Path>

The global prefix, for the default global file <prefix>/etc/npmrc. By default, the PREFIX environment variable. A prefix key in a layer wins over both.

Field builtinFile#

silk
pub builtinFile: Option<Path>

npm's built-in npmrc file, in npm's install directory. It is not read if left out.

Field commandLine#

silk
pub commandLine: Option<List<NpmEntry>>

The command-line layer, such as NpmIni.parse(b"registry=https://example.test/\n").

NpmCredentials#

silk
pub struct NpmCredentials

The credentials that npm sends to a registry.

Details#

npm sends Authorization: Bearer <token> if there is a token, or else Authorization: Basic <basic> if there is a basic value. NpmCredentials.authorization gives that header value. A client certificate can come with either one, or alone.

Field registryKey#

silk
pub registryKey: String

The key prefix that had the credentials, such as //registry.npmjs.org/.

Field bearer#

silk
pub bearer: Option<String>

The value of <registryKey>:_authToken.

Field basic#

silk
pub basic: Option<String>

The Base64 text for basic authentication: <registryKey>:_auth as written, or else <registryKey>:username and the Base64-decoded <registryKey>:_password joined by : and encoded.

Field certificateFile#

silk
pub certificateFile: Option<String>

The value of <registryKey>:certfile, a path to a PEM client certificate. It is set only together with NpmCredentials.keyFile.

Field keyFile#

silk
pub keyFile: Option<String>

The value of <registryKey>:keyfile, a path to the PEM key of the client certificate.

Implementation NpmCredentials#

silk
impl NpmCredentials

Method token#

silk
pub fn token<'a>(self: &'a NpmCredentials) -> Option<string<'a>>

Returns the bearer token, or None if the credentials have no token. The text borrows from self.

Method authorization#

silk
pub effect fn authorization(self: &NpmCredentials) -> Option<String>
    ! OutOfMemoryError
    ? &mut Allocator

Returns the value of the Authorization header npm sends: Bearer <token>, or else Basic <basic>, or None if the credentials are only a client certificate.

Errors#

  • OutOfMemoryError if the Allocator cannot supply the text.

NpmConfig#

silk
pub struct NpmConfig

npm's configuration: layers of keys, from the command line down to npm's built-in file.

When to use#

Use NpmConfig.load to read the configuration that npm would use in a directory. Use NpmConfig.make, NpmConfig.parseLayer, and NpmConfig.addLayer to build one from your own text, for example in a test.

Details#

When two layers set a key, the higher one wins. From highest to lowest: command line, environment, project, user, global, built-in.

Implementation NpmConfig#

silk
impl NpmConfig

Associated function make#

silk
pub fn make() -> NpmConfig

Returns a configuration with no layers, no home directory, and no working directory.

Associated function load#

silk
pub effect fn load(options: NpmConfigOptions) -> NpmConfig
    ! HostInputError | FileError | OutOfMemoryError
    ? &mut FileSystem | &mut HostInput | &mut Allocator

Reads npm's configuration for the working directory, from all files, the environment, and the command-line values in options.

Details#

The layers are read in npm's order: built-in file, command line, environment, project file, user file, global file. A later file is found with the layers before it:

  • The project directory is prefix from the command line, or else the nearest directory, from the working directory up, with a package.json file or a node_modules directory, or else the working directory. If a directory above it has a package.json whose workspaces patterns name it, that directory is used, unless workspaces is false on the command line. The project file is skipped in global mode (global is true or location is global), and when it is the user file.

  • The user file is userconfig, by default ~/.npmrc.

  • The global file is globalconfig, by default <prefix>/etc/npmrc, where prefix is the key or else the global prefix of options or the PREFIX environment variable.

A file that cannot be read, for any reason, is a layer with no entries, and its error is kept in NpmConfigLayer.error. A user or global file that is the same path as a file read before it is skipped; npm stops with an error in that case. Keys and text values have ${NAME} expanded.

Errors#

  • HostInputError if the environment or the working directory cannot be read.

  • FileError with reason InvalidPath if the working directory of HostInput is not an absolute / path. Pass workingDirectory in options to avoid it.

  • OutOfMemoryError if the Allocator cannot supply the configuration.

Associated function parseLayer#

silk
pub effect fn parseLayer(
    source: NpmConfigSource,
    file: Option<Path>,
    bytes: &[u8],
  ) -> NpmConfigLayer
    ! HostInputError | OutOfMemoryError
    ? &mut HostInput | &mut Allocator

Returns the layer for the ini text bytes, with ${NAME} expanded in keys and text values.

When to use#

Use it to add text that is not in a file, such as values from your own command line, or to build a configuration in a test. Add the result with NpmConfig.addLayer.

Details#

The text is parsed with NpmIni.parse. Keys inside an ini [section] are left out. Keys and text values have ${NAME} expanded with NpmConfig.expand; the items of a key[] list are expanded only for npm's list options ca, cidr, diff, include, noproxy, omit, package, and workspace, as in npm. If two keys are the same after expansion, the later one wins. file is recorded in the layer as it is.

Errors#

  • HostInputError if an environment variable cannot be read.

  • OutOfMemoryError if the Allocator cannot supply the layer.

Associated function readLayer#

silk
pub effect fn readLayer(source: NpmConfigSource, path: Path) -> NpmConfigLayer
    ! HostInputError | OutOfMemoryError
    ? &mut FileSystem | &mut HostInput | &mut Allocator

Reads the file path as the layer source.

Details#

If the file cannot be read, for any reason, the layer has no entries and keeps the error in NpmConfigLayer.error, as npm ignores such a file. Otherwise it is the same as NpmConfig.parseLayer for the contents.

Errors#

  • HostInputError if an environment variable cannot be read.

  • OutOfMemoryError if the Allocator cannot supply the layer.

Associated function environmentLayer#

silk
pub effect fn environmentLayer() -> NpmConfigLayer
    ! HostInputError | OutOfMemoryError
    ? &mut HostInput | &mut Allocator

Returns the environment layer: one entry for each variable npm_config_<name> with a non-empty value.

Details#

The prefix npm_config_ matches in any case. Unless <name> starts with //, each _ after its first character becomes - and ASCII letters become lowercase, so NPM_CONFIG_SAVE_EXACT sets save-exact. The text true, false, and null become a boolean or a null. Keys and text values have ${NAME} expanded. If two variables give the same key, the later one in the order of the host wins.

Errors#

  • HostInputError if the environment cannot be read.

  • OutOfMemoryError if the Allocator cannot supply the layer.

Method addLayer#

silk
pub effect fn addLayer(self: &mut NpmConfig, layer: NpmConfigLayer) -> ()
    ! OutOfMemoryError
    ? &mut Allocator

Adds layer to the configuration. A layer with the same source is replaced.

Errors#

  • OutOfMemoryError if the Allocator cannot supply room for the layer.

Method layers#

silk
pub fn layers<'a>(self: &'a NpmConfig) -> &'a [NpmConfigLayer]

Returns the layers, from the lowest priority to the highest.

Method get#

silk
pub fn get<'a>(self: &'a NpmConfig, key: string) -> Option<&'a NpmEntry>

Returns the entry for key from the layer with the highest priority that sets it, or None if no layer sets it.

Details#

key is compared byte for byte, after ${NAME} expansion of the keys in the layers. For a list, leave out the [].

Method text#

silk
pub fn text<'a>(self: &'a NpmConfig, key: string) -> Option<string<'a>>

Returns the text of the first value of key, from the layer with the highest priority that sets it.

Details#

Returns None if no layer sets key, or if the winning value is a boolean or a null. The text borrows from self.

Method flag#

silk
pub fn flag(self: &NpmConfig, key: string) -> Option<bool>

Returns the boolean value of key, from the layer with the highest priority that sets it.

Returns None if no layer sets key, or if the winning value is not true or false.

Method path#

silk
pub effect fn path(self: &NpmConfig, key: string) -> Option<Path>
    ! FileError | OutOfMemoryError
    ? &mut Allocator

Returns the text value of key as a path, as npm reads its path options.

Details#

A value that starts with ~/ is resolved in the home directory. Any other relative value is resolved in the working directory, and an absolute value is normalized. Returns None if no layer sets key as text, or if the value needs a home or working directory that the configuration does not have.

Errors#

  • FileError with reason InvalidPath if the value has a NUL byte or goes above the root.

  • OutOfMemoryError if the Allocator cannot supply the path.

Method userFile#

silk
pub effect fn userFile(self: &NpmConfig) -> Option<Path>
    ! FileError | OutOfMemoryError
    ? &mut Allocator

Returns the user file: the userconfig path, or else .npmrc in the home directory, or None if neither is known.

Errors#

  • FileError with reason InvalidPath if userconfig has a NUL byte or goes above the root.

  • OutOfMemoryError if the Allocator cannot supply the path.

Method globalFile#

silk
pub effect fn globalFile(self: &NpmConfig, globalPrefix: Option<Path>) -> Option<Path>
    ! HostInputError | FileError | OutOfMemoryError
    ? &mut HostInput | &mut Allocator

Returns the global file: the globalconfig path, or else etc/npmrc in the global prefix.

Details#

The global prefix is the prefix path, or else globalPrefix, or else the PREFIX environment variable. Returns None if none of them is known.

Errors#

  • HostInputError if the environment cannot be read.

  • FileError with reason InvalidPath if a path has a NUL byte or goes above the root.

  • OutOfMemoryError if the Allocator cannot supply the path.

Method registryFor#

silk
pub fn registryFor<'a>(self: &'a NpmConfig, name: string) -> string<'a>

Returns the registry URL for the package name, as npm chooses it.

Details#

For a scoped name such as @acme/widgets, it is the text of @acme:registry if that is set and not empty. Otherwise it is the text of registry, or DEFAULT_REGISTRY. name can also be a spec such as @acme/widgets@^2; only the scope before the first / is read. The text borrows from self.

Method registry#

silk
pub fn registry<'a>(self: &'a NpmConfig) -> string<'a>

Returns the text of registry, or DEFAULT_REGISTRY if it is not set or empty. The text borrows from self.

Method credentialsFor#

silk
pub effect fn credentialsFor(self: &NpmConfig, url: string, registry: string) -> Option<
    NpmCredentials
  >
    ! OutOfMemoryError
    ? &mut Allocator

Returns the credentials npm would send with a request to url, or None if there are none.

Details#

The lookup starts with the key prefix //<host>/<path> of url, without the scheme, the user, the query, and the fragment, and with a default port left out. While the prefix is longer than //, it checks <prefix>:_authToken, then <prefix>:_auth, then <prefix>:username with <prefix>:_password, then <prefix>:certfile with <prefix>:keyfile, and stops at the first prefix that has one of them set to a non-empty value. Otherwise it removes the last path name or the last / and tries again. So //npm.test/team/:_authToken covers https://npm.test/team/pkg.

If no prefix has credentials, and registry is a different URL on the same host and port as url, the credentials of registry are used, as npm does for tarball URLs. Pass the result of NpmConfig.registryFor for the package as registry.

Credentials only for a host-wide key, such as an _authToken with no //host/ prefix, are not used, as npm 9 and later refuse them.

Errors#

  • OutOfMemoryError if the Allocator cannot supply the credentials.

Gotchas#

It returns None if url is not a valid absolute URL.

Associated function nerfDart#

silk
pub effect fn nerfDart(url: string) -> Option<String>
    ! OutOfMemoryError
    ? &mut Allocator

Returns the key prefix npm uses for the credentials of url, such as //registry.npmjs.org/ for https://registry.npmjs.org/some/pkg.

Details#

It is //, the host with a port that is not the default, and the path up to and with its last /. The scheme, the user, the query, and the fragment are left out. Returns None if url is not a valid absolute URL.

Errors#

  • OutOfMemoryError if the Allocator cannot supply the text.

Associated function expand#

silk
pub effect fn expand(text: string) -> String
    ! HostInputError | OutOfMemoryError
    ? &mut HostInput | &mut Allocator

Returns text with each ${NAME} replaced by the value of the environment variable NAME, as npm expands .npmrc keys and values.

Details#

NAME is one or more characters other than $, {, and }. An unset variable leaves ${NAME} as it is; a variable set to empty text gives empty text. For k backslashes right before $: if k is even, k / 2 backslashes stay and the variable is expanded; if k is odd, (k + 1) / 2 backslashes are removed and ${NAME} stays.

Errors#

  • HostInputError if an environment variable cannot be read.

  • OutOfMemoryError if the Allocator cannot supply the text.

Category: Data formats.

Profiles: aarch64-apple-darwin, aarch64-unknown-linux-gnu, aarch64-unknown-linux-gnu-no-libc, x86_64-unknown-linux-gnu, x86_64-unknown-linux-gnu-no-libc, wasm32-unknown-unknown, wasm32-wasip1, wasm32-wasip2, x86_64-pc-windows-msvc, wasm64-unknown-unknown.

View the source of this page