npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@adaptably/adapt

v8.2.1

Published

Keep your Node.js application's configuration in one place. Access it simply and declaratively. Easily change it based on your application's environment.

Downloads

27

Readme

@adaptably/adapt

Keep your Node.js application's configuration in one place. Access it simply and declaratively. Easily change it based on your application's environment.

Installation

npm install @adaptably/adapt

Basic Usage

Setting Up

To get started, all you need is a Configuration File (adapt.json) in the root of your project.

You can then use the Selecting Function to access your configuration data.

For example:

adapt.json

{
  "app": {
    "name": "hello-world"
  }
}

app.js

import adapt from '@adaptably/adapt'

const appName = adapt('app.name')
console.log(appName)

CLI

node app.js
> "hello-world"

Adding Adaptive Objects

Maybe your app's configuration values change based on its environment. To handle this, add Adaptive Objects and the mode variable.

adapt.json

{
  "app": {
    "names": {
      "dev": "hello-world-dev",
      "production": "hello-world-production"
    }
  }
}

app.js

import adapt from '@adaptably/adapt'

const appName = adapt('app.name')
console.log(appName)

CLI

mode=dev node app.js
> "hello-world-dev"

mode=production node app.js
> "hello-world-production"

Adding Adaptive Values

If there's configuration data you'd rather keep secret, bake in some Adaptive Values.

adapt will look in the Environment File for these values. If it can't find them there, it will look in process.env.

This is useful in production environments where the adapt.env.json file may not exist.

Note: Values in the Environment File will take precedence over (but not replace) values in process.env.

adapt.json

{
  "api": {
    "token": "[API_TOKEN]"
  }
}

adapt.env.json

{
  "API_TOKEN": "super-secret-token"
}

app.js

import adapt from '@adaptably/adapt'

const apiToken = adapt('api.token')
console.log(apiToken)

CLI

node app.js
> "super-secret-token"

Adaptive Values + Adaptive Objects

You can use Adaptive Objects in the Environment File too.

adapt.json

{
  "app": {
    "names": {
      "dev": "hello-world-dev",
      "production": "hello-world-production"
    }
  },

  "api": {
    "token": "[API_TOKEN]"
  }
}

adapt.env.json

{
  "API_TOKEN": {
    "dev": "super-secret-token-dev",
    "production": "super-secret-token-production"
  }
}

app.js

import adapt from '@adaptably/adapt'

const apiToken = adapt('api.token')
console.log(apiToken)

CLI

mode=dev node app.js
> "super-secret-token-dev"

mode=production node app.js
> "super-secret-token-production"

Adding Adaptive References

Sometimes you may want to put configuration values together. In this case, you can use Adaptive References.

adapt.json

{
  "database": {
    "host": "127.0.0.1",
    "user": "root",
    "connectionString": "mysql://{database.user}@{database.host}"
  }
}

app.js

import adapt from '@adaptably/adapt'

const connectionString = adapt('database.connectionString')
console.log(connectionString)

CLI

node app.js
> "mysql://[email protected]"

Putting It All Together

With our powers combined, make your application adaptable!

adapt.json

{
  "allTheThings": "app-[APP_NAME]-with-{services.logging.key}",

  "app": {
    "name": "hello-world-[APP_NAME]"
  },

  "api": {
    "tokens": {
      "dev": "not-secret-token",
      "staging": "[API_TOKEN]",
      "production": "[API_TOKEN]"
    }
  },

  "services": {
    "logging": {
      "keys": {
        "_default": "default-logging-key",
        "staging": "[LOGGING_KEY]",
        "production": "[LOGGING_KEY]"
      }
    }
  }
}

adapt.env.json

{
  "APP_NAME": {
    "dev": "from-environment-dev",
    "production": "from-environment-production"
  },

  "API_TOKEN": "super-secret-token",

  "LOGGING_KEY": {
    "staging": "super-secret-logging-key-staging",
    "production": "super-secret-logging-key-production"
  }
}

app.js

import adapt from '@adaptably/adapt'

const allTheThings = adapt('allTheThings')
const appName = adapt('app.name')
const apiToken = adapt('api.token')
const loggingKey = adapt('services.logging.key')

console.log('App Name:', appName)
console.log('API Token:', apiToken)
console.log('Logging Key:', loggingKey)
console.log('All the Things:', allTheThings)

CLI

mode=dev node app.js
> "App Name: hello-world-from-environment-dev"
> "API Token: not-secret-token"
> "Logging Key: default-logging-key"
> "All the Things: app-from-environment-dev-with-default-logging-key"

mode=staging node app.js
> "App Name: hello-world-from-environment-staging"
> "API Token: super-secret-token"
> "Logging Key: super-secret-logging-key-staging"
> "All the Things: app-from-environment-staging-with-super-secret-logging-key-staging"

mode=production node app.js
> "App Name: hello-world-from-environment-production"
> "API Token: super-secret-token"
> "Logging Key: super-secret-logging-key-production"
> "All the Things: app-from-environment-staging-with-super-secret-logging-key-production"

Configuration

The Configuration File

The Configuration File lives at adapt.json in the root of your project. To change the default location, see Customizing File Locations.

This file can contain Adaptive Objects and Adaptive Values which will be parsed by the Selecting Function.

Example Configuration File

{
  "api": {
    "keys": {
      "_default": "bcd-234",
      "staging": "abc-123"
      "production": "[API_KEY]"
    }
  },

  "general": {
    "number": 5,
    "text": "Hello world"
  }
}

The Environment File

The Environment File lives at adapt.env.json in the root of your project. To change the default location, see Customizing File Locations.

This file is optional and contains environment variables for your application. It typically should not be committed to source control.

The Environment File file can contain Adaptive Objects which will be parsed by the selecting function.

Example Environment Files

Basic
{
  "API_KEY": "api-key",
  "DATABASE_URL": "db-url"
}
With Adaptive Objects
{
  "APP_ID": "abc123",

  "API_KEY": {
    "_default": "base-key",
    "production": "production-key"
  },

  "DATABASE_URL": {
    "dev": "dev-db",
    "staging": "staging-db",
    "production": "production-db"
  }
}

Notes on the Environment File

  • If the selecting function can't find a value in the Environment File, it will look in process.env. This is useful in production environments where the adapt.env.json file may not exist.
  • Values in the Environment File will take precedence over (but not replace) values in process.env.
  • Values in the Environment File must be strings (in order to work with Adaptive Values in the Configuration File).
  • Neither Adaptive Values nor Adaptive References can be used in the Environment File.

Customizing File Locations

When importing adapt, it will look in thee root of your project for the Configuration and Environment files.

To customize where adapt looks for these files, use the loadAdapt function instead of the default export:

import { loadAdapt } from '@adaptably/adapt'

const adapt = loadAdapt({
  configurationDirectory: '/my/custom/directory'
})

Programmatic Configuration

If you want to get even closer to the metal, you can skip file loading altogether and give adapt the data it needs programatically using the createSelectingFunction function:

import { createSelectingFunction } from '@adaptably/adapt'

const adapt = createSelectingFunction({
  configuration: {
    // Provide configuration data like in the Configuration File.
  },

  environment: {
    // Provide environment data like in the Environment File.
  },

  // Optionally define a mode (or use `process.env.mode`).
  mode: 'dev'
})

Detailed Usage

The Selecting Function

Usage

import adapt from '@adaptably/adapt'

Syntax

adapt(selector)

Arguments

| Name | Type | Description | Example | | :-- | :-- | :-- | :-- | | selector | String | A string in dot notation which targets a key in the configuration file. | api.key |

Exceptions

Throws a standard Error if:

Normal Keys

Normal keys can be accessed by name, using dot notation.

Using the Example Configuration File:

adapt('api.keys.staging') // 'abc-123'
adapt('general.number') // 5
adapt('general.text') // 'Hello world'

Adaptive Objects

In the Configuration File

In the Configuration File, Adaptive Objects have two special qualities:

  • The key which contains them is plural (i.e. tokens),
  • They are an object with keys representing application modes, such as:
"keys": {
  "dev": "key-dev",
  "staging": "key-staging"
}

Adaptive Objects in the Configuration File will be accessed when the singular form of a given selector (api.key) cannot be found.

A key from the object will be chosen based on the mode variable.

See Adding Adaptive Objects for an example.

In the Environment File

In the Environment File, Adaptive Objects have one special quality:

  • They are an object with keys representing application modes, such as:
"API_TOKEN": {
  "dev": "token-dev",
  "staging": "token-staging"
}

Adaptive Objects in the Environment File will be accessed when the Configuration File contains an Adaptive Value.

A key from the object will be chosen based on the mode variable.

See Adaptive Values + Adaptive Objects for an example.

The Default Key

All Adaptive Objects can contain a _default key.

This key will be accessed if the mode variable is not set, or if there are no keys within the Adaptive Object which match the current mode.

See Putting it All Together for an example.

The mode Variable

Adaptive Objects can only function if the mode is set.

By default, adapt will look in the environment for process.env.mode.

The mode variable can also be set manually using Programmatic Configuration.

Adaptive Values

Adaptive Values are used in the Configuration File to reference data in the environment.

These values are surrounded in brackets, such as [API_KEY]. This tells the Selecting Function to replace this section with a value from the Environment File or process.env.

See Adding Adaptive Values for an example.

Interpolated Adaptive Values

Adaptive Values can contain additional text and/or multiple bracketed sections. For example:

{
  "database": "mysql://[DATABASE_USER]:[DATABASE_PASSWORD]"
}

Adaptive References

Adaptive References are used in the Configuration File to reference other configuration values.

These values are surrounded in curly braces which contain a selector, such as {database.url}. This tells the Selecting Function to replace this section with the value of the given selector from elsewhere in the Configuration File.

See Adding Adaptive Values for an example.

Interpolated Adaptive References

Adaptive References can contain additional text and/or multiple curly braced sections. For example:

{
  "database": "mysql://{database.user}@{database.host}"
}

See Putting it All Together for an example.

Preloading Environment Data

By default, adapt will not load data from the Environment File into process.env. If you'd like to do this you can use the adapt command.

The adapt Command

The adapt command will run shell commands with the environment variables defined in your Environment File loaded into process.env.

This can be useful when running a command line utility which relies on environment variables.

Usage

adapt '[command]'

Example

adapt.env.json

{
  "DATABASE_URL": {
    "testing": "my-testing-database",
    "production": "my-production-database"
  }
}

CLI

mode=testing adapt "echo $DATABASE_URL"
> "my-testing-database"

mode=production adapt "echo $DATABASE_URL"
> "my-production-database"