Security News
Supply Chain Attack Detected in Solana's web3.js Library
A supply chain attack has been detected in versions 1.95.6 and 1.95.7 of the popular @solana/web3.js library.
@travetto/config
Advanced tools
Install: @travetto/config
npm install @travetto/config
# or
yarn add @travetto/config
The config module provides support for loading application config on startup. Configuration values support the common YAML constructs as defined in YAML. Additionally, the configuration is built upon the Schema module, to enforce type correctness, and allow for validation of configuration as an entrypoint into the application. Given that all @Config classes are @Schema-based classes, all the standard @Schema and @Field functionality applies.
The configuration information is comprised of:
ext
can be yaml
, yml
, json
, properties
):resources/application.<ext>
- Load the default application.<ext>
if available.resources/*.<ext>
- Load profile specific configurations as defined by the values in process.env.TRV_PROFILES
resources/{env}.<ext>
- Load environment specific profile configurations as defined by the values of process.env.TRV_ENV
.
By default all configuration data is inert, and will only be applied when constructing an instance of a configuration class.A more complete example setup would look like:
Config: resources/application.yml
---
database:
host: localhost
creds:
user: test
password: test
Config: resources/prod.json
{
"database": {
"host": "prod-host-db",
"creds": {
"user": "admin-user"
}
}
}
with environment variables
Config: Environment variables
TRV_ENV = prod
TRV_PROFILES = prod
At runtime the resolved config would be:
Terminal: Runtime Resolution
$ trv main doc/resolve.ts
Config {
sources: [
'application.1 - file://./doc/resources/application.yml',
'prod.1 - file://./doc/resources/prod.json',
'override.3 - memory://override'
],
active: {
DBConfig: { host: 'prod-host-db', port: 2000, creds: { user: 'admin-user' } }
}
}
The framework provides two simple base classes that assist with existing patterns of usage to make adding in new configuration sources as easy as possible. The goal here is for the developer to either instantiate or extend these classes and produce a configuration source unique to their needs:
Code: Memory Provider
import { ConfigData } from '../parser/types';
import { ConfigSource, ConfigValue } from './types';
/**
* Meant to be instantiated and provided as a unique config source
*/
export class MemoryConfigSource implements ConfigSource {
priority = 1;
data: Record<string, ConfigData>;
name = 'memory';
constructor(data: Record<string, ConfigData>, priority: number = 1) {
this.data = data;
this.priority = priority;
}
getValues(profiles: string[]): ConfigValue[] {
const out: ConfigValue[] = [];
for (const profile of profiles) {
if (this.data[profile]) {
out.push({ profile, config: this.data[profile], source: `${this.name}://${profile}`, priority: this.priority });
}
}
return out;
}
}
Code: Environment JSON Provider
import { Env, GlobalEnv } from '@travetto/base';
import { ConfigSource, ConfigValue } from './types';
/**
* Represents the environment mapped data as a JSON blob
*/
export class EnvConfigSource implements ConfigSource {
priority: number;
name = 'env';
#envKey: string;
constructor(key: string, priority: number) {
this.#envKey = key;
this.priority = priority;
}
getValues(profiles: string[]): ConfigValue[] {
try {
const data = JSON.parse(Env.get(this.#envKey, '{}'));
return [{ profile: GlobalEnv.envName, config: data, source: `${this.name}://${this.#envKey}`, priority: this.priority }];
} catch (e) {
console.error(`env.${this.#envKey} is an invalid format`, { text: Env.get(this.#envKey) });
return [];
}
}
}
In addition to files and environment variables, configuration sources can also be provided via the class itself. This is useful for reading remote configurations, or dealing with complex configuration normalization. The only caveat to this pattern, is that the these configuration sources cannot rely on the Configuration service for input. This means any needed configuration will need to be accessed via specific patterns.
Code: Custom Configuration Source
import { ConfigSource, ConfigValue } from '@travetto/config';
import { Injectable } from '@travetto/di';
@Injectable()
export class CustomConfigSource implements ConfigSource {
priority = 1000;
name = 'custom';
async getValues(): Promise<ConfigValue[]> {
return [
{
config: { user: { name: 'bob' } },
priority: this.priority,
profile: 'override',
source: `custom://${CustomConfigSource.name}`
}
];
}
}
At startup, the Configuration service will log out all the registered configuration objects. The configuration state output is useful to determine if everything is configured properly when diagnosing runtime errors. This service will find all configurations, and output a redacted version with all secrets removed. The default pattern for secrets is /password|private|secret/i
. More values can be added in your configuration under the path config.secrets
. These values can either be simple strings (for exact match), or /pattern/
to create a regular expression.
The Configuration service provides injectable access to all of the loaded configuration. For simplicity, a decorator, @Config allows for classes to automatically be bound with config information on post construction via the Dependency Injection module. The decorator will install a postConstruct
method if not already defined, that performs the binding of configuration. This is due to the fact that we cannot rewrite the constructor, and order of operation matters.
Additionally there are times in which you may want to also support configuration via environment variables. EnvVar supports override configuration values when environment variables are present.
The decorator takes in a namespace, of what part of the resolved configuration you want to bind to your class. Given the following class:
Code: Database config object
import { Config, EnvVar } from '@travetto/config';
@Config('database')
export class DBConfig {
host: string;
@EnvVar('DATABASE_PORT')
port: number;
creds: {
user: string;
password: string;
};
}
You can see that the DBConfig
allows for the port
to be overridden by the DATABASE_PORT
environment variable.
Terminal: Resolved database config
$ trv main doc/dbconfig-run.ts
{
message: 'Failed to construct @travetto/config:doc/dbconfig○DBConfig as validation errors have occurred',
category: 'data',
type: 'ValidationResultError',
at: 2029-03-14T04:00:00.618Z,
class: '@travetto/config:doc/dbconfig○DBConfig',
file: './doc/dbconfig.ts',
errors: [
{
kind: 'required',
active: true,
value: undefined,
message: 'port is required',
path: 'port',
type: undefined
}
]
}
What you see, is that the configuration structure must be honored and the application will fail to start if the constraints do not hold true. This helps to ensure that the configuration, as input to the system, is verified and correct.
By passing in the port via the environment variable, the config will construct properly, and the application will startup correctly:
Terminal: Resolved database config
$ DATABASE_PORT=200 trv main doc/dbconfig-run.ts
Config {
sources: [
'application.1 - file://./doc/resources/application.yml',
'prod.1 - file://./doc/resources/prod.json',
'override.3 - memory://override'
],
active: {
DBConfig: { host: 'prod-host-db', port: 200, creds: { user: 'admin-user' } }
}
}
Additionally you may notice that the password
field is missing, as it is redacted by default.
FAQs
Configuration support
The npm package @travetto/config receives a total of 49 weekly downloads. As such, @travetto/config popularity was classified as not popular.
We found that @travetto/config demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 0 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
A supply chain attack has been detected in versions 1.95.6 and 1.95.7 of the popular @solana/web3.js library.
Research
Security News
A malicious npm package targets Solana developers, rerouting funds in 2% of transactions to a hardcoded address.
Security News
Research
Socket researchers have discovered malicious npm packages targeting crypto developers, stealing credentials and wallet data using spyware delivered through typosquats of popular cryptographic libraries.