Config
![Greenkeeper badge](https://badges.greenkeeper.io/SlimIO/Config.svg)
SlimIO - Reactive JSON Configuration loader. This package is used in SlimIO core and addons to safely hot reload configuration upon JSON Schema.
Features
- Hot-reloading of configuration
- Reactive with observable key(s)
- Safe with JSON Schema validation
- Support TOML as input (enable the parser when the file extension end with .toml)
Requirements
Node.js version 10 and upper are required to run this project. We do not provide support for previous versions.
Getting Started
This package is available in the Node Package Repository and can be easily installed with npm or yarn.
$ npm i @slimio/config
$ yarn add @slimio/config
Usage example
Create a simple json file for your project (As below)
{
"loglevel": 5,
"logsize": 4048,
"login": "administrator"
}
Now, create a new Configuration instance and read it
const Config = require("@slimio/config");
async function main() {
const cfg = new Config("./path/to/config.json");
await cfg.read();
console.log(cfg.get("loglevel"));
cfg.observableOf("login").subscribe(console.log);
cfg.set("login", "admin");
console.log(cfg.payload);
await cfg.close();
}
main().catch(console.error);
Note: config.json should exist (if not, it will throw an Error). Look at createOnNoEntry
option for more information !
Events
Configuration class is extended by a Node.js EventEmitter. The class can trigger several events:
event name | description |
---|
configWritten | The configuration payload has been written on the local disk |
watcherInitialized | The file watcher has been initialized (it will hot reload the configuration on modification) |
reload | The configuration has been hot reloaded successfully |
close | Event triggered when the configuration is asked to be closed |
API
This section describe how works the methods of Config class. For a complete definition, take a look at index.d.ts
!
constructor< T > (configFilePath: string, options?: Config.Options)
Create a new Config Object:
const cfg = new Config("./path/to/file.json", {
createOnNoEntry: true,
autoReload: true
});
Available options are:
name | type | default value | description |
---|
createOnNoEntry | boolean | false | Create the file with default payload value if he doesn't exist on the local disk |
writeOnSet | boolean | false | Write the file on the disk after each time .set() is called |
autoReload | boolean | false | Setup hot reload of the configuration file |
reloadDelay | number | 500ms | The delay to wait before hot reloading the configuration, it's a security to avoid event spamming |
defaultSchema | plainObject | null | The default JSON Schema for the configuration |
Note: When no schema is provided, it will search for a file prefixed by .schema
with the same config name.
read (defaultPayload?: T): Promise< this >
Will trigger and read the local configuration (on disk). A default payload
value can be provided in case the file doesn't exist !
const { strictEqual } = require("assert");
const cfg = new Config("./path/to/file.json");
strictEqual(cfg.configHasBeenRead, false);
await cfg.read();
strictEqual(cfg.configHasBeenRead, true);
Retriggering the method will made an hot-reload of all properties. For a cold reload you will have to close the configuration before.
Warning When the file doesn't exist, the configuration is written at the next loop iteration (with lazyWriteOnDisk).
![](https://i.imgur.com/uMY4DZV.png)
setupAutoReload (): void
Setup hot reload (with a file watcher). This method is automatically triggered if the Configuration has been created with the option autoReload
set to true.
We use the package node-watch to achieve the hot reload.
get< H > (fieldPath: string, depth?: number): H
Get a value from a key (fieldPath). For example, let take a json payload with a root foo
field.
const cfg = new Config("./path/to/file.json");
await cfg.read();
const fooValue = cfg.get("foo");
Under the hood the method work with lodash.get
function.
If the retrieved value is a JavaScript object, you can limit the depth by setting depth
option.
set< H > (fieldPath: string, fieldValue: H): void
Set a given field in the configuration.
const cfg = new Config("./config.json", {
createOnNoEntry: true
});
await cfg.read({ foo: "bar" });
cfg.set("foo", "hello world!");
await cfg.writeOnDisk();
Under the hood the method work with lodash.set
function.
observableOf (fieldPath: string, depth?: number): ObservableLike
Observe a given configuration key with an Observable Like object!
const { writeFile } = require("fs").promises;
const cfg = new Config("./config.json", {
autoReload: true,
createOnNoEntry: true
});
await cfg.read({ foo: "bar" });
cfg.observableOf("foo").subscribe(console.log);
const newPayload = { foo: "world" };
await writeFile("./config.json", JSON.stringify(newPayload, null, 4));
writeOnDisk (): Promise< void >
Write the configuration on the disk.
lazyWriteOnDisk (): void
Write the configuration on the disk (only at the next event-loop iteration). Use the event configWritten
to known when the configuration will be written.
const cfg = new Config("./config.json", {
createOnNoEntry: true
});
await cfg.read();
cfg.once("configWritten", () => {
console.log("Configuration written!");
});
cfg.lazyWriteOnDisk();
close (): Promise< void >
Close (and write on disk) the configuration (it will close the watcher and complete/clean all active observers subscribers).
Properties
Following properties are static members of Config class.
STRINGIFY_SPACE
The STRINGIFY_SPACE
property allow you to redine the espace used internaly for JSON.stringify
method. The default value is 4.
DEFAULT_SCHEMA
The DEFAULT_SCHEMA
property allow you to redefine the default schema that should be applied if no schema is provided when constructor is triggered!
The default value is the following Object:
{
title: "CONFIG",
additionalProperties: true
}
Dependencies
Name | Refactoring | Security Risk | Usage |
---|
@iarna/toml | Minor | Low | Better TOML parsing and stringifying all in that familiar JSON interface. |
@slimio/is | Minor | Low | JavaScript Type checker |
ajv | Minor | High | The fastest JSON Schema Validator |
lodash.clonedeep | Minor | Low | Clone deep an Object |
lodash.get | Minor | Low | Get deep a value |
lodash.set | Minor | Low | Set deep a value |
node-watch | Minor | Low | A wrapper and enhancements for fs.watch |
zen-observable | Minor | Low | ECMAScript Observable implementation |
Contributions Guidelines
TBC
License
MIT