Configuration utilities
Quickstart
import {
intSetting,
invalidSource,
settingsProvider,
stringSetting,
} from '@opvious/stl-settings';
const settings = settingsProvider((env) => ({
port: intSetting(env.PORT ?? 8080),
auth: {
clientID: stringSetting(env.CLIENT_ID ?? 'my-client'),
clientSecret: stringSetting({
source: env.CLIENT_SECRET ?? invalidSource,
sensitive: true,
}),
},
tag: stringSetting(env.TAG),
}));
const val = settings();
Importantly, val's type will automatically be inferred as:
{
readonly port: number;
readonly auth: {
readonly clientID: string;
readonly clientSecret: string;
}
readonly tag: string | undefined;
}
If CLIENT_SECRET isn't defined in the environment, the config provider will
throw an informative exception. To test different setting values without needing
mocks, pass in a custom environment when calling the config provider.
const val = settings({
CLIENT_ID: 'test-id',
CLIENT_SECRET: 'test-secret',
});
Defining a custom setting
We provide a convenience factory builder for types which do not need any
non-standard creation arguments.
import {simpleSettingFactory} from '@opvious/stl-settings';
const dateSetting = simpleSettingFactory((s): Date => new Date(s));
If additional arguments are desired, it's always possible--just more verbose--to
use the underlying setting factory directly. For example, here's one way to
implement an enum setting:
import {
newSetting,
Setting,
SettingParams,
SettingSource
} from '@opvious/stl-settings';
export interface EnumSettingParams<E extends string, S>
extends SettingParams<S> {
readonly symbols: ReadonlyArray<E>;
}
export function enumSetting<E extends string, S extends SettingSource>(
params: EnumSettingParams<E, S>
): Setting<S, E> {
return newSetting(params, (s): any => {
if (!~params.symbols.indexOf(s as any)) {
throw new Error('Invalid enum value');
}
return s;
});
}
Recommended project structure
In production code, we recommend using modular configuration types. Performing
post-processing on setting values is easy with a settingsManager:
import {settingsManager} from '@opvious/stl-settings';
const withSettings = settingsManager((env) => ({}));
export interface ModuleAConfig {}
export interface ModuleBConfig {}
export interface Config {
readonly moduleA: ModuleAConfig;
readonly moduleB: ModuleBConfig;
}
export const config = withSettings((val) => {
return {};
});
import * as sut from '../src/config.js';
const env = {};
expect(config(env)).toEqual();