env-verifier
Advanced tools
Comparing version 1.4.1 to 1.5.0
@@ -1,34 +0,3 @@ | ||
declare type Cast<X extends any, Y extends any> = X extends Y ? X : Y; | ||
declare type TransformTuple_<U extends any> = (string | ((_: string) => U))[]; | ||
declare type MappedConfigElement_<E extends any> = E extends any[] ? E extends TransformTuple_<infer R> ? R : never : E extends InsertValue<infer U> ? U : E extends SecretKey ? Secret : E extends string ? string | undefined : MappedConfig<E>; | ||
declare type MappedConfigElement<E extends any> = MappedConfigElement_<E> extends infer X ? Cast<X, any> : never; | ||
export declare type MappedConfig<T> = { | ||
[P in keyof T]: MappedConfigElement<T[P]>; | ||
}; | ||
export declare type TransformTuple<T> = [string, (_: string) => T]; | ||
export declare type ConfigWithEnvKeys<T> = { | ||
[P in keyof T]: T[P] extends InsertValue<infer U> ? InsertValue<U> : T[P] extends SecretKey ? SecretKey : T[P] extends string ? string : T[P] extends TransformTuple<infer U> ? TransformTuple<U> : T[P] extends ConfigWithEnvKeys<T[P]> ? ConfigWithEnvKeys<T[P]> : never; | ||
}; | ||
declare type MissingValue = { | ||
path: string; | ||
envKey: string; | ||
}; | ||
export declare type VerifiedConfig<T> = { | ||
[P in keyof T]: T[P] extends SecretKey ? Secret : T[P] extends TransformTuple_<infer U> ? U : T[P] extends InsertValue<infer U> ? U : T[P] extends string ? string : VerifiedConfig<T[P]>; | ||
}; | ||
export declare class InsertValue<T> { | ||
value: T; | ||
constructor(value: T); | ||
} | ||
export declare class SecretKey { | ||
secret: string; | ||
constructor(secret: string); | ||
} | ||
export declare class Secret { | ||
toJSON(): string; | ||
reveal: { | ||
(): string; | ||
}; | ||
constructor(secret: string); | ||
} | ||
import { ConfigWithEnvKeys, MappedConfig, VerifiedConfig, MissingValue } from './types'; | ||
import { InsertValue, SecretKey, TransformValue } from './classes'; | ||
export declare type VerifyReturnObject<T> = { | ||
@@ -51,2 +20,6 @@ config: MappedConfig<T>; | ||
export declare function secret(envKey: string): SecretKey; | ||
export {}; | ||
export declare function transform<T>(envKey: string, transformFunction: (envValue: string) => T): TransformValue<T>; | ||
export declare function transformFP<T>(transformFunction: (envValue: string) => T, envKey: string): TransformValue<T>; | ||
export declare function transformFP<T>(transformFunction: (envValue: string) => T): (envKey: string) => TransformValue<T>; | ||
export { ConfigWithEnvKeys, MappedConfig, VerifiedConfig, MappedConfigElement, TransformTuple, } from './types'; | ||
export { TransformValue, InsertValue, SecretKey, Secret } from './classes'; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.secret = exports.insert = exports.strictVerify = exports.verify = exports.Secret = exports.SecretKey = exports.InsertValue = void 0; | ||
class InsertValue { | ||
constructor(value) { | ||
this.value = value; | ||
} | ||
} | ||
exports.InsertValue = InsertValue; | ||
class SecretKey { | ||
constructor(secret) { | ||
this.secret = secret; | ||
} | ||
} | ||
exports.SecretKey = SecretKey; | ||
class Secret { | ||
constructor(secret) { | ||
this.reveal = () => secret; | ||
} | ||
toJSON() { | ||
return '[secret]'; | ||
} | ||
} | ||
exports.Secret = Secret; | ||
const isNode = () => typeof process === 'object' && process + '' === '[object process]'; | ||
const getSecretObject = (secret) => { | ||
const secretObj = new Secret(secret); | ||
if (isNode()) { | ||
const util = require('util'); | ||
secretObj[util.inspect.custom] = () => '[secret]'; | ||
} | ||
return secretObj; | ||
}; | ||
const getEnvValueOrErrorCurried = (env, subPath) => (key) => { | ||
const envValue = env[key]; | ||
if (envValue === undefined || envValue.length === 0) { | ||
const error = { envKey: key, path: subPath }; | ||
return [undefined, [error]]; | ||
} | ||
return [envValue, []]; | ||
}; | ||
exports.Secret = exports.SecretKey = exports.InsertValue = exports.TransformValue = exports.transformFP = exports.transform = exports.secret = exports.insert = exports.strictVerify = exports.verify = void 0; | ||
const classes_1 = require("./classes"); | ||
const config_resolvers_1 = require("./config-resolvers"); | ||
const getMapConfigFunction = ({ config, env, path = '', }) => (key) => { | ||
const value = config[key]; | ||
const subPath = path.length === 0 ? key + '' : `${path}.${key}`; | ||
const getEnvValueOrError = getEnvValueOrErrorCurried(env, subPath); | ||
if (value instanceof SecretKey) { | ||
const secretKey = value.secret; | ||
const [secretValue, errors] = getEnvValueOrError(secretKey); | ||
return [ | ||
{ [key]: getSecretObject(secretValue) }, | ||
errors, | ||
]; | ||
} | ||
if (value instanceof InsertValue) { | ||
return [{ [key]: value.value }, []]; | ||
} | ||
if (Array.isArray(value)) { | ||
const [envKey, transformFn] = value; | ||
const [envValue, errors] = getEnvValueOrError(envKey); | ||
const transformedValue = envValue && transformFn(envValue); | ||
return [{ [key]: transformedValue }, errors]; | ||
} | ||
if (typeof value === 'string') { | ||
const [envValue, errors] = getEnvValueOrError(value); | ||
return [{ [key]: envValue }, errors]; | ||
} | ||
const subPath = path.length === 0 ? `${key}` : `${path}.${key}`; | ||
const { resolveSecret, resolveInsert, resolveTransformTuple, resolveTransformer, resolveEnvValue } = config_resolvers_1.getResolvers(env, subPath); | ||
if (value instanceof classes_1.SecretKey) | ||
return resolveSecret(key, value); | ||
if (value instanceof classes_1.InsertValue) | ||
return resolveInsert(key, value); | ||
if (value instanceof classes_1.TransformValue) | ||
return resolveTransformer(key, value); | ||
if (Array.isArray(value)) | ||
return resolveTransformTuple(key, value); | ||
if (typeof value === 'string') | ||
return resolveEnvValue(key, value); | ||
const { errors, config: subConfig } = recursiveVerify({ | ||
@@ -108,9 +61,23 @@ config: value, | ||
function insert(value) { | ||
return new InsertValue(value); | ||
return new classes_1.InsertValue(value); | ||
} | ||
exports.insert = insert; | ||
function secret(envKey) { | ||
return new SecretKey(envKey); | ||
return new classes_1.SecretKey(envKey); | ||
} | ||
exports.secret = secret; | ||
//# sourceMappingURL=index.js.map | ||
function transform(envKey, transformFunction) { | ||
return new classes_1.TransformValue(envKey, transformFunction); | ||
} | ||
exports.transform = transform; | ||
function transformFP(transformFunction, envKey) { | ||
if (envKey) | ||
return new classes_1.TransformValue(envKey, transformFunction); | ||
return (envKey_) => new classes_1.TransformValue(envKey_, transformFunction); | ||
} | ||
exports.transformFP = transformFP; | ||
var classes_2 = require("./classes"); | ||
Object.defineProperty(exports, "TransformValue", { enumerable: true, get: function () { return classes_2.TransformValue; } }); | ||
Object.defineProperty(exports, "InsertValue", { enumerable: true, get: function () { return classes_2.InsertValue; } }); | ||
Object.defineProperty(exports, "SecretKey", { enumerable: true, get: function () { return classes_2.SecretKey; } }); | ||
Object.defineProperty(exports, "Secret", { enumerable: true, get: function () { return classes_2.Secret; } }); |
{ | ||
"name": "env-verifier", | ||
"version": "1.4.1", | ||
"version": "1.5.0", | ||
"description": "\"Make sure you have all your env variables!\"", | ||
@@ -11,2 +11,3 @@ "main": "dist/index.js", | ||
"prepack": "tsc", | ||
"prepare": "husky install", | ||
"build": "tsc" | ||
@@ -24,4 +25,8 @@ }, | ||
"devDependencies": { | ||
"@commitlint/cli": "^13.1.0", | ||
"@commitlint/config-conventional": "^13.1.0", | ||
"@semantic-release/git": "^9.0.0", | ||
"@types/jest": "^26.0.10", | ||
"@types/node": "^12.7.1", | ||
"husky": "^7.0.1", | ||
"jest": "^26.6.3", | ||
@@ -28,0 +33,0 @@ "onchange": "^7.0.2", |
@@ -5,2 +5,4 @@ # env-verifier | ||
![Build](https://github.com/pluralsight/env-verifier/actions/workflows/test-and-release.yml/badge.svg?branch=master) | ||
[GitHub](https://github.com/pluralsight/env-verifier) | ||
@@ -13,6 +15,9 @@ | ||
Certain types of apps require the use of different variables depending on the environment that the app is run in. | ||
The purpose of this package is to fail early whenever one of those values is missing from the environment object (ie: `process.env`). | ||
Using this package properly will prevent the sometimes cryptic errors that occur when environment variables are missing. | ||
Because every missing environment variable that `env-verifier` encountered is returned (or is displayed in a thrown error), this package can also help with the: `run the app, app crashes because of missing environment variable, add environment variable` loop that sometimes occurs. | ||
Because every missing environment variable that `env-verifier` encountered is returned (or is displayed in a thrown error), this package can also help with the: `run the app, app crashes because of missing environment variable, add environment variable, repeat` loop that sometimes occurs. | ||
## Getting Started | ||
@@ -49,3 +54,3 @@ | ||
This package exposes two verification functions - `verify` and `strictVerify`. Use `verify` (as seen below) when you want to handle reporting missing values, and `strictVerify` (as seen above) when you want, when any `env` misses are encountered, us to throw a descriptive error containing all `env` misses. | ||
This package exposes two verification functions - `verify` and `strictVerify`. Use `verify` (as seen below) when you want to handle reporting missing values, and `strictVerify` (as seen above) when you want, when any `env` misses are encountered, a descriptive error containing all `env` misses to be thrown. | ||
@@ -85,4 +90,5 @@ Use example for `verify`: | ||
- [Error Generation and Reporting](#error-generation-and-reporting) | ||
- [Variable Transformation (TransformTuple)](#variable-transformation) | ||
- [Variable Transformation](#variable-transformation) | ||
- [Dynamic Typings](#dynamic-typings) | ||
- [`env-verifier` vs `convict`](#env-verifier-vs-convict) | ||
@@ -98,2 +104,7 @@ ### Function Parameters and Return Types | ||
export function transform<T>(envKey: string, transformFn: (envValue: string) => T) => T // see `Variable Transformation` documentation | ||
export function transformFP<T>(transformFn: (envValue: string) => T, envKey: string) => T | ||
export function transformFP<T>(transformFn: (envValue: string) => T) => ((envKey: string) => T) // see `Variable Transformation` documentation | ||
export type TransformTuple = [string, (envValue: string) => any] | ||
@@ -291,23 +302,51 @@ | ||
### Variable Transformation (TransformTuple) | ||
### Variable Transformation | ||
Since `env-verifier` only takes environment key-value pair objects that have `strings` as the values, its sometimes 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 (called a `TransformTuple` in this context) containing the `env` variable name, and the function that you would like to use to transform the `env` variable value like so: | ||
This can be done in two ways: | ||
1. By passing in an array (called a `TransformTuple` in this context) containing the `env` variable name, and the function that you would like to use to transform the `env` variable value | ||
1. By calling the `transform` function which takes the `env` variable name and the transformer function. | ||
Here is an example for both: | ||
```javascript | ||
const config = { | ||
useNewFeature: ['USE_NEW_FEATURE', trueOrFalse => trueOrFalse === 'true'], | ||
useNewFeature: ['USE_NEW_FEATURE', trueOrFalse => trueOrFalse === 'true'], // results a boolean | ||
serverHosts: ['SERVER_HOSTS', csvString => csvString.split(',')] // results in a string array | ||
buildDate: transform('BUILD_DATE', dateString => new Date(dateString)) // results in a `Date` object | ||
... //other env variables | ||
} | ||
verify(config) | ||
module.exports = verify(config) | ||
``` | ||
Transformation functions will not be run if its corresponding env value is missing. | ||
Functions passed to either `transform` or given in a `TransformTuple` will not be run if its corresponding env value is missing. | ||
A `transformFP` function is also provided that accepts the transforming function first and will return a partially applied function if an environment key string is not supplied: | ||
```javascript | ||
import { transformFP, verify } from 'env-verifier' | ||
const parseBoolean = transformFP(trueOrFalse => trueOrFalse === 'true') | ||
export const config = verify({ | ||
useNewFeature: parseBoolean('USE_NEW_FEATURE'), // results in a boolean value | ||
hosts: transformFP(csvList => csvList.split(','), 'HOSTS') // results in a string array | ||
... other values | ||
}) | ||
``` | ||
### Dynamic Typings | ||
**Important**: as of `v1.4.0` `env-verifier` should now be able to correctly and dynamically infer the return types of both `verify` and `strictVerify` without any extra help. the below is only valid for versions that pre-date `v1.4.0` | ||
--- | ||
**Important** | ||
As of `v1.4.0`, `env-verifier` should now be able to correctly and dynamically infer the return types of both `verify` and `strictVerify` without any extra help. the below is only valid for versions that pre-date `v1.4.0` | ||
--- | ||
`env-verifier` tries to give typescript typings for the config object that it returns, but needs a little help to get the correct types | ||
@@ -365,2 +404,23 @@ | ||
### `env-verifier` vs `convict` | ||
Mozilla produces the excellent [`convict`](https://github.com/mozilla/node-convict) package that does most (if not all) of the same things that this package does. Here are a quick list of comparisons between the two: | ||
|Feature|`env-verifier`|`convict`| | ||
|-|-|-| | ||
| Config Merging | ⚠️ | ✔️ | | ||
| Nested Structures | ✔️ | ✔️ | | ||
| Environmental Variables | ✔️ | ✔️ | | ||
| Command-line arguments | ❌ | ✔️ | | ||
| Validation | ✔️ | ✔️ | | ||
| Secret Obfuscation | ✔️ | ✔️ | | ||
`convict` does more than what's included on the above list, and certainly more than `env-verifier` can do; so, it may be the correct choice for your project, especially if your project is a large one with many different/changing contributors. | ||
However `env-verifier` excels in the following: | ||
* Simplicity: Does one thing, and does it well | ||
* Size: ~8kb packed, ~18kb unpacked, 4 source files total | ||
* No production dependencies | ||
## Prerequisites | ||
@@ -367,0 +427,0 @@ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
11
257
464
27339
11
1