configly-js
Version:
The dead simple place to put and retrieve static/config data into your Node.js application / JS
261 lines (219 loc) • 8.53 kB
JavaScript
;
Object.defineProperty(exports, '__esModule', { value: true });
var axios = /*#__PURE__*/require('axios');
var qs = /*#__PURE__*/require('qs');
var removeSlash = /*#__PURE__*/require('remove-trailing-slash');
var VERSION = /*#__PURE__*/require('../package.json').version;
var GET_API_PATH = '/api/v1/value';
/**
* Config.ly: the dead simple place to store and retrieve your static/config data.
*
* Remember: *do NOT* assign the result of a get() to a long-lived variable; in order for
* the value to fetch from the server, you must call get().
*
* Each get(key) returns a Promise; the first argument to the Promise fulfillment method is the
* Configly value for the supplied key. Please see the example:
*
* const Configly = require('Configly');
* const configly = Configly.init('API_KEY');
*
* configly.get('keyOne').then((valueForKeyOne) => console.log(valueForKeyOne));
*
* // or
*
* const run = async () => {
* return await configly.get('keyOne');
* }
*
* Note that get(key) may make a server request or fetch a cached value. You should
* assume it'll make a (fast) HTTP request. If you need something guaranteed to be faster, we
* recommend storing the value to a local variable; BUT, be aware that this means you won't
* receive updates to that variable, so be sure to call get() periodically.
*/
var Configly = /*#__PURE__*/function () {
/**
* This method should NOT be called externally; please use Configly.init().
*/
function Configly() {
this.cache = {};
this.cacheTtl = {};
this.apiKey = '';
this.options = {
host: 'https://api.config.ly',
timeout: 3000,
enableCache: true
};
}
/*
* Initialize the `Configly` singleton with your account's `API Key` and an
* optional dictionary of `options`.
*
* @param {String} apiKey - your readonly Config.ly API key. You can find it at
* http://config.ly/config.
* @param {Object} [options] (optional)
* @property {Number} host (default: https://config.ly/) - Overrides the host for requests
* @property {Number} enableCache (default: true) - disables the cache, resulting in an HTTP
* fetch on every `get` call
* @property {Number} timeout (default: 3000) - ms timeout for requests to Configly for data.
* @return Configly instance
* @throws Error if an API Key is not supplied or if init is called multiple times.
*/
Configly.init = function init(apiKey, options) {
if (!apiKey || !apiKey.length || apiKey.length == 0) {
throw new Error('You must supply your API Key. You can find it by logging in to Config.ly');
}
if (!!Configly.instance) {
throw new Error('configly.init() is called multiple times. It can only be called once.');
}
var inst = new Configly();
options = options || {};
inst.options.host = removeSlash(options.host || inst.options.host);
inst.options.enableCache = options.enableCache === undefined ? inst.options.enableCache : options.enableCache;
inst.apiKey = apiKey;
inst.options.timeout = options.timeout || inst.options.timeout;
Configly.instance = inst;
return Configly.instance;
}
/*
* @return existing Configy instance. Configly.init() must be called before any invocation of
* getInstance()
*/
;
Configly.getInstance = function getInstance() {
if (!Configly.isInitialized()) {
throw new Error('Configly.getInstance() is called before Configly.init(); you must call init.');
}
return Configly.instance;
}
/*
* @return true if init() has been called
*/
;
Configly.isInitialized = function isInitialized() {
return !!Configly.instance;
};
Configly.getUnixTimestampSecs = function getUnixTimestampSecs() {
return Math.round(Date.now() / 1000);
};
var _proto = Configly.prototype;
_proto._isCached = function _isCached(key) {
var value = this.cache[key];
if (!value) {
return false;
}
if (this.cacheTtl[key] < Configly.getUnixTimestampSecs()) {
return false;
}
return true;
};
_proto._cacheGet = function _cacheGet(key) {
return this.cache[key];
}
/**
* Fetch the value for the supplied key. This is an async call; it may be lightning fast as the
* value may be cached.
*
* Configly.init() must be called before any invocation of get
*
* @param {String} key - the key to fetch.
* @param {Object?} [options] overrides the global parameters set in the constructor for this
* `get` request only (optional)
* @property {Number} enableCache (default: true) - disables the cache, resulting in an HTTP
* fetch on every `get` call.
* @property {Number} timeout (default: 3000) - timeout for request to Configly for data in ms.
* @return { Promse<String | Number | Boolean | Array | Object | Error> } returns, on success,
* a promise of fulfilled with the stored value(s) as typed in Config.ly. On error, returns
* a failed promise with error:
* - TypeError if key is not a string or omitted
* - Error if key an empty string
*/
;
_proto.get = function get(key, options) {
var _this = this;
if (typeof key !== 'string') {
return Promise.reject(new TypeError('key must be a string'));
}
if (!key || key.length == 0) {
return Promise.reject(new Error('key must be a non-empty string'));
}
options = options || {};
var headers = {
'Accept': 'application/json'
}; // XXX: I think setting custom headers of X- is deprecated but I couldn't find another good
// header to use.
headers['X-Lib-Version'] = ['configly-node', VERSION].join('/');
var cacheIsEnabled = true;
if (options.enableCache !== undefined) {
cacheIsEnabled = options.enableCache;
} else if (!this.options.enableCache) {
cacheIsEnabled = false;
} // Check the cache
if (cacheIsEnabled && this._isCached(key)) {
return Promise.resolve(this._cacheGet(key));
}
var url = "" + this.options.host + GET_API_PATH;
return axios.get(url, {
auth: {
username: this.apiKey
},
headers: headers,
params: {
keys: [key]
},
paramsSerializer: function paramsSerializer(params) {
return qs.stringify(params, {
arrayFormat: 'brackets'
});
},
timeout: options.timeout || this.options.timeout || 3000
}).then(function (response) {
var _ref = response.data.data[key] || {},
value = _ref.value,
ttl = _ref.ttl; // There should always be a TTL. But just in case.
ttl = ttl || 60;
if (cacheIsEnabled && value !== undefined) {
_this.cacheTtl[key] = Configly.getUnixTimestampSecs() + ttl;
_this.cache[key] = value;
}
return value;
})["catch"](Configly.handleGetError);
};
Configly.makeError = function makeError(status, message, originalError) {
return {
status: status,
message: message,
originalError: originalError
};
};
Configly.handleGetError = function handleGetError(error) {
var status = ERRORS.OTHER;
var message = ['Something went wrong. Have you upgraded to the latest client?', "Take a look at 'originalError' inside the error object for more details."].join('');
if (error.response) {
var statusCode = error.response.status;
status = statusCode === 401 ? ERRORS.INVALID_API_KEY : ERRORS.OTHER;
message = (error.response.data || '').substring(0, 1000);
} else if (error.code === 'ECONNREFUSED') {
status = ERRORS.CONNECTION_ERROR;
message = ['Configly didn\'t receive an HTTP response.', 'This could be because of a network disruption with the server or a bad supplied hostname.', 'If you\'ve supplied a host parameter, please ensure it is correct.', 'Otherwise, try again.'].join(' ');
}
return Promise.reject(Configly.makeError(status, message, error));
};
/**
* Destroys singleton; really meant for testing snd likely should not be used
* externally.
*/
_proto.destroy = function destroy() {
Configly.instance = undefined;
};
return Configly;
}();
var ERRORS = {
OTHER: 'OTHER',
CONNECTION_ERROR: 'CONNECTION_ERROR',
INVALID_API_KEY: 'INVALID_API_KEY'
};
Object.freeze(ERRORS);
exports.Configly = Configly;
exports.ERRORS = ERRORS;
exports.default = Configly;
//# sourceMappingURL=configly-js.cjs.development.js.map