Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@jepz20/conman

Package Overview
Dependencies
Maintainers
1
Versions
11
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@jepz20/conman - npm Package Compare versions

Comparing version 0.0.8 to 0.0.9

4

package.json
{
"name": "@jepz20/conman",
"version": "0.0.8",
"version": "0.0.9",
"description": "Configuration manager that supports ttl and plugabble sources",

@@ -17,3 +17,3 @@ "main": "./src/conman",

},
"gitHead": "072fbce84301f7f39f0c7385d9b9c4b9e165f895",
"gitHead": "86f055464765681dd538c96d5bf15e804c511571",
"lint-staged": {

@@ -20,0 +20,0 @@ "src/**/*.*": [

@@ -14,4 +14,3 @@ const { mergeDeepRight } = require('ramda');

const cacheFileName = `${appRoot}/conman.cache.json`;
let isInitialized = false;
const defaultCacheFileName = `${appRoot}/conman.cache.json`;

@@ -23,21 +22,5 @@ const defaultOptions = {

useFile: true,
cacheFileName
defaultCacheFileName
};
let conman;
let sources = [];
let options = defaultOptions;
let privateCache;
let ttlInterval;
let selector;
let logger;
function _prepareCacheObject(tree) {
return {
lastModified: new Date().getTime(),
data: tree
};
}
const _log = opts => (type, ...args) => {

@@ -49,187 +32,194 @@ if (opts.logEnabled) {

// _serialPromises(() => {
function conman(userOptions) {
let sources = [];
let privateCache;
let ttlInterval;
let logger;
let options = { ...defaultOptions, ...userOptions };
// })
function _writeToFile(cacheObject, opts) {
if (!opts.useFile) {
return Promise.resolve();
logger = _log(options);
const selector = nodeSelector(logger);
function _prepareCacheObject(tree) {
return {
lastModified: new Date().getTime(),
data: tree
};
}
logger('log', 'Writing conman cache to file');
return jsonfile
.writeFile(opts.cacheFileName, cacheObject, {
spaces: 2,
EOL: '\r\n'
})
.then(res => {
logger(
'log',
`Succesfully wrote conman cache to file ${opts.cacheFileName}`
);
return res;
})
.catch(error => {
logger(
'error',
`Couldn't write cache to file ${opts.cacheFileName}`,
error
);
});
}
function _writeToFile(cacheObject, opts) {
if (!opts.useFile) {
return Promise.resolve();
}
function _isExpired(cache, opts) {
return new Date().getTime() - cache.lastModified <= opts.ttl;
}
logger('log', 'Writing conman cache to file');
return jsonfile
.writeFile(opts.cacheFileName, cacheObject, {
spaces: 2,
EOL: '\r\n'
})
.then(res => {
logger(
'log',
`Succesfully wrote conman cache to file ${opts.cacheFileName}`
);
return res;
})
.catch(error => {
logger(
'error',
`Couldn't write cache to file ${opts.cacheFileName}`,
error
);
});
}
function _readFromFile(opts) {
return jsonfile
.readFile(opts.cacheFileName)
.then(cache => {
if (cache && cache.lastModified && _isExpired(cache, opts)) {
logger('log', `Succesfully read cache from file ${opts.cacheFileName}`);
return cache.data;
}
return null;
})
.catch(err => {
logger(
'error',
`Could not read cache config file "${opts.cacheFileName}"`,
err
);
return null;
});
}
function _isExpired(cache, opts) {
return new Date().getTime() - cache.lastModified <= opts.ttl;
}
function _validateSource(source) {
if (typeof source.build !== 'function') {
return 'Source should have a build function';
function _readFromFile(opts) {
return jsonfile
.readFile(opts.cacheFileName)
.then(cache => {
if (cache && cache.lastModified && _isExpired(cache, opts)) {
logger(
'log',
`Succesfully read cache from file ${opts.cacheFileName}`
);
return cache.data;
}
return null;
})
.catch(err => {
logger(
'error',
`Could not read cache config file "${opts.cacheFileName}"`,
err
);
return null;
});
}
if (!source.type) {
return 'Source should have a type';
}
return null;
}
function _triggerInterval() {
clearInterval(ttlInterval);
if (options.ttl <= 0) {
return;
function _validateSource(source) {
if (typeof source.build !== 'function') {
return 'Source should have a build function';
}
if (!source.type) {
return 'Source should have a type';
}
return null;
}
ttlInterval = setInterval(build, options.ttl);
}
function _triggerInterval() {
clearInterval(ttlInterval);
if (options.ttl <= 0) {
return;
}
function _init(userOptions = {}) {
options = { ...defaultOptions, ...userOptions };
logger = _log(options);
isInitialized = true;
selector = nodeSelector(logger);
return conman;
}
ttlInterval = setInterval(build, options.ttl);
}
function addSource(source) {
const sourceError = _validateSource(source);
if (sourceError) {
throw new Error(sourceError);
function addSource(source) {
const sourceError = _validateSource(source);
if (sourceError) {
throw new Error(sourceError);
}
logger('log', `Source "${source.type}" added to conman`);
sources.push(source);
return this;
}
logger('log', `Source "${source.type}" added to conman`);
sources.push(source);
return conman;
}
function _get(key, _privateCache) {
if (key === undefined) {
return _privateCache;
function _get(key, _privateCache) {
const safeCache = _privateCache || {};
if (key === undefined) {
return safeCache;
}
return selector.query(safeCache || {}, key);
}
return selector.query(_privateCache, key);
}
function get(keys) {
if (Array.isArray(keys)) {
return keys.map(key => _get(key, privateCache));
}
function get(keys) {
if (!isInitialized) {
throw new Error('Conman has not been initialize');
return _get(keys, privateCache);
}
if (Array.isArray(keys)) {
return keys.map(key => _get(key, privateCache));
function getObfuscate(keys, params) {
return obfuscate(get(keys), params);
}
return _get(keys, privateCache);
}
function _buildSources(_sources) {
async function buildSource(config, source) {
const sourceConfig = await source.build(config);
const parseConfig = source.key
? { [source.key]: sourceConfig }
: sourceConfig;
function getObfuscate(keys, params) {
return obfuscate(get(keys), params);
}
return mergeDeepRight(config, parseConfig);
}
function _buildSources(_sources) {
async function buildSource(config, source) {
const sourceConfig = await source.build(config);
const parseConfig = source.key
? { [source.key]: sourceConfig }
: sourceConfig;
return serialize(_sources, buildSource, {});
}
return mergeDeepRight(config, parseConfig);
function _setPrivateCache(config) {
privateCache = config;
return config;
}
return serialize(_sources, buildSource, {});
}
async function _buildAndSaveCache(_sources) {
const sourcesTypes = _sources.map(({ name, type }) => name || type);
logger(
'log',
`Build triggered for sources: "${sourcesTypes.join()}" at ${new Date().toISOString()}`
);
const configs = await _buildSources(_sources);
logger(
'log',
`Build completed for sources: "${sourcesTypes.join()}" at ${new Date().toISOString()}`
);
await _writeToFile(_prepareCacheObject(configs), options);
return _setPrivateCache(configs);
}
function _setPrivateCache(config) {
privateCache = config;
return config;
}
async function build() {
_triggerInterval();
async function _buildAndSaveCache(_sources) {
const sourcesTypes = _sources.map(({ name, type }) => name || type);
logger(
'log',
`Build triggered for sources: "${sourcesTypes.join()}" at ${new Date().toISOString()}`
);
const configs = await _buildSources(_sources);
logger(
'log',
`Build completed for sources: "${sourcesTypes.join()}" at ${new Date().toISOString()}`
);
await _writeToFile(_prepareCacheObject(configs), options);
return _setPrivateCache(configs);
}
// read from file if its the first build
if (!privateCache && options.useFile) {
const cache = await _readFromFile(options);
if (!cache) {
return _buildAndSaveCache(sources);
}
return _setPrivateCache(cache);
}
async function build() {
_triggerInterval();
return _buildAndSaveCache(sources);
}
// read from file if its the first build
if (!privateCache && options.useFile) {
const cache = await _readFromFile(options);
if (!cache) {
return _buildAndSaveCache(sources);
}
return _setPrivateCache(cache);
function stop() {
clearInterval(ttlInterval);
}
return _buildAndSaveCache(sources);
}
function reset() {
sources = [];
options = defaultOptions;
ttlInterval = undefined;
privateCache = undefined;
logger = undefined;
clearInterval(ttlInterval);
}
function stop() {
clearInterval(ttlInterval);
return {
build,
stop,
reset,
addSource,
get,
getObfuscate
};
}
function reset() {
sources = [];
options = defaultOptions;
isInitialized = false;
ttlInterval = undefined;
privateCache = undefined;
logger = undefined;
clearInterval(ttlInterval);
}
conman = _init;
conman.build = build;
conman.stop = stop;
conman.reset = reset;
conman.addSource = addSource;
conman.get = get;
conman.getObfuscate = getObfuscate;
module.exports = conman;
module.exports = { create: conman };
jest.mock('jsonfile');
const jsonfile = require('jsonfile');
const conman = require('./conman');
const Conman = require('./conman');

@@ -34,2 +34,7 @@ const source = (obj = {}, { key, name } = {}) => {

const logger = {
log: jest.fn(),
error: jest.fn()
};
describe('conman library', () => {

@@ -43,7 +48,9 @@ beforeEach(() => {

jsonfile.readFile.mockReset();
conman.reset();
logger.log.mockReset();
logger.error.mockReset();
});
it('should work with default options and no sources', async () => {
const config = await conman().build();
const conman = Conman();
const config = await conman.build();
conman.stop();

@@ -55,5 +62,4 @@ expect(config).toEqual({});

const source1 = asyncSource({ test: 'test' });
const config = await conman()
.addSource(source1)
.build();
const conman = Conman();
const config = await conman.addSource(source1).build();
conman.stop();

@@ -65,5 +71,4 @@ expect(config).toEqual({ test: 'test' });

const source1 = source({ test: 'test' }, { key: 'TEST' });
const config = await conman()
.addSource(source1)
.build();
const conman = Conman();
const config = await conman.addSource(source1).build();
conman.stop();

@@ -76,3 +81,4 @@ expect(config).toEqual({ TEST: { test: 'test' } });

const source2 = source({ test: 'usesConfig' });
const config = await conman()
const conman = Conman();
const config = await conman
.addSource(source1)

@@ -88,3 +94,4 @@ .addSource(source2)

const source2 = asyncSource({ test: 'usesConfig' });
const config = await conman()
const conman = Conman();
const config = await conman
.addSource(source1)

@@ -99,5 +106,4 @@ .addSource(source2)

const source1 = source({ test: 'test async' });
const config = await conman()
.addSource(source1)
.build();
const conman = Conman();
const config = await conman.addSource(source1).build();
conman.stop();

@@ -110,3 +116,4 @@ expect(config).toEqual({ test: 'test async' });

const source2 = source({ test: 'test', test3: 'test3' });
const config = await conman()
const conman = Conman();
const config = await conman
.addSource(source1)

@@ -123,5 +130,4 @@ .addSource(source2)

const source1 = source({ test: 'test async' });
await conman()
.addSource(source1)
.build();
const conman = Conman();
await conman.addSource(source1).build();
conman.stop();

@@ -137,5 +143,4 @@ expect(conman.get('test')).toBe('test async');

});
await conman()
.addSource(source1)
.build();
const conman = Conman();
await conman.addSource(source1).build();
conman.stop();

@@ -153,5 +158,4 @@ expect(conman.get(['test', 'test2'])).toEqual(['test async', 'test2']);

});
await conman()
.addSource(source1)
.build();
const conman = Conman();
await conman.addSource(source1).build();
conman.stop();

@@ -173,5 +177,4 @@ expect(conman.get('test.test2.test3')).toBe('test3');

});
await conman()
.addSource(source1)
.build();
const conman = Conman();
await conman.addSource(source1).build();
conman.stop();

@@ -199,5 +202,4 @@ expect(conman.getObfuscate('test')).toBe('te**');

});
await conman()
.addSource(source1)
.build();
const conman = Conman();
await conman.addSource(source1).build();
conman.stop();

@@ -217,5 +219,4 @@ expect(

});
await conman()
.addSource(source1)
.build();
const conman = Conman();
await conman.addSource(source1).build();
conman.stop();

@@ -227,5 +228,4 @@ expect(conman.get('test.test2.test4')).toBe(undefined);

const source1 = source({ test: 'test async', test2: 'test2' });
await conman()
.addSource(source1)
.build();
const conman = Conman();
await conman.addSource(source1).build();
conman.stop();

@@ -238,5 +238,4 @@ expect(conman.get()).toEqual({ test: 'test async', test2: 'test2' });

jest.spyOn(source1, 'build');
await conman({ ttl: 1000 })
.addSource(source1)
.build();
const conman = Conman({ ttl: 1000 });
await conman.addSource(source1).build();

@@ -250,6 +249,3 @@ await new Promise(r => setTimeout(r, 3000));

const options = {
logger: {
log: jest.fn(),
error: jest.fn()
},
logger,
logEnabled: true,

@@ -262,6 +258,4 @@ useFile: false,

jest.spyOn(source1, 'build');
await conman(options)
.addSource(source1)
.build();
const conman = Conman(options);
await conman.addSource(source1).build();
expect(options.logger.log).toHaveBeenCalled();

@@ -281,5 +275,4 @@ expect(jsonfile.writeFile).toHaveBeenCalledTimes(0);

});
const config = await conman()
.addSource(source1)
.build();
const conman = Conman();
const config = await conman.addSource(source1).build();
conman.stop();

@@ -299,5 +292,4 @@ expect(config).toEqual({

});
const config = await conman()
.addSource(source1)
.build();
const conman = Conman();
const config = await conman.addSource(source1).build();
conman.stop();

@@ -309,4 +301,51 @@ expect(config).toEqual({

it('should build even if failed to read file and logs an error', async () => {
const source1 = source({ test: 'builtfromsource' });
jsonfile.readFile.mockRejectedValueOnce();
const conman = Conman({
logEnabled: true,
logger
});
const config = await conman.addSource(source1).build();
conman.stop();
expect(config).toEqual({
test: 'builtfromsource'
});
expect(logger.error).toHaveBeenCalledTimes(1);
});
it('should build even if failed to write file and logs an error', async () => {
const source1 = source({ test: 'test', test3: 'test3' });
jsonfile.writeFile.mockRejectedValueOnce();
const conman = Conman({
logEnabled: true,
logger
});
const config = await conman.addSource(source1).build();
conman.stop();
expect(config).toEqual({ test: 'test', test3: 'test3' });
expect(logger.error).toHaveBeenCalledTimes(1);
});
it(`should create independent instances with the provider`, async () => {
const instance1 = Conman({ ttl: 0 });
const instance2 = Conman({ ttl: 0 });
await instance1
.addSource(source({ test: 'instance1' }))
.build();
await instance2
.addSource(source({ test: 'instance2' }))
.build();
expect(instance1.get()).toEqual({ test: 'instance1' });
expect(instance2.get()).toEqual({ test: 'instance2' });
instance1.reset();
expect(instance1.get()).toEqual({});
expect(instance2.get()).toEqual({ test: 'instance2' });
});
it('should throw an error if the source is missing its build property', async () => {
expect(() => conman().addSource({ type: 'source' })).toThrow();
expect(() => Conman().addSource({ type: 'source' })).toThrow();
});

@@ -316,3 +355,3 @@

expect(() =>
conman().addSource({ type: 'source', build: 'not a function' })
Conman().addSource({ type: 'source', build: 'not a function' })
).toThrow();

@@ -323,3 +362,3 @@ });

expect(() =>
conman().addSource({
Conman().addSource({
build() {

@@ -326,0 +365,0 @@ return {};

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc