Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

env-var

Package Overview
Dependencies
Maintainers
2
Versions
49
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

env-var - npm Package Compare versions

Comparing version 5.2.0 to 6.0.0

17

CHANGELOG.md

@@ -0,1 +1,18 @@

## 6.0.0 (12/02/20)
* Add support for setting an example value via the `example(string)` function.
* Passing default values is now performed using the `default(string)` function.
* Defer checks for `required()` until an accessor such as `asString()` is invoked.
* Fix typings issue where `required()` was undefined on a `IPresentVariable`.
Migration from 5.x to 6.0.0 should be smooth. Change any instance of
`env.get(target, default)` to `env.get(target).default(default)`. For example:
```js
// Old 5.x code
const emailAddr = env.get('EMAIL_ADDR', 'admin@example.com').asString()
// New 6.x compatible code
const emailAddr = env.get('EMAIL_ADDR').default('admin@example.com').asString()
```
## 5.2.0 (22/11/19)

@@ -2,0 +19,0 @@ * The `required()` function now verifies the variable is not an empty string

42

env-var.d.ts

@@ -13,2 +13,20 @@

/**
* Provide an example value that can be used in error output if the variable
* is not set, or is set to an invalid value
*/
example: (example: string) => IPresentVariable
/**
* Set a default value for this variable. This will be used if a value is not
* set in the process environment
*/
default: (value: string) => IPresentVariable;
/**
* Ensures the variable is set on process.env. If it's not set an exception
* will be thrown. Can pass false to bypass the check.
*/
required: (isRequired?: boolean) => IPresentVariable;
/**
* Converts a number to an integer and verifies it's in port ranges 0-65535

@@ -108,8 +126,20 @@ */

/**
* Converts a bas64 environment variable to ut8
* Decodes a base64-encoded environment variable
*/
convertFromBase64: () => IOptionalVariable
convertFromBase64: () => IOptionalVariable;
/**
* Ensures the variable is set on process.env, if not an exception will be thrown.
* Provide an example value that can be used in error output if the variable
* is not set, or is set to an invalid value
*/
example: (value: string) => IOptionalVariable;
/**
* Set a default value for this variable. This will be used if a value is not
* set in the process environment
*/
default: (value: string) => IPresentVariable;
/**
* Ensures the variable is set on process.env. If it's not set an exception will be thrown.
* Can pass false to bypass the check

@@ -226,7 +256,2 @@ */

/**
* Gets an environment variable, using the default value if it is not already set
*/
get (varName: string, defaultValue: string): PresentVariable;
/**
* Returns a new env-var instance, where the given object is used for the environment variable mapping.

@@ -255,3 +280,2 @@ * Use this when writing unit tests or in environments outside node.js.

export function get(varName: string): IOptionalVariable;
export function get(varName: string, defaultValue: string): IPresentVariable;
export function from<T extends Extensions, K extends keyof T>(values: NodeJS.ProcessEnv, extensions?: T): IEnv<

@@ -258,0 +282,0 @@ IPresentVariable & Record<K, (...args: any[]) => ReturnType<T[K]>>,

'use strict'
const variable = require('./lib/variable')
const EnvVarError = require('./lib/env-error')

@@ -26,6 +27,5 @@ /**

* @param {String} variableName Name of the environment variable requested
* @param {String} defaultValue Optional default to use as the value
* @return {Object}
*/
get: (variableName, defaultValue) => {
get: function (variableName) {
if (!variableName) {

@@ -35,3 +35,7 @@ return container

return variable(container, variableName, defaultValue, extraAccessors || {})
if (arguments.length > 1) {
throw new EnvVarError('It looks like you passed more than one argument to env.get(). Since env-var@6.0.0 this is no longer supported. To set a default value use env.get(TARGET).default(DEFAULT)')
}
return variable(container, variableName, extraAccessors || {})
}

@@ -38,0 +42,0 @@ }

@@ -15,4 +15,7 @@ 'use strict'

*/
module.exports = function getVariableAccessors (container, varName, defValue, extraAccessors) {
module.exports = function getVariableAccessors (container, varName, extraAccessors) {
let isBase64 = false
let isRequired = false
let defValue
let example

@@ -24,3 +27,13 @@ /**

function raiseError (value, msg) {
throw new EnvVarError(`"${varName}" ${msg}, but was "${value}"`)
let errMsg = `"${varName}" ${msg}`
if (value) {
errMsg = `${errMsg}, but is set to "${value}"`
}
if (example) {
errMsg = `${errMsg}. An example of a valid value would be: ${example}`
}
throw new EnvVarError(errMsg)
}

@@ -37,11 +50,19 @@

if (typeof value === 'undefined') {
if (typeof defValue === 'undefined') {
// Need to return since no value is available. If a value needed to
// be available required() should be called, or a default passed
return
if (typeof defValue === 'undefined' && isRequired) {
// Var is not set, nor is a default. Throw an error
raiseError(undefined, 'is a required variable, but it was not set')
} else if (defValue) {
value = defValue
} else {
// return undefined since variable is not required and
// there's no default value provided
return undefined
}
}
// Assign the default as the value since process.env does not contain
// the desired variable
value = defValue
if (isRequired) {
// Need to verify that required variables aren't just whitespace
if (value.trim().length === 0) {
raiseError(undefined, 'is a required variable, but its value was empty')
}
}

@@ -97,2 +118,6 @@

/**
* Instructs env-var to first convert the value of the variable from base64
* when reading it using a function such as asString()
*/
convertFromBase64: function () {

@@ -105,19 +130,43 @@ isBase64 = true

/**
* Set a default value for the variable
* @param {String} value
*/
default: function (value) {
if (typeof value === 'number') {
defValue = value.toString()
} else if (Array.isArray(value) || (typeof value === 'object' && value !== null)) {
defValue = JSON.stringify(value)
} else if (typeof value !== 'string') {
throw new EnvVarError('values passed to default() must be of Number, String, Array, or Object type')
} else {
defValue = value
}
return accessors
},
/**
* Ensures a variable is set in the given environment container. Throws an
* EnvVarError if the variable is not set or a default is not provided
* @param {Boolean} isRequired
* @param {Boolean} required
*/
required: function (isRequired) {
if (isRequired === false) {
return accessors
required: function (required) {
if (typeof required === 'undefined') {
// If no value is passed assume that developer means "true"
// This is to retain support legacy usage (and intuitive)
isRequired = true
} else {
isRequired = required
}
if (typeof container[varName] === 'undefined' && typeof defValue === 'undefined') {
throw new EnvVarError(`"${varName}" is a required variable, but it was not set`)
}
return accessors
},
const value = typeof container[varName] === 'undefined' ? defValue : container[varName]
if (value.trim().length === 0) {
throw new EnvVarError(`"${varName}" is a required variable, but its value was empty`)
}
/**
* Set an example value for this variable. If the variable value is not set
* or is set to an invalid value this example will be show in error output.
* @param {String} example
*/
example: function (ex) {
example = ex

@@ -124,0 +173,0 @@ return accessors

{
"name": "env-var",
"version": "5.2.0",
"version": "6.0.0",
"description": "Verification, sanatization, and type coercion for environment variables in Node.js",

@@ -54,10 +54,10 @@ "main": "env-var.js",

"devDependencies": {
"@types/node": "~12.12.0",
"@types/node": "~13.7.0",
"bluebird": "~3.7.0",
"chai": "~4.2.0",
"coveralls": "~3.0.0",
"husky": "~3.1.0",
"mocha": "~6.2.0",
"husky": "~4.2.2",
"mocha": "~7.0.1",
"mocha-lcov-reporter": "~1.3.0",
"nyc": "~14.1.0",
"nyc": "~15.0.0",
"standard": "~14.3.0",

@@ -64,0 +64,0 @@ "typescript": "~3.1.3"

@@ -14,7 +14,15 @@ # env-var

Verification, sanitization, and type coercion for environment variables in
Node.js. Supports TypeScript!
<br>
<br>
</div>
Verification, sanitization, and type coercion for environment variables in
Node.js. Particularly useful in TypeScript environments.
* 🏋 Lightweight, at just 4.2kB when minified
* 🧹 Cleaner code, as [shown here](https://gist.github.com/evanshortiss/0cb049bf676b6138d13384671dad750d)
* 🚫 [Fail fast](https://en.wikipedia.org/wiki/Fail-fast) if your environment is misconfigured
* 👩‍💻 Friendly error messages and example values improve developer experience
* 🎉 TypeScript support provides compile time safety and better developer experience
## Install

@@ -46,10 +54,10 @@ **Note:** env-var requires Node version 8 or later.

.required()
// Convert DB_PASSWORD from base64 to a regular utf8 string (optional)
// Decode DB_PASSWORD from base64 to a utf8 string (optional)
.convertFromBase64()
// Call asString (or other methods) to get the variable value (required)
// Call asString (or other APIs) to get the variable value (required)
.asString();
// Read in a port (checks that PORT is in the raneg 0 to 65535) or use a
// default value of 5432 instead
const PORT = env.get('PORT', 5432).asPortNumber()
// Read in a port (checks that PORT is in the range 0 to 65535)
// Alternatively, use amdefault value of 5432 if PORT is not defined
const PORT = env.get('PORT').default('5432').asPortNumber()
```

@@ -62,13 +70,50 @@

// Read a PORT environment variable and ensure it's a positive number
// An EnvVarError will be thrown if the variable is not set, or is not a number
// Read a PORT environment variable and ensure it's a positive integer.
// An EnvVarError will be thrown if the variable is not set, or if it
// is not a positive integer.
const PORT: number = env.get('PORT').required().asIntPositive();
```
## Benefits
Fail fast if your environment is misconfigured. Also,
[this code](https://gist.github.com/evanshortiss/75d936665a2a240fa1966770a85fb137) without
`env-var` would require multiple `assert` calls, other logic, and be more
complex to understand as [demonstrated here](https://gist.github.com/evanshortiss/0cb049bf676b6138d13384671dad750d).
## Usage with dotenv
There is no tight coupling between [env-var](https://www.npmjs.com/package/env-var)
[dotenv](https://www.npmjs.com/package/dotenv). Just `npm install dotenv` and
use it whatever way you're used to. This loose coupling is a good thing since
it reduces package bloat - only install what you need!
You can use `dotenv` with `env-var` via a `require()` calls in your code or
preloading it with the `--require` or `-r` flag in the `node` CLI.
Both examples below assume you have a `.env` file in your repository and it
contains a line similar to `MY_VAR=a-string-value!`.
### Load dotenv via require()
This is per the default usage described by [dotenv's README](https://www.npmjs.com/package/dotenv#usage).
```js
// Read in the .env file
require('dotenv').config()
// Read the MY_VAR entry that dotenv created
const env = require('env-var')
const myVar = env.get('MY_VAR').asString()
```
### Preload dotenv via CLI Args
This is per the [preload section](https://www.npmjs.com/package/dotenv#preload)
of the dotenv README. Run the following code by using the
`node -r dotenv/config your_script.js` command.
```js
// This is just a regular node script, but we started it using the command
// "node -r dotenv/config your_script.js" via the terminal. This tells node
// to load our variables using dotenv before running the rest of our script!
// Read the MY_VAR entry that dotenv created
const env = require('env-var')
const myVar = env.get('MY_VAR').asString()
```
## API

@@ -79,8 +124,9 @@

* module (env-var)
* [EnvVarError()](#envvarerror)
* [from()](#fromvalues-extraaccessors)
* [get()](#getvarname-default)
* [get()](#getvarname)
* [variable](#variable)
* [required()](#requiredisrequired--true)
* [covertFromBase64()](#convertfrombase64)
* [example(string)](#examplestring)
* [default(string)](#defaultstring)
* [asArray()](#asarraydelimiter-string)

@@ -103,30 +149,8 @@ * [asBoolStrict()](#asboolstrict)

* [asUrlString()](#asurlstring)
* [EnvVarError()](#envvarerror)
### EnvVarError()
This is the error class used to represent errors raised by this module. Sample
usage:
```js
const env = require('env-var')
let value = null
try {
// will throw if you have not set this variable
value = env.get('MISSING_VARIABLE').required().asString()
// if catch error is set, we'll end up throwing here instead
throw new Error('some other error')
} catch (e) {
if (e instanceof env.EnvVarError) {
console.log('we got an env-var error', e)
} else {
console.log('we got some error that wasn\'t an env-var error', e)
}
}
```
### from(values, extraAccessors)
This function is useful if you're not in a typical Node.js environment, or for
testing. It allows you to generate an env-var instance that reads from the
given `values` instead of the default `process.env`.
given `values` instead of the default `process.env` Object.

@@ -139,149 +163,80 @@ ```js

// apiUrl will be 'https://my.api.com/'
const apiUrl = mockedEnv.get('API_BASE_URL').asUrlString()
const apiUrl = env.get('API_BASE_URL').asUrlString()
```
#### extraAccessors
When calling `from()` you can also pass an optional parameter containing
additional accessors that will be attached to any variables gotten by that
env-var instance.
When calling `env.from()` you can also pass an optional parameter containing
custom accessors that will be attached to any variables returned by that
env-var instance. This feature is explained in the
[extraAccessors section](#extraAccessors) of these docs.
Accessor functions must accept at least one argument:
### get(varname)
This function has two behaviours:
- `{*} value`: The value that the accessor should process.
1. Calling with a string argument will make it read that value from the environment
2. If no string argument is passed it will return the entire environment object
**Important:** Do not assume that `value` is a string!
Examples:
Example:
```js
const { from } = require('env-var')
const env = require('env-var')
// Environment variable that we will use for this example:
process.env.ADMIN = 'admin@example.com'
// #1 - Read the requested variable and parse it to a positive integer
const limit = env.get('MAX_CONNECTIONS').asIntPositive()
// Add an accessor named 'checkEmail' that verifies that the value is a
// valid-looking email address.
const env = from(process.env, {
checkEmail: (value) => {
const split = String(value).split('@')
// #2 - Returns the entire process.env object
const allVars = env.get()
```
// Validating email addresses is hard.
if (split.length !== 2) {
throw new Error('must contain exactly one "@"')
}
### variable
A variable is returned by calling `env.get(varname)`. It exposes the following
functions to validate and access the underlying value, set a default, or set
an example value:
return value
}
})
#### example(string)
Allows a developer to provide an example of a valid value for the environment
variable. If the variable is not set (and `required()` was called), or the
variable is set incorrectly this will be included in error output to help
developers diagnose the error.
// We specified 'checkEmail' as the name for the accessor above, so now
// we can call `checkEmail()` like any other accessor.
let validEmail = env.get('ADMIN').checkEmail()
```
For example:
The accessor function may accept additional arguments if desired; these must be
provided explicitly when the accessor is invoked.
For example, we can modify the `checkEmail()` accessor from above so that it
optionally verifies the domain of the email address:
```js
const { from } = require('env-var')
const env = require('env-var')
// Environment variable that we will use for this example:
process.env.ADMIN = 'admin@example.com'
const ADMIN_EMAIL = env.get('ADMIN_EMAIL')
.required()
.example('admin@example.com')
.asString()
```
// Add an accessor named 'checkEmail' that verifies that the value is a
// valid-looking email address.
//
// Note that the accessor function also accepts an optional second
// parameter `requiredDomain` which can be provided when the accessor is
// invoked (see below).
const env = from(process.env, {
checkEmail: (value, requiredDomain) => {
const split = String(value).split('@')
If *ADMIN_EMAIL* was not set this code would throw an error similar to that
below to help a developer diagnose the issue:
// Validating email addresses is hard.
if (split.length !== 2) {
throw new Error('must contain exactly one "@"')
}
if (requiredDomain && (split[1] !== requiredDomain)) {
throw new Error(`must end with @${requiredDomain}`)
}
return value
}
})
// We specified 'checkEmail' as the name for the accessor above, so now
// we can call `checkEmail()` like any other accessor.
//
// `env-var` will provide the first argument for the accessor function
// (`value`), but we declared a second argument `requiredDomain`, which
// we can provide when we invoke the accessor.
// Calling the accessor without additional parameters accepts an email
// address with any domain.
let validEmail = env.get('ADMIN').checkEmail()
// If we specify a parameter, then the email address must end with the
// domain we specified.
let invalidEmail = env.get('ADMIN').checkEmail('github.com')
```
env-var: "ADMIN_EMAIL" is a required variable, but it was not set. An example
of a valid value would be "admin@example.com"
```
This feature is also available for TypeScript users. The `ExtensionFn` type is
expoed to help in the creation of these new accessors.
#### default(string)
Allows a default value to be provided for use if the desired environment
variable is not set in the program environment.
```ts
import { from, ExtensionFn, EnvVarError } from 'env-var'
Example:
// Environment variable that we will use for this example:
process.env.ADMIN = 'admin@example.com'
const checkEmail: ExtensionFn<string> = (value) => {
const split = String(value).split('@')
// Validating email addresses is hard.
if (split.length !== 2) {
throw new Error('must contain exactly one "@"')
}
return value
}
const env = from(process.env, {
checkEmail
})
// Returns the email string if it's valid, otherwise it will throw
env.get('ADMIN').checkEmail()
```
### get([varname, [default]])
You can call this function 3 different ways:
```js
const env = require('env-var')
// #1 - Return the requested variable (we're also checking it's a positive int)
const limit = env.get('SOME_LIMIT').asIntPositive()
// #2 - Return the requested variable, or use the given default if it isn't set
const limit = env.get('SOME_LIMIT', '10').asIntPositive()
// #3 - Return the environment object (process.env by default - see env.from() docs for more)
const allvars = env.get()
// Use POOL_SIZE if set, else use a value of 10
const POOL_SIZE = env.get('POOL_SIZE').default('10').asIntPositive()
```
### variable
A variable is returned by calling `env.get`. It has the exposes the following
functions to validate and access the underlying value.
#### required(isRequired = true)
Ensure the variable is set on *process.env*. If the variable is not set or empty
this function will throw an `EnvVarError`. If the variable is set it returns itself
so you can access the underlying variable.
Ensure the variable is set on *process.env*. If the variable is not set, or is
set to an empty value, this function will cause an `EnvVarError` to be thrown
when you attempt to read the value using `asString` or a similar function.
Can be bypassed by passing `false`, i.e `required(false)`
The `required()` check can be bypassed by passing `false`, i.e
`required(false)`
Full example:
Example:

@@ -291,17 +246,17 @@ ```js

// Read PORT variable and ensure it's a positive integer. If it is not a
// positive integer, not set or empty the process will exit with an error
// (unless you catch it using a try/catch or "uncaughtException" handler)
// Get the value of NODE_ENV as a string. Could be undefined since we're
// not calling required() before asString()
const NODE_ENV = env.get('NODE_ENV').asString()
const PORT = env.get('PORT').required().asIntPositive()
// If mode is production then this is required, else use default
const SECRET = env.get('SECRET', 'bad-secret').required(NODE_ENV === 'production').asString()
// Read PORT variable and ensure it's in a valid port range. If it's not in
// valid port ranges, not set, or empty an EnvVarError will be thrown
const PORT = env.get('PORT').required().asPortNumber()
app.listen(PORT)
// If mode is production then this is required
const SECRET = env.get('SECRET').required(NODE_ENV === 'production').asString()
```
#### convertFromBase64()
Sometimes environment variables need to be encoded as base64. You can use this
function to convert them to UTF-8 strings before parsing them.
It's a common need to set an environment variable in base64 format. This
function can be used to decode a base64 environment variable to UTF8.

@@ -319,3 +274,3 @@ For example if we run the script script below, using the command `DB_PASSWORD=

#### asPortNumber()
Converts the value of the environment variable to a string and verifies it's
Converts the value of the environment variable to an integer and verifies it's
within the valid port range of 0-65535. As a result well known ports are

@@ -397,2 +352,25 @@ considered valid by this function.

### EnvVarError()
This is the error class used to represent errors raised by this module. Sample
usage:
```js
const env = require('env-var')
let value = null
try {
// will throw if you have not set this variable
value = env.get('MISSING_VARIABLE').required().asString()
// if catch error is set, we'll end up throwing here instead
throw new Error('some other error')
} catch (e) {
if (e instanceof env.EnvVarError) {
console.log('we got an env-var error', e)
} else {
console.log('we got some error that wasn\'t an env-var error', e)
}
}
```
## Examples

@@ -421,3 +399,3 @@

// Return a float, or 23.2 if not set
const floatVar = env.get('FLOAT', '23.2').asFloat();
const floatVar = env.get('FLOAT').default('23.2').asFloat();

@@ -440,2 +418,118 @@ // Return a Boolean. Throws an exception if not set or parsing fails

## extraAccessors
When calling `from()` you can also pass an optional parameter containing
additional accessors that will be attached to any variables gotten by that
env-var instance.
Accessor functions must accept at least one argument:
- `{*} value`: The value that the accessor should process.
**Important:** Do not assume that `value` is a string!
Example:
```js
const { from } = require('env-var')
// Environment variable that we will use for this example:
process.env.ADMIN = 'admin@example.com'
// Add an accessor named 'asEmail' that verifies that the value is a
// valid-looking email address.
const env = from(process.env, {
asEmail: (value) => {
const split = String(value).split('@')
// Validating email addresses is hard.
if (split.length !== 2) {
throw new Error('must contain exactly one "@"')
}
return value
}
})
// We specified 'asEmail' as the name for the accessor above, so now
// we can call `asEmail()` like any other accessor.
let validEmail = env.get('ADMIN').asEmail()
```
The accessor function may accept additional arguments if desired; these must be
provided explicitly when the accessor is invoked.
For example, we can modify the `asEmail()` accessor from above so that it
optionally verifies the domain of the email address:
```js
const { from } = require('env-var')
// Environment variable that we will use for this example:
process.env.ADMIN = 'admin@example.com'
// Add an accessor named 'asEmail' that verifies that the value is a
// valid-looking email address.
//
// Note that the accessor function also accepts an optional second
// parameter `requiredDomain` which can be provided when the accessor is
// invoked (see below).
const env = from(process.env, {
asEmail: (value, requiredDomain) => {
const split = String(value).split('@')
// Validating email addresses is hard.
if (split.length !== 2) {
throw new Error('must contain exactly one "@"')
}
if (requiredDomain && (split[1] !== requiredDomain)) {
throw new Error(`must end with @${requiredDomain}`)
}
return value
}
})
// We specified 'asEmail' as the name for the accessor above, so now
// we can call `asEmail()` like any other accessor.
//
// `env-var` will provide the first argument for the accessor function
// (`value`), but we declared a second argument `requiredDomain`, which
// we can provide when we invoke the accessor.
// Calling the accessor without additional parameters accepts an email
// address with any domain.
let validEmail = env.get('ADMIN').asEmail()
// If we specify a parameter, then the email address must end with the
// domain we specified.
let invalidEmail = env.get('ADMIN').asEmail('github.com')
```
This feature is also available for TypeScript users. The `ExtensionFn` type is
exposed to help in the creation of these new accessors.
```ts
import { from, ExtensionFn, EnvVarError } from 'env-var'
// Environment variable that we will use for this example:
process.env.ADMIN = 'admin@example.com'
const asEmail: ExtensionFn<string> = (value) => {
const split = String(value).split('@')
// Validating email addresses is hard.
if (split.length !== 2) {
throw new Error('must contain exactly one "@"')
}
return value
}
const env = from(process.env, {
asEmail
})
// Returns the email string if it's valid, otherwise it will throw
env.get('ADMIN').asEmail()
```
## Contributing

@@ -445,5 +539,5 @@ Contributions are welcomed. If you'd like to discuss an idea open an issue, or a

If you want to add a new global accessor, it's easy. Add a file to
`lib/accessors`, with the name of the type e.g add a file named `number-zero.js`
into that folder and populate it with code following this structure:
If you want to add a new global accessor add a file to `lib/accessors`, with
the name of the type e.g add a file named `number-zero.js` into that folder
and populate it with code following this structure:

@@ -453,2 +547,3 @@ ```js

* Validate that the environment value is an integer and equals zero.
* This is a strange example, but hopefully demonstrates the idea.
* @param {String} environmentValue this is the string from process.env

@@ -495,1 +590,4 @@ */

* @rmblstrp
* @shawnmclean
* @todofixthis
* @xuo

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc