unleash-client
Advanced tools
Comparing version 0.1.1 to 1.0.0-alpha.1
@@ -1,26 +0,24 @@ | ||
var unleash = require('unleash-client'); | ||
var util = require('util'); | ||
const { Strategy, initialize, isEnabled } = require('../lib'); | ||
unleash.initialize({ | ||
// Define custom strategy: | ||
class ActiveForUserWithEmailStrategy extends Strategy { | ||
constructor () { | ||
super('ActiveForUserWithEmail'); | ||
} | ||
isEnabled (parameters, context) { | ||
return parameters.emails.includes(context.email); | ||
} | ||
} | ||
const client = initialize({ | ||
url: 'http://unleash.herokuapp.com/features', | ||
refreshIntervall: 10000, | ||
strategies: [new ActiveForUserWithEmailStrategy()] | ||
strategies: [new ActiveForUserWithEmailStrategy()], | ||
}); | ||
console.log("Fetching toggles from: http://unleash.herokuapp.com"); | ||
console.log('Fetching toggles from: http://unleash.herokuapp.com', client); | ||
setInterval(function() { | ||
console.log("featureX enabled: " + unleash.isEnabled("featureX", {email: 'user@mail.com'})); | ||
setInterval(() => { | ||
console.log(`featureX enabled: ${isEnabled('featureX', { email: 'user@mail.com' })}`); | ||
}, 1000); | ||
//Define custom strategy: | ||
function ActiveForUserWithEmailStrategy() { | ||
this.name = 'ActiveForUserWithEmail'; | ||
} | ||
util.inherits(ActiveForUserWithEmailStrategy, unleash.Strategy); | ||
ActiveForUserWithEmailStrategy.prototype.isEnabled = function(parameters, context) { | ||
return parameters.emails.indexOf(context.email) !== -1; | ||
}; |
@@ -1,10 +0,11 @@ | ||
var unleash = require('unleash-client'); | ||
unleash.initialize({ | ||
url: 'http://unleash.herokuapp.com/features' | ||
const { initialize, isEnabled } = require('../lib'); | ||
initialize({ | ||
url: 'http://unleash.herokuapp.com/features', | ||
}); | ||
console.log("Fetching toggles from: http://unleash.herokuapp.com"); | ||
console.log('Fetching toggles from: http://unleash.herokuapp.com'); | ||
setInterval(function() { | ||
console.log("featureX enabled: " + unleash.isEnabled("featureX")); | ||
setInterval(() => { | ||
console.log(`featureX enabled: ${isEnabled('featureX')}`); | ||
}, 1000); |
@@ -1,24 +0,55 @@ | ||
function isEnabled(name, context) { | ||
var toggle = this.repository.getToggle(name); | ||
if(toggle && toggle.enabled) { | ||
var currentStrategy = this.strategies[toggle.strategy]; | ||
return currentStrategy && currentStrategy.isEnabled(toggle.parameters, context); | ||
} else { | ||
return false; | ||
'use strict'; | ||
var UnleashClient = (function () { | ||
function UnleashClient(repository, strategies, errorHandler) { | ||
this.repository = repository; | ||
this.errorHandler = errorHandler || function () { }; | ||
this.strategies = strategies || []; | ||
strategies.forEach(function (strategy) { | ||
if (!strategy || | ||
!strategy.name || | ||
typeof strategy.name !== 'string' || | ||
!strategy.isEnabled || | ||
typeof strategy.isEnabled !== 'function') { | ||
throw new Error('Invalid strategy data / interface'); | ||
} | ||
}); | ||
} | ||
} | ||
function Unleash(repository, strategies) { | ||
this.repository = repository; | ||
this.strategies = {}; | ||
var s = this.strategies; | ||
strategies.forEach(function(strategy) { | ||
s[strategy.name] = strategy; | ||
}); | ||
} | ||
Unleash.prototype.isEnabled = isEnabled; | ||
module.exports = Unleash; | ||
UnleashClient.prototype.getStrategy = function (name) { | ||
var match; | ||
this.strategies.some(function (strategy) { | ||
if (strategy.name === name) { | ||
match = strategy; | ||
return true; | ||
} | ||
return false; | ||
}); | ||
return match; | ||
}; | ||
UnleashClient.prototype.isEnabled = function (name, context, fallbackValue) { | ||
var _this = this; | ||
var feature = this.repository.getToggle(name); | ||
if (!feature && typeof fallbackValue === 'boolean') { | ||
return fallbackValue; | ||
} | ||
if (!feature || !feature.enabled) { | ||
return false; | ||
} | ||
if (!Array.isArray(feature.strategies)) { | ||
this.errorHandler(new Error("Malformed feature, strategies not an array, is a " + typeof feature.strategies)); | ||
return false; | ||
} | ||
return feature.strategies.length > 0 && feature.strategies | ||
.some(function (strategySelector) { | ||
var strategy = _this.getStrategy(strategySelector.name); | ||
if (!strategy) { | ||
_this.errorHandler(new Error("Missing strategy " + strategySelector.name)); | ||
return false; | ||
} | ||
return strategy.isEnabled(strategySelector.parameters, context); | ||
}); | ||
}; | ||
return UnleashClient; | ||
}()); | ||
exports.__esModule = true; | ||
exports["default"] = UnleashClient; | ||
//# sourceMappingURL=client.js.map |
@@ -1,58 +0,87 @@ | ||
var fs = require('fs'); | ||
var backupFileName = "/unleash-repo.json"; | ||
function Repository(options) { | ||
this._repository = {}; | ||
this.backupFile = options.backupPath + backupFileName; | ||
this._loadBackup(); | ||
} | ||
Repository.prototype._setToggles = function(toggles) { | ||
var repo = {}; | ||
toggles.forEach(function(toggle) { | ||
repo[toggle.name] = toggle; | ||
}); | ||
this._repository = repo; | ||
this._saveBackup(repo); | ||
'use strict'; | ||
var __extends = (this && this.__extends) || function (d, b) { | ||
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; | ||
function __() { this.constructor = d; } | ||
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); | ||
}; | ||
Repository.prototype._setRepository = function(repository) { | ||
this._repository = repository; | ||
}; | ||
Repository.prototype.getRepository = function() { | ||
return this._repository; | ||
}; | ||
Repository.prototype.getToggle = function(name) { | ||
return this._repository[name]; | ||
}; | ||
Repository.prototype._saveBackup = function(repository) { | ||
fs.writeFile(this.backupFile, JSON.stringify(repository), function(err) { | ||
if(err) { | ||
console.log(err); | ||
var request = require('request'); | ||
var events_1 = require('events'); | ||
var data_formatter_1 = require('./data-formatter'); | ||
var storage_1 = require('./storage'); | ||
var Repository = (function (_super) { | ||
__extends(Repository, _super); | ||
function Repository(backupPath, url, refreshIntervall, StorageImpl) { | ||
var _this = this; | ||
if (StorageImpl === void 0) { StorageImpl = storage_1.Storage; } | ||
_super.call(this); | ||
if (!url.startsWith('http')) { | ||
throw new Error("Wrong url: " + url); | ||
} | ||
}); | ||
}; | ||
Repository.prototype._loadBackup = function() { | ||
var save = this._setRepository.bind(this); | ||
fs.readFile(this.backupFile, function(err, data) { | ||
if (err) { | ||
if(err.errno !== 34) { | ||
console.log("Error reading unleash bakcup file"); | ||
this.url = url; | ||
this.storage = new StorageImpl(backupPath); | ||
this.storage.on('error', function (err) { return _this.emit('error', err); }); | ||
this.storage.on('ready', function () { return _this.emit('ready'); }); | ||
process.nextTick(function () { return _this.fetch(); }); | ||
if (refreshIntervall > 0) { | ||
this.timer = setInterval(function () { return _this.fetch(); }, refreshIntervall); | ||
this.timer.unref(); | ||
} | ||
} | ||
Repository.prototype.validateFeature = function (feature) { | ||
var errors = []; | ||
if (!Array.isArray(feature.strategies)) { | ||
errors.push("feature.strategies should be an array, but was " + typeof feature.strategies); | ||
} | ||
if (typeof feature.enabled !== 'boolean') { | ||
errors.push("feature.enabled should be an boolean, but was " + typeof feature.enabled); | ||
} | ||
if (errors.length > 0) { | ||
var err = new Error(errors.join(', ')); | ||
this.emit('error', err); | ||
} | ||
}; | ||
Repository.prototype.fetch = function () { | ||
var _this = this; | ||
request({ | ||
url: this.url, | ||
headers: { 'If-None-Match': this.etag } | ||
}, function (error, res, body) { | ||
if (error) { | ||
return _this.emit('error', error); | ||
} | ||
} else { | ||
if (res.statusCode === 304) { | ||
// No new data | ||
return; | ||
} | ||
if (res.statusCode !== 200) { | ||
return _this.emit('error', new Error('Reponse was not statusCode 200')); | ||
} | ||
try { | ||
save(JSON.parse(data)); | ||
} catch(error) { | ||
console.log("Error parsing the Unleash backup file", error); | ||
var payload = JSON.parse(body); | ||
var data = data_formatter_1.pickData(data_formatter_1.toNewFormat(payload)); | ||
var obj = data.features.reduce(function (o, feature) { | ||
_this.validateFeature(feature); | ||
o[feature.name] = feature; | ||
return o; | ||
}, {}); | ||
_this.storage.reset(obj); | ||
_this.etag = res.headers.etag; | ||
_this.emit('data'); | ||
} | ||
} | ||
}); | ||
}; | ||
module.exports = Repository; | ||
catch (err) { | ||
_this.emit('error', err); | ||
} | ||
}); | ||
}; | ||
Repository.prototype.stop = function () { | ||
clearInterval(this.timer); | ||
}; | ||
Repository.prototype.getToggle = function (name) { | ||
return this.storage.get(name); | ||
}; | ||
return Repository; | ||
}(events_1.EventEmitter)); | ||
exports.__esModule = true; | ||
exports["default"] = Repository; | ||
; | ||
//# sourceMappingURL=repository.js.map |
@@ -1,14 +0,16 @@ | ||
//Constructor function | ||
function Strategy(name) { | ||
this.name = name || "unknown"; | ||
} | ||
Strategy.prototype.getName = function() { | ||
return this.name; | ||
}; | ||
Strategy.prototype.isEnabled = function(parameters, context) { | ||
return false; | ||
}; | ||
module.exports = Strategy; | ||
'use strict'; | ||
var Strategy = (function () { | ||
function Strategy(name, returnValue) { | ||
if (returnValue === void 0) { returnValue = false; } | ||
this.name = name || 'unknown'; | ||
this.returnValue = returnValue; | ||
} | ||
Strategy.prototype.isEnabled = function (parameters, context) { | ||
return this.returnValue; | ||
}; | ||
return Strategy; | ||
}()); | ||
exports.Strategy = Strategy; | ||
; | ||
; | ||
//# sourceMappingURL=strategy.js.map |
{ | ||
"name": "unleash-client", | ||
"version": "0.1.1", | ||
"version": "1.0.0-alpha.1", | ||
"description": "Unleash Client for Node", | ||
"main": "unleash.js", | ||
"main": "lib/index", | ||
"scripts": { | ||
"test": "mocha test test/**/*.js", | ||
"tdd": "mocha --watch test test/**/*.js", | ||
"coverage": "istanbul cover _mocha -- test test/**/*.js" | ||
"lint": "eslint .", | ||
"build": "tsc src/*.ts -d --sourceMap --outdir ./lib --lib ES6,ES5", | ||
"postinstall": "npm run build", | ||
"test": "ava test", | ||
"coverage": "nyc --check-coverage=true npm test", | ||
"coveralls": "nyc report --reporter=text-lcov | coveralls" | ||
}, | ||
@@ -25,11 +28,34 @@ "repository": { | ||
"dependencies": { | ||
"request": "^2.53.0" | ||
"debug": "^2.2.0", | ||
"request": "^2.74.0" | ||
}, | ||
"engines": { | ||
"node": "6" | ||
}, | ||
"files": [ | ||
"lib", | ||
"examples" | ||
], | ||
"devDependencies": { | ||
"chai": "^2.1.0", | ||
"expect.js": "^0.3.1", | ||
"istanbul": "^0.3.6", | ||
"mocha": "^2.1.0", | ||
"nock": "^0.59.1" | ||
"@types/node": "^6.0.41", | ||
"@types/request": "0.0.31", | ||
"ava": "^0.16.0", | ||
"coveralls": "^2.11.2", | ||
"eslint": "^3.3.1", | ||
"eslint-config-finn": "^1.0.0-alpha.9", | ||
"mkdirp": "^0.5.1", | ||
"nock": "^1.2.1", | ||
"nyc": "^8.3.0", | ||
"typescript": "^2.0.3" | ||
}, | ||
"nyc": { | ||
"lines": 95, | ||
"statements": 95, | ||
"functions": 95, | ||
"branches": 80, | ||
"include": [ | ||
"lib/**.js" | ||
], | ||
"all": true | ||
} | ||
} |
# unleash-client-node | ||
[![Build Status](https://travis-ci.org/finn-no/unleash-client-node.svg)](https://travis-ci.org/finn-no/unleash-client-node) | ||
[![Build Status](https://travis-ci.org/finn-no/unleash-client-node.svg?branch=master)](https://travis-ci.org/finn-no/unleash-client-node) | ||
[![Code Climate](https://codeclimate.com/github/finn-no/unleash-client-node/badges/gpa.svg)](https://codeclimate.com/github/finn-no/unleash-client-node) | ||
[![Coverage Status](https://coveralls.io/repos/finn-no/unleash-client-node/badge.svg?branch=master)](https://coveralls.io/r/finn-no/unleash-client-node?branch=master) | ||
[![Dependency Status](https://david-dm.org/finn-no/unleash-client-node.svg)](https://david-dm.org/finn-no/unleash-client-node) | ||
[![devDependency Status](https://david-dm.org/finn-no/unleash-client-node/dev-status.svg)](https://david-dm.org/finn-no/unleash-client-node#info=devDependencies) | ||
@@ -12,5 +16,13 @@ This is the node client for Unleash. Read more about the [Unleash project](https://github.com/finn-no/unleash) | ||
and poll updates from the unleash-server at regular intervals. | ||
```js | ||
var unleash = require('unleash-client'); | ||
unleash.initialize({url: 'http://unleash.herokuapp.com/features'}); | ||
const { initialize } = require('unleash-client'); | ||
const instance = initialize({ | ||
url: 'http://unleash.herokuapp.com/features' | ||
}); | ||
// optional events | ||
instance.on('error', console.error.bind(console, 'error')); | ||
instance.on('warn', console.warn.bind(console, 'warn')); | ||
instance.on('ready', console.warn.bind(console, 'ready')); | ||
``` | ||
@@ -23,4 +35,4 @@ | ||
```js | ||
var unleash = require('unleash-client'); | ||
unleash.isEnabled('app.ToggleX'); | ||
const { isEnabled } = require('unleash-client'); | ||
isEnabled('app.ToggleX'); | ||
``` | ||
@@ -33,3 +45,4 @@ | ||
```js | ||
unleash.destroy() | ||
const { destroy } = require('unleash-client'); | ||
destroy(); | ||
``` | ||
@@ -51,12 +64,12 @@ | ||
```js | ||
var unleash = require('unleash-client'); | ||
function ActiveForUserWithEmailStrategy() { | ||
this.name = 'ActiveForUserWithEmail'; | ||
const { Strategy, initialize } = require('unleash-client'); | ||
class ActiveForUserWithEmailStrategy extends Strategy { | ||
constructor() { | ||
super('ActiveForUserWithEmail'); | ||
} | ||
isEnabled (parameters, context) { | ||
return parameters.emails.indexOf(context.email) !== -1; | ||
} | ||
} | ||
util.inherits(ActiveForUserWithEmailStrategy, unleash.Strategy); | ||
ActiveForUserWithEmailStrategy.prototype.isEnabled = function(parameters, context) { | ||
return parameters.emails.indexOf(context.email) !== -1; | ||
}; | ||
``` | ||
@@ -67,3 +80,3 @@ | ||
```js | ||
unleash.initialize({ | ||
initialize({ | ||
url: 'http://unleash.herokuapp.com/features', | ||
@@ -73,1 +86,17 @@ strategies: [new ActiveForUserWithEmailStrategy()] | ||
``` | ||
## Alternative usage | ||
Its also possible to ship the unleash instance around yourself, instead of using on the default `require.cache` to have share one instance. | ||
```js | ||
const { Unleash } = require('unleash-client'); | ||
const instance = new Unleash({ | ||
url: 'http://unleash.herokuapp.com/features' | ||
}); | ||
instance.on('ready', console.log.bind(console, 'ready')); | ||
instance.on('error', console.log.bind(console, 'error')) | ||
``` |
Install scripts
Supply chain riskInstall scripts are run when the package is installed. The majority of malware in npm is hidden in install scripts.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
32605
30
474
97
1
2
10
1
2
+ Addeddebug@^2.2.0
+ Addeddebug@2.6.9(transitive)
+ Addedms@2.0.0(transitive)
Updatedrequest@^2.74.0