bottleneck
Advanced tools
Comparing version 1.9.1 to 1.10.0
(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){ | ||
// Generated by CoffeeScript 1.9.3 | ||
// Generated by CoffeeScript 1.10.0 | ||
(function() { | ||
var Bottleneck, | ||
var Bottleneck, MIDDLE_PRIORITY, NB_PRIORITIES, | ||
bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, | ||
slice = [].slice; | ||
NB_PRIORITIES = 10; | ||
MIDDLE_PRIORITY = 5; | ||
Bottleneck = (function() { | ||
@@ -14,2 +18,3 @@ var e; | ||
OVERFLOW: 2, | ||
OVERFLOW_PRIORITY: 4, | ||
BLOCK: 3 | ||
@@ -20,7 +25,10 @@ }; | ||
Bottleneck.DLList = Bottleneck.prototype.DLList = require("./DLList"); | ||
Bottleneck.Promise = Bottleneck.prototype.Promise = (function() { | ||
var error1; | ||
try { | ||
return require("bluebird"); | ||
} catch (_error) { | ||
e = _error; | ||
} catch (error1) { | ||
e = error1; | ||
return typeof Promise !== "undefined" && Promise !== null ? Promise : function() { | ||
@@ -37,6 +45,8 @@ throw new Error("Bottleneck: install 'bluebird' or use Node 0.12 or higher for Promise support"); | ||
this.strategy = strategy != null ? strategy : Bottleneck.prototype.strategy.LEAK; | ||
this.schedulePriority = bind(this.schedulePriority, this); | ||
this.submitPriority = bind(this.submitPriority, this); | ||
this.submit = bind(this.submit, this); | ||
this._nextRequest = Date.now(); | ||
this._nbRunning = 0; | ||
this._queue = []; | ||
this._queues = this._makeQueues(); | ||
this._timeouts = []; | ||
@@ -50,2 +60,11 @@ this._unblockTime = 0; | ||
Bottleneck.prototype._makeQueues = function() { | ||
var i, j, ref, results; | ||
results = []; | ||
for (i = j = 1, ref = NB_PRIORITIES; 1 <= ref ? j <= ref : j >= ref; i = 1 <= ref ? ++j : --j) { | ||
results.push(new Bottleneck.prototype.DLList()); | ||
} | ||
return results; | ||
}; | ||
Bottleneck.prototype.chain = function(limiter) { | ||
@@ -60,4 +79,47 @@ this.limiter = limiter; | ||
Bottleneck.prototype._sanitizePriority = function(priority) { | ||
var sProperty; | ||
sProperty = ~~priority !== priority ? MIDDLE_PRIORITY : priority; | ||
if (sProperty < 0) { | ||
return 0; | ||
} else if (sProperty > NB_PRIORITIES - 1) { | ||
return NB_PRIORITIES - 1; | ||
} else { | ||
return sProperty; | ||
} | ||
}; | ||
Bottleneck.prototype._find = function(arr, fn) { | ||
var i, j, len, x; | ||
for (i = j = 0, len = arr.length; j < len; i = ++j) { | ||
x = arr[i]; | ||
if (fn(x)) { | ||
return x; | ||
} | ||
} | ||
return []; | ||
}; | ||
Bottleneck.prototype.nbQueued = function(priority) { | ||
if (priority != null) { | ||
return this._queues[this._sanitizePriority(priority)].length; | ||
} else { | ||
return this._queues.reduce((function(a, b) { | ||
return a + b.length; | ||
}), 0); | ||
} | ||
}; | ||
Bottleneck.prototype._getFirst = function(arr) { | ||
return this._find(arr, function(x) { | ||
return x.length > 0; | ||
}); | ||
}; | ||
Bottleneck.prototype._conditionsCheck = function() { | ||
return (this._nbRunning < this.maxNb || this.maxNb <= 0) && ((this.reservoir == null) || this.reservoir > 0); | ||
}; | ||
Bottleneck.prototype.check = function() { | ||
return (this._nbRunning < this.maxNb || this.maxNb <= 0) && (this._nextRequest - Date.now()) <= 0 && ((this.reservoir == null) || this.reservoir > 0); | ||
return this._conditionsCheck() && (this._nextRequest - Date.now()) <= 0; | ||
}; | ||
@@ -67,3 +129,3 @@ | ||
var done, index, next, wait; | ||
if ((this._nbRunning < this.maxNb || this.maxNb <= 0) && this._queue.length > 0 && ((this.reservoir == null) || this.reservoir > 0)) { | ||
if (this._conditionsCheck() && this.nbQueued() > 0) { | ||
this._nbRunning++; | ||
@@ -75,3 +137,3 @@ if (this.reservoir != null) { | ||
this._nextRequest = Date.now() + wait + this.minTime; | ||
next = this._queue.shift(); | ||
next = (this._getFirst(this._queues)).shift(); | ||
done = false; | ||
@@ -107,18 +169,24 @@ index = -1 + this._timeouts.push(setTimeout((function(_this) { | ||
Bottleneck.prototype.submit = function() { | ||
var args, cb, i, reachedHighWaterMark, task; | ||
task = arguments[0], args = 3 <= arguments.length ? slice.call(arguments, 1, i = arguments.length - 1) : (i = 1, []), cb = arguments[i++]; | ||
reachedHighWaterMark = this.highWater > 0 && this._queue.length === this.highWater; | ||
var args; | ||
args = 1 <= arguments.length ? slice.call(arguments, 0) : []; | ||
return this.submitPriority.apply({}, Array.prototype.concat(MIDDLE_PRIORITY, args)); | ||
}; | ||
Bottleneck.prototype.submitPriority = function() { | ||
var args, cb, j, priority, reachedHighWaterMark, shifted, task; | ||
priority = arguments[0], task = arguments[1], args = 4 <= arguments.length ? slice.call(arguments, 2, j = arguments.length - 1) : (j = 2, []), cb = arguments[j++]; | ||
priority = this._sanitizePriority(priority); | ||
reachedHighWaterMark = this.highWater > 0 && this.nbQueued() === this.highWater; | ||
if (this.strategy === Bottleneck.prototype.strategy.BLOCK && (reachedHighWaterMark || this.isBlocked())) { | ||
this._unblockTime = Date.now() + this.penalty; | ||
this._nextRequest = this._unblockTime + this.minTime; | ||
this._queue = []; | ||
this._queues = this._makeQueues(); | ||
return true; | ||
} else if (reachedHighWaterMark) { | ||
if (this.strategy === Bottleneck.prototype.strategy.LEAK) { | ||
this._queue.shift(); | ||
} else if (this.strategy === Bottleneck.prototype.strategy.OVERFLOW) { | ||
shifted = this.strategy === Bottleneck.prototype.strategy.LEAK ? (this._getFirst(this._queues.slice(priority).reverse())).shift() : this.strategy === Bottleneck.prototype.strategy.OVERFLOW_PRIORITY ? (this._getFirst(this._queues.slice(priority + 1).reverse())).shift() : this.strategy === Bottleneck.prototype.strategy.OVERFLOW ? null : void 0; | ||
if (shifted == null) { | ||
return reachedHighWaterMark; | ||
} | ||
} | ||
this._queue.push({ | ||
this._queues[priority].push({ | ||
task: task, | ||
@@ -133,4 +201,11 @@ args: args, | ||
Bottleneck.prototype.schedule = function() { | ||
var args, task, wrapped; | ||
task = arguments[0], args = 2 <= arguments.length ? slice.call(arguments, 1) : []; | ||
var args; | ||
args = 1 <= arguments.length ? slice.call(arguments, 0) : []; | ||
return this.schedulePriority.apply({}, Array.prototype.concat(MIDDLE_PRIORITY, args)); | ||
}; | ||
Bottleneck.prototype.schedulePriority = function() { | ||
var args, priority, task, wrapped; | ||
priority = arguments[0], task = arguments[1], args = 3 <= arguments.length ? slice.call(arguments, 2) : []; | ||
priority = this._sanitizePriority(priority); | ||
wrapped = function(cb) { | ||
@@ -149,3 +224,3 @@ return (task.apply({}, args)).then(function() { | ||
return function(resolve, reject) { | ||
return _this.submit.apply({}, Array.prototype.concat.call(wrapped, function() { | ||
return _this.submitPriority.apply({}, Array.prototype.concat.call(priority, wrapped, function() { | ||
var args, error; | ||
@@ -188,16 +263,13 @@ error = arguments[0], args = 2 <= arguments.length ? slice.call(arguments, 1) : []; | ||
Bottleneck.prototype.stopAll = function(interrupt) { | ||
var a, i, len, ref; | ||
var a, j, len, ref; | ||
this.interrupt = interrupt != null ? interrupt : this.interrupt; | ||
ref = this._timeouts; | ||
for (i = 0, len = ref.length; i < len; i++) { | ||
a = ref[i]; | ||
for (j = 0, len = ref.length; j < len; j++) { | ||
a = ref[j]; | ||
clearTimeout(a); | ||
} | ||
this._tryToRun = function() {}; | ||
this.submit = function() { | ||
return this.check = this.submit = this.submitPriority = this.schedule = this.schedulePriority = function() { | ||
return false; | ||
}; | ||
return this.check = function() { | ||
return false; | ||
}; | ||
}; | ||
@@ -213,4 +285,4 @@ | ||
},{"./Cluster":2,"bluebird":undefined}],2:[function(require,module,exports){ | ||
// Generated by CoffeeScript 1.9.3 | ||
},{"./Cluster":2,"./DLList":3,"bluebird":undefined}],2:[function(require,module,exports){ | ||
// Generated by CoffeeScript 1.10.0 | ||
(function() { | ||
@@ -297,4 +369,62 @@ var Cluster, | ||
},{"./Bottleneck":1}],3:[function(require,module,exports){ | ||
// Generated by CoffeeScript 1.10.0 | ||
(function() { | ||
var DLList; | ||
DLList = (function() { | ||
function DLList() { | ||
this._first = null; | ||
this._last = null; | ||
this.length = 0; | ||
} | ||
DLList.prototype.push = function(value) { | ||
var node; | ||
this.length++; | ||
node = { | ||
value: value, | ||
next: null | ||
}; | ||
if (this._last != null) { | ||
this._last.next = node; | ||
this._last = node; | ||
} else { | ||
this._first = this._last = node; | ||
} | ||
return void 0; | ||
}; | ||
DLList.prototype.shift = function() { | ||
var ref1, value; | ||
if (this._first == null) { | ||
return void 0; | ||
} else { | ||
this.length--; | ||
} | ||
value = this._first.value; | ||
this._first = (ref1 = this._first.next) != null ? ref1 : (this._last = null); | ||
return value; | ||
}; | ||
DLList.prototype.getArray = function() { | ||
var node, ref, results; | ||
node = this._first; | ||
results = []; | ||
while (node != null) { | ||
results.push((ref = node, node = node.next, ref.value)); | ||
} | ||
return results; | ||
}; | ||
return DLList; | ||
})(); | ||
module.exports = DLList; | ||
}).call(this); | ||
},{}],4:[function(require,module,exports){ | ||
(function (global){ | ||
// Generated by CoffeeScript 1.9.3 | ||
// Generated by CoffeeScript 1.10.0 | ||
(function() { | ||
@@ -310,2 +440,2 @@ module.exports = require("./Bottleneck"); | ||
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) | ||
},{"./Bottleneck":1}]},{},[3]); | ||
},{"./Bottleneck":1}]},{},[4]); |
@@ -1,1 +0,1 @@ | ||
(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){(function(){var Bottleneck,bind=function(fn,me){return function(){return fn.apply(me,arguments)}},slice=[].slice;Bottleneck=function(){var e;Bottleneck.strategy=Bottleneck.prototype.strategy={LEAK:1,OVERFLOW:2,BLOCK:3};Bottleneck.Cluster=Bottleneck.prototype.Cluster=require("./Cluster");Bottleneck.Promise=Bottleneck.prototype.Promise=function(){try{return require("bluebird")}catch(_error){e=_error;return typeof Promise!=="undefined"&&Promise!==null?Promise:function(){throw new Error("Bottleneck: install 'bluebird' or use Node 0.12 or higher for Promise support")}}}();function Bottleneck(maxNb,minTime,highWater,strategy){this.maxNb=maxNb!=null?maxNb:0;this.minTime=minTime!=null?minTime:0;this.highWater=highWater!=null?highWater:0;this.strategy=strategy!=null?strategy:Bottleneck.prototype.strategy.LEAK;this.submit=bind(this.submit,this);this._nextRequest=Date.now();this._nbRunning=0;this._queue=[];this._timeouts=[];this._unblockTime=0;this.penalty=15*this.minTime||5e3;this.interrupt=false;this.reservoir=null;this.limiter=null}Bottleneck.prototype.chain=function(limiter){this.limiter=limiter;return this};Bottleneck.prototype.isBlocked=function(){return this._unblockTime>=Date.now()};Bottleneck.prototype.check=function(){return(this._nbRunning<this.maxNb||this.maxNb<=0)&&this._nextRequest-Date.now()<=0&&(this.reservoir==null||this.reservoir>0)};Bottleneck.prototype._tryToRun=function(){var done,index,next,wait;if((this._nbRunning<this.maxNb||this.maxNb<=0)&&this._queue.length>0&&(this.reservoir==null||this.reservoir>0)){this._nbRunning++;if(this.reservoir!=null){this.reservoir--}wait=Math.max(this._nextRequest-Date.now(),0);this._nextRequest=Date.now()+wait+this.minTime;next=this._queue.shift();done=false;index=-1+this._timeouts.push(setTimeout(function(_this){return function(){var completed;completed=function(){var ref;if(!done){done=true;delete _this._timeouts[index];_this._nbRunning--;_this._tryToRun();if(!_this.interrupt){return(ref=next.cb)!=null?ref.apply({},Array.prototype.slice.call(arguments,0)):void 0}}};if(_this.limiter!=null){return _this.limiter.submit.apply(_this.limiter,Array.prototype.concat.call(next.task,next.args,completed))}else{return next.task.apply({},next.args.concat(completed))}}}(this),wait));return true}else{return false}};Bottleneck.prototype.submit=function(){var args,cb,i,reachedHighWaterMark,task;task=arguments[0],args=3<=arguments.length?slice.call(arguments,1,i=arguments.length-1):(i=1,[]),cb=arguments[i++];reachedHighWaterMark=this.highWater>0&&this._queue.length===this.highWater;if(this.strategy===Bottleneck.prototype.strategy.BLOCK&&(reachedHighWaterMark||this.isBlocked())){this._unblockTime=Date.now()+this.penalty;this._nextRequest=this._unblockTime+this.minTime;this._queue=[];return true}else if(reachedHighWaterMark){if(this.strategy===Bottleneck.prototype.strategy.LEAK){this._queue.shift()}else if(this.strategy===Bottleneck.prototype.strategy.OVERFLOW){return reachedHighWaterMark}}this._queue.push({task:task,args:args,cb:cb});this._tryToRun();return reachedHighWaterMark};Bottleneck.prototype.schedule=function(){var args,task,wrapped;task=arguments[0],args=2<=arguments.length?slice.call(arguments,1):[];wrapped=function(cb){return task.apply({},args).then(function(){var args;args=1<=arguments.length?slice.call(arguments,0):[];return cb.apply({},Array.prototype.concat.call([],null,args))})["catch"](function(){var args;args=1<=arguments.length?slice.call(arguments,0):[];return cb.apply({},Array.prototype.concat.call({},args))})};return new Bottleneck.prototype.Promise(function(_this){return function(resolve,reject){return _this.submit.apply({},Array.prototype.concat.call(wrapped,function(){var args,error;error=arguments[0],args=2<=arguments.length?slice.call(arguments,1):[];return(error!=null?reject:resolve).apply({},args)}))}}(this))};Bottleneck.prototype.changeSettings=function(maxNb,minTime,highWater,strategy){this.maxNb=maxNb!=null?maxNb:this.maxNb;this.minTime=minTime!=null?minTime:this.minTime;this.highWater=highWater!=null?highWater:this.highWater;this.strategy=strategy!=null?strategy:this.strategy;while(this._tryToRun()){}return this};Bottleneck.prototype.changePenalty=function(penalty){this.penalty=penalty!=null?penalty:this.penalty;return this};Bottleneck.prototype.changeReservoir=function(reservoir){this.reservoir=reservoir;while(this._tryToRun()){}return this};Bottleneck.prototype.incrementReservoir=function(incr){if(incr==null){incr=0}this.changeReservoir(this.reservoir+incr);return this};Bottleneck.prototype.stopAll=function(interrupt){var a,i,len,ref;this.interrupt=interrupt!=null?interrupt:this.interrupt;ref=this._timeouts;for(i=0,len=ref.length;i<len;i++){a=ref[i];clearTimeout(a)}this._tryToRun=function(){};this.submit=function(){return false};return this.check=function(){return false}};return Bottleneck}();module.exports=Bottleneck}).call(this)},{"./Cluster":2,bluebird:undefined}],2:[function(require,module,exports){(function(){var Cluster,hasProp={}.hasOwnProperty;Cluster=function(){function Cluster(maxNb,minTime,highWater,strategy){this.maxNb=maxNb;this.minTime=minTime;this.highWater=highWater;this.strategy=strategy;this.limiters={};this.Bottleneck=require("./Bottleneck");this.startAutoCleanup()}Cluster.prototype.key=function(key){var ref;if(key==null){key=""}return(ref=this.limiters[key])!=null?ref:this.limiters[key]=new this.Bottleneck(this.maxNb,this.minTime,this.highWater,this.strategy)};Cluster.prototype.deleteKey=function(key){if(key==null){key=""}return delete this.limiters[key]};Cluster.prototype.all=function(cb){var k,ref,results,v;ref=this.limiters;results=[];for(k in ref){if(!hasProp.call(ref,k))continue;v=ref[k];results.push(cb(v))}return results};Cluster.prototype.keys=function(){return Object.keys(this.limiters)};Cluster.prototype.startAutoCleanup=function(){var base;this.stopAutoCleanup();return typeof(base=this.interval=setInterval(function(_this){return function(){var k,ref,results,time,v;time=Date.now();ref=_this.limiters;results=[];for(k in ref){v=ref[k];if(v._nextRequest+1e3*60*5<time){results.push(_this.deleteKey(k))}else{results.push(void 0)}}return results}}(this),1e3*30)).unref==="function"?base.unref():void 0};Cluster.prototype.stopAutoCleanup=function(){return clearInterval(this.interval)};return Cluster}();module.exports=Cluster}).call(this)},{"./Bottleneck":1}],3:[function(require,module,exports){(function(global){(function(){module.exports=require("./Bottleneck");if(global.window!=null){global.window.Bottleneck=module.exports}}).call(this)}).call(this,typeof global!=="undefined"?global:typeof self!=="undefined"?self:typeof window!=="undefined"?window:{})},{"./Bottleneck":1}]},{},[3]); | ||
(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){(function(){var Bottleneck,MIDDLE_PRIORITY,NB_PRIORITIES,bind=function(fn,me){return function(){return fn.apply(me,arguments)}},slice=[].slice;NB_PRIORITIES=10;MIDDLE_PRIORITY=5;Bottleneck=function(){var e;Bottleneck.strategy=Bottleneck.prototype.strategy={LEAK:1,OVERFLOW:2,OVERFLOW_PRIORITY:4,BLOCK:3};Bottleneck.Cluster=Bottleneck.prototype.Cluster=require("./Cluster");Bottleneck.DLList=Bottleneck.prototype.DLList=require("./DLList");Bottleneck.Promise=Bottleneck.prototype.Promise=function(){var error1;try{return require("bluebird")}catch(error1){e=error1;return typeof Promise!=="undefined"&&Promise!==null?Promise:function(){throw new Error("Bottleneck: install 'bluebird' or use Node 0.12 or higher for Promise support")}}}();function Bottleneck(maxNb,minTime,highWater,strategy){this.maxNb=maxNb!=null?maxNb:0;this.minTime=minTime!=null?minTime:0;this.highWater=highWater!=null?highWater:0;this.strategy=strategy!=null?strategy:Bottleneck.prototype.strategy.LEAK;this.schedulePriority=bind(this.schedulePriority,this);this.submitPriority=bind(this.submitPriority,this);this.submit=bind(this.submit,this);this._nextRequest=Date.now();this._nbRunning=0;this._queues=this._makeQueues();this._timeouts=[];this._unblockTime=0;this.penalty=15*this.minTime||5e3;this.interrupt=false;this.reservoir=null;this.limiter=null}Bottleneck.prototype._makeQueues=function(){var i,j,ref,results;results=[];for(i=j=1,ref=NB_PRIORITIES;1<=ref?j<=ref:j>=ref;i=1<=ref?++j:--j){results.push(new Bottleneck.prototype.DLList)}return results};Bottleneck.prototype.chain=function(limiter){this.limiter=limiter;return this};Bottleneck.prototype.isBlocked=function(){return this._unblockTime>=Date.now()};Bottleneck.prototype._sanitizePriority=function(priority){var sProperty;sProperty=~~priority!==priority?MIDDLE_PRIORITY:priority;if(sProperty<0){return 0}else if(sProperty>NB_PRIORITIES-1){return NB_PRIORITIES-1}else{return sProperty}};Bottleneck.prototype._find=function(arr,fn){var i,j,len,x;for(i=j=0,len=arr.length;j<len;i=++j){x=arr[i];if(fn(x)){return x}}return[]};Bottleneck.prototype.nbQueued=function(priority){if(priority!=null){return this._queues[this._sanitizePriority(priority)].length}else{return this._queues.reduce(function(a,b){return a+b.length},0)}};Bottleneck.prototype._getFirst=function(arr){return this._find(arr,function(x){return x.length>0})};Bottleneck.prototype._conditionsCheck=function(){return(this._nbRunning<this.maxNb||this.maxNb<=0)&&(this.reservoir==null||this.reservoir>0)};Bottleneck.prototype.check=function(){return this._conditionsCheck()&&this._nextRequest-Date.now()<=0};Bottleneck.prototype._tryToRun=function(){var done,index,next,wait;if(this._conditionsCheck()&&this.nbQueued()>0){this._nbRunning++;if(this.reservoir!=null){this.reservoir--}wait=Math.max(this._nextRequest-Date.now(),0);this._nextRequest=Date.now()+wait+this.minTime;next=this._getFirst(this._queues).shift();done=false;index=-1+this._timeouts.push(setTimeout(function(_this){return function(){var completed;completed=function(){var ref;if(!done){done=true;delete _this._timeouts[index];_this._nbRunning--;_this._tryToRun();if(!_this.interrupt){return(ref=next.cb)!=null?ref.apply({},Array.prototype.slice.call(arguments,0)):void 0}}};if(_this.limiter!=null){return _this.limiter.submit.apply(_this.limiter,Array.prototype.concat.call(next.task,next.args,completed))}else{return next.task.apply({},next.args.concat(completed))}}}(this),wait));return true}else{return false}};Bottleneck.prototype.submit=function(){var args;args=1<=arguments.length?slice.call(arguments,0):[];return this.submitPriority.apply({},Array.prototype.concat(MIDDLE_PRIORITY,args))};Bottleneck.prototype.submitPriority=function(){var args,cb,j,priority,reachedHighWaterMark,shifted,task;priority=arguments[0],task=arguments[1],args=4<=arguments.length?slice.call(arguments,2,j=arguments.length-1):(j=2,[]),cb=arguments[j++];priority=this._sanitizePriority(priority);reachedHighWaterMark=this.highWater>0&&this.nbQueued()===this.highWater;if(this.strategy===Bottleneck.prototype.strategy.BLOCK&&(reachedHighWaterMark||this.isBlocked())){this._unblockTime=Date.now()+this.penalty;this._nextRequest=this._unblockTime+this.minTime;this._queues=this._makeQueues();return true}else if(reachedHighWaterMark){shifted=this.strategy===Bottleneck.prototype.strategy.LEAK?this._getFirst(this._queues.slice(priority).reverse()).shift():this.strategy===Bottleneck.prototype.strategy.OVERFLOW_PRIORITY?this._getFirst(this._queues.slice(priority+1).reverse()).shift():this.strategy===Bottleneck.prototype.strategy.OVERFLOW?null:void 0;if(shifted==null){return reachedHighWaterMark}}this._queues[priority].push({task:task,args:args,cb:cb});this._tryToRun();return reachedHighWaterMark};Bottleneck.prototype.schedule=function(){var args;args=1<=arguments.length?slice.call(arguments,0):[];return this.schedulePriority.apply({},Array.prototype.concat(MIDDLE_PRIORITY,args))};Bottleneck.prototype.schedulePriority=function(){var args,priority,task,wrapped;priority=arguments[0],task=arguments[1],args=3<=arguments.length?slice.call(arguments,2):[];priority=this._sanitizePriority(priority);wrapped=function(cb){return task.apply({},args).then(function(){var args;args=1<=arguments.length?slice.call(arguments,0):[];return cb.apply({},Array.prototype.concat.call([],null,args))})["catch"](function(){var args;args=1<=arguments.length?slice.call(arguments,0):[];return cb.apply({},Array.prototype.concat.call({},args))})};return new Bottleneck.prototype.Promise(function(_this){return function(resolve,reject){return _this.submitPriority.apply({},Array.prototype.concat.call(priority,wrapped,function(){var args,error;error=arguments[0],args=2<=arguments.length?slice.call(arguments,1):[];return(error!=null?reject:resolve).apply({},args)}))}}(this))};Bottleneck.prototype.changeSettings=function(maxNb,minTime,highWater,strategy){this.maxNb=maxNb!=null?maxNb:this.maxNb;this.minTime=minTime!=null?minTime:this.minTime;this.highWater=highWater!=null?highWater:this.highWater;this.strategy=strategy!=null?strategy:this.strategy;while(this._tryToRun()){}return this};Bottleneck.prototype.changePenalty=function(penalty){this.penalty=penalty!=null?penalty:this.penalty;return this};Bottleneck.prototype.changeReservoir=function(reservoir){this.reservoir=reservoir;while(this._tryToRun()){}return this};Bottleneck.prototype.incrementReservoir=function(incr){if(incr==null){incr=0}this.changeReservoir(this.reservoir+incr);return this};Bottleneck.prototype.stopAll=function(interrupt){var a,j,len,ref;this.interrupt=interrupt!=null?interrupt:this.interrupt;ref=this._timeouts;for(j=0,len=ref.length;j<len;j++){a=ref[j];clearTimeout(a)}this._tryToRun=function(){};return this.check=this.submit=this.submitPriority=this.schedule=this.schedulePriority=function(){return false}};return Bottleneck}();module.exports=Bottleneck}).call(this)},{"./Cluster":2,"./DLList":3,bluebird:undefined}],2:[function(require,module,exports){(function(){var Cluster,hasProp={}.hasOwnProperty;Cluster=function(){function Cluster(maxNb,minTime,highWater,strategy){this.maxNb=maxNb;this.minTime=minTime;this.highWater=highWater;this.strategy=strategy;this.limiters={};this.Bottleneck=require("./Bottleneck");this.startAutoCleanup()}Cluster.prototype.key=function(key){var ref;if(key==null){key=""}return(ref=this.limiters[key])!=null?ref:this.limiters[key]=new this.Bottleneck(this.maxNb,this.minTime,this.highWater,this.strategy)};Cluster.prototype.deleteKey=function(key){if(key==null){key=""}return delete this.limiters[key]};Cluster.prototype.all=function(cb){var k,ref,results,v;ref=this.limiters;results=[];for(k in ref){if(!hasProp.call(ref,k))continue;v=ref[k];results.push(cb(v))}return results};Cluster.prototype.keys=function(){return Object.keys(this.limiters)};Cluster.prototype.startAutoCleanup=function(){var base;this.stopAutoCleanup();return typeof(base=this.interval=setInterval(function(_this){return function(){var k,ref,results,time,v;time=Date.now();ref=_this.limiters;results=[];for(k in ref){v=ref[k];if(v._nextRequest+1e3*60*5<time){results.push(_this.deleteKey(k))}else{results.push(void 0)}}return results}}(this),1e3*30)).unref==="function"?base.unref():void 0};Cluster.prototype.stopAutoCleanup=function(){return clearInterval(this.interval)};return Cluster}();module.exports=Cluster}).call(this)},{"./Bottleneck":1}],3:[function(require,module,exports){(function(){var DLList;DLList=function(){function DLList(){this._first=null;this._last=null;this.length=0}DLList.prototype.push=function(value){var node;this.length++;node={value:value,next:null};if(this._last!=null){this._last.next=node;this._last=node}else{this._first=this._last=node}return void 0};DLList.prototype.shift=function(){var ref1,value;if(this._first==null){return void 0}else{this.length--}value=this._first.value;this._first=(ref1=this._first.next)!=null?ref1:this._last=null;return value};DLList.prototype.getArray=function(){var node,ref,results;node=this._first;results=[];while(node!=null){results.push((ref=node,node=node.next,ref.value))}return results};return DLList}();module.exports=DLList}).call(this)},{}],4:[function(require,module,exports){(function(global){(function(){module.exports=require("./Bottleneck");if(global.window!=null){global.window.Bottleneck=module.exports}}).call(this)}).call(this,typeof global!=="undefined"?global:typeof self!=="undefined"?self:typeof window!=="undefined"?window:{})},{"./Bottleneck":1}]},{},[4]); |
{ | ||
"name": "bottleneck", | ||
"main": "bottleneck.js", | ||
"version": "1.9.1", | ||
"version": "1.10.0", | ||
"homepage": "https://github.com/SGrondin/bottleneck", | ||
@@ -6,0 +6,0 @@ "authors": [ |
@@ -1,7 +0,11 @@ | ||
// Generated by CoffeeScript 1.9.3 | ||
// Generated by CoffeeScript 1.10.0 | ||
(function() { | ||
var Bottleneck, | ||
var Bottleneck, MIDDLE_PRIORITY, NB_PRIORITIES, | ||
bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, | ||
slice = [].slice; | ||
NB_PRIORITIES = 10; | ||
MIDDLE_PRIORITY = 5; | ||
Bottleneck = (function() { | ||
@@ -13,2 +17,3 @@ var e; | ||
OVERFLOW: 2, | ||
OVERFLOW_PRIORITY: 4, | ||
BLOCK: 3 | ||
@@ -19,7 +24,10 @@ }; | ||
Bottleneck.DLList = Bottleneck.prototype.DLList = require("./DLList"); | ||
Bottleneck.Promise = Bottleneck.prototype.Promise = (function() { | ||
var error1; | ||
try { | ||
return require("bluebird"); | ||
} catch (_error) { | ||
e = _error; | ||
} catch (error1) { | ||
e = error1; | ||
return typeof Promise !== "undefined" && Promise !== null ? Promise : function() { | ||
@@ -36,6 +44,8 @@ throw new Error("Bottleneck: install 'bluebird' or use Node 0.12 or higher for Promise support"); | ||
this.strategy = strategy != null ? strategy : Bottleneck.prototype.strategy.LEAK; | ||
this.schedulePriority = bind(this.schedulePriority, this); | ||
this.submitPriority = bind(this.submitPriority, this); | ||
this.submit = bind(this.submit, this); | ||
this._nextRequest = Date.now(); | ||
this._nbRunning = 0; | ||
this._queue = []; | ||
this._queues = this._makeQueues(); | ||
this._timeouts = []; | ||
@@ -49,2 +59,11 @@ this._unblockTime = 0; | ||
Bottleneck.prototype._makeQueues = function() { | ||
var i, j, ref, results; | ||
results = []; | ||
for (i = j = 1, ref = NB_PRIORITIES; 1 <= ref ? j <= ref : j >= ref; i = 1 <= ref ? ++j : --j) { | ||
results.push(new Bottleneck.prototype.DLList()); | ||
} | ||
return results; | ||
}; | ||
Bottleneck.prototype.chain = function(limiter) { | ||
@@ -59,4 +78,47 @@ this.limiter = limiter; | ||
Bottleneck.prototype._sanitizePriority = function(priority) { | ||
var sProperty; | ||
sProperty = ~~priority !== priority ? MIDDLE_PRIORITY : priority; | ||
if (sProperty < 0) { | ||
return 0; | ||
} else if (sProperty > NB_PRIORITIES - 1) { | ||
return NB_PRIORITIES - 1; | ||
} else { | ||
return sProperty; | ||
} | ||
}; | ||
Bottleneck.prototype._find = function(arr, fn) { | ||
var i, j, len, x; | ||
for (i = j = 0, len = arr.length; j < len; i = ++j) { | ||
x = arr[i]; | ||
if (fn(x)) { | ||
return x; | ||
} | ||
} | ||
return []; | ||
}; | ||
Bottleneck.prototype.nbQueued = function(priority) { | ||
if (priority != null) { | ||
return this._queues[this._sanitizePriority(priority)].length; | ||
} else { | ||
return this._queues.reduce((function(a, b) { | ||
return a + b.length; | ||
}), 0); | ||
} | ||
}; | ||
Bottleneck.prototype._getFirst = function(arr) { | ||
return this._find(arr, function(x) { | ||
return x.length > 0; | ||
}); | ||
}; | ||
Bottleneck.prototype._conditionsCheck = function() { | ||
return (this._nbRunning < this.maxNb || this.maxNb <= 0) && ((this.reservoir == null) || this.reservoir > 0); | ||
}; | ||
Bottleneck.prototype.check = function() { | ||
return (this._nbRunning < this.maxNb || this.maxNb <= 0) && (this._nextRequest - Date.now()) <= 0 && ((this.reservoir == null) || this.reservoir > 0); | ||
return this._conditionsCheck() && (this._nextRequest - Date.now()) <= 0; | ||
}; | ||
@@ -66,3 +128,3 @@ | ||
var done, index, next, wait; | ||
if ((this._nbRunning < this.maxNb || this.maxNb <= 0) && this._queue.length > 0 && ((this.reservoir == null) || this.reservoir > 0)) { | ||
if (this._conditionsCheck() && this.nbQueued() > 0) { | ||
this._nbRunning++; | ||
@@ -74,3 +136,3 @@ if (this.reservoir != null) { | ||
this._nextRequest = Date.now() + wait + this.minTime; | ||
next = this._queue.shift(); | ||
next = (this._getFirst(this._queues)).shift(); | ||
done = false; | ||
@@ -106,18 +168,24 @@ index = -1 + this._timeouts.push(setTimeout((function(_this) { | ||
Bottleneck.prototype.submit = function() { | ||
var args, cb, i, reachedHighWaterMark, task; | ||
task = arguments[0], args = 3 <= arguments.length ? slice.call(arguments, 1, i = arguments.length - 1) : (i = 1, []), cb = arguments[i++]; | ||
reachedHighWaterMark = this.highWater > 0 && this._queue.length === this.highWater; | ||
var args; | ||
args = 1 <= arguments.length ? slice.call(arguments, 0) : []; | ||
return this.submitPriority.apply({}, Array.prototype.concat(MIDDLE_PRIORITY, args)); | ||
}; | ||
Bottleneck.prototype.submitPriority = function() { | ||
var args, cb, j, priority, reachedHighWaterMark, shifted, task; | ||
priority = arguments[0], task = arguments[1], args = 4 <= arguments.length ? slice.call(arguments, 2, j = arguments.length - 1) : (j = 2, []), cb = arguments[j++]; | ||
priority = this._sanitizePriority(priority); | ||
reachedHighWaterMark = this.highWater > 0 && this.nbQueued() === this.highWater; | ||
if (this.strategy === Bottleneck.prototype.strategy.BLOCK && (reachedHighWaterMark || this.isBlocked())) { | ||
this._unblockTime = Date.now() + this.penalty; | ||
this._nextRequest = this._unblockTime + this.minTime; | ||
this._queue = []; | ||
this._queues = this._makeQueues(); | ||
return true; | ||
} else if (reachedHighWaterMark) { | ||
if (this.strategy === Bottleneck.prototype.strategy.LEAK) { | ||
this._queue.shift(); | ||
} else if (this.strategy === Bottleneck.prototype.strategy.OVERFLOW) { | ||
shifted = this.strategy === Bottleneck.prototype.strategy.LEAK ? (this._getFirst(this._queues.slice(priority).reverse())).shift() : this.strategy === Bottleneck.prototype.strategy.OVERFLOW_PRIORITY ? (this._getFirst(this._queues.slice(priority + 1).reverse())).shift() : this.strategy === Bottleneck.prototype.strategy.OVERFLOW ? null : void 0; | ||
if (shifted == null) { | ||
return reachedHighWaterMark; | ||
} | ||
} | ||
this._queue.push({ | ||
this._queues[priority].push({ | ||
task: task, | ||
@@ -132,4 +200,11 @@ args: args, | ||
Bottleneck.prototype.schedule = function() { | ||
var args, task, wrapped; | ||
task = arguments[0], args = 2 <= arguments.length ? slice.call(arguments, 1) : []; | ||
var args; | ||
args = 1 <= arguments.length ? slice.call(arguments, 0) : []; | ||
return this.schedulePriority.apply({}, Array.prototype.concat(MIDDLE_PRIORITY, args)); | ||
}; | ||
Bottleneck.prototype.schedulePriority = function() { | ||
var args, priority, task, wrapped; | ||
priority = arguments[0], task = arguments[1], args = 3 <= arguments.length ? slice.call(arguments, 2) : []; | ||
priority = this._sanitizePriority(priority); | ||
wrapped = function(cb) { | ||
@@ -148,3 +223,3 @@ return (task.apply({}, args)).then(function() { | ||
return function(resolve, reject) { | ||
return _this.submit.apply({}, Array.prototype.concat.call(wrapped, function() { | ||
return _this.submitPriority.apply({}, Array.prototype.concat.call(priority, wrapped, function() { | ||
var args, error; | ||
@@ -187,16 +262,13 @@ error = arguments[0], args = 2 <= arguments.length ? slice.call(arguments, 1) : []; | ||
Bottleneck.prototype.stopAll = function(interrupt) { | ||
var a, i, len, ref; | ||
var a, j, len, ref; | ||
this.interrupt = interrupt != null ? interrupt : this.interrupt; | ||
ref = this._timeouts; | ||
for (i = 0, len = ref.length; i < len; i++) { | ||
a = ref[i]; | ||
for (j = 0, len = ref.length; j < len; j++) { | ||
a = ref[j]; | ||
clearTimeout(a); | ||
} | ||
this._tryToRun = function() {}; | ||
this.submit = function() { | ||
return this.check = this.submit = this.submitPriority = this.schedule = this.schedulePriority = function() { | ||
return false; | ||
}; | ||
return this.check = function() { | ||
return false; | ||
}; | ||
}; | ||
@@ -203,0 +275,0 @@ |
@@ -1,2 +0,2 @@ | ||
// Generated by CoffeeScript 1.9.3 | ||
// Generated by CoffeeScript 1.10.0 | ||
(function() { | ||
@@ -3,0 +3,0 @@ var Cluster, |
@@ -1,2 +0,2 @@ | ||
// Generated by CoffeeScript 1.9.3 | ||
// Generated by CoffeeScript 1.10.0 | ||
(function() { | ||
@@ -3,0 +3,0 @@ module.exports = require("./Bottleneck"); |
{ | ||
"name": "bottleneck", | ||
"version": "1.9.1", | ||
"version": "1.10.0", | ||
"description": "Async rate limiter", | ||
"main": "lib/index.js", | ||
"scripts": { | ||
"test": "echo \"No test specified\" && exit 1", | ||
"test": "./node_modules/mocha/bin/mocha test/index.js", | ||
"make": "./scripts/recompile.sh" | ||
@@ -35,6 +35,7 @@ }, | ||
"devDependencies": { | ||
"coffee-script": "1.9.x", | ||
"coffee-script": "1.10.x", | ||
"browserify": "*", | ||
"mocha":"*", | ||
"uglify-js": "*" | ||
} | ||
} |
@@ -8,7 +8,7 @@ # bottleneck | ||
Bottleneck is a tiny and efficient Asynchronous Rate Limiter for Node.JS and the browser. When dealing with services with limited resources, it's important to ensure that they don't become overloaded. | ||
Bottleneck is a tiny and efficient Task Scheduler and Rate Limiter for Node.JS and the browser. When dealing with services with limited resources, it's important to ensure that they don't become overloaded. | ||
Bottleneck is the easiest solution as it doesn't add any complexity to the code. | ||
Bottleneck is the easiest solution as it doesn't much complexity to the code. | ||
It's battle-hardened, reliable and production-ready. [DNSChain](https://github.com/okTurtles/dnschain) uses it to serve millions of queries per day. | ||
It's battle-hardened, reliable and production-ready. It's used on a large scale in both private companies and open source software. | ||
@@ -31,2 +31,3 @@ | ||
###### Example | ||
@@ -56,3 +57,3 @@ | ||
Bottleneck builds a queue of requests and executes them as soon as possible. All the requests will be executed *in order*. | ||
Bottleneck builds a queue of requests and executes them as soon as possible. All the requests will be executed *in the order that they were received*. See [priorities](https://github.com/SGrondin/bottleneck#priorities) if you wish to alter this behavior. | ||
@@ -86,5 +87,6 @@ This is sufficient for the vast majority of applications. **Read the [Gotchas](https://github.com/SGrondin/bottleneck#gotchas) section** and you're good to go. Or keep reading to learn about all the fine tuning available for the more complex use cases. | ||
### schedule() | ||
Adds a request to the queue. This is the Promise version of `submit`. It uses the [bluebird](https://github.com/petkaantonov/bluebird) package if available and otherwise uses the built-in [Promise](http://caniuse.com/#feat=promises) object. | ||
Adds a request to the queue. This is the Promise version of `submit`. It uses the [bluebird](https://github.com/petkaantonov/bluebird) package if installed and otherwise uses the built-in [Promise](http://caniuse.com/#feat=promises) object. | ||
@@ -96,3 +98,3 @@ ```js | ||
limiter.schedule(fn, arg1, arg2, argN); | ||
limiter.schedule(fn, arg1, arg2, argN); // This also returns a promise, for chaining | ||
``` | ||
@@ -122,2 +124,3 @@ | ||
## Gotchas | ||
@@ -129,18 +132,52 @@ | ||
* If you want to rate limit a synchronous function (console.log(), for example), you must wrap it in a closure to make it asynchronous. See [this](https://github.com/SGrondin/bottleneck#rate-limiting-synchronous-functions) example. | ||
* If you want to rate limit a synchronous function (`console.log(), for example), you must wrap it in a closure to make it asynchronous. See [this](https://github.com/SGrondin/bottleneck#rate-limiting-synchronous-functions) example. | ||
### strategies | ||
A strategy is a simple algorithm that is executed every time adding a request would cause the queue's length to exceed `highWater`. | ||
### Priorities | ||
Every request has a priority level. It's `5` for every request added with `submit`/`schedule`. There exists a variant of those functions that lets you set the priority of a request. | ||
Priority `0` is the most important and `9` is the least important. | ||
**More important requests will *always* be executed before less important ones. For requests with the same priority level, the oldest one is executed first.** | ||
#### submitPriority() | ||
```js | ||
limiter.submitPriority(priority, someAsyncCall, arg1, arg2, argN, cb); | ||
``` | ||
#### schedulePriority() | ||
```js | ||
limiter.schedulePriority(priority, fn, arg1, arg2, argN); | ||
``` | ||
### Strategies | ||
A strategy is a simple algorithm that is executed every time adding a request would cause the number of queued requests to exceed `highWater`. | ||
#### Bottleneck.strategy.LEAK | ||
When submitting a new request, if the queue length reaches `highWater`, drop the oldest request in the queue. This is useful when requests that have been waiting for too long are not important anymore. | ||
When submitting a new request, if the queue length reaches `highWater`, drop the oldest request with the lowest priority. This is useful when requests that have been waiting for too long are not important anymore. If all the queued up requests are more important than the one being added, it won't be added. | ||
#### Bottleneck.strategy.OVERFLOW_PRIORITY | ||
Same as `LEAK`, except that it will only drop requests that are *less important* than the one being added. If all the queued up requests are as important or more than the new one, it won't be added. | ||
#### Bottleneck.strategy.OVERFLOW | ||
When submitting a new request, if the queue length reaches `highWater`, do not add the new request. | ||
When submitting a new request, if the queue length reaches `highWater`, do not add the new request. This strategy totally ignores priority levels. | ||
#### Bottleneck.strategy.BLOCK | ||
When submitting a new request, if the queue length reaches `highWater`, the limiter falls into "blocked mode". All queued requests are dropped and no new requests will be accepted into the queue until the limiter unblocks. It will unblock after `penalty` milliseconds have passed without receiving a new request. `penalty` is equal to `15 * minTime` (or `5000` if `minTime` is `0`) by default and can be changed by calling `changePenalty()`. This strategy is ideal when bruteforce attacks are to be expected. | ||
When submitting a new request, if the queue length reaches `highWater`, the limiter falls into "blocked mode". All queued requests are dropped and no new requests will be accepted until the limiter unblocks. It will unblock after `penalty` milliseconds have passed without receiving a new request. `penalty` is equal to `15 * minTime` (or `5000` if `minTime` is `0`) by default and can be changed by calling `changePenalty()`. This strategy is ideal when bruteforce attacks are to be expected. This strategy totally ignores priority levels. | ||
### nbQueued() | ||
```js | ||
limiter.nbQueued(priority); | ||
``` | ||
`priority` is optional. Without that argument, it'll return the total number of requests waiting to be executed, otherwise it'll only count the number of requests with that specific priority. | ||
### check() | ||
@@ -153,2 +190,3 @@ | ||
### isBlocked() | ||
@@ -181,3 +219,3 @@ | ||
For example, imagine that 3 60-second requests are submitted at time T+0 with `maxConcurrent = 0` and `minTime = 2000`. The requests will be launched at T+0 seconds, T+2 seconds and T+4 seconds respectively. If right after adding the requests to Bottleneck, you were to call `limiter.changeSettings(1);`, it won't change the fact that there will be 3 requests running at the same time for roughly 60 seconds. Once again, `changeSettings` only affects requests that have not yet been added. | ||
For example, imagine that three 60-second requests are submitted at time T with `maxConcurrent = 0` and `minTime = 2000`. The requests will be launched at T seconds, T+2 seconds and T+4 seconds respectively. If right after adding the requests to Bottleneck, you were to call `limiter.changeSettings(1);`, it won't change the fact that there will be 3 requests running at the same time for roughly 60 seconds. Once again, `changeSettings` only affects requests that have not yet been added. | ||
@@ -206,2 +244,3 @@ This is by design, as Bottleneck made a promise to execute those requests according to the settings valid at the time. Changing settings afterwards should not break previous assumptions, as that would make code very error-prone and Bottleneck a tool that cannot be relied upon. | ||
### chain() | ||
@@ -223,7 +262,8 @@ | ||
## Execution guarantee | ||
Bottleneck will execute every request in order. They will **all** *eventually* be executed as long as: | ||
Bottleneck will execute every request in order of priority first, oldest to youngest within each priority level. You can be certain that they will **all** *eventually* be executed as long as: | ||
* `highWater` is set to `0` (default), which prevents the strategy from ever being run. | ||
* `highWater` is set to `0` (default), which prevents the strategy from ever being run **OR** you never exceed the `highWater`. | ||
* `maxConcurrent` is set to `0` (default) **OR** all requests call the callback *eventually* (in the case of promises, they must be resolved or rejected eventually). | ||
@@ -251,2 +291,3 @@ * `reservoir` is `null` (default). | ||
### key() | ||
@@ -258,2 +299,3 @@ | ||
### stopAutoCleanup() | ||
@@ -263,2 +305,3 @@ | ||
### startAutoCleanup() | ||
@@ -268,2 +311,3 @@ | ||
### deleteKey() | ||
@@ -275,2 +319,3 @@ | ||
### all() | ||
@@ -288,2 +333,3 @@ | ||
### keys() | ||
@@ -293,2 +339,3 @@ | ||
## Rate-limiting synchronous functions | ||
@@ -329,5 +376,6 @@ | ||
## Contributing | ||
This README file is always in need of better explanations and examples. If things can be clearer and simpler, please consider forking this repo and submitting a Pull Request. | ||
This README file is always in need of better explanations and examples. If things can be clearer and simpler, please consider forking this repo and submitting a Pull Request, or simply open an issue. | ||
@@ -334,0 +382,0 @@ Suggestions and bug reports are also welcome. |
Sorry, the diff of this file is not supported yet
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
No tests
QualityPackage does not have any tests. This is a strong signal of a poorly maintained or low quality package.
Found 1 instance in 1 package
70002
21
1070
2
374
4
8