Socket
Socket
Sign inDemoInstall

env-verifier

Package Overview
Dependencies
0
Maintainers
1
Versions
12
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 1.0.2 to 1.1.2

.prettierignore

17

dist/index.d.ts
export interface MappedConfig {
[key: string]: string | undefined | MappedConfig;
[key: string]: any | string | undefined | MappedConfig;
}
interface ConfigWithEnvKeys {
[key: string]: string | ConfigWithEnvKeys;
export interface TransformFn {
(envValue: string): any;
}
export declare type TransformTuple = [string, TransformFn];
export interface ConfigWithEnvKeys {
[key: string]: string | InsertValue | TransformTuple | ConfigWithEnvKeys;
}
export interface VerifiedConfig {
[key: string]: string | VerifiedConfig;
[key: string]: any | string | VerifiedConfig;
}
declare class InsertValue {
value: any;
constructor(value: any);
}
export declare function verify(config: ConfigWithEnvKeys, env?: {

@@ -19,2 +27,3 @@ [key: string]: string | undefined;

}): VerifiedConfig;
export declare function insert(value: any): InsertValue;
export {};
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
class InsertValue {
constructor(value) {
this.value = value;
}
}
const recursiveVerify = ({ config, env, errors = [], path = '' }) => {

@@ -7,7 +12,21 @@ const mapConf = (key) => {

const subPath = path.length === 0 ? key : `${path}.${key}`;
if (typeof value === 'string') {
const envValue = env[value];
const getValueFromEnv = (key) => {
const envValue = env[key];
if (envValue === undefined || envValue.length === 0) {
errors.push(new Error(`environment value ${value} is missing from config object at ${subPath}`));
errors.push(new Error(`environment value ${key} is missing from config object at ${subPath}`));
return undefined;
}
return envValue;
};
if (value instanceof InsertValue) {
return { [key]: value.value };
}
else if (Array.isArray(value)) {
const [envKey, transformFn] = value;
const envValue = getValueFromEnv(envKey);
const transforedValue = envValue && transformFn(envValue);
return { [key]: transforedValue };
}
else if (typeof value === 'string') {
const envValue = getValueFromEnv(value);
return { [key]: envValue };

@@ -47,2 +66,6 @@ }

exports.strictVerify = strictVerify;
function insert(value) {
return new InsertValue(value);
}
exports.insert = insert;
//# sourceMappingURL=index.js.map

@@ -52,19 +52,64 @@ "use strict";

const env = {
a: 'A'
PRESENT: 'present'
};
const config = {
1: 'a',
2: 'zz-top',
1: 'PRESENT',
2: 'MISSING',
3: {
6: {
7: 'IM_ALSO_MISSING'
7: 'MISSING'
},
4: 'IM_MISSING',
5: 'ME_TOO'
4: 'MISSING',
5: 'MISSING'
}
};
expect(index_1.verify(config, env).errors.length).toEqual(4);
const result = index_1.verify(config, env).errors;
expect(result.length).toEqual(4);
});
});
});
describe('with transform functions', () => {
const env = {
PRESENT: 'present'
};
it('allows a tuple with a string and transform function', () => {
const configObj = {
present: ['PRESENT', (envVal) => envVal]
};
expect(() => index_1.verify(configObj, env)).not.toThrow();
});
it('allows the same tuple in a nested object', () => {
const configObj = {
nested: {
present: ['PRESENT', (envVal) => envVal]
}
};
const result = index_1.verify(configObj, env).config;
expect(result.nested.present).toEqual(env.PRESENT);
});
it('runs the transform function and inserts the transformed value', () => {
const transformed = ['hi', { there: ['this'] }, 'is', 'transformed'];
const expected = expect.objectContaining(transformed);
const configObj = {
present: ['PRESENT', (_envVal) => transformed]
};
const { present: result } = index_1.verify(configObj, env).config;
expect(result).toEqual(expected);
});
it('still returns an error if the env value is missing', () => {
const configObj = {
missing: ['MISSING', (envValue) => envValue]
};
const { errors } = index_1.verify(configObj, env);
expect(errors.length).toEqual(1);
});
it('does not call the transform function if the env value is missing', () => {
const transformFn = jest.fn();
const configObj = {
missing: ['MISSING', transformFn]
};
index_1.verify(configObj, env);
expect(transformFn).not.toHaveBeenCalled();
});
});
describe('strictVerfiy', () => {

@@ -104,3 +149,58 @@ it('should throw an error on missing .env value', () => {

});
describe('with insert()', () => {
const env = {
PRESENT: 'present'
};
it('does not error out when called with insert()', () => {
const configObj = {
nonEnvValue: index_1.insert('nonEnvValue')
};
expect(() => index_1.verify(configObj, env)).not.toThrow();
});
it('inserts the given value into config object', () => {
const configObj = {
nonEnvValue: index_1.insert('nonEnvValue')
};
const { nonEnvValue } = index_1.verify(configObj, env).config;
expect(nonEnvValue).toEqual('nonEnvValue');
});
it('inserts given value in nested config object', () => {
const configObj = {
a: {
nonEnvValue: index_1.insert('nonEnvValue')
}
};
const { config } = index_1.verify(configObj, env);
expect(config.a.nonEnvValue).toEqual('nonEnvValue');
});
});
describe('integration of all features', () => {
const env = {
PRESENT: 'present'
};
it('mixes and matches features across nested config object', () => {
const mixed = {
present: 'PRESENT',
transformed: ['PRESENT', (_value) => 'transformed'],
inserted: index_1.insert('inserted')
};
const configObj = {
mixed,
...mixed
};
const expected = expect.objectContaining({
present: 'present',
transformed: 'transformed',
inserted: 'inserted',
mixed: {
present: 'present',
transformed: 'transformed',
inserted: 'inserted'
}
});
const { config } = index_1.verify(configObj, env);
expect(config).toEqual(expected);
});
});
});
//# sourceMappingURL=index.spec.js.map
{
"name": "env-verifier",
"version": "1.0.2",
"version": "1.1.2",
"description": "\"Make sure you have all your env variables!\"",

@@ -5,0 +5,0 @@ "main": "dist/index.js",

# env-verifier
Quickly verify that incoming variables from process.env aren't `undefined`
Quickly verify that incoming variables from process.env aren't missing.

@@ -24,34 +24,51 @@ [GitHub](https://github.com/pluralsight/env-verifier)

There are two functions exposed - `verify` or `strictVerify`. Use `verify` when you whant to handle your own missing values, and `strictVerify` when you want us to throw a descriptive error. Simply change your code to something like this:
to get up and running quickly with a verified config file, you can replace the above with something like this:
```javascript
const { config, errors } = verify({
const { verify } = require('env-verifier')
const config = {
database: {
name: 'DB_NAME'
host: 'DB_HOST'
password: 'DB_PASSWORD'
name: DB_NAME
host: DB_HOST
password: DB_PASSWORD
},
baseUrl: 'BASE_URL'
}, env)
if (errors.length) {
logger.error(errors)
baseUrl: BASE_URL
}
module.exports = config
const { config: builtConfig, errors } = verify(config)
errors.foreach(error => console.error(error))
module.exports = builtConfig
```
You can pass in an `env` parameter as long as its an object that is non-nested and has key value pairs with `undefined` or `string` as their value type
This package exposes two verification functions - `verify` and `strictVerify`. Use `verify` (as seen above) when you want to handle reporting missing values, and `strictVerify` when you want us to throw a descriptive error.
Function signatures (using typescript):
You can pass in your own `env` object as a parameter as long as its an object that is non-nested and has key value pairs with `undefined` or `string` as their value type.
Function signatures:
```typescript
interface Config {
[key: string]: string | Config
export interface TransformFn {
(envValue: string): any
}
//see below
// [envKeyName, TransformFn]
export type TransformTuple = [string, TransformFn]
interface ConfigWithEnvKeys {
[key: string]: string | InsertValue | TransformTuple | ConfigWithEnvKeys
}
interface MappedConfig {
[key: string]: string | undefined | Config
[key: string]: any | string | undefined | Config
}
export interface VerifiedConfig {
[key: string]: any | string | VerifiedConfig
}
interface Env {

@@ -61,5 +78,7 @@ [key: string]: string | undefined

function insert(value: any): InsertValue //see inserting arbitrary values below
function verify(config: Config, env: Env = process.env): { config: MappedConfig, errors: string[] }
function strictVerify(config: Config, env: Env = process.env): Config //Throws on .env miss
function strictVerify(config: Config, env: Env = process.env): VerifiedConfig //See Errors section
```

@@ -70,2 +89,3 @@

```javascript
//will throw on undefined or empty string env variables
module.exports = strictVerify({

@@ -81,2 +101,47 @@ database: {

#### Arbitrary value insertion
You may have values that aren't present on your `env` object, but that you would like to live in your config object, this can be achieved by using the `insert()` function.
```javascript
const { verify, insert } = require('env-verifier')
module.exports = verify({
appName: insert('my_app')
... // other env key names
})
//exports:
{
appName: 'my_app'
... // other env values
}
```
#### Error generation and reporting
Error reports are generated when an `env` variable is missing. An `env` variable is considered missing under the following circumstances:
- `undefined` is returned from the `env` object.
- an empty string, `''`, is returned from the `env` object.
`strictVerify` will not throw an error on the first encountered missing `env` value. Instead it will continue in order to report all missing `env` variables.
#### Variable Transformation (TransformTuple)
Since process.env only returns strings, sometimes its necessary to transform those strings into something else (IE: transform the string `"true"` to a boolean `true`)
This can be done by passing in an array (TransformTuple) containing the `env` variable name, and the function that you would like to use to transform the `env` variable value like so:
```javascript
const config = {
useNewFeature: ['USE_NEW_FEATURE', trueOrFalse => trueOrFalse === 'true'],
... //other env variables
}
verify(config)
```
Transformation functions will not be run if its corresponding env value is missing.
### Prerequisites

@@ -88,3 +153,3 @@

One of these
One of these:

@@ -95,3 +160,3 @@ ```bash

And one of these
And one of these:

@@ -106,5 +171,5 @@ ```javascript

After you've ran `npm install`, just run `npm test`
After you've ran `npm install`, just run `npm test`.
We use jest as our testing framework
We use jest as our testing framework.

@@ -127,2 +192,2 @@ ## Contributing

This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.

@@ -1,2 +0,2 @@

import { verify, strictVerify } from './index'
import { verify, strictVerify, ConfigWithEnvKeys, insert } from './index'

@@ -54,19 +54,81 @@ describe('env-verify', () => {

const env = {
a: 'A'
PRESENT: 'present'
}
const config = {
1: 'a',
2: 'zz-top',
1: 'PRESENT',
2: 'MISSING',
3: {
6: {
7: 'IM_ALSO_MISSING'
7: 'MISSING'
},
4: 'IM_MISSING',
5: 'ME_TOO'
4: 'MISSING',
5: 'MISSING'
}
}
expect(verify(config, env).errors.length).toEqual(4)
const result = verify(config, env).errors
expect(result.length).toEqual(4)
})
})
})
describe('with transform functions', () => {
const env = {
PRESENT: 'present'
}
it('allows a tuple with a string and transform function', () => {
const configObj: ConfigWithEnvKeys = {
present: ['PRESENT', (envVal: string): any => envVal]
}
expect(() => verify(configObj, env)).not.toThrow()
})
it('allows the same tuple in a nested object', () => {
const configObj: ConfigWithEnvKeys = {
nested: {
present: ['PRESENT', (envVal: string) => envVal]
}
}
const result = verify(configObj, env).config
expect(result.nested.present).toEqual(env.PRESENT)
})
it('runs the transform function and inserts the transformed value', () => {
const transformed = ['hi', { there: ['this'] }, 'is', 'transformed']
const expected = expect.objectContaining(transformed)
const configObj: ConfigWithEnvKeys = {
present: ['PRESENT', (_envVal: string) => transformed]
}
const { present: result } = verify(configObj, env).config
expect(result).toEqual(expected)
})
it('still returns an error if the env value is missing', () => {
const configObj: ConfigWithEnvKeys = {
missing: ['MISSING', (envValue: string) => envValue]
}
const { errors } = verify(configObj, env)
expect(errors.length).toEqual(1)
})
it('does not call the transform function if the env value is missing', () => {
const transformFn = jest.fn()
const configObj: any = {
missing: ['MISSING', transformFn]
}
verify(configObj, env)
expect(transformFn).not.toHaveBeenCalled()
})
})
describe('strictVerfiy', () => {

@@ -108,2 +170,70 @@ it('should throw an error on missing .env value', () => {

})
describe('with insert()', () => {
const env = {
PRESENT: 'present'
}
it('does not error out when called with insert()', () => {
const configObj = {
nonEnvValue: insert('nonEnvValue')
}
expect(() => verify(configObj, env)).not.toThrow()
})
it('inserts the given value into config object', () => {
const configObj = {
nonEnvValue: insert('nonEnvValue')
}
const { nonEnvValue } = verify(configObj, env).config
expect(nonEnvValue).toEqual('nonEnvValue')
})
it('inserts given value in nested config object', () => {
const configObj = {
a: {
nonEnvValue: insert('nonEnvValue')
}
}
const { config } = verify(configObj, env)
expect(config.a.nonEnvValue).toEqual('nonEnvValue')
})
})
describe('integration of all features', () => {
const env = {
PRESENT: 'present'
}
it('mixes and matches features across nested config object', () => {
const mixed: ConfigWithEnvKeys = {
present: 'PRESENT',
transformed: ['PRESENT', (_value: string) => 'transformed'],
inserted: insert('inserted')
}
const configObj = {
mixed,
...mixed
}
const expected = expect.objectContaining({
present: 'present',
transformed: 'transformed',
inserted: 'inserted',
mixed: {
present: 'present',
transformed: 'transformed',
inserted: 'inserted'
}
})
const { config } = verify(configObj, env)
expect(config).toEqual(expected)
})
})
})
export interface MappedConfig {
[key: string]: string | undefined | MappedConfig
[key: string]: any | string | undefined | MappedConfig
}
interface ConfigWithEnvKeys {
[key: string]: string | ConfigWithEnvKeys
export interface TransformFn {
(envValue: string): any
}
export type TransformTuple = [string, TransformFn]
export interface ConfigWithEnvKeys {
[key: string]: string | InsertValue | TransformTuple | ConfigWithEnvKeys
}
interface VerifyParamCollection {

@@ -16,5 +23,12 @@ config: ConfigWithEnvKeys

export interface VerifiedConfig {
[key: string]: string | VerifiedConfig
[key: string]: any | string | VerifiedConfig
}
class InsertValue {
value: any
constructor(value: any) {
this.value = value
}
}
const recursiveVerify = ({

@@ -30,12 +44,29 @@ config,

if (typeof value === 'string') {
const envValue = env[value]
const getValueFromEnv = (key: string): string => {
const envValue = env[key]
if (envValue === undefined || envValue.length === 0) {
errors.push(
new Error(
`environment value ${value} is missing from config object at ${subPath}`
`environment value ${key} is missing from config object at ${subPath}`
)
)
return undefined
}
return { [key]: envValue } as ConfigWithEnvKeys
return envValue
}
if (value instanceof InsertValue) {
return { [key]: value.value }
} else if (Array.isArray(value)) {
const [envKey, transformFn] = value as TransformTuple
const envValue = getValueFromEnv(envKey)
const transforedValue = envValue && transformFn(envValue)
return { [key]: transforedValue }
} else if (typeof value === 'string') {
const envValue = getValueFromEnv(value as string)
return { [key]: envValue }
} else {

@@ -86,1 +117,5 @@ const { errors: subErrors, config: subConfig } = recursiveVerify({

}
export function insert(value: any): InsertValue {
return new InsertValue(value)
}

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

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

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc