diff --git a/lib/db.js b/lib/db.js
index e5ab7f7..42b8e35 100644
--- a/lib/db.js
+++ b/lib/db.js
@@ -1,3 +1,4 @@
+///
const ms = require('ms');
const fs = require('fs');
const _ = require('lodash');
@@ -37,7 +38,7 @@ class LimitDBRedis extends EventEmitter {
/**
* Creates an instance of LimitDB client for Redis.
- * @param {params} params - The configuration for the database and client.
+ * @param {LimitDBParams} params - The configuration for the database and client.
*/
constructor(config) {
super();
@@ -149,9 +150,9 @@ class LimitDBRedis extends EventEmitter {
}
/**
- * @param {string} type
- * @param {object} params
- * @returns
+ * @param {Bucket & { overrides: Object?, overridesCache: Object?, overridesMatch: Object? }} type
+ * @param {GetParams | PutParams | TakeParams | TakeElevatedParams} params
+ * @returns {NormalizedType}
*/
bucketKeyConfig(type, params) {
if (typeof params.configOverride === 'object') {
@@ -194,9 +195,9 @@ class LimitDBRedis extends EventEmitter {
/**
* Take N elements from a bucket if available.
*
- * @param {takeParams} params - The params for take.
- * @param {function(Error, takeResult)} callback.
- * @param {function(key, bucketKeyConfig, count)} takeFunc
+ * @param {TakeParams} params - The params for take.
+ * @param {function(null, TakeResult) | function(Error)} callback
+ * @param {function(key: string, bucketKeyConfig: NormalizedType, count: number)} takeFunc
*/
_doTake(params, callback, takeFunc) {
const valError = validateParams(params, this.buckets);
@@ -255,8 +256,8 @@ class LimitDBRedis extends EventEmitter {
/**
* Take N elements from a bucket if available.
*
- * @param {takeParams} params - The params for take.
- * @param {function(Error, takeResult)} callback.
+ * @param {TakeParams} params
+ * @param {function(null, TakeResult) | function(Error)} callback
*/
take(params, callback) {
this._doTake(params, callback, (key, bucketKeyConfig, count) => {
@@ -289,6 +290,12 @@ class LimitDBRedis extends EventEmitter {
})
}
+ /**
+ * Take N elements from a bucket if available, use elevated limits if configured.
+ *
+ * @param {TakeElevatedParams} params
+ * @param {function(null, TakeElevatedResult) | function(Error)} callback
+ */
takeElevated(params, callback) {
let erlParams;
@@ -355,8 +362,8 @@ class LimitDBRedis extends EventEmitter {
* Take N elements from a bucket if available otherwise wait for them.
* The callback is called when the number of request tokens is available.
*
- * @param {waitParams} params - The params for take.
- * @param {function(Error, waitResult)} callback.
+ * @param {WaitParams} params - The params for take.
+ * @param {function(null, WaitResult) | function(Error)} callback
*/
wait(params, callback) {
this.take(params, (err, result) => {
@@ -385,8 +392,8 @@ class LimitDBRedis extends EventEmitter {
/**
* Put N elements in the bucket.
*
- * @param {putParams} params - The params for take.
- * @param {function(Error, putResult)} [callback].
+ * @param {PutParams} params - The params for take.
+ * @param {function(null, PutResult) | function(Error)} [callback]
*/
put(params, callback) {
callback = callback || _.noop;
@@ -438,8 +445,8 @@ class LimitDBRedis extends EventEmitter {
/**
* Get elements in the bucket.
*
- * @param {getParams} params - The params for take.
- * @param {function(Error, getResult)} [callback].
+ * @param {GetParams} params - The params for take.
+ * @param {function(null, GetResult) | function(Error)} [callback]
*/
get(params, callback) {
callback = callback || _.noop;
@@ -508,69 +515,4 @@ class LimitDBRedis extends EventEmitter {
}
-module.exports = LimitDBRedis;
-
-/**
- * And now some typedefs for you:
- *
- * @typedef {Object} type
- * @property {integer} [per_interval] The number of tokens to add per interval.
- * @property {integer} [interval] The length of the interval in milliseconds.
- * @property {integer} [size] The maximum number of tokens in the bucket.
- * @property {integer} [per_second] The number of tokens to add per second. Equivalent to "interval: 1000, per_interval: x".
- * @property {integer} [per_minute] The number of tokens to add per minute. Equivalent to "interval: 60000, per_interval: x".
- * @property {integer} [per_hour] The number of tokens to add per hour. Equivalent to "interval: 3600000, per_interval: x".
- * @property {integer} [per_day] The number of tokens to add per day. Equivalent to "interval: 86400000, per_interval: x".
- *
- * @typedef {Object} params
- * uri nodes buckets prefix
- * @property {string} [params.uri] Address of Redis.
- * @property {Object.} [params.nodes] Redis Cluster Configuration https://github.com/luin/ioredis#cluster".
- * @property {Object.} [params.types] The buckets configuration.
- * @property {string} [params.prefix] Prefix keys in Redis.
- * @property {type} [params.configOverride] Bucket configuration override
- *
- * @typedef takeParams
- * @property {string} type The name of the bucket type.
- * @property {string} key The key of the bucket instance.
- * @property {integer} [count=1] The number of tokens to take from the bucket.
- * @property {type} configOverride Externally provided bucket configruation
- *
- * @typedef takeResult
- * @property {boolean} conformant Returns true if there is enough capacity in the bucket and the tokens has been removed.
- * @property {integer} remaining The number of tokens remaining in the bucket.
- * @property {integer} reset A unix timestamp indicating when the bucket is going to be full.
- * @property {integer} limit The size of the bucket.
- *
- * @typedef waitParams
- * @property {string} type The name of the bucket type.
- * @property {string} key The key of the bucket instance.
- * @property {integer} [count=1] The number of tokens to wait for.
- * @property {type} configOverride Externally provided bucket configruation
- *
- * @typedef waitResult
- * @property {integer} remaining The number of tokens remaining in the bucket.
- * @property {integer} reset A unix timestamp indicating when the bucket is going to be full.
- * @property {integer} limit The size of the bucket.
- *
- * @typedef putParams
- * @property {string} type The name of the bucket type.
- * @property {string} key The key of the bucket instance.
- * @property {integer} [count=SIZE] The number of tokens to put in the bucket. Defaults to the size of the bucket.
- * @property {type} configOverride Externally provided bucket configruation
- *
- * @typedef putResult
- * @property {integer} remaining The number of tokens remaining in the bucket.
- * @property {integer} reset A unix timestamp indicating when the bucket is going to be full.
- * @property {integer} limit The size of the bucket.
- *
- * @typedef getParams
- * @property {string} type The name of the bucket type.
- * @property {string} key The key of the bucket instance.
- * @property {type} configOverride Externally provided bucket configruation
- *
- * @typedef getResult
- * @property {integer} remaining The number of tokens remaining in the bucket.
- * @property {integer} reset A unix timestamp indicating when the bucket is going to be full.
- * @property {integer} limit The size of the bucket.
-*/
+module.exports = LimitDBRedis;
\ No newline at end of file
diff --git a/lib/types.js b/lib/types.js
new file mode 100644
index 0000000..9f1b888
--- /dev/null
+++ b/lib/types.js
@@ -0,0 +1,155 @@
+// --- Public Types ---
+
+/**
+ * @typedef {Object} LimitDBParams
+ * uri nodes buckets prefix
+ * @property {string} [params.uri] Address of Redis.
+ * @property {Object.} [params.nodes] Redis Cluster Configuration https://github.com/luin/ioredis#cluster".
+ * @property {Object.} [params.types] The buckets configuration.
+ * @property {string} [params.prefix] Prefix keys in Redis.
+ * @property {Bucket} [params.configOverride] Bucket configuration override
+ */
+
+/**
+* @typedef {Object} Bucket
+* @property {number} [per_interval] The number of tokens to add per interval.
+* @property {number} [interval] The length of the interval in milliseconds.
+* @property {number} [size] The maximum number of tokens in the bucket.
+* @property {number} [per_second] The number of tokens to add per second. Equivalent to "interval: 1000, per_interval: x".
+* @property {number} [per_minute] The number of tokens to add per minute. Equivalent to "interval: 60000, per_interval: x".
+* @property {number} [per_hour] The number of tokens to add per hour. Equivalent to "interval: 3600000, per_interval: x".
+* @property {number} [per_day] The number of tokens to add per day. Equivalent to "interval: 86400000, per_interval: x".
+* @property {number} [unlimited] the maximum number of tokens in the bucket. equivalent to "size: x".
+* @property {number} [skip_n_calls] the number of calls to skip. equivalent to "size: x".
+* @property {ElevatedLimitParams} [elevated_limits] The elevated limit configuration.
+*/
+
+/**
+ * @typedef TakeParams
+ * @property {string} type The name of the bucket type.
+ * @property {string} key The key of the bucket instance.
+ * @property {number} [count=1] The number of tokens to take from the bucket.
+ * @property {Bucket} configOverride Externally provided bucket configuration
+*/
+
+/**
+ * @typedef TakeResult
+ * @property {boolean} conformant Returns true if there is enough capacity in the bucket and the tokens has been removed.
+ * @property {number} remaining The number of tokens remaining in the bucket.
+ * @property {number} reset A unix timestamp indicating when the bucket is going to be full.
+ * @property {number} limit The size of the bucket.
+ */
+/**
+
+ * @typedef WaitParams
+ * @property {string} type The name of the bucket type.
+ * @property {string} key The key of the bucket instance.
+ * @property {number} [count=1] The number of tokens to wait for.
+ * @property {Bucket} configOverride Externally provided bucket configuration
+ */
+
+/**
+ * @typedef WaitResult
+ * @property {number} remaining The number of tokens remaining in the bucket.
+ * @property {number} reset A unix timestamp indicating when the bucket is going to be full.
+ * @property {number} limit The size of the bucket.
+ */
+
+/**
+ * @typedef PutParams
+ * @property {string} type The name of the bucket type.
+ * @property {string} key The key of the bucket instance.
+ * @property {number} [count=SIZE] The number of tokens to put in the bucket. Defaults to the size of the bucket.
+ * @property {Bucket} configOverride Externally provided bucket configruation
+ */
+
+/**
+ * @typedef PutResult
+ * @property {number} remaining The number of tokens remaining in the bucket.
+ * @property {number} reset A unix timestamp indicating when the bucket is going to be full.
+ * @property {number} limit The size of the bucket.
+ */
+
+/**
+ * @typedef GetParams
+ * @property {string} type The name of the bucket type.
+ * @property {string} key The key of the bucket instance.
+ * @property {Bucket} configOverride Externally provided bucket configuration
+ */
+
+/**
+ * @typedef GetResult
+ * @property {number} remaining The number of tokens remaining in the bucket.
+ * @property {number} reset A unix timestamp indicating when the bucket is going to be full.
+ * @property {number} limit The size of the bucket.
+ */
+
+/**
+ * @typedef {Object} TakeElevatedParams
+ * @property {string} type - The name of the bucket type.
+ * @property {string} key - The key of the bucket instance.
+ * @property {number} [count=1] - The number of tokens to take from the bucket.
+ * @property {ElevatedLimitParams} [elevated_limits] - (Optional) The elevated limit configuration.
+ * @property {Bucket} configOverride Externally provided bucket configuration
+ */
+
+/**
+ * @typedef {Object} ElevatedLimitParams
+ * @property {string} erl_is_active_key - The key to check if the elevated limits are active.
+ * @property {string} erl_quota_key - The key to store the quota for the elevated limits.
+ * @property {number} erl_activation_period_seconds - The activation period for the elevated limits in seconds.
+ * // temporal options
+ * @property {number} [per_interval] The number of tokens to add per interval.
+ * @property {number} [interval] The length of the interval in milliseconds.
+ * @property {number} [size] The maximum number of tokens in the bucket.
+ * @property {number} [per_second] The number of tokens to add per second. Equivalent to "interval: 1000, per_interval: x".
+ * @property {number} [per_minute] The number of tokens to add per minute. Equivalent to "interval: 60000, per_interval: x".
+ * @property {number} [per_hour] The number of tokens to add per hour. Equivalent to "interval: 3600000, per_interval: x".
+ * @property {number} [per_day] The number of tokens to add per day. Equivalent to "interval: 86400000, per_interval: x".
+ * @property {number} [unlimited] The maximum number of tokens in the bucket. Equivalent to "size: x".
+ */
+
+/**
+ * @typedef {Object} TakeElevatedResult
+ * @property {boolean} conformant - Returns true if there is enough capacity in the bucket and the tokens has been removed.
+ * @property {number} remaining - The number of tokens remaining in the bucket.
+ * @property {number} reset - A unix timestamp indicating when the bucket is going to be full.
+ * @property {number} limit - The size of the bucket.
+ * @property {boolean} delayed - Indicates if the operation was delayed.
+ * @property {Elevated_result} elevated_limits - The elevated limit result
+ */
+
+/**
+ * @typedef {Object} Elevated_result
+ * @property {boolean} erl_configured_for_bucket - Indicates if the bucket is configured for elevated limits.
+ * @property {boolean} triggered - Indicates if the elevated limits were triggered.
+ * @property {boolean} activated - Indicates if the elevated limits were activated.
+ * @property {number} quota_remaining - The remaining quota for elevated limits.
+ * @property {number} quota_allocated - The allocated quota for elevated limits.
+ * @property {number} erl_activation_period_seconds - The activation period for elevated limits in seconds.
+ */
+
+// --- Internal Types ---
+
+/**
+ * @typedef {Object} NormalizedType -- the internal representation of a bucket
+ * @property {number} [per_interval] The number of tokens to add per interval.
+ * @property {number} [interval] The length of the interval in milliseconds.
+ * @property {number} [size] The maximum number of tokens in the bucket.
+ * @property {number} [ttl] The time to live for the bucket in seconds.
+ * @property {number} [ms_per_interval] The number of milliseconds per interval.
+ * @property {number} [drip_interval] The interval for the drip in milliseconds.
+ * @property {number} [unlimited] the maximum number of tokens in the bucket. equivalent to "size: x".
+ * @property {number} [skip_n_calls] the number of calls to skip. equivalent to "size: x".
+ * @property {NormalizedType} [elevated_limits] The elevated limit configuration.
+ * @property {boolean} [erl_configured_for_bucket] Indicates if the bucket is configured for elevated limits.
+ */
+
+/**
+ * @typedef {Object} ElevatedLimitConfiguration
+ * @property {string} erl_is_active_key - The key to check if the elevated limits are active.
+ * @property {string} erl_quota_key - The key to store the quota for the elevated limits.
+ * @property {number} erl_activation_period_seconds - The activation period for the elevated limits in seconds.
+ * @property {number} erl_quota - The quota for the elevated limits.
+ * @property {string} erl_quota_interval - The interval for the quota.
+ */
diff --git a/lib/utils.js b/lib/utils.js
index 6a21b0c..a93f8dc 100644
--- a/lib/utils.js
+++ b/lib/utils.js
@@ -1,3 +1,4 @@
+///
const ms = require('ms');
const _ = require('lodash');
const LRU = require('lru-cache');
@@ -17,7 +18,12 @@ const ERL_QUOTA_INTERVALS = {
};
const ERL_QUOTA_INTERVALS_SHORTCUTS = Object.keys(ERL_QUOTA_INTERVALS);
-function normalizeTemporals(params) {
+/**
+ *
+ * @param {Bucket} params
+ * @returns {NormalizedType}
+ */
+function parseIntervals(params) {
const type = _.pick(params, [
'per_interval',
'interval',
@@ -43,19 +49,24 @@ function normalizeTemporals(params) {
type.ms_per_interval = type.per_interval / type.interval;
type.drip_interval = type.interval / type.per_interval;
}
-
- if (params.elevated_limits) {
- type.elevated_limits = normalizeElevatedTemporals(params.elevated_limits);
- }
-
- return type;
+ return type
}
-function normalizeElevatedTemporals(params) {
- let type = normalizeTemporals(params);
+/**
+ *
+ * @param {Bucket} params
+ * @returns {NormalizedType}
+ */
+function normalizeTemporals(params) {
+ const type = parseIntervals(params);
- if (typeof type.size !== 'undefined' && typeof type.per_interval !== 'undefined') {
- type.erl_configured_for_bucket = true;
+ if (params.elevated_limits) {
+ const elevatedLimits = parseIntervals(params.elevated_limits);
+ const isErlDefined = !_.isUndefined(elevatedLimits.size) && !_.isUndefined(elevatedLimits.per_interval);
+ type.elevated_limits = {
+ ...elevatedLimits,
+ erl_configured_for_bucket: isErlDefined,
+ };
}
return type;
@@ -103,7 +114,7 @@ function normalizeType(params) {
/**
* Load the buckets configuration.
*
- * @param {Object.} bucketsConfig The buckets configuration.
+ * @param {Object.} bucketsConfig The buckets configuration.
* @memberof LimitDB
*/
function buildBuckets(bucketsConfig) {
@@ -132,6 +143,12 @@ function randomBetween(min, max) {
return Math.random() * (max - min) + min;
}
+/**
+ * Extracts ERL configuration from the ERL parameters
+ *
+ * @param {ElevatedLimitParams} params The object to extract the ERL parameters from.
+ * @returns {ElevatedLimitConfiguration} The extracted ERL parameters.
+ */
function getERLParams(params) {
const type = _.pick(params, [
'erl_is_active_key',
@@ -159,6 +176,13 @@ function endOfMonthTimestamp() {
return Date.UTC(curDate.getUTCFullYear(), curDate.getUTCMonth() + 1, 1, 0, 0, 0, 0);
}
+/**
+ * Resolves the elevated parameters by providing default values for elevated_limits unless they are defined in the bucketKeyConfig.
+ *
+ * @param {ElevatedLimitParams} erlParams - The ERL parameters to resolve.
+ * @param {NormalizedType} bucketKeyConfig - The configuration of the bucket key.
+ * @returns {NormalizedType & ElevatedLimitConfiguration} The resolved ERL parameters.
+ */
function resolveElevatedParams(erlParams, bucketKeyConfig) {
// provide default values for elevated_limits unless the bucketKeyConfig has them
return {
diff --git a/lib/validation.js b/lib/validation.js
index b834e29..dad5679 100644
--- a/lib/validation.js
+++ b/lib/validation.js
@@ -58,6 +58,12 @@ function validateOverride(configOverride) {
}
}
+/**
+ * Validates the elevated limits parameters.
+ *
+ * @param {ElevatedLimitConfiguration} params The parameters to validate.
+ * @returns {LimitdRedisValidationError | void} The error, if any.
+ */
function validateERLParams(params) {
if (!params) {
return new LimitdRedisValidationError('elevated_limits object is required for elevated limits', { code: 107 });