2.10.3 β€’ Published 10 days ago

@calvear/env v2.10.3

Weekly downloads
-
License
MIT
Repository
github
Last release
10 days ago

πŸ“– About

Eases NodeJS environment variable handling, like env-cmd or dotenv, but with powerfull features and extensibility for adding custom providers (as plugins) for load, pull and push the variables from different stores.

πŸ“Œ Requirements

First, download and install NodeJS. Version 16 or higher is required.

Validate installed versions of node and npm with:

> node -v
v16.14.2

> npm -v
8.3.0

You can initialize a new npm project using:

> npm init

⚑️ Quick start

πŸ”” Make sure that you have NodeJS 14+ installed on your computer.

  • Installs the package:
> npm install @calvear/env

  added 1 packages, and audited 1 packages in 1s

  found 0 vulnerabilities

> _
  • Executes binary directly:
> node_modules/.bin/env --help

  Usage: env [command] [options..] [: subcmd [:]] [options..]

  Commands:
	env [options..] [: <subcmd> :]
	env pull [options..]
	env push [options..]
	env schema [options..]

> _
  • Or add desired commands in your npm script in package.json:
{
  ...,
  "scripts": {
	// starts project injecting "dev" environment variables and debug log level
	"start:dev": "env -e dev -m debug : node dist/main.js : --log debug",
	// starts project injecting "prod" environment variables
	"start:prod": "env -e prod -m debug : node dist/main.js",
	...,
	// builds project injecting "prod" environment variables
	"build:prod": "env -e prod -m build : tsc",
	...,
	"env:schema": "env schema -e dev --ci",
	// uploads environment "dev" variables
	"env:push:dev": "env push -e dev",
	// downloads environment "dev" variables
	"env:pull:dev": "env pull -e dev"
  },
  ...
}
  • Execs your command:

file: dist/main.js

console.log(`My environment loaded is: ${process.env.ENV}`);
> npm run start:dev

  13:31:59.865 INFO  loading dev environment in debug mode
  13:31:59.911 DEBUG using package-json provider
  13:31:59.912 DEBUG using app-settings provider
  13:31:59.914 DEBUG using secrets provider
  13:32:00.109 DEBUG environment loaded:
  {
	NODE_ENV: 'development',
	ENV: 'dev',
	VERSION: '1.0.0',
	NAME: '@my-app',
	VAR1: true,
	VAR2: true,
	GROUP1__VAR1: 'G1V2',
	ARR1: '1,val,true',
	SECRET: '***'
  }
  13:32:00.116 INFO  executing command > node dist/main.js
  My environment loaded is: dev
  13:32:00.232 INFO  process finished successfully

> _

β›© Structure

β”œβ”€β”€ src/
β”‚Β Β  β”œβ”€β”€ commands/ # lib commands handlers
β”‚Β Β  β”‚Β Β  β”œβ”€β”€ env.command.ts
β”‚Β Β  β”‚Β Β  β”œβ”€β”€ export.command.ts
β”‚Β Β  β”‚Β Β  β”œβ”€β”€ pull.command.ts
β”‚Β Β  β”‚Β Β  β”œβ”€β”€ push.command.ts
β”‚Β Β  β”‚Β Β  └── schema.command.ts
β”‚Β Β  β”œβ”€β”€ interfaces/ # provider interfaces
β”‚Β Β  β”œβ”€β”€ providers/ # integrated providers
β”‚Β Β  β”‚Β Β  β”œβ”€β”€ package-json.provider.ts
β”‚Β Β  β”‚Β Β  β”œβ”€β”€ app-settings.provider.ts
β”‚Β Β  β”‚Β Β  β”œβ”€β”€ secrets.provider.ts
β”‚Β Β  β”‚Β Β  └── local.provider.ts
β”‚Β Β  β”œβ”€β”€ utils/
β”‚Β Β  β”‚Β Β  β”œβ”€β”€ command.util.ts
β”‚Β Β  β”‚Β Β  β”œβ”€β”€ interpolate.util.ts
β”‚Β Β  β”‚Β Β  β”œβ”€β”€ json.util.ts
β”‚Β Β  β”‚Β Β  β”œβ”€β”€ normalize.util.ts
β”‚Β Β  β”‚Β Β  β”œβ”€β”€ schema.util.ts
β”‚Β Β  β”‚Β Β  └── logger.ts
β”‚Β Β  β”œβ”€β”€ arguments.ts # global arguments
β”‚Β Β  β”œβ”€β”€ exec.ts # initialization logic (load config, commands, etc.)
β”‚Β Β  └── main.ts
β”œβ”€β”€ tests/ # integration tests
β”œβ”€β”€ .eslintrc.json
β”œβ”€β”€ jest.config.json
β”œβ”€β”€ tsconfig.build.json
└── tsconfig.json

βš™οΈ Commands & Options

Options handling has the ability of replace arguments itself, using [[ and ]] as delimiters. So, in example for define your config file path, you must use your root argument, supposing root has the value of "config", this definition [[root]]/any-config-file.json will be config/any-config-file.json, or if your env argument is "dev", this definition [[root]]/config-file.[[env]].json will be config/config-file.dev.json.

Global options

OptionDescriptionTypeDefaultRequired?
--helpShows helpbooleanNo
--e, --envEnvironment for loadstringYes
-m, --modesExecution modesstring[][]No
--nd, --nestingDelimiterNesting level delimiter for flattenstring__No
--arrDesc, --arrayDescompositionWhether serialize or break down arraysbooleanfalseNo
-x, --expandInterpolates environment variables using itselfbooleanfalseNo
-ciContinuous Integration modebooleanfalseNo

Workspace options

OptionDescriptionTypeDefaultRequired?
--rootDefault environment folder pathstringenvNo
-c, --configFileConfig JSON file pathstring[[root]]/settings/settings.jsonNo
-s, --schemaFileEnvironment Schema JSON file pathstring[[root]]/settings/schema.jsonNo

JSON Schema options

OptionDescriptionTypeDefaultRequired?
-r, --resolveWhether merges new schema or overridemerge, overridemergeNo
--null, --nullableWhether variables are nullable by defaultbooleantrueNo
--df, --detectFormatWhether format of strings variables are included in schemabooleantrueNo

Logger options

OptionDescriptionTypeDefaultRequired?
--log, --logLevelLog levelsilly, trace, debug, info, warn, errorinfoNo
  • env

Inject your environment variables into process.env and executes a command.

env -e [env] [options..] [: subcmd [:]] [options..]

Examples:

> env -e dev -m test unit : npm test
> env -e dev -m debug : npm start : -c [[root]]/[[env]].settings.json
> env -e prod -m build optimize : npm build
  • pull

Pulls environment variables from providers stores.

env pull -e [env] [options..]
OptionDescriptionTypeDefaultRequired?
-o, --overwriteOverwrite local variablesbooleanfalseNo

Examples:

> env pull -e dev
  • push

Pushes environment variables to providers stores.

env push -e [env] [options..]
OptionDescriptionTypeDefaultRequired?
-f, --forceForce push for secrets (replace all)booleanfalseNo

Examples:

> env push -e dev
  • schema

Generates validation schema from providers output variables.

env schema -e [env] -m [modes] [options..]

Examples:

> env schema -e dev -m build
  • export

Export unified environment variables to a file from providers.

env export -e [env] -m [modes] [options..]
OptionDescriptionTypeDefaultRequired?
-u, -p, --uriUri for export file with variablesstring.envNo
-f, --formatFormat for export variablesstringdotenvNo

Examples:

> env export -e dev -m build -f json --uri [[env]].env.json

πŸ“‘ Providers

Main feature of this library is using providers for get and set environment variables. So, you can define your own provider, but lib came with 3 integrated providers:

  • package-json

Load some info from your project package.json.

Info read is:

{
	"version": "1.0.0",
	"project": "project-name",
	"name": "@package-name",
	"title": "app-name",
	"description": "any description"
}
OptionDescriptionTypeDefaultRequired?
--vp, --varPrefixPrefix for loaded variablesstring""No

Examples:

> env -e dev -m build : react-script build : --vp REACT_APP_
  • app-settings

Non secrets loader for appsettings.json.

appsettings.json file has the format below:

{
	"|DEFAULT|": {},
	"|MODE|": {},
	"|ENV|": {}
}

In example:

{
	"|DEFAULT|": {
		"VAR1": "v1_default"
	},
	"|MODE|": {
		"build": {
			"NODE_ENV": "production"
		},
		"debug": {
			"NODE_ENV": "development"
		},
		"test": {
			"NODE_ENV": "test"
		}
	},
	"|ENV|": {
		"dev": {
			"C1": "V1",
			"C2": "V2",
			"C3": 3,
			"GROUP1": {
				"VAR1": null,
				"VAR2": "G1V2",
				"VAR3": true,
				"GROUP2": {
					"VAR1": "G1G2V1"
				}
			},
			"C4": "23"
		}
	}
}
OptionDescriptionTypeDefaultRequired?
--ef, --envFileEnvironment variables file pathstring[[root]]/appsettings.jsonNo
--sp, --sectionPrefixPrefix for env and modes in env filestring | No
  • secrets

Secrets loader for env/[[env]].env.json.

OptionDescriptionTypeDefaultRequired?
--sf, --secretsFileSecret variables file pathstring[[root]]/[[env]].env.jsonNo
  • local

Local variables loader for env/[[env]].local.env.json.

OptionDescriptionTypeDefaultRequired?
--lf, --localFileLocal variables file pathstring[[root]]/[[env]].local.env.jsonNo
  • package-json

Load some info from your project package.json.

Info read is:

{
	"version": "1.0.0",
	"project": "project-name",
	"name": "@package-name",
	"title": "app-name",
	"description": "any description"
}
OptionDescriptionTypeDefaultRequired?
--vp, --varPrefixPrefix for loaded variablesstring""No

Examples:

> env -e dev -m build : react-script build : --vp REACT_APP_

βœ’ Creating Custom Providers

You can create your custom providers, in two ways:

  • Local Script: you must create a JavaScript file (.js), exporting by default your "provider" following standard interface exported by this lib.
  • NPM Package: you must create your custom NPM library and export by default your "provider" using standard interface exported by this lib.

How to load your provider is shown in Config Section.

In example, a provider exported by your NPM package written in TypeScript should be like:

import { CommandArguments, EnvProvider } from '@calvear/env';
import { logger, readJson, writeJson } from '@calvear/env/utils';

const KEY = 'my-unique-provider-key';

interface MyProviderCommandArguments extends CommandArguments {
	anyExtraOption: boolean;
}

export const MyProvider: EnvProvider<MyProviderCommandArguments> = {
	// unique identifier for provider
	key: KEY,

	// (optional) allows to provider adds new arguments/options
	// to commands using yargs for builder
	builder: (builder) => {
		builder.options({
			anyExtraOption: {
				group: KEY,
				alias: ['a', 'aeo'],
				type: 'boolean',
				default: false,
				describe: 'Any option description',
			},
		});
	},

	// call on environment variables loading,
	// may be a Promise
	load: ({ env, modes, ...options }) => {
		if (env === 'dev')
			return {
				NODE_ENV: 'development',
			};

		// you can return a list of JSON environment variables for merge
		return [
			{
				NODE_ENV: 'production',
				ANY_VAR: 'ABC', // will be replaced by value below
			},
			{
				ANY_VAR: 'ANY_VALUE',
				ANY_GROUP: {
					INNER_VAR: 12,
				},
			},
		];
	},

	// (optional) call on pulling variables from provider store,
	// config may pass in your config file
	pull: ({ env, modes, ...options }, config) => {
		// anyway you want for pulling variables to cache
	},

	// (optional) call on pushing/updating variables to provider store,
	// config may pass in your config file
	push: ({ env, modes, ...options }, config) => {
		// anyway you should do for pushing or updating your variables
	},
};

πŸ“₯ Config

You can configure any config argument inside you config file, but commonly providers are designed for this purpose.

{
	"log": "silly",
	// will hide values of keys SECRET and MY_API_KEY in logging
	"logMaskValuesOfKeys": ["SECRET", "MY_API_KEY"],
	// integrated providers and custom providers together
	"providers": [
		{
			"path": "package-json",
			"type": "integrated"
		},
		{
			"path": "app-settings",
			"type": "integrated"
		},
		{
			"path": "secrets",
			"type": "integrated"
		},
		{
			"path": "local",
			"type": "integrated"
		},
		{
			// custom NPM package
			"path": "@npm-package",
			"type": "module",
			"config": {
				"any-config": "any value"
			}
		},
		{
			// custom script inside project
			"path": "scripts/custom-loader.js",
			"type": "script"
		}
	]
}

πŸ“‘ Roadmap

  • Environment injection handling
  • Customizable variables store providers
  • Commands
    • push executes a pushing action over every providers
    • pull executes a pulling action over every providers
    • schema regenerates JSON schema using providers output
    • export exports environment variables in json or dotenv format
    • prepare prepares environment (creates folder and files required)
  • Improve documentation
  • Providers pull history
  • Providers pull and push difference calc and prompts
  • Providers dependsOn option
  • Programatic module

🧿 Linting

Project uses ESLint, for code formatting and code styling normalizing.

  • eslint: linter integrated with TypeScript.

For correct interpretation of linters, is recommended to use Visual Studio Code as IDE and install the plugins in .vscode folder at 'extensions.json', as well as use the config provided in 'settings.json'

πŸ“‹ Changelog

For last changes see CHANGELOG.md file for details.

πŸ› οΈ Built with

πŸ“„ License

This project is licensed under the MIT License - see LICENSE.md file for details.


⌨ by Alvear Candia, Cristopher Alejandro

2.10.3

10 days ago

2.10.2

3 months ago

2.10.1

3 months ago

2.9.2

4 months ago

2.9.1

5 months ago

2.9.0

5 months ago

2.8.0

8 months ago

2.7.0

1 year ago

2.6.1

1 year ago

2.3.0

2 years ago

2.4.0

2 years ago

2.6.0

2 years ago

2.2.1

2 years ago

2.2.0

2 years ago

2.1.1

2 years ago

2.2.2

2 years ago

2.1.0

2 years ago

1.2.4

2 years ago

2.0.1

2 years ago

2.0.0

2 years ago

1.2.3

2 years ago

1.2.2

2 years ago

1.2.1

2 years ago

1.2.0

2 years ago

1.0.1

2 years ago

1.0.0

2 years ago