@juiceit/rule-engine
v2.0.20
Published
Reusable JuiceIT rules engine for dataActions evaluation
Maintainers
Readme
@juiceit/rule-engine
Reusable rules engine for evaluating dataActions rules against extracted
document data. It supports deterministic actions and optional LLM-backed actions
for cases where a provider needs to reason over one or more source fields.
Installation
npm install @juiceit/rule-engineCurrent package version: 2.0.10.
Technology Support
| Item | Support |
| --- | --- |
| Runtime | Node.js >=18 |
| Package Manager | npm >=9 |
| Module System | CommonJS (require) |
| Language | JavaScript (Node backend) |
| Platforms | Windows, Linux, macOS |
| Browser Runtime | Not intended for direct browser execution |
| CI Test Matrix | Node.js 18, 20, 22 |
What It Does
- Accepts extracted document data with either
Sectionsorsections. - Evaluates rules by ascending
order. - Supports section-relative paths such as
Header.InvoiceNumberandSections.*paths. - Supports full payload paths when the first segment is a top-level
rawDatakey, such asupload_parameters.ClaimId,inbound_request.steps.0.response,supportingDocuments.0.Custom.reviewed, or rootCustom.*. - Runs deterministic actions locally:
set-value,set-expression, andfind-replace. - Runs
mode: "llm"rules through the built-in Gemini executor or a customsystemVars.llmExecutor. - Returns both the full transformed payload and the normalized
rawData.DocumentType/rawData.Sectionsshape.
Quick Start
const { runRuleEngine } = require("@juiceit/rule-engine");
const rawData = {
DocumentType: "Invoice",
Sections: {
Header: {
InvoiceNumber: "INV-001",
VendorName: "Old Vendor"
}
}
};
const ruleSet = [
{
id: "replace-vendor",
enabled: true,
conditions: [
{
operator: "equals",
field: "Header.InvoiceNumber",
value: "INV-001"
}
],
thenActions: [
{
actionType: "set-value",
targetField: "Header.VendorName",
config: { value: "New Vendor" }
}
]
}
];
const result = await runRuleEngine(rawData, ruleSet);
console.log(result.rawData.Sections.Header.VendorName); // "New Vendor"Rule Modes
Rules default to deterministic execution:
{
id: "replace-vendor",
mode: "deterministic",
enabled: true,
order: 1,
conditions: [],
thenActions: []
}Use mode: "llm" when a rule should call the configured LLM provider as a
full rawData mutation step:
{
id: "same-person-llm",
mode: "llm",
enabled: true,
order: 1,
conditions: [],
llm: {
instruction: "Check if the CV and ID document belong to the same person and write the result to Sections.Custom.samePersonResult"
},
thenActions: null
}For LLM rules, thenActions must be null. The rule engine intentionally does
not use sourceFields, targetField, or collection metadata for built-in LLM
execution. It sends only the rule instruction and the complete current rawData
JSON to the LLM executor, expects a complete updated rawData JSON object back,
and passes that mutated document to the next rule.
API
await runRuleEngine(rawData, ruleSet, systemVars?)
Runs rules and returns transformed output.
Returns:
{
appliedData: { ... },
rawData: {
DocumentType: "...",
Sections: { ... }
}
}runRuleEngine() is asynchronous from version 2.0.0 because rules with
mode: "llm" can call an AI provider before writing the action result.
Deterministic rules still execute with the same rule semantics.
LLM Configuration
LLM execution uses Gemini by default with GOOGLE_API_KEY:
GOOGLE_API_KEY=your-google-api-key
JUICEIT_RULE_ENGINE_LLM_MODEL=gemini-2.5-flashConsuming services can also pass the values directly from secrets:
const result = await runRuleEngine(data, rules, {
GOOGLE_API_KEY: secrets?.GOOGLE_API_KEY,
JUICEIT_RULE_ENGINE_LLM_MODEL: secrets?.GEMINI_MODEL_NAME,
JUICEIT_RULE_ENGINE_LLM_TIMEOUT_MS: 120000,
JUICEIT_RULE_ENGINE_LLM_RETRIES: 1
});Options can also be nested under llm:
const result = await runRuleEngine(rawData, ruleSet, {
llm: {
model: "gemini-2.5-flash",
timeoutMs: 120000,
retries: 1
}
});The built-in Gemini executor defaults to a 120 second request timeout because full-rawData LLM rules can send and receive larger JSON payloads.
Set GOOGLE_API_KEY in the runtime environment.
The engine reads .env from the consuming service working directory, then
applies environment-specific overrides based on RUNTIME_ENV, NODE_ENV,
ENVIRONMENT, or STAGE:
- Production:
.env.production,.env.prod - QA:
.env.qa - Development:
.env.development,.env.dev
Supported environment variable names:
GOOGLE_API_KEYJUICEIT_RULE_ENGINE_LLM_MODELGEMINI_MODELJUICEIT_RULE_ENGINE_LLM_ENDPOINTGEMINI_ENDPOINTJUICEIT_RULE_ENGINE_LLM_TIMEOUT_MSJUICEIT_RULE_ENGINE_LLM_RETRIES
For tests or backend-owned provider logic, pass systemVars.llmExecutor.
const result = await runRuleEngine(rawData, ruleSet, {
llmExecutor: async ({ instruction, rawData, rule }) => {
const nextRawData = JSON.parse(JSON.stringify(rawData));
nextRawData.Sections.Custom.samePersonResult = "Match";
return {
rawData: nextRawData,
confidenceInterval: 96,
reason: "ID numbers match after removing spaces."
};
}
});The custom executor must return an object with rawData. Optional
confidenceInterval is normalized to 0-100, and reason is returned as text.
Additional Exports
previewExpressionKeys(rawData, systemVars?)RULE_ENGINE_VERSIONRULE_ENGINE_CHANGELOGSUPPORTED_CONDITION_OPERATORSSUPPORTED_ACTION_TYPESALLOWED_EXPRESSION_FUNCTIONSDISALLOWED_EXPRESSION_FUNCTIONSDOCUMENTED_FILTREX_FUNCTIONSSUPPORTED_FUNCTIONS_BY_GROUP
Documentation
Development
npm test
npm run package:check
npm run prepublishOnlynpm run package:check runs npm pack --dry-run so the published package
surface can be verified before publishing. The package files whitelist
currently publishes index.js and src.
Contributing
Please see CONTRIBUTING.md.
Security
Please see SECURITY.md.
License
MIT
