Security News
Weekly Downloads Now Available in npm Package Search Results
Socket's package search now displays weekly downloads for npm packages, helping developers quickly assess popularity and make more informed decisions.
@gradeup/youknowwho
Advanced tools
Rule engine for most of generic decisions and flow control.
Rules consists of Conditions and Actions. Action of a rule is applied when its concerned conditions evaluate to true.
Id : Unique identification of a rule
Name : Not used anywhere except for Logging
Tags : Each rule can be associated with many tags. They help in applying selective rules.
Description : Personal comments for a rule
External Reference : If rules are created by some other entity, this is used to create that bonding
Status : Enabled / Disabled
Priority : An integer value, which decides the order of rule execution. Lower the integer value, higher will be its priority and Earlier will be the execution of rule.
Conditional Operator : Operator Applied to all conditions to calculate final True/False value for conditions.
Conditions : They are applied sequentially, and are blocking in manner. Next condition is applied only after previous has been evaluated.
Actions : They are applied only after conditions evaluate to True
according to conditional operator's value. They are sequential, and blocking in manner. Next Action is applied only after previous has been evaluated.
Each condition has 4 parts
Possible options are
( '=', 'Equals ( = )')
( '!=', 'Not Equals ( != )'),
( '>', 'Great than Integer ( > )')
Before comparing, the value on both sides is parsed as float using parseFloat.
( '>=', 'Great than Equals Integer( >= )')
Before comparing, the value on both sides is parsed as float using parseFloat.
( '<', 'Less than Integer( < )')
Before comparing, the value on both sides is parsed as float using parseFloat.
( '<=', 'Less than Equals Integer(<= )')
Before comparing, the value on both sides is parsed as float using parseFloat.
('range', 'In Numerical Range ( range )')
('!range', 'Not In Numerical Range ( !range )')
E.g. : 1,2, 4~5, 6~10,11,12~
('datetimerange', 'In DateTime Range (datetimerange )'), ('!datetimerange', 'Not In DateTime Range (!datetimerange )'),
E.g. : 2015-06-11 00:00:00~ 2015-07-12 00:00:00
NOTE * ALWAYS specify datetime in YYYY-MM-DD HH:mm:ss format * If datetimeformat is invalid then that condition is given benefit of doubt and marked as null. Same is true of condition value is also not correct datetime value
('timerange', 'In Time Range ( timerange )'), ('!timerange', 'Not In Time Range ( !timerange )'),
NOTE * Format HH:mm:ss~HH:mm:ss * If time is invalid then that condition is given benefit of doubt and marked as null. Same is true of condition value is also not correct datetime value
('regex', 'In Regex ( regex )'), ('!regex', 'Not In Regex ( !regex)'),
E.g. ["a", "b", "c"]
('stringrange', 'In String Array ( stringrange)'), ('!stringrange', 'Not In String Array ( !stringrange )'),
E.g. [1, 2, 3]
('set', 'Is a part of the Set (set)'), ('!set', 'Is not a part of the set (!set)'),
('includesint', 'Does array contains the given integer ( includesint )'), ('!includesint', 'Does array not contains the given integer ( !includesint )'),
('includesstring', 'Does array contains the given string ( includesstring )'), ('!includesstring', 'Does array not contains the given string ( !includesstring )'),
The value to the condition can be a static value or something that belongs to the input message of the rule. To provide dynamic input values, use the lodash template syntax. like
<%= input.variable1 %>
Each Action has 3 parts
Set Variable : Sets a variable in the source message
Set Number : Sets a variable as Number in the source message
Stop Processing more rules : Stop Processing more rule after this action. This will continue processing all actions of the rule which is being processed, and will exit after that. This will NOT stop the next action. Hence it should ideally be the last action of a rule. Generally used to handle those cases when we want to return from a function on meeting a particular condition
DANGEROUS_EVAL : This uses eval
to evaluate the key and overwrite it. The value should be a valid expression like
Math.log(9) * 4
Key : For Set variable, Set Number or according to action
Value : For set variable or according to action. See Rule Action Value for options
boolean : "true" or "false" is converted to boolean TRUE/FALSE
template string : Specify string in lodash format <%= variable %>
and it will be treated as a lodash template. The variables in the template are picked from message.
normal string : any string other than above two will be treated as a normal string.
The function is expected to be in following format
function custom(callback, arg) {
.... do something with arg()
callback();
}
Each function's 1st argument will be the callback it is expected to call once its execution is over.
There is no differentiation in blocking and non-blocking functions, and also in sync and async functions, since we are anyway passing a callback.
arg : arg is the argument which can be passed to function by previous rules/actions. Each message will have a key :=> msg.execargs which will have key for each function. E.g. if user wishes to pass an object as an argument to function f1 , it will set it in msg.execargs.f1 . NOTE : At the end , execargs key will be deleted from message, hence try not to put anything of persistence there.
function context : Rule engine will expose a execContext which will be the object which will hold all function definitions and will be supplied as the context (this) in function execution.
Error handling/ exceptions : All functions will be called within a try-catch exception handling and rule engine is not expected to handle any error/exception.
( Tag 0.0.7 ) UPDATED : wont emit logs anymore. This will be taken care by Meta object
Load the Rules first( and again and again ...) and simply apply them .
# loaded_hash is hash generated for the list of rules.
# This can be used to differentiate the set of rules.
loaded_hash = ruleEngineObject.loadRules(arrayOfRules);
Applying Rules
/*
msg : the object which needs to be changed. This object is passed by reference and if user wishes to keep the original object sane then he/she needs to clone the object before passing here ( using lodash/underscore or similar )
ruletag : single tag. TODO : support for multiple tags
generateMeta : (boolean) If you want to generate meta information of rule execution ( will be 50% slower to execute a rule ). Default false
*/
meta_object = ruleEngineObject.applyRules(msg, ruletag, generateMeta);
Var arrayOfRules = [
{
"id": 1, // rule ID , has to be unique
"name": "Natural Number ", // Dont care
"external_reference": "", // Dont care
"conditionsOperator": "&&", // very important
"priority": 170001,
"tags": [
"natural",
""
],
"conditions": [
{
"id": 1,
"key": "integer",
"operation": ">",
"value": "0"
}
],
"actions": [
{
"id": 2,
"action": "SET_VARIABLE",
"key": "is_natural",
"value": 1
}
]
}
];
This calculates a hash of loaded rules , which helps in audit. This is a simple md5 hash.
It might be possible for the user to cache the input and output of the rule engine. An input object can contain any number of keys but the keys on which conditions are applied are the actual keys which give the rule engine its dynamic nature. After rules are loaded user can call getLoadedMeta
to get loaded rules hash and array of condition keys.
User is expected to create a sub object consisting of these condition keys only , hash it and use it for cache.
Use RULES HASH + HASH of object having condition keys only as Cache Key. value can be Output of the rule engine.
E.g. If condition keys are [key1, key2] and object which is generally passed to rule engine is { key1: 1, key2 : 2, key3 : 3}, then user should create a smaller object { key1: 1, key2: 2} , take hash of this, and append loaded-rules-hash in it and use that as the key of cache.
ruleEngineObject.getLoadedMeta()
// will return an object like this
{ rules_load:
{ hash: '3f2ddc875c24b0aabe238a21d9da8e0a',
load_start: '1469687197716',
load_end: '1469687197727',
load_exec_time: 11,
uniqueConditionKeys : ['key1', 'key2'],
uniqueActionKeys : ['keyA', 'keyB']
}
}
Meta object saves the state of each rule , condition and action with variups required timestamps. It is not in the scope of this project to analyze the performace/metrics of the engine/rules. This can help in re-arranging conditions, removing redundant /slow rules, etc. . Idea should be to minimize the number of conditions/rules for each message. Schema of meta object
Rules, conditions and actions are dictionary based to have easy accessibility
{
"rules": { // Rules object, each key: val is rule id : data
"1": { // rule ID
"ruleid": 1, // rule id
"exec_order": 1, // Execution order of rules by RE. starts with 0
"conditions": { // conditions object
"1": { // condition ID
"cid": 1, // condition ID
"lval": -1, // Left value of condition
"op": ">", // Operation applied
"rval": "0", // Right value of operation
"d": false // decision for this condition
}
},
"applied": false, // Rules was applied or not
"actions": {} // actions
},
},
"rules_load": {
"hash": "feb65a88a9f346494ad5a12de14dc7ec", // hash of loaded rules
"load_start": "1463996594477", // Rules load start time
"load_end": "1463996594479", // Rules loading end time
"load_exec_time": 2 // milliseconds for rule loading
},
"startTime": "1463996594492", // start time of RE execution
"endTime": "1463996594494", // end time ( Unix Milliseconds )
"execTime": 2 //exec time for RE
}
$ npm run benchmark
Start Benchmark Set 1 : with 1 Rule : natural number
ruleengine x 123,730 ops/sec ±2.79% (82 runs sampled)
native x 39,966,923 ops/sec ±2.55% (83 runs sampled)
Fastest is native
Why will we never support 'calling rules' with multiple tag options ?
Then conditional operators among tags will be a major requirement and tags are essentially rule groups.
Changing Rule Engine execution from sync to async :
While sync offered a lot more performance benefit, ease of usage and code simplicity, it lacked a majority extensibility, i.e. executing custom functions in code flows. Conditions, while sync, are forcefully made async to keep the options open, and to keep performance realistic.
FAQs
Rule engine for most of generic decision makings
The npm package @gradeup/youknowwho receives a total of 3 weekly downloads. As such, @gradeup/youknowwho popularity was classified as not popular.
We found that @gradeup/youknowwho demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 6 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Socket's package search now displays weekly downloads for npm packages, helping developers quickly assess popularity and make more informed decisions.
Security News
A Stanford study reveals 9.5% of engineers contribute almost nothing, costing tech $90B annually, with remote work fueling the rise of "ghost engineers."
Research
Security News
Socket’s threat research team has detected six malicious npm packages typosquatting popular libraries to insert SSH backdoors.