@unrdf/hooks 26.4.2 → 26.4.4
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/LICENSE +24 -0
- package/README.md +562 -53
- package/examples/atomvm-fibo-hooks-demo.mjs +323 -0
- package/examples/delta-monitoring-example.mjs +213 -0
- package/examples/fibo-jtbd-governance.mjs +388 -0
- package/examples/hook-chains/node_modules/.bin/jiti +21 -0
- package/examples/hook-chains/node_modules/.bin/msw +21 -0
- package/examples/hook-chains/node_modules/.bin/terser +21 -0
- package/examples/hook-chains/node_modules/.bin/tsc +21 -0
- package/examples/hook-chains/node_modules/.bin/tsserver +21 -0
- package/examples/hook-chains/node_modules/.bin/tsx +21 -0
- package/examples/hook-chains/node_modules/.bin/vite +21 -0
- package/examples/hook-chains/node_modules/.bin/vitest +2 -2
- package/examples/hook-chains/node_modules/.bin/yaml +21 -0
- package/examples/hook-chains/package.json +2 -2
- package/examples/hook-chains/unrdf-hooks-example-chains-5.0.0.tgz +0 -0
- package/examples/hooks-marketplace.mjs +261 -0
- package/examples/n3-reasoning-example.mjs +279 -0
- package/examples/policy-hooks/node_modules/.bin/jiti +21 -0
- package/examples/policy-hooks/node_modules/.bin/msw +21 -0
- package/examples/policy-hooks/node_modules/.bin/terser +21 -0
- package/examples/policy-hooks/node_modules/.bin/tsc +21 -0
- package/examples/policy-hooks/node_modules/.bin/tsserver +21 -0
- package/examples/policy-hooks/node_modules/.bin/tsx +21 -0
- package/examples/policy-hooks/node_modules/.bin/vite +21 -0
- package/examples/policy-hooks/node_modules/.bin/vitest +2 -2
- package/examples/policy-hooks/node_modules/.bin/yaml +21 -0
- package/examples/policy-hooks/package.json +2 -2
- package/examples/policy-hooks/unrdf-hooks-example-policy-5.0.0.tgz +0 -0
- package/examples/shacl-repair-example.mjs +191 -0
- package/examples/window-condition-example.mjs +285 -0
- package/package.json +6 -3
- package/src/atomvm.mjs +9 -0
- package/src/define.mjs +114 -0
- package/src/executor.mjs +23 -0
- package/src/hooks/atomvm-bridge.mjs +332 -0
- package/src/hooks/builtin-hooks.mjs +13 -7
- package/src/hooks/condition-evaluator.mjs +684 -77
- package/src/hooks/define-hook.mjs +23 -21
- package/src/hooks/effect-executor.mjs +630 -0
- package/src/hooks/effect-sandbox.mjs +19 -9
- package/src/hooks/file-resolver.mjs +155 -1
- package/src/hooks/hook-chain-compiler.mjs +11 -1
- package/src/hooks/hook-executor.mjs +98 -73
- package/src/hooks/knowledge-hook-engine.mjs +133 -7
- package/src/hooks/ontology-learner.mjs +190 -0
- package/src/hooks/policy-pack.mjs +7 -1
- package/src/hooks/query-optimizer.mjs +1 -5
- package/src/hooks/query.mjs +3 -3
- package/src/hooks/schemas.mjs +55 -5
- package/src/hooks/security/error-sanitizer.mjs +46 -24
- package/src/hooks/self-play-autonomics.mjs +423 -0
- package/src/hooks/telemetry.mjs +32 -9
- package/src/hooks/validate.mjs +100 -33
- package/src/index.mjs +2 -0
- package/src/lib/admit-hook.mjs +615 -0
- package/src/policy-compiler.mjs +23 -13
- package/dist/index.d.mts +0 -1738
- package/dist/index.d.ts +0 -1738
- package/dist/index.mjs +0 -1738
package/LICENSE
CHANGED
|
@@ -19,3 +19,27 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
19
19
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
20
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
21
|
SOFTWARE.
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## Third-Party Licenses
|
|
26
|
+
|
|
27
|
+
This package includes or depends on the following third-party components:
|
|
28
|
+
|
|
29
|
+
### eyereasoner (eye-js)
|
|
30
|
+
- **License**: MIT
|
|
31
|
+
- **Copyright**: Copyright (c) 2022 Jesse Wright
|
|
32
|
+
- **Repository**: https://github.com/eyereasoner/eye-js
|
|
33
|
+
- **Description**: EYE reasoner for browser and Node.js via WebAssembly
|
|
34
|
+
|
|
35
|
+
### swipl-wasm (SWI-Prolog WebAssembly)
|
|
36
|
+
- **License**: BSD-2-Clause (Simplified BSD)
|
|
37
|
+
- **Copyright**: Copyright (c) SWI-Prolog contributors
|
|
38
|
+
- **Repository**: https://github.com/nickmcdowall/swipl-wasm
|
|
39
|
+
- **Description**: SWI-Prolog compiled to WebAssembly, bundled by eyereasoner
|
|
40
|
+
|
|
41
|
+
### @noble/hashes
|
|
42
|
+
- **License**: MIT
|
|
43
|
+
- **Copyright**: Copyright (c) 2022 Paul Miller
|
|
44
|
+
- **Repository**: https://github.com/paulmillr/noble-hashes
|
|
45
|
+
- **Description**: Cryptographic hash functions (BLAKE3) for receipt hashing
|
package/README.md
CHANGED
|
@@ -1,86 +1,595 @@
|
|
|
1
|
-
# @unrdf/hooks
|
|
1
|
+
# @unrdf/hooks - Knowledge Hook Engine
|
|
2
2
|
|
|
3
|
-
 
|
|
4
4
|
|
|
5
|
+
> Production-grade policy definition and execution framework for RDF knowledge graphs
|
|
6
|
+
>
|
|
7
|
+
> Implements 9 condition kinds, deterministic receipt chaining, SPARQL transformations, SHACL enforcement, N3 forward-chaining inference, and Datalog logic programming
|
|
5
8
|
|
|
6
|
-
|
|
9
|
+
## Overview
|
|
7
10
|
|
|
8
|
-
The
|
|
11
|
+
The hooks package provides a complete governance layer for RDF operations with 6 core priorities:
|
|
9
12
|
|
|
10
|
-
|
|
13
|
+
1. **withReceipt Integration** - BLAKE3 cryptographic audit trails with receipt chaining
|
|
14
|
+
2. **SPARQL CONSTRUCT Effects** - RDF-native transformations (SPARQL-native, no JavaScript)
|
|
15
|
+
3. **SHACL Enforcement Modes** - Three modes (block/annotate/repair) for soft-fail governance
|
|
16
|
+
4. **Input/Output Hash Receipts** - State change proof via canonical hashing with delta tracking
|
|
17
|
+
5. **N3 Forward-Chaining Rules** - Inference engine via EYE reasoner with explicit rule definitions
|
|
18
|
+
6. **Datalog Logic Programming** - Constraint evaluation via bottom-up fixpoint with goal satisfaction
|
|
19
|
+
|
|
20
|
+
## Quick Start
|
|
21
|
+
|
|
22
|
+
### Installation
|
|
11
23
|
|
|
12
24
|
```bash
|
|
13
|
-
pnpm add @unrdf/hooks
|
|
25
|
+
pnpm add @unrdf/hooks @unrdf/v6-core @unrdf/oxigraph
|
|
14
26
|
```
|
|
15
27
|
|
|
16
|
-
|
|
28
|
+
### Basic Hook Definition
|
|
17
29
|
|
|
18
|
-
|
|
30
|
+
```javascript
|
|
31
|
+
import { KnowledgeHookEngine, createKnowledgeHook } from '@unrdf/hooks';
|
|
32
|
+
import { createStore } from '@unrdf/oxigraph';
|
|
33
|
+
import { createContext } from '@unrdf/v6-core/receipt-pattern';
|
|
19
34
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
35
|
+
const store = createStore();
|
|
36
|
+
const engine = new KnowledgeHookEngine(store);
|
|
37
|
+
const context = createContext({
|
|
38
|
+
nodeId: 'my-app',
|
|
39
|
+
t_ns: BigInt(Date.now() * 1000000)
|
|
40
|
+
});
|
|
25
41
|
|
|
26
|
-
|
|
42
|
+
// Define a hook with SHACL condition (soft-fail annotation)
|
|
43
|
+
const hook = createKnowledgeHook({
|
|
44
|
+
name: 'validate-compliance',
|
|
45
|
+
condition: {
|
|
46
|
+
kind: 'shacl',
|
|
47
|
+
ref: { uri: 'file:///shapes/compliance.ttl' },
|
|
48
|
+
enforcementMode: 'annotate' // Log violations but don't block
|
|
49
|
+
},
|
|
50
|
+
effects: [{
|
|
51
|
+
kind: 'sparql-construct',
|
|
52
|
+
query: `
|
|
53
|
+
CONSTRUCT {
|
|
54
|
+
?s ex:status ex:Valid ;
|
|
55
|
+
ex:validatedAt ?now .
|
|
56
|
+
}
|
|
57
|
+
WHERE {
|
|
58
|
+
?s ?p ?o .
|
|
59
|
+
BIND (NOW() as ?now)
|
|
60
|
+
}
|
|
61
|
+
`
|
|
62
|
+
}]
|
|
63
|
+
});
|
|
27
64
|
|
|
28
|
-
|
|
65
|
+
// Execute with receipt chaining
|
|
66
|
+
const result = await engine.execute(context, [hook]);
|
|
67
|
+
|
|
68
|
+
// Access deterministic receipt chain
|
|
69
|
+
console.log('Receipt Hash:', result.receipt.receiptHash); // BLAKE3(entire receipt)
|
|
70
|
+
console.log('Input Hash:', result.receipt.input_hash); // BLAKE3(store before)
|
|
71
|
+
console.log('Output Hash:', result.receipt.output_hash); // BLAKE3(store after)
|
|
72
|
+
console.log('Previous Hash:', result.receipt.previousReceiptHash); // Links to prior op
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## 9 Condition Kinds
|
|
76
|
+
|
|
77
|
+
### 1. SPARQL ASK (Boolean Query)
|
|
78
|
+
|
|
79
|
+
Returns true if SPARQL ASK query matches any bindings.
|
|
80
|
+
|
|
81
|
+
```javascript
|
|
82
|
+
{
|
|
83
|
+
kind: 'sparql-ask',
|
|
84
|
+
query: 'ASK { ?s ?p ?o }'
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
**Use Case**: Quick boolean checks without result binding.
|
|
89
|
+
|
|
90
|
+
### 2. SPARQL SELECT (Result Set)
|
|
91
|
+
|
|
92
|
+
Returns true if SELECT query has results.
|
|
93
|
+
|
|
94
|
+
```javascript
|
|
95
|
+
{
|
|
96
|
+
kind: 'sparql-select',
|
|
97
|
+
query: 'SELECT ?s WHERE { ?s a ex:Person }'
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
**Use Case**: Condition depends on having matching results.
|
|
102
|
+
|
|
103
|
+
### 3. SHACL Validation (RDF Shape)
|
|
104
|
+
|
|
105
|
+
Validates store against SHACL shape. Three enforcement modes for soft-fail governance.
|
|
106
|
+
|
|
107
|
+
```javascript
|
|
108
|
+
{
|
|
109
|
+
kind: 'shacl',
|
|
110
|
+
ref: { uri: 'file:///shapes/person.ttl' },
|
|
111
|
+
enforcementMode: 'block', // or 'annotate', 'repair'
|
|
112
|
+
repairConstruct: 'CONSTRUCT { ?s ex:status ex:Repaired } WHERE { ... }'
|
|
113
|
+
}
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
**Enforcement Modes**:
|
|
117
|
+
- `block`: Fail if violations exist (strict governance)
|
|
118
|
+
- `annotate`: Execute but add violations as RDF triples (soft-fail + audit trail)
|
|
119
|
+
- `repair`: Auto-fix via SPARQL CONSTRUCT then re-validate (self-healing)
|
|
120
|
+
|
|
121
|
+
### 4. Delta (Change Detection)
|
|
122
|
+
|
|
123
|
+
Detects RDF changes (add/delete patterns) for reactive governance.
|
|
124
|
+
|
|
125
|
+
```javascript
|
|
126
|
+
{
|
|
127
|
+
kind: 'delta',
|
|
128
|
+
adds: [{ subject: '?s', predicate: 'rdf:type', object: 'ex:Trade' }],
|
|
129
|
+
deletes: []
|
|
130
|
+
}
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
**Use Case**: Trigger hooks only on specific RDF changes.
|
|
134
|
+
|
|
135
|
+
### 5. Threshold (Numeric Comparison)
|
|
136
|
+
|
|
137
|
+
Compares numeric values against threshold for quantitative governance.
|
|
138
|
+
|
|
139
|
+
```javascript
|
|
140
|
+
{
|
|
141
|
+
kind: 'threshold',
|
|
142
|
+
query: 'SELECT (COUNT(?s) as ?count) WHERE { ?s a ex:Trade }',
|
|
143
|
+
operator: 'greaterThan',
|
|
144
|
+
value: 100
|
|
145
|
+
}
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
**Operators**: `greaterThan`, `lessThan`, `equal`, `greaterThanOrEqual`, `lessThanOrEqual`
|
|
149
|
+
|
|
150
|
+
### 6. Count (Pattern Aggregation)
|
|
151
|
+
|
|
152
|
+
Counts matching patterns against expected value.
|
|
153
|
+
|
|
154
|
+
```javascript
|
|
155
|
+
{
|
|
156
|
+
kind: 'count',
|
|
157
|
+
pattern: { subject: '?s', predicate: 'ex:status', object: 'ex:Active' },
|
|
158
|
+
expected: 5
|
|
159
|
+
}
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
**Use Case**: Enforce cardinality constraints.
|
|
163
|
+
|
|
164
|
+
### 7. Window (Time Range Evaluation)
|
|
165
|
+
|
|
166
|
+
Evaluates conditions within time windows for temporal governance.
|
|
167
|
+
|
|
168
|
+
```javascript
|
|
169
|
+
{
|
|
170
|
+
kind: 'window',
|
|
171
|
+
windowMs: 60000,
|
|
172
|
+
maxMatches: 10,
|
|
173
|
+
query: 'SELECT ?timestamp WHERE { ?s ex:timestamp ?timestamp }'
|
|
174
|
+
}
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
**Use Case**: Rate limiting, temporal constraints.
|
|
178
|
+
|
|
179
|
+
### 8. N3 Forward-Chaining Inference ⭐
|
|
180
|
+
|
|
181
|
+
Evaluates N3 rules via EYE reasoner for declarative inference.
|
|
182
|
+
|
|
183
|
+
```javascript
|
|
184
|
+
{
|
|
185
|
+
kind: 'n3',
|
|
186
|
+
rules: `
|
|
187
|
+
{ ?x a :RestrictedClass } => { ?x :requiresApproval true } .
|
|
188
|
+
{ ?x :riskScore ?score . ?score > 50 } => { ?x :requiresReview true } .
|
|
189
|
+
`,
|
|
190
|
+
askQuery: 'ASK { ?s :requiresApproval true }'
|
|
191
|
+
}
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
**Use Case**: Declarative rule application without imperative code.
|
|
195
|
+
|
|
196
|
+
### 9. Datalog Logic Programming ⭐
|
|
197
|
+
|
|
198
|
+
Evaluates Datalog goals via bottom-up fixpoint for constraint solving.
|
|
199
|
+
|
|
200
|
+
```javascript
|
|
201
|
+
{
|
|
202
|
+
kind: 'datalog',
|
|
203
|
+
facts: [
|
|
204
|
+
'user(alice)',
|
|
205
|
+
'admin(alice)',
|
|
206
|
+
'group(admins)',
|
|
207
|
+
'member(alice, admins)'
|
|
208
|
+
],
|
|
209
|
+
rules: [
|
|
210
|
+
'allowed(X) :- admin(X)',
|
|
211
|
+
'allowed(X) :- member(X, admins)'
|
|
212
|
+
],
|
|
213
|
+
goal: 'allowed(alice)'
|
|
214
|
+
}
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
**Use Case**: Access control, permission evaluation via logical rules.
|
|
218
|
+
|
|
219
|
+
## Effects (Transformations)
|
|
220
|
+
|
|
221
|
+
### SPARQL CONSTRUCT (RDF-Native)
|
|
222
|
+
|
|
223
|
+
RDF-native transformation via SPARQL. No JavaScript required.
|
|
224
|
+
|
|
225
|
+
```javascript
|
|
226
|
+
{
|
|
227
|
+
kind: 'sparql-construct',
|
|
228
|
+
query: `
|
|
229
|
+
CONSTRUCT {
|
|
230
|
+
?s ex:processed true ;
|
|
231
|
+
ex:processedAt ?now ;
|
|
232
|
+
ex:delta ?deltaSize .
|
|
233
|
+
}
|
|
234
|
+
WHERE {
|
|
235
|
+
?s ?p ?o .
|
|
236
|
+
BIND (NOW() as ?now)
|
|
237
|
+
BIND (1 as ?deltaSize)
|
|
238
|
+
}
|
|
239
|
+
`
|
|
240
|
+
}
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
**Advantage**: Pure RDF transformation, deterministic, no execution risk.
|
|
244
|
+
|
|
245
|
+
### JavaScript Function (Legacy)
|
|
246
|
+
|
|
247
|
+
Execute custom logic. Included for backwards compatibility.
|
|
248
|
+
|
|
249
|
+
```javascript
|
|
250
|
+
{
|
|
251
|
+
kind: 'function',
|
|
252
|
+
inline: async (store, quad) => {
|
|
253
|
+
// Custom transformation
|
|
254
|
+
return { success: true };
|
|
255
|
+
},
|
|
256
|
+
timeout: 30000,
|
|
257
|
+
sandbox: false
|
|
258
|
+
}
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
## SHACL Enforcement Modes (Priority 3)
|
|
262
|
+
|
|
263
|
+
### Block Mode (Default)
|
|
264
|
+
|
|
265
|
+
Prevents hook execution if SHACL validation fails. Strict governance.
|
|
29
266
|
|
|
30
267
|
```javascript
|
|
31
|
-
|
|
268
|
+
{
|
|
269
|
+
kind: 'shacl',
|
|
270
|
+
ref: { uri: 'file:///shapes/strict.ttl' },
|
|
271
|
+
enforcementMode: 'block'
|
|
272
|
+
}
|
|
273
|
+
// Hook blocked if shape violations exist
|
|
274
|
+
// Result: Clean state or error
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
**Use Case**: Regulatory compliance, immutable audit trails.
|
|
278
|
+
|
|
279
|
+
### Annotate Mode (Soft-Fail)
|
|
280
|
+
|
|
281
|
+
Executes hook but adds SHACL violations as RDF triples. Audit trail with soft-fail.
|
|
282
|
+
|
|
283
|
+
```javascript
|
|
284
|
+
{
|
|
285
|
+
kind: 'shacl',
|
|
286
|
+
ref: { uri: 'file:///shapes/audit.ttl' },
|
|
287
|
+
enforcementMode: 'annotate'
|
|
288
|
+
}
|
|
289
|
+
// Violations materialized as RDF quads
|
|
290
|
+
// Result: Store updated + violations tracked in store
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
**Use Case**: Logging, risk management, warning systems.
|
|
294
|
+
|
|
295
|
+
### Repair Mode (Self-Healing)
|
|
296
|
+
|
|
297
|
+
Auto-repairs violations via SPARQL CONSTRUCT, then re-validates.
|
|
32
298
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
299
|
+
```javascript
|
|
300
|
+
{
|
|
301
|
+
kind: 'shacl',
|
|
302
|
+
ref: { uri: 'file:///shapes/auto-fix.ttl' },
|
|
303
|
+
enforcementMode: 'repair',
|
|
304
|
+
repairConstruct: `
|
|
305
|
+
CONSTRUCT {
|
|
306
|
+
?violation ex:repaired true .
|
|
307
|
+
?entity ex:status ex:Repaired .
|
|
308
|
+
}
|
|
309
|
+
WHERE {
|
|
310
|
+
?violation a sh:ValidationResult .
|
|
311
|
+
?violation sh:focusNode ?entity
|
|
40
312
|
}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
313
|
+
`
|
|
314
|
+
}
|
|
315
|
+
// Auto-fix violations, then re-validate
|
|
316
|
+
// Result: Clean state via automatic correction
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
**Use Case**: Data quality, auto-remediation, self-healing systems.
|
|
320
|
+
|
|
321
|
+
## Receipt Chaining (Priority 1 & 4)
|
|
322
|
+
|
|
323
|
+
Every hook execution produces a deterministic receipt with cryptographic proof:
|
|
324
|
+
|
|
325
|
+
```javascript
|
|
326
|
+
{
|
|
327
|
+
receiptHash: 'a3f7...', // BLAKE3(entire receipt)
|
|
328
|
+
payloadHash: 'b9e2...', // BLAKE3(payload/hook definitions)
|
|
329
|
+
input_hash: 'c4d1...', // BLAKE3(store state before)
|
|
330
|
+
output_hash: 'e7f3...', // BLAKE3(store state after)
|
|
331
|
+
previousReceiptHash: '8f2a...', // Links to prior operation
|
|
332
|
+
timestamp: 1234567890000,
|
|
333
|
+
nodeId: 'my-app',
|
|
334
|
+
delta: {
|
|
335
|
+
adds: [{ subject, predicate, object }],
|
|
336
|
+
deletes: [{ subject, predicate, object }]
|
|
337
|
+
},
|
|
338
|
+
hooksExecuted: 3,
|
|
339
|
+
successful: 2,
|
|
340
|
+
failed: 0
|
|
341
|
+
}
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
**Verify Chain Integrity**:
|
|
44
345
|
|
|
45
|
-
|
|
46
|
-
const
|
|
346
|
+
```javascript
|
|
347
|
+
const receipt1 = await engine.execute(ctx1, hooks1);
|
|
348
|
+
const receipt2 = await engine.execute(
|
|
349
|
+
createContext({
|
|
350
|
+
...ctx2,
|
|
351
|
+
previousReceiptHash: receipt1.receipt.receiptHash
|
|
352
|
+
}),
|
|
353
|
+
hooks2
|
|
354
|
+
);
|
|
355
|
+
|
|
356
|
+
// receipt2.receipt.previousReceiptHash === receipt1.receipt.receiptHash ✅
|
|
357
|
+
// Proves immutable chain of operations
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
## CLI Integration
|
|
361
|
+
|
|
362
|
+
All 6 priorities exposed via `@unrdf/cli`:
|
|
363
|
+
|
|
364
|
+
```bash
|
|
365
|
+
# List all condition kinds and effects
|
|
366
|
+
unrdf hooks list-conditions
|
|
367
|
+
|
|
368
|
+
# Execute hooks with receipt chain
|
|
369
|
+
unrdf hooks execute \
|
|
370
|
+
--store data.nq \
|
|
371
|
+
--config hooks.json \
|
|
372
|
+
--show-receipts \
|
|
373
|
+
--output results.json
|
|
374
|
+
|
|
375
|
+
# Validate hook configuration
|
|
376
|
+
unrdf hooks define --config hooks.json --validate
|
|
377
|
+
|
|
378
|
+
# Test single condition
|
|
379
|
+
unrdf hooks evaluate-condition \
|
|
380
|
+
--store data.nq \
|
|
381
|
+
--condition shacl \
|
|
382
|
+
--config '{"ref": {"uri": "file:///shapes/test.ttl"}, "enforcementMode": "block"}'
|
|
383
|
+
|
|
384
|
+
# Display receipt chain verification
|
|
385
|
+
unrdf hooks receipts --file results.json --verify
|
|
386
|
+
|
|
387
|
+
# Generate hooks from policy template
|
|
388
|
+
unrdf hooks template --type fibo --output hooks.json
|
|
47
389
|
```
|
|
48
390
|
|
|
49
|
-
##
|
|
391
|
+
## FIBO Case Study
|
|
392
|
+
|
|
393
|
+
Financial regulatory compliance using all 6 priorities.
|
|
394
|
+
|
|
395
|
+
See: `examples/fibo-jtbd-governance.mjs`
|
|
396
|
+
|
|
397
|
+
**5 Jobs-to-Be-Done**:
|
|
398
|
+
|
|
399
|
+
1. **Verify Regulatory Compliance** - SHACL validation + SPARQL construction
|
|
400
|
+
2. **Assess Counterparty Risk** - N3 forward-chaining inference
|
|
401
|
+
3. **Manage Liquidity Positions** - Datalog logic programming
|
|
402
|
+
4. **Maintain Audit Trail** - Receipt chaining with BLAKE3
|
|
403
|
+
5. **Auto-Repair Violations** - SHACL repair mode with CONSTRUCT
|
|
404
|
+
|
|
405
|
+
Run example:
|
|
406
|
+
|
|
407
|
+
```bash
|
|
408
|
+
node examples/fibo-jtbd-governance.mjs
|
|
409
|
+
```
|
|
50
410
|
|
|
51
|
-
|
|
52
|
-
- ✅ Pre-write validation (block invalid data)
|
|
53
|
-
- ✅ Post-write transformation (modify data)
|
|
54
|
-
- ✅ Hook composition (chain multiple hooks)
|
|
55
|
-
- ✅ Type-safe hook definitions
|
|
56
|
-
- ✅ Async/await support
|
|
411
|
+
## AtomVM Integration
|
|
57
412
|
|
|
58
|
-
|
|
413
|
+
Execute hooks from Erlang/BEAM processes via bridge.
|
|
59
414
|
|
|
60
|
-
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
415
|
+
See: `examples/atomvm-fibo-hooks-demo.mjs`
|
|
416
|
+
|
|
417
|
+
```javascript
|
|
418
|
+
import { HooksBridge } from '@unrdf/hooks/atomvm';
|
|
419
|
+
|
|
420
|
+
const bridge = new HooksBridge(store);
|
|
421
|
+
|
|
422
|
+
// From Erlang: register hook
|
|
423
|
+
const hookId = await bridge.registerHook({
|
|
424
|
+
name: 'erlang-compliance',
|
|
425
|
+
condition: { kind: 'shacl', ref: { uri: '...' } },
|
|
426
|
+
effects: [{ kind: 'sparql-construct', query: '...' }]
|
|
427
|
+
});
|
|
428
|
+
|
|
429
|
+
// From Erlang: evaluate condition
|
|
430
|
+
const result = await bridge.evaluateCondition({
|
|
431
|
+
kind: 'datalog',
|
|
432
|
+
facts: ['user(alice)'],
|
|
433
|
+
rules: ['allowed(X) :- user(X)'],
|
|
434
|
+
goal: 'allowed(alice)'
|
|
435
|
+
});
|
|
436
|
+
|
|
437
|
+
// Full workflow with receipt
|
|
438
|
+
const receipt = await bridge.executeHooks(context, [hook]);
|
|
439
|
+
```
|
|
440
|
+
|
|
441
|
+
## Performance Characteristics
|
|
442
|
+
|
|
443
|
+
| Operation | Latency | Notes |
|
|
444
|
+
|-----------|---------|-------|
|
|
445
|
+
| Receipt Creation | <1ms | BLAKE3 hashing |
|
|
446
|
+
| SPARQL ASK | 1-5ms | Depends on query complexity |
|
|
447
|
+
| SPARQL SELECT | 2-8ms | Result binding overhead |
|
|
448
|
+
| SHACL Validation | 5-15ms | Shape size dependent |
|
|
449
|
+
| N3 Inference | 10-100ms | Rule complexity & triple count |
|
|
450
|
+
| Datalog Goal | 1-30ms | Fixpoint iterations |
|
|
451
|
+
| Full Hook Execution | <150ms | All conditions + effects + receipt |
|
|
452
|
+
|
|
453
|
+
## Architecture
|
|
454
|
+
|
|
455
|
+
```
|
|
456
|
+
┌─────────────────────────────────────────────────────────┐
|
|
457
|
+
│ User Application / CLI (@unrdf/cli) │
|
|
458
|
+
└─────────────────────────────────────────────────────────┘
|
|
459
|
+
↓
|
|
460
|
+
┌─────────────────────────────────────────────────────────┐
|
|
461
|
+
│ KnowledgeHookEngine │
|
|
462
|
+
│ ├─ Register hooks (6 priorities) │
|
|
463
|
+
│ ├─ Evaluate 9 condition kinds │
|
|
464
|
+
│ ├─ Execute effects (SPARQL/Function) │
|
|
465
|
+
│ ├─ SHACL enforcement (block/annotate/repair) │
|
|
466
|
+
│ ├─ Track receipts (BLAKE3 chaining) │
|
|
467
|
+
│ └─ Manage deltas (adds/deletes) │
|
|
468
|
+
└─────────────────────────────────────────────────────────┘
|
|
469
|
+
↓ ↓ ↓
|
|
470
|
+
┌─────────┐ ┌───────────┐ ┌──────────────┐
|
|
471
|
+
│ SPARQL │ │ SHACL │ │ Condition │
|
|
472
|
+
│ Engine │ │ Validator │ │ Evaluator │
|
|
473
|
+
│(ASK/SEL)│ │ (3 modes) │ │(N3/Datalog) │
|
|
474
|
+
└─────────┘ └───────────┘ └──────────────┘
|
|
475
|
+
↓ ↓ ↓
|
|
476
|
+
└────────────────────┬────────────────────┘
|
|
477
|
+
↓
|
|
478
|
+
┌──────────────────────┐
|
|
479
|
+
│ @unrdf/oxigraph │
|
|
480
|
+
│ (RDF Store + SPARQL) │
|
|
481
|
+
└──────────────────────┘
|
|
482
|
+
↓
|
|
483
|
+
┌──────────────────────┐
|
|
484
|
+
│ v6-core Receipt │
|
|
485
|
+
│ (BLAKE3 Hashing + │
|
|
486
|
+
│ Deterministic Chain)│
|
|
487
|
+
└──────────────────────┘
|
|
488
|
+
```
|
|
65
489
|
|
|
66
490
|
## Documentation
|
|
67
491
|
|
|
68
|
-
- **[
|
|
69
|
-
- **[
|
|
70
|
-
- **[
|
|
71
|
-
- **[
|
|
492
|
+
- **[EXAMPLES.md](./EXAMPLES.md)** - All 9 condition kinds + effects + FIBO + AtomVM
|
|
493
|
+
- **[API-REFERENCE.md](./API-REFERENCE.md)** - Complete Zod schemas and API
|
|
494
|
+
- **[ARCHITECTURE.md](./ARCHITECTURE.md)** - Design decisions and data flows
|
|
495
|
+
- **[DEPLOYMENT.md](./DEPLOYMENT.md)** - Production checklist and monitoring
|
|
496
|
+
|
|
497
|
+
## Source Examples
|
|
498
|
+
|
|
499
|
+
Learn by example following the 80/20 principle:
|
|
72
500
|
|
|
73
|
-
|
|
501
|
+
- **[basic.mjs](./examples/basic.mjs)** - Minimal hook definition and execution (5 min)
|
|
502
|
+
- **[knowledge-hook-manager-usage.mjs](./examples/knowledge-hook-manager-usage.mjs)** - Manager API (10 min)
|
|
503
|
+
- **[validate-hooks.mjs](./examples/validate-hooks.mjs)** - Hook validation and debugging (15 min)
|
|
74
504
|
|
|
75
|
-
|
|
505
|
+
## Testing
|
|
76
506
|
|
|
77
|
-
|
|
507
|
+
```bash
|
|
508
|
+
# Full test suite
|
|
509
|
+
pnpm test
|
|
510
|
+
|
|
511
|
+
# Hooks-specific tests
|
|
512
|
+
pnpm test hooks.test.mjs
|
|
513
|
+
|
|
514
|
+
# Watch mode
|
|
515
|
+
pnpm test:watch
|
|
78
516
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
517
|
+
# Coverage
|
|
518
|
+
pnpm test --coverage
|
|
519
|
+
|
|
520
|
+
# Benchmarks
|
|
521
|
+
pnpm benchmark
|
|
522
|
+
```
|
|
523
|
+
|
|
524
|
+
## API Quick Reference
|
|
525
|
+
|
|
526
|
+
### KnowledgeHookEngine
|
|
527
|
+
|
|
528
|
+
```javascript
|
|
529
|
+
class KnowledgeHookEngine {
|
|
530
|
+
// Register a hook with 6 priorities
|
|
531
|
+
registerHook(hook: KnowledgeHook): string;
|
|
532
|
+
|
|
533
|
+
// Evaluate any of 9 condition kinds
|
|
534
|
+
async evaluateCondition(
|
|
535
|
+
condition: Condition
|
|
536
|
+
): Promise<boolean>;
|
|
537
|
+
|
|
538
|
+
// Execute hooks with receipt chaining
|
|
539
|
+
async execute(
|
|
540
|
+
context: ExecutionContext,
|
|
541
|
+
hooks: KnowledgeHook[]
|
|
542
|
+
): Promise<ExecutionResult>;
|
|
543
|
+
|
|
544
|
+
// Get receipt chain (BLAKE3 linked)
|
|
545
|
+
getReceiptChain(): Receipt[];
|
|
546
|
+
}
|
|
547
|
+
```
|
|
548
|
+
|
|
549
|
+
### Hook Definition (Zod)
|
|
550
|
+
|
|
551
|
+
```javascript
|
|
552
|
+
const KnowledgeHook = {
|
|
553
|
+
name: string; // Hook identifier
|
|
554
|
+
condition: Condition; // 9 kinds
|
|
555
|
+
effects: Effect[]; // Transformations
|
|
556
|
+
metadata?: Record<string, any>;
|
|
557
|
+
}
|
|
558
|
+
```
|
|
559
|
+
|
|
560
|
+
See [API-REFERENCE.md](./API-REFERENCE.md) for complete schema.
|
|
561
|
+
|
|
562
|
+
## Contributing
|
|
563
|
+
|
|
564
|
+
See [CONTRIBUTING.md](./docs/CONTRIBUTING.md) for development guidelines.
|
|
565
|
+
|
|
566
|
+
All code follows:
|
|
567
|
+
- 100% ESM (.mjs)
|
|
568
|
+
- JSDoc documentation
|
|
569
|
+
- Zod validation
|
|
570
|
+
- <500 lines per file
|
|
571
|
+
- 80%+ test coverage
|
|
572
|
+
|
|
573
|
+
## Key Files
|
|
574
|
+
|
|
575
|
+
- **src/hooks/knowledge-hook-engine.mjs** - Core executor (6 priorities)
|
|
576
|
+
- **src/hooks/condition-evaluator.mjs** - 9 condition kinds
|
|
577
|
+
- **src/hooks/validate.mjs** - SHACL validation (3 modes)
|
|
578
|
+
- **src/hooks/schemas.mjs** - Complete Zod schemas
|
|
579
|
+
- **test/comprehensive-hook-types.test.mjs** - Full test suite
|
|
83
580
|
|
|
84
581
|
## License
|
|
85
582
|
|
|
86
|
-
MIT
|
|
583
|
+
MIT — see [LICENSE](./LICENSE) for full text.
|
|
584
|
+
|
|
585
|
+
### Third-Party Dependencies
|
|
586
|
+
|
|
587
|
+
This package depends on the following notable third-party libraries:
|
|
588
|
+
|
|
589
|
+
| Dependency | License | Purpose |
|
|
590
|
+
|------------|---------|---------|
|
|
591
|
+
| [eyereasoner](https://github.com/eyereasoner/eye-js) | MIT | N3 forward-chaining inference via EYE reasoner (WebAssembly) |
|
|
592
|
+
| [swipl-wasm](https://github.com/nickmcdowall/swipl-wasm) | BSD-2-Clause | SWI-Prolog runtime bundled by eyereasoner |
|
|
593
|
+
| [@noble/hashes](https://github.com/paulmillr/noble-hashes) | MIT | BLAKE3 cryptographic hashing for receipt chains |
|
|
594
|
+
|
|
595
|
+
All dependencies use permissive open-source licenses compatible with MIT.
|