@strattadb/environment
Version:
Environment variable configuration for Node.js made easy.
112 lines (92 loc) • 2.62 kB
text/typescript
import EnvironmentVariableError from './EnvironmentVariableError';
import { Parser } from './parsers';
import { logDebug } from './debug';
export type Env<TSchemaData> = {
[TKey in keyof TSchemaData]: TSchemaData[TKey];
};
/**
* A schema defines the environment variable
* requirements.
*/
export type Schema<TSchemaData> = {
[TKey in keyof TSchemaData]: SchemaEntry<TSchemaData[TKey]>;
};
export type SchemaEntry<TType> = {
/**
* The parser function used to parse
* the environment variable string.
*/
parser: Parser<TType>;
/**
* The name of the environment variable variable to look up.
*/
envVarName: string;
/**
* Helper text describing the variable.
*/
description?: string;
} & SchemaEntryRequiredInfo<TType>;
export type SchemaEntryRequiredInfo<TType> =
| {
required: true;
defaultValue?: undefined;
}
| {
required: false;
/**
* The default value to be used if the env variable is not defined.
* It will not be parsed or validated.
*/
defaultValue: TType;
};
/**
* Returns an env object based on a schema.
*/
export function makeEnv<TSchemaData extends Record<string, any>>(
schema: Schema<TSchemaData>,
processEnv: NodeJS.ProcessEnv = process.env,
): Env<TSchemaData> {
logDebug('making env object...');
const env = Object.entries(schema).reduce((acc, [key, schemaEntry]) => {
const value = getValue(key, schemaEntry, processEnv);
return { ...acc, [key]: value };
}, {}) as Env<TSchemaData>;
logDebug('env object ready: %o', env);
return env;
}
function getValue<TType>(
key: string,
schemaEntry: SchemaEntry<TType>,
processEnv: NodeJS.ProcessEnv,
): TType {
const envVarValue = processEnv[schemaEntry.envVarName];
if (envVarValue === undefined) {
if (schemaEntry.required) {
let message = `${schemaEntry.envVarName} is required but is not set`;
if (schemaEntry.description) {
message += `. Variable description: ${schemaEntry.description}`;
}
throw new EnvironmentVariableError(message);
}
return schemaEntry.defaultValue;
}
const value = parseEnvVarValue(key, envVarValue, schemaEntry);
return value;
}
function parseEnvVarValue<TType>(
key: string,
serializedValue: string,
schemaEntry: SchemaEntry<TType>,
): TType {
let value: TType;
try {
value = schemaEntry.parser(serializedValue);
} catch (error) {
throw new EnvironmentVariableError(
`${key} has invalid format. Reason: ${
(error as Error).message
}. Got: '${serializedValue}'`,
);
}
return value;
}