UNPKG

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
'use strict'; 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