@edgerules/node 0.0.0-alpha.202607061032 → 0.0.0-alpha.202607061957
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md
ADDED
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
# @edgerules/node
|
|
2
|
+
|
|
3
|
+
[](https://sonarcloud.io/summary/new_code?id=rimvydasb_edgerules)
|
|
4
|
+
[](https://sonarcloud.io/summary/new_code?id=rimvydasb_edgerules)
|
|
5
|
+
[](https://sonarcloud.io/summary/new_code?id=rimvydasb_edgerules)
|
|
6
|
+
[](https://sonarcloud.io/summary/new_code?id=rimvydasb_edgerules)
|
|
7
|
+
[](https://sonarcloud.io/summary/new_code?id=rimvydasb_edgerules)
|
|
8
|
+
|
|
9
|
+
EdgeRules decision service for **Node.js**. Ships two builds:
|
|
10
|
+
|
|
11
|
+
| Export | Description |
|
|
12
|
+
|---|---|
|
|
13
|
+
| `@edgerules/node` | Production build — execution only (`DecisionService`) |
|
|
14
|
+
| `@edgerules/node/mutable` | Development build — execution + CRUD (`MutableDecisionService`) |
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## Installation
|
|
19
|
+
|
|
20
|
+
```sh
|
|
21
|
+
npm install @edgerules/node @edgerules/portable
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
> Requires Node.js 18 or later (ESM only).
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## Production Usage
|
|
29
|
+
|
|
30
|
+
### Load from an EdgeRules DSL string
|
|
31
|
+
|
|
32
|
+
```typescript
|
|
33
|
+
import { DecisionService } from '@edgerules/node';
|
|
34
|
+
|
|
35
|
+
const service = new DecisionService(`{
|
|
36
|
+
applicant: {
|
|
37
|
+
age: <number, required: true>
|
|
38
|
+
income: <number, default: 0>
|
|
39
|
+
}
|
|
40
|
+
isEligible: applicant.age >= 18 and applicant.income >= 1000
|
|
41
|
+
}`);
|
|
42
|
+
|
|
43
|
+
// Execute the whole model — inputs are bound via a model-shaped request object
|
|
44
|
+
const result = service.execute('*', { applicant: { age: 25, income: 2500 } });
|
|
45
|
+
// { applicant: { age: 25, income: 2500 }, isEligible: true }
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### Load from a Portable JSON model
|
|
49
|
+
|
|
50
|
+
```typescript
|
|
51
|
+
import { DecisionService } from '@edgerules/node';
|
|
52
|
+
import type { PortableRootContext } from '@edgerules/portable';
|
|
53
|
+
|
|
54
|
+
const model: PortableRootContext = {
|
|
55
|
+
'@version': '1.0',
|
|
56
|
+
'@model-name': 'Tax Calculator',
|
|
57
|
+
taxRate: 0.21,
|
|
58
|
+
calculateTax: {
|
|
59
|
+
'@kind': 'function',
|
|
60
|
+
'@parameters': { amount: 'number' },
|
|
61
|
+
'@body': {
|
|
62
|
+
'@kind': 'context',
|
|
63
|
+
result: 'amount * taxRate',
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
const service = new DecisionService(model);
|
|
69
|
+
|
|
70
|
+
// Execute a specific function — pass its arguments as request bindings
|
|
71
|
+
const tax = service.execute('calculateTax', { amount: 100 });
|
|
72
|
+
// { result: 21 }
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### Executing a ruleset
|
|
76
|
+
|
|
77
|
+
```typescript
|
|
78
|
+
const service = new DecisionService(`{
|
|
79
|
+
ruleset risk(age: number, income: number): {
|
|
80
|
+
hitPolicy: "first-match"
|
|
81
|
+
rules: [
|
|
82
|
+
{ when: { age: 18..25, income: < 30000 }, then: { level: "high", limit: 1000 } }
|
|
83
|
+
{ when: { age: 18..25, income: >= 30000 }, then: { level: "medium", limit: 5000 } }
|
|
84
|
+
{ when: { age: > 25 }, then: { level: "low", limit: 20000 } }
|
|
85
|
+
]
|
|
86
|
+
default: { level: "none", limit: 0 }
|
|
87
|
+
}
|
|
88
|
+
decision: risk(age: applicant.age, income: applicant.income)
|
|
89
|
+
}`);
|
|
90
|
+
|
|
91
|
+
const result = service.execute('decision', { applicant: { age: 23, income: 25000 } });
|
|
92
|
+
// { level: "high", limit: 1000 }
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### Error handling
|
|
96
|
+
|
|
97
|
+
Every execution or model error is a structured `PortableError` — never a plain string.
|
|
98
|
+
|
|
99
|
+
```typescript
|
|
100
|
+
import { DecisionService } from '@edgerules/node';
|
|
101
|
+
import type { PortableError } from '@edgerules/portable';
|
|
102
|
+
|
|
103
|
+
try {
|
|
104
|
+
service.execute('unknownField');
|
|
105
|
+
} catch (err) {
|
|
106
|
+
const error = err as PortableError;
|
|
107
|
+
console.error(error.type); // "EntryNotFound"
|
|
108
|
+
console.error(error.message); // human-readable, safe to surface
|
|
109
|
+
console.error(error.path); // "unknownField"
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
| `error.type` | Meaning |
|
|
114
|
+
|---|---|
|
|
115
|
+
| `EntryNotFound` | Path does not exist in the model |
|
|
116
|
+
| `WrongFieldPath` | Invalid path, out-of-bounds array index |
|
|
117
|
+
| `Parse` | Expression string failed to parse |
|
|
118
|
+
| `Linking` | Type mismatch or broken reference |
|
|
119
|
+
| `Execution` | Runtime error during evaluation |
|
|
120
|
+
|
|
121
|
+
---
|
|
122
|
+
|
|
123
|
+
## Mutable / Development Usage
|
|
124
|
+
|
|
125
|
+
Use the `./mutable` subpath import to access `MutableDecisionService`, which adds CRUD operations on top of execution.
|
|
126
|
+
This build is intended for IDEs, rule editors, and test tooling — **not** for production traffic.
|
|
127
|
+
|
|
128
|
+
```typescript
|
|
129
|
+
import { MutableDecisionService } from '@edgerules/node/mutable';
|
|
130
|
+
|
|
131
|
+
const service = new MutableDecisionService(`{
|
|
132
|
+
taxRate: 0.21
|
|
133
|
+
tax: amount * taxRate
|
|
134
|
+
}`);
|
|
135
|
+
|
|
136
|
+
// Read a node enriched with linked type information
|
|
137
|
+
const node = service.get('taxRate');
|
|
138
|
+
// { "@kind": "expression", "expression": 0.21, "type": "number", "readOnly": true }
|
|
139
|
+
|
|
140
|
+
// Update a field at runtime — the engine relinks lazily on the next execute
|
|
141
|
+
service.set('taxRate', 0.25);
|
|
142
|
+
|
|
143
|
+
// Read the entire model snapshot
|
|
144
|
+
const model = service.get('*');
|
|
145
|
+
|
|
146
|
+
// Add a new typed input
|
|
147
|
+
service.set('amount', { '@kind': 'type', type: 'number', required: true });
|
|
148
|
+
|
|
149
|
+
// Remove a field
|
|
150
|
+
service.remove('taxRate');
|
|
151
|
+
|
|
152
|
+
// Rename a field
|
|
153
|
+
service.rename('tax', 'vat');
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### `get` filters
|
|
157
|
+
|
|
158
|
+
```typescript
|
|
159
|
+
// Default FIELDS view — returns expressions, typed holes, and function schemas
|
|
160
|
+
service.get('isEligible');
|
|
161
|
+
|
|
162
|
+
// Full function definition (body included)
|
|
163
|
+
service.get('isEligible', 'FUNCTION_DEFINITIONS');
|
|
164
|
+
|
|
165
|
+
// Type definition
|
|
166
|
+
service.get('Customer', 'TYPE_DEFINITIONS');
|
|
167
|
+
|
|
168
|
+
// Everything at once
|
|
169
|
+
service.get('*', 'ALL');
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
---
|
|
173
|
+
|
|
174
|
+
## API Reference
|
|
175
|
+
|
|
176
|
+
### `DecisionService`
|
|
177
|
+
|
|
178
|
+
| Method | Description |
|
|
179
|
+
|---|---|
|
|
180
|
+
| `new DecisionService(model)` | Create from DSL string or `PortableRootContext` |
|
|
181
|
+
| `execute(method, args?)` | Evaluate `method` (field path, function, or `"*"`) against optional request bindings |
|
|
182
|
+
|
|
183
|
+
### `MutableDecisionService` (dev build)
|
|
184
|
+
|
|
185
|
+
Inherits `execute` and adds:
|
|
186
|
+
|
|
187
|
+
| Method | Description |
|
|
188
|
+
|---|---|
|
|
189
|
+
| `get(path, filter?)` | Read a node enriched with inferred types |
|
|
190
|
+
| `set(path, node)` | Write an expression, typed hole, function, type, or context |
|
|
191
|
+
| `remove(path)` | Delete an entry |
|
|
192
|
+
| `rename(oldPath, newPath)` | Rename an entry within its context |
|
|
193
|
+
|
|
194
|
+
---
|
|
195
|
+
|
|
196
|
+
## Related packages
|
|
197
|
+
|
|
198
|
+
- [`@edgerules/web`](https://www.npmjs.com/package/@edgerules/web) — same API for the browser
|
|
199
|
+
- [`@edgerules/portable`](https://www.npmjs.com/package/@edgerules/portable) — Portable JSON type definitions
|
|
Binary file
|
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@edgerules/node",
|
|
3
|
-
"version": "0.0.0-alpha.
|
|
3
|
+
"version": "0.0.0-alpha.202607061957",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "EdgeRules decision service for Node.js.",
|
|
6
6
|
"dependencies": {
|
|
7
|
-
"@edgerules/portable": "0.0.0-alpha.
|
|
7
|
+
"@edgerules/portable": "0.0.0-alpha.202607061957"
|
|
8
8
|
},
|
|
9
9
|
"devDependencies": {
|
|
10
10
|
"@edgerules/core": "*",
|