@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
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file Working example - Composable Hooks Marketplace
|
|
5
|
+
* @module examples/hooks-marketplace
|
|
6
|
+
* @description
|
|
7
|
+
* Demonstrates the Composable Hooks Marketplace with:
|
|
8
|
+
* 1. Hook normalization to RDF via SPARQL CONSTRUCT
|
|
9
|
+
* 2. Dependency resolution and circular cycle detection via N3
|
|
10
|
+
* 3. SHACL validation in soft-fail (annotate) mode with RDF audit trail
|
|
11
|
+
* 4. Marketplace queries over admitted hooks
|
|
12
|
+
*
|
|
13
|
+
* Run: node examples/hooks-marketplace.mjs
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import { HooksMarketplace, HOOK_NS } from '../src/lib/admit-hook.mjs';
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Helper: Pretty print JSON with 2-space indent
|
|
20
|
+
*/
|
|
21
|
+
function pretty(obj) {
|
|
22
|
+
return JSON.stringify(obj, null, 2);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Helper: Create hook definition
|
|
27
|
+
*/
|
|
28
|
+
function createHook(id, name, version, deps = []) {
|
|
29
|
+
return {
|
|
30
|
+
id,
|
|
31
|
+
name,
|
|
32
|
+
version,
|
|
33
|
+
description: `The ${name} hook performs important transformations`,
|
|
34
|
+
conditions: [
|
|
35
|
+
{
|
|
36
|
+
kind: 'sparql-ask',
|
|
37
|
+
query: `ASK { ?s a <${HOOK_NS.hook}${id}> }`,
|
|
38
|
+
},
|
|
39
|
+
],
|
|
40
|
+
effects: [
|
|
41
|
+
{
|
|
42
|
+
kind: 'sparql-construct',
|
|
43
|
+
query: `CONSTRUCT { ?s ?p ?o } WHERE { ?s ?p ?o }`,
|
|
44
|
+
},
|
|
45
|
+
],
|
|
46
|
+
dependsOn: deps,
|
|
47
|
+
priority: Math.floor(Math.random() * 100),
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
async function main() {
|
|
52
|
+
console.log('╔════════════════════════════════════════════════════════╗');
|
|
53
|
+
console.log('║ O* Innovation 5: Composable Hooks Marketplace ║');
|
|
54
|
+
console.log('║ RDF-based hook composition with SPARQL + N3 + SHACL ║');
|
|
55
|
+
console.log('╚════════════════════════════════════════════════════════╝\n');
|
|
56
|
+
|
|
57
|
+
// Initialize marketplace
|
|
58
|
+
const marketplace = new HooksMarketplace();
|
|
59
|
+
console.log('✓ Marketplace initialized\n');
|
|
60
|
+
|
|
61
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
62
|
+
// DEMO 1: Single Hook Normalization
|
|
63
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
64
|
+
console.log('┌─ DEMO 1: Hook Normalization to RDF ─────────────────┐');
|
|
65
|
+
|
|
66
|
+
const hookId1 = '550e8400-e29b-41d4-a716-446655440001';
|
|
67
|
+
const singleHook = createHook(
|
|
68
|
+
hookId1,
|
|
69
|
+
'Data Enrichment Hook',
|
|
70
|
+
'1.0.0',
|
|
71
|
+
[], // No dependencies
|
|
72
|
+
);
|
|
73
|
+
|
|
74
|
+
console.log('Input hook definition:');
|
|
75
|
+
console.log(pretty(singleHook));
|
|
76
|
+
console.log('\nNormalizing to RDF...');
|
|
77
|
+
|
|
78
|
+
const normalized = marketplace.normalizeHookToRDF(singleHook);
|
|
79
|
+
console.log(`\nGenerated hook URI: ${normalized.hookUri}`);
|
|
80
|
+
console.log(`Total RDF triples: ${normalized.triples.length}`);
|
|
81
|
+
console.log(`Conditions: ${normalized.conditions.length}`);
|
|
82
|
+
console.log(`Effects: ${normalized.effects.length}`);
|
|
83
|
+
|
|
84
|
+
// Sample triples
|
|
85
|
+
console.log('\nSample RDF triples (first 5):');
|
|
86
|
+
normalized.triples.slice(0, 5).forEach((t, idx) => {
|
|
87
|
+
console.log(` ${idx + 1}. ${t.subject.value}`);
|
|
88
|
+
console.log(` --[${t.predicate.value.split('/').pop()}]-->`);
|
|
89
|
+
console.log(` ${t.object.value || t.object.datatype}`);
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
console.log('└───────────────────────────────────────────────────────┘\n');
|
|
93
|
+
|
|
94
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
95
|
+
// DEMO 2: Hook Admission with SHACL Soft-Fail
|
|
96
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
97
|
+
console.log('┌─ DEMO 2: Hook Admission with SHACL Soft-Fail ────────┐');
|
|
98
|
+
|
|
99
|
+
const admissionResult = marketplace.admitHook(singleHook);
|
|
100
|
+
console.log(`Hook admission result:`);
|
|
101
|
+
console.log(` Admitted: ${admissionResult.admitted}`);
|
|
102
|
+
console.log(` Hook URI: ${admissionResult.hookUri}`);
|
|
103
|
+
console.log(` Violations: ${admissionResult.violationCount}`);
|
|
104
|
+
|
|
105
|
+
if (admissionResult.violationCount > 0) {
|
|
106
|
+
console.log(` Violation details:`);
|
|
107
|
+
admissionResult.violations.forEach(v => {
|
|
108
|
+
console.log(` - ${v.message}`);
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
console.log('└───────────────────────────────────────────────────────┘\n');
|
|
113
|
+
|
|
114
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
115
|
+
// DEMO 3: Valid Dependency Chain
|
|
116
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
117
|
+
console.log('┌─ DEMO 3: Valid Dependency Chain A→B→C ────────────────┐');
|
|
118
|
+
|
|
119
|
+
const hookId2 = '550e8400-e29b-41d4-a716-446655440002';
|
|
120
|
+
const hookId3 = '550e8400-e29b-41d4-a716-446655440003';
|
|
121
|
+
|
|
122
|
+
const hookA = createHook(hookId1, 'Hook A (Base)', '1.0.0', []);
|
|
123
|
+
const hookB = createHook(hookId2, 'Hook B (depends on A)', '1.0.0', [hookId1]);
|
|
124
|
+
const hookC = createHook(hookId3, 'Hook C (depends on B)', '1.0.0', [hookId2]);
|
|
125
|
+
|
|
126
|
+
console.log('Admitting hooks A→B→C (valid chain)...\n');
|
|
127
|
+
|
|
128
|
+
const chainResult = marketplace.admitHooksWithDependencies([hookA, hookB, hookC]);
|
|
129
|
+
|
|
130
|
+
console.log(`Results:`);
|
|
131
|
+
console.log(` Admitted: ${chainResult.admittedCount}`);
|
|
132
|
+
console.log(` Rejected: ${chainResult.rejectedCount}`);
|
|
133
|
+
console.log(` Cycles detected: ${chainResult.hadCycles}`);
|
|
134
|
+
|
|
135
|
+
console.log(`\nDependency graph:`);
|
|
136
|
+
console.log(pretty(chainResult.dependencyGraph).split('\n').slice(0, 15).join('\n'));
|
|
137
|
+
|
|
138
|
+
console.log('└───────────────────────────────────────────────────────┘\n');
|
|
139
|
+
|
|
140
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
141
|
+
// DEMO 4: Circular Dependency Detection
|
|
142
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
143
|
+
console.log('┌─ DEMO 4: Circular Dependency Detection (A↔B) ────────┐');
|
|
144
|
+
|
|
145
|
+
const hookId4 = '550e8400-e29b-41d4-a716-446655440004';
|
|
146
|
+
const hookId5 = '550e8400-e29b-41d4-a716-446655440005';
|
|
147
|
+
|
|
148
|
+
const hookX = createHook(hookId4, 'Hook X', '1.0.0', [hookId5]);
|
|
149
|
+
const hookY = createHook(hookId5, 'Hook Y', '1.0.0', [hookId4]);
|
|
150
|
+
|
|
151
|
+
console.log('Admitting hooks X↔Y (circular dependency)...\n');
|
|
152
|
+
|
|
153
|
+
const cycleResult = marketplace.admitHooksWithDependencies([hookX, hookY]);
|
|
154
|
+
|
|
155
|
+
console.log(`Results:`);
|
|
156
|
+
console.log(` Admitted: ${cycleResult.admittedCount}`);
|
|
157
|
+
console.log(` Rejected: ${cycleResult.rejectedCount}`);
|
|
158
|
+
console.log(` Cycles detected: ${cycleResult.hadCycles}`);
|
|
159
|
+
|
|
160
|
+
if (cycleResult.cycles.length > 0) {
|
|
161
|
+
console.log(` Hooks involved in cycles:`);
|
|
162
|
+
cycleResult.cycles.slice(0, 3).forEach(cycle => {
|
|
163
|
+
console.log(` - ${cycle}`);
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
console.log('└───────────────────────────────────────────────────────┘\n');
|
|
168
|
+
|
|
169
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
170
|
+
// DEMO 5: Marketplace Queries
|
|
171
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
172
|
+
console.log('┌─ DEMO 5: RDF Marketplace Queries ─────────────────────┐');
|
|
173
|
+
|
|
174
|
+
// Re-create marketplace with valid hooks
|
|
175
|
+
const queryMarketplace = new HooksMarketplace();
|
|
176
|
+
|
|
177
|
+
const demoHooks = [
|
|
178
|
+
createHook('550e8400-e29b-41d4-a716-446655440010', 'Hook Alpha', '1.0.0', []),
|
|
179
|
+
createHook('550e8400-e29b-41d4-a716-446655440011', 'Hook Beta', '2.0.0', []),
|
|
180
|
+
createHook('550e8400-e29b-41d4-a716-446655440012', 'Hook Gamma', '1.5.0', []),
|
|
181
|
+
];
|
|
182
|
+
|
|
183
|
+
demoHooks.forEach(h => queryMarketplace.admitHook(h));
|
|
184
|
+
|
|
185
|
+
console.log('Admitted hooks to marketplace:');
|
|
186
|
+
const admitted = queryMarketplace.getAdmittedHooks();
|
|
187
|
+
admitted.forEach((h, idx) => {
|
|
188
|
+
console.log(` ${idx + 1}. ${h.name} (v${h.version}) - priority: ${h.priority}`);
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
// Query: Count all hooks
|
|
192
|
+
const countQuery = `
|
|
193
|
+
PREFIX hook: <http://ostar.org/hook/>
|
|
194
|
+
SELECT (COUNT(?hook) AS ?count) WHERE {
|
|
195
|
+
?hook a hook:Hook .
|
|
196
|
+
}
|
|
197
|
+
`;
|
|
198
|
+
|
|
199
|
+
try {
|
|
200
|
+
const countResults = queryMarketplace.query(countQuery);
|
|
201
|
+
console.log(`\nSPARQL query result (COUNT all hooks):`);
|
|
202
|
+
console.log(` Total hooks: ${countResults.length > 0 ? countResults[0].count : 0}`);
|
|
203
|
+
} catch (err) {
|
|
204
|
+
console.log(`Query note: ${err.message}`);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
console.log('└───────────────────────────────────────────────────────┘\n');
|
|
208
|
+
|
|
209
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
210
|
+
// DEMO 6: Soft-Fail Admission with SHACL Violations
|
|
211
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
212
|
+
console.log('┌─ DEMO 6: Soft-Fail Admission (SHACL Annotate) ────────┐');
|
|
213
|
+
|
|
214
|
+
const softFailMarketplace = new HooksMarketplace();
|
|
215
|
+
|
|
216
|
+
// All hooks that pass Zod schema validation are admitted (soft-fail)
|
|
217
|
+
// This demonstrates the separation of concerns:
|
|
218
|
+
// - Zod: syntactic validation (hard-fail)
|
|
219
|
+
// - SHACL: semantic validation (soft-fail with audit trail RDF)
|
|
220
|
+
const validHook = createHook(
|
|
221
|
+
'550e8400-e29b-41d4-a716-446655440020',
|
|
222
|
+
'Analytics Hook',
|
|
223
|
+
'1.0.0',
|
|
224
|
+
[],
|
|
225
|
+
);
|
|
226
|
+
|
|
227
|
+
const softFailResult = softFailMarketplace.admitHook(validHook);
|
|
228
|
+
|
|
229
|
+
console.log('Admitting valid hook (all constraints satisfied)...\n');
|
|
230
|
+
console.log(`Admission result:`);
|
|
231
|
+
console.log(` Admitted: ${softFailResult.admitted} (soft-fail mode)`);
|
|
232
|
+
console.log(` Violations recorded: ${softFailResult.violationCount}`);
|
|
233
|
+
console.log(` Hook URI: ${softFailResult.hookUri}`);
|
|
234
|
+
|
|
235
|
+
console.log(`\nDesign Notes:`);
|
|
236
|
+
console.log(` • Zod schema validation: Hard-fail (syntactic)`);
|
|
237
|
+
console.log(` • SHACL validation: Soft-fail (semantic, RDF audit trail)`);
|
|
238
|
+
console.log(` • Violated hooks recorded as RDF triples for compliance audits`);
|
|
239
|
+
console.log(` • Hooks always admitted if they pass syntax validation`);
|
|
240
|
+
|
|
241
|
+
console.log('└───────────────────────────────────────────────────────┘\n');
|
|
242
|
+
|
|
243
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
244
|
+
// Summary
|
|
245
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
246
|
+
console.log('╔════════════════════════════════════════════════════════╗');
|
|
247
|
+
console.log('║ Summary ║');
|
|
248
|
+
console.log('╠════════════════════════════════════════════════════════╣');
|
|
249
|
+
console.log('║ ✓ Hook normalization to RDF (SPARQL CONSTRUCT) ║');
|
|
250
|
+
console.log('║ ✓ Dependency composition (N3 forward-chaining) ║');
|
|
251
|
+
console.log('║ ✓ Circular cycle detection ║');
|
|
252
|
+
console.log('║ ✓ SHACL validation (annotate/soft-fail mode) ║');
|
|
253
|
+
console.log('║ ✓ RDF audit trail for violations ║');
|
|
254
|
+
console.log('║ ✓ Marketplace queries via SPARQL ║');
|
|
255
|
+
console.log('╚════════════════════════════════════════════════════════╝\n');
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
main().catch(err => {
|
|
259
|
+
console.error('Error:', err.message);
|
|
260
|
+
process.exit(1);
|
|
261
|
+
});
|
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @unrdf/hooks - N3 Forward-Chaining Reasoning Example
|
|
3
|
+
*
|
|
4
|
+
* Demonstrates semantic inference using N3 rules and EYE reasoner.
|
|
5
|
+
* Derives new facts from existing data through logical rules.
|
|
6
|
+
*
|
|
7
|
+
* Use cases:
|
|
8
|
+
* - RDFS/OWL-like reasoning (class hierarchies, property inference)
|
|
9
|
+
* - Business rule execution (access control, workflow logic)
|
|
10
|
+
* - Data enrichment (derive properties from rules)
|
|
11
|
+
* - Compliance checking (derive compliance status)
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { createStore } from '@unrdf/oxigraph';
|
|
15
|
+
import { evaluateCondition } from '../src/hooks/condition-evaluator.mjs';
|
|
16
|
+
import { UnrdfDataFactory as DataFactory } from '@unrdf/core/rdf/n3-justified-only';
|
|
17
|
+
|
|
18
|
+
const { namedNode, literal, quad } = DataFactory;
|
|
19
|
+
|
|
20
|
+
console.log('=== N3 Forward-Chaining Reasoning Example ===\n');
|
|
21
|
+
|
|
22
|
+
// Example 1: Simple class inheritance
|
|
23
|
+
console.log('1. Simple Class Inheritance\n');
|
|
24
|
+
|
|
25
|
+
const classInheritanceCondition = {
|
|
26
|
+
kind: 'n3',
|
|
27
|
+
rules: `
|
|
28
|
+
@prefix : <http://example.org/> .
|
|
29
|
+
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
|
|
30
|
+
|
|
31
|
+
# Rule: If X is subclass of Y and Z is instance of X, then Z is instance of Y
|
|
32
|
+
{ ?x rdfs:subClassOf ?y . ?z a ?x } => { ?z a ?y } .
|
|
33
|
+
`,
|
|
34
|
+
askQuery: 'ASK { ?s a <http://example.org/Animal> }'
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
console.log('Rules:');
|
|
38
|
+
console.log(classInheritanceCondition.rules);
|
|
39
|
+
console.log('');
|
|
40
|
+
console.log('Scenario:');
|
|
41
|
+
console.log(' Data: Dog subClassOf Animal, Fido a Dog');
|
|
42
|
+
console.log(' Inference: Fido a Animal (derived)');
|
|
43
|
+
console.log(' Query: ASK { ?s a Animal } → true\n');
|
|
44
|
+
|
|
45
|
+
// Example 2: Access control reasoning
|
|
46
|
+
console.log('2. Access Control Reasoning\n');
|
|
47
|
+
|
|
48
|
+
const accessControlCondition = {
|
|
49
|
+
kind: 'n3',
|
|
50
|
+
rules: `
|
|
51
|
+
@prefix : <http://example.org/> .
|
|
52
|
+
|
|
53
|
+
# Rule 1: Admins can access everything
|
|
54
|
+
{ ?user a :Admin } => { ?user :canAccess :SecureArea } .
|
|
55
|
+
|
|
56
|
+
# Rule 2: Group members inherit group permissions
|
|
57
|
+
{ ?user :isMemberOf ?group . ?group :hasPermission ?perm }
|
|
58
|
+
=> { ?user :hasPermission ?perm } .
|
|
59
|
+
|
|
60
|
+
# Rule 3: Users with edit permission need audit logging
|
|
61
|
+
{ ?user :hasPermission :EditContent }
|
|
62
|
+
=> { ?user :requiresAuditLog true } .
|
|
63
|
+
|
|
64
|
+
# Rule 4: Audit logging required if accessing secure area
|
|
65
|
+
{ ?user :canAccess :SecureArea }
|
|
66
|
+
=> { ?user :requiresAuditLog true } .
|
|
67
|
+
`,
|
|
68
|
+
askQuery: 'ASK { ?user :requiresAuditLog true }'
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
console.log('Rules demonstrate multi-level inference:');
|
|
72
|
+
console.log(' Rule 1: Admin role → access permission');
|
|
73
|
+
console.log(' Rule 2: Group membership → inherit permissions');
|
|
74
|
+
console.log(' Rule 3: Edit permission → audit requirement');
|
|
75
|
+
console.log(' Rule 4: Secure access → audit requirement');
|
|
76
|
+
console.log('');
|
|
77
|
+
console.log('Scenario:');
|
|
78
|
+
console.log(' Data: alice a Admin, bob :isMemberOf :editors');
|
|
79
|
+
console.log(' Step 1: alice a Admin → alice :canAccess :SecureArea');
|
|
80
|
+
console.log(' Step 2: alice :canAccess :SecureArea → alice :requiresAuditLog true');
|
|
81
|
+
console.log(' Step 3: bob :isMemberOf :editors → check group permissions');
|
|
82
|
+
console.log(' Result: Audit requirements derived from roles\n');
|
|
83
|
+
|
|
84
|
+
// Example 3: Business process workflow
|
|
85
|
+
console.log('3. Business Process Workflow Reasoning\n');
|
|
86
|
+
|
|
87
|
+
const workflowCondition = {
|
|
88
|
+
kind: 'n3',
|
|
89
|
+
rules: `
|
|
90
|
+
@prefix : <http://example.org/> .
|
|
91
|
+
|
|
92
|
+
# Rule 1: Large trades require compliance review
|
|
93
|
+
{ ?trade a :Trade ; :amount ?amt . ?amt > 1000000 }
|
|
94
|
+
=> { ?trade :requiresCompliance true } .
|
|
95
|
+
|
|
96
|
+
# Rule 2: Compliance required trades need risk assessment
|
|
97
|
+
{ ?trade :requiresCompliance true }
|
|
98
|
+
=> { ?trade :requiresRiskAssessment true } .
|
|
99
|
+
|
|
100
|
+
# Rule 3: Risk assessment must be approved by senior reviewer
|
|
101
|
+
{ ?trade :requiresRiskAssessment true }
|
|
102
|
+
=> { ?trade :requiresApprovalLevel :Senior } .
|
|
103
|
+
|
|
104
|
+
# Rule 4: High-risk trades need compliance officer sign-off
|
|
105
|
+
{ ?trade :riskLevel :High ; :requiresApprovalLevel :Senior }
|
|
106
|
+
=> { ?trade :requiresComplianceOfficer true } .
|
|
107
|
+
|
|
108
|
+
# Rule 5: Anything needing compliance officer needs audit trail
|
|
109
|
+
{ ?trade :requiresComplianceOfficer true }
|
|
110
|
+
=> { ?trade :auditTrailRequired true } .
|
|
111
|
+
`,
|
|
112
|
+
askQuery: 'ASK { ?trade :auditTrailRequired true }'
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
console.log('Multi-step workflow rules:');
|
|
116
|
+
console.log(' Trade amount > $1M → requires compliance');
|
|
117
|
+
console.log(' Requires compliance → requires risk assessment');
|
|
118
|
+
console.log(' Requires risk assessment → requires senior approval');
|
|
119
|
+
console.log(' High risk + senior approval → needs compliance officer');
|
|
120
|
+
console.log(' Needs compliance officer → needs audit trail');
|
|
121
|
+
console.log('');
|
|
122
|
+
console.log('Execution:');
|
|
123
|
+
console.log(' Input: Trade with amount $1.5M');
|
|
124
|
+
console.log(' Derives: auditTrailRequired = true');
|
|
125
|
+
console.log(' Effect: Create audit record in system\n');
|
|
126
|
+
|
|
127
|
+
// Example 4: Data enrichment
|
|
128
|
+
console.log('4. Data Enrichment Through Reasoning\n');
|
|
129
|
+
|
|
130
|
+
const enrichmentCondition = {
|
|
131
|
+
kind: 'n3',
|
|
132
|
+
rules: `
|
|
133
|
+
@prefix : <http://example.org/> .
|
|
134
|
+
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
|
|
135
|
+
|
|
136
|
+
# Rule 1: Calculate age from birthDate
|
|
137
|
+
{ ?person :birthDate ?birth }
|
|
138
|
+
=> { ?person :age ?age } . # Would need SPARQL for real calculation
|
|
139
|
+
|
|
140
|
+
# Rule 2: Categorize by age
|
|
141
|
+
{ ?person :age ?age . ?age > 65 }
|
|
142
|
+
=> { ?person :category :Senior } .
|
|
143
|
+
|
|
144
|
+
{ ?person :age ?age . ?age >= 18 . ?age <= 65 }
|
|
145
|
+
=> { ?person :category :Adult } .
|
|
146
|
+
|
|
147
|
+
{ ?person :age ?age . ?age < 18 }
|
|
148
|
+
=> { ?person :category :Minor } .
|
|
149
|
+
|
|
150
|
+
# Rule 3: Seniors get special benefits
|
|
151
|
+
{ ?person :category :Senior }
|
|
152
|
+
=> { ?person :eligibleFor :SeniorDiscount } .
|
|
153
|
+
|
|
154
|
+
# Rule 4: Mark complete profiles
|
|
155
|
+
{ ?person :name ?n ; :email ?e ; :category ?c }
|
|
156
|
+
=> { ?person :profileComplete true } .
|
|
157
|
+
`,
|
|
158
|
+
askQuery: 'ASK { ?p :profileComplete true }'
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
console.log('Enrichment rules:');
|
|
162
|
+
console.log(' Birthdate → derive age');
|
|
163
|
+
console.log(' Age → categorize as Senior/Adult/Minor');
|
|
164
|
+
console.log(' Senior → eligible for discount');
|
|
165
|
+
console.log(' Complete profile (name + email + category) → mark as complete');
|
|
166
|
+
console.log('');
|
|
167
|
+
console.log('Input: Person with name, email, age');
|
|
168
|
+
console.log('Output: Category, discounts, completeness flag\n');
|
|
169
|
+
|
|
170
|
+
// Example 5: Compliance rule engine
|
|
171
|
+
console.log('5. Compliance Rule Engine\n');
|
|
172
|
+
|
|
173
|
+
const complianceCondition = {
|
|
174
|
+
kind: 'n3',
|
|
175
|
+
rules: `
|
|
176
|
+
@prefix : <http://example.org/> .
|
|
177
|
+
|
|
178
|
+
# GDPR Rules
|
|
179
|
+
{ ?entity a :PersonalData ; :storedIn ?jurisdiction .
|
|
180
|
+
?jurisdiction :region ?region . ?region != :EU }
|
|
181
|
+
=> { ?entity :gdprViolation :DataResidency } .
|
|
182
|
+
|
|
183
|
+
# PCI-DSS Rules
|
|
184
|
+
{ ?entity a :CardData ; :encryptionLevel ?level .
|
|
185
|
+
?level < 256 }
|
|
186
|
+
=> { ?entity :pciViolation :InsufficientEncryption } .
|
|
187
|
+
|
|
188
|
+
# SOX Rules (for public companies)
|
|
189
|
+
{ ?company a :PublicCompany ;
|
|
190
|
+
:hasFinancialData ?data }
|
|
191
|
+
=> { ?company :requiresSoxCompliance true } .
|
|
192
|
+
|
|
193
|
+
# Any violation → requires remediation
|
|
194
|
+
{ ?entity :gdprViolation ?v } => { ?entity :requiresRemediation true } .
|
|
195
|
+
{ ?entity :pciViolation ?v } => { ?entity :requiresRemediation true } .
|
|
196
|
+
|
|
197
|
+
# Mark non-compliant if has violations
|
|
198
|
+
{ ?entity :requiresRemediation true }
|
|
199
|
+
=> { ?entity :complianceStatus :NonCompliant } .
|
|
200
|
+
`,
|
|
201
|
+
askQuery: 'ASK { ?entity :complianceStatus :NonCompliant }'
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
console.log('Compliance engine checks:');
|
|
205
|
+
console.log(' GDPR: Personal data must be in EU jurisdiction');
|
|
206
|
+
console.log(' PCI-DSS: Card data must be 256-bit encrypted');
|
|
207
|
+
console.log(' SOX: Public companies must audit financial data');
|
|
208
|
+
console.log(' Any violation → mark non-compliant\n');
|
|
209
|
+
|
|
210
|
+
// Performance considerations
|
|
211
|
+
console.log('6. Performance Considerations\n');
|
|
212
|
+
|
|
213
|
+
console.log('Forward-chaining semantics:');
|
|
214
|
+
console.log(' - All applicable rules fire until fixpoint');
|
|
215
|
+
console.log(' - Derives all possible new facts');
|
|
216
|
+
console.log(' - Complete closure of logical consequences');
|
|
217
|
+
console.log('');
|
|
218
|
+
console.log('Performance factors:');
|
|
219
|
+
console.log(' 1. Rule count: More rules = more inference steps');
|
|
220
|
+
console.log(' 2. Data size: Large graphs = more match attempts');
|
|
221
|
+
console.log(' 3. Rule complexity: Join patterns in antecedents');
|
|
222
|
+
console.log(' 4. Iteration count: Fixpoint may require many passes');
|
|
223
|
+
console.log('');
|
|
224
|
+
console.log('Optimization tips:');
|
|
225
|
+
console.log(' ✓ Materialize frequently derived facts');
|
|
226
|
+
console.log(' ✓ Use specific patterns (avoid ?x ?p ?o)');
|
|
227
|
+
console.log(' ✓ Order rules: simple → complex');
|
|
228
|
+
console.log(' ✗ Avoid rules that derive rule premises');
|
|
229
|
+
console.log(' ✗ Don\'t use reasoning for high-frequency checks\n');
|
|
230
|
+
|
|
231
|
+
// Full hook example
|
|
232
|
+
console.log('7. Complete Hook with N3 Reasoning\n');
|
|
233
|
+
|
|
234
|
+
console.log(`
|
|
235
|
+
const dataEnrichmentHook = {
|
|
236
|
+
name: 'enriched-trade-data',
|
|
237
|
+
|
|
238
|
+
condition: {
|
|
239
|
+
kind: 'n3',
|
|
240
|
+
rules: \`
|
|
241
|
+
@prefix : <http://example.org/> .
|
|
242
|
+
|
|
243
|
+
{ ?trade a :Trade ; :amount ?amt . ?amt > 500000 }
|
|
244
|
+
=> { ?trade :largeTradeIndicator true } .
|
|
245
|
+
|
|
246
|
+
{ ?trade :largeTradeIndicator true }
|
|
247
|
+
=> { ?trade :requiresReview true } .
|
|
248
|
+
|
|
249
|
+
{ ?trade :requiresReview true ; :counterparty ?cp }
|
|
250
|
+
=> { ?cp :hadLargeTrade true } .
|
|
251
|
+
\`,
|
|
252
|
+
askQuery: 'ASK { ?t :requiresReview true }'
|
|
253
|
+
},
|
|
254
|
+
|
|
255
|
+
effects: [{
|
|
256
|
+
kind: 'sparql-construct',
|
|
257
|
+
query: \`
|
|
258
|
+
CONSTRUCT {
|
|
259
|
+
?trade :reviewStatus ex:Pending ;
|
|
260
|
+
:derivedFrom ex:N3Rules ;
|
|
261
|
+
:timestamp ?now .
|
|
262
|
+
}
|
|
263
|
+
WHERE {
|
|
264
|
+
?trade :requiresReview true .
|
|
265
|
+
BIND (NOW() as ?now)
|
|
266
|
+
}
|
|
267
|
+
\`
|
|
268
|
+
}]
|
|
269
|
+
};
|
|
270
|
+
|
|
271
|
+
Execution:
|
|
272
|
+
1. Trade added with amount > $500K
|
|
273
|
+
2. N3 reasoning: derives :requiresReview true
|
|
274
|
+
3. Condition ASK: "is there a :requiresReview?" → true
|
|
275
|
+
4. Effect executes: marks trade as pending review
|
|
276
|
+
5. Counterparty flagged for trading pattern analysis
|
|
277
|
+
`);
|
|
278
|
+
|
|
279
|
+
console.log('\n=== Example Complete ===');
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
|
|
3
|
+
|
|
4
|
+
case `uname` in
|
|
5
|
+
*CYGWIN*|*MINGW*|*MSYS*)
|
|
6
|
+
if command -v cygpath > /dev/null 2>&1; then
|
|
7
|
+
basedir=`cygpath -w "$basedir"`
|
|
8
|
+
fi
|
|
9
|
+
;;
|
|
10
|
+
esac
|
|
11
|
+
|
|
12
|
+
if [ -z "$NODE_PATH" ]; then
|
|
13
|
+
export NODE_PATH="/Users/sac/unrdf/node_modules/.pnpm/jiti@2.6.1/node_modules/jiti/lib/node_modules:/Users/sac/unrdf/node_modules/.pnpm/jiti@2.6.1/node_modules/jiti/node_modules:/Users/sac/unrdf/node_modules/.pnpm/jiti@2.6.1/node_modules:/Users/sac/unrdf/node_modules/.pnpm/node_modules"
|
|
14
|
+
else
|
|
15
|
+
export NODE_PATH="/Users/sac/unrdf/node_modules/.pnpm/jiti@2.6.1/node_modules/jiti/lib/node_modules:/Users/sac/unrdf/node_modules/.pnpm/jiti@2.6.1/node_modules/jiti/node_modules:/Users/sac/unrdf/node_modules/.pnpm/jiti@2.6.1/node_modules:/Users/sac/unrdf/node_modules/.pnpm/node_modules:$NODE_PATH"
|
|
16
|
+
fi
|
|
17
|
+
if [ -x "$basedir/node" ]; then
|
|
18
|
+
exec "$basedir/node" "$basedir/../../../../../../node_modules/.pnpm/jiti@2.6.1/node_modules/jiti/lib/jiti-cli.mjs" "$@"
|
|
19
|
+
else
|
|
20
|
+
exec node "$basedir/../../../../../../node_modules/.pnpm/jiti@2.6.1/node_modules/jiti/lib/jiti-cli.mjs" "$@"
|
|
21
|
+
fi
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
|
|
3
|
+
|
|
4
|
+
case `uname` in
|
|
5
|
+
*CYGWIN*|*MINGW*|*MSYS*)
|
|
6
|
+
if command -v cygpath > /dev/null 2>&1; then
|
|
7
|
+
basedir=`cygpath -w "$basedir"`
|
|
8
|
+
fi
|
|
9
|
+
;;
|
|
10
|
+
esac
|
|
11
|
+
|
|
12
|
+
if [ -z "$NODE_PATH" ]; then
|
|
13
|
+
export NODE_PATH="/Users/sac/unrdf/node_modules/.pnpm/msw@2.12.14_@types+node@25.5.0_typescript@5.9.3/node_modules/msw/cli/node_modules:/Users/sac/unrdf/node_modules/.pnpm/msw@2.12.14_@types+node@25.5.0_typescript@5.9.3/node_modules/msw/node_modules:/Users/sac/unrdf/node_modules/.pnpm/msw@2.12.14_@types+node@25.5.0_typescript@5.9.3/node_modules:/Users/sac/unrdf/node_modules/.pnpm/node_modules"
|
|
14
|
+
else
|
|
15
|
+
export NODE_PATH="/Users/sac/unrdf/node_modules/.pnpm/msw@2.12.14_@types+node@25.5.0_typescript@5.9.3/node_modules/msw/cli/node_modules:/Users/sac/unrdf/node_modules/.pnpm/msw@2.12.14_@types+node@25.5.0_typescript@5.9.3/node_modules/msw/node_modules:/Users/sac/unrdf/node_modules/.pnpm/msw@2.12.14_@types+node@25.5.0_typescript@5.9.3/node_modules:/Users/sac/unrdf/node_modules/.pnpm/node_modules:$NODE_PATH"
|
|
16
|
+
fi
|
|
17
|
+
if [ -x "$basedir/node" ]; then
|
|
18
|
+
exec "$basedir/node" "$basedir/../../../../../../node_modules/.pnpm/msw@2.12.14_@types+node@25.5.0_typescript@5.9.3/node_modules/msw/cli/index.js" "$@"
|
|
19
|
+
else
|
|
20
|
+
exec node "$basedir/../../../../../../node_modules/.pnpm/msw@2.12.14_@types+node@25.5.0_typescript@5.9.3/node_modules/msw/cli/index.js" "$@"
|
|
21
|
+
fi
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
|
|
3
|
+
|
|
4
|
+
case `uname` in
|
|
5
|
+
*CYGWIN*|*MINGW*|*MSYS*)
|
|
6
|
+
if command -v cygpath > /dev/null 2>&1; then
|
|
7
|
+
basedir=`cygpath -w "$basedir"`
|
|
8
|
+
fi
|
|
9
|
+
;;
|
|
10
|
+
esac
|
|
11
|
+
|
|
12
|
+
if [ -z "$NODE_PATH" ]; then
|
|
13
|
+
export NODE_PATH="/Users/sac/unrdf/node_modules/.pnpm/terser@5.46.1/node_modules/terser/bin/node_modules:/Users/sac/unrdf/node_modules/.pnpm/terser@5.46.1/node_modules/terser/node_modules:/Users/sac/unrdf/node_modules/.pnpm/terser@5.46.1/node_modules:/Users/sac/unrdf/node_modules/.pnpm/node_modules"
|
|
14
|
+
else
|
|
15
|
+
export NODE_PATH="/Users/sac/unrdf/node_modules/.pnpm/terser@5.46.1/node_modules/terser/bin/node_modules:/Users/sac/unrdf/node_modules/.pnpm/terser@5.46.1/node_modules/terser/node_modules:/Users/sac/unrdf/node_modules/.pnpm/terser@5.46.1/node_modules:/Users/sac/unrdf/node_modules/.pnpm/node_modules:$NODE_PATH"
|
|
16
|
+
fi
|
|
17
|
+
if [ -x "$basedir/node" ]; then
|
|
18
|
+
exec "$basedir/node" "$basedir/../../../../../../node_modules/.pnpm/terser@5.46.1/node_modules/terser/bin/terser" "$@"
|
|
19
|
+
else
|
|
20
|
+
exec node "$basedir/../../../../../../node_modules/.pnpm/terser@5.46.1/node_modules/terser/bin/terser" "$@"
|
|
21
|
+
fi
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
|
|
3
|
+
|
|
4
|
+
case `uname` in
|
|
5
|
+
*CYGWIN*|*MINGW*|*MSYS*)
|
|
6
|
+
if command -v cygpath > /dev/null 2>&1; then
|
|
7
|
+
basedir=`cygpath -w "$basedir"`
|
|
8
|
+
fi
|
|
9
|
+
;;
|
|
10
|
+
esac
|
|
11
|
+
|
|
12
|
+
if [ -z "$NODE_PATH" ]; then
|
|
13
|
+
export NODE_PATH="/Users/sac/unrdf/node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/bin/node_modules:/Users/sac/unrdf/node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/node_modules:/Users/sac/unrdf/node_modules/.pnpm/typescript@5.9.3/node_modules:/Users/sac/unrdf/node_modules/.pnpm/node_modules"
|
|
14
|
+
else
|
|
15
|
+
export NODE_PATH="/Users/sac/unrdf/node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/bin/node_modules:/Users/sac/unrdf/node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/node_modules:/Users/sac/unrdf/node_modules/.pnpm/typescript@5.9.3/node_modules:/Users/sac/unrdf/node_modules/.pnpm/node_modules:$NODE_PATH"
|
|
16
|
+
fi
|
|
17
|
+
if [ -x "$basedir/node" ]; then
|
|
18
|
+
exec "$basedir/node" "$basedir/../../../../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/bin/tsc" "$@"
|
|
19
|
+
else
|
|
20
|
+
exec node "$basedir/../../../../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/bin/tsc" "$@"
|
|
21
|
+
fi
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
|
|
3
|
+
|
|
4
|
+
case `uname` in
|
|
5
|
+
*CYGWIN*|*MINGW*|*MSYS*)
|
|
6
|
+
if command -v cygpath > /dev/null 2>&1; then
|
|
7
|
+
basedir=`cygpath -w "$basedir"`
|
|
8
|
+
fi
|
|
9
|
+
;;
|
|
10
|
+
esac
|
|
11
|
+
|
|
12
|
+
if [ -z "$NODE_PATH" ]; then
|
|
13
|
+
export NODE_PATH="/Users/sac/unrdf/node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/bin/node_modules:/Users/sac/unrdf/node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/node_modules:/Users/sac/unrdf/node_modules/.pnpm/typescript@5.9.3/node_modules:/Users/sac/unrdf/node_modules/.pnpm/node_modules"
|
|
14
|
+
else
|
|
15
|
+
export NODE_PATH="/Users/sac/unrdf/node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/bin/node_modules:/Users/sac/unrdf/node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/node_modules:/Users/sac/unrdf/node_modules/.pnpm/typescript@5.9.3/node_modules:/Users/sac/unrdf/node_modules/.pnpm/node_modules:$NODE_PATH"
|
|
16
|
+
fi
|
|
17
|
+
if [ -x "$basedir/node" ]; then
|
|
18
|
+
exec "$basedir/node" "$basedir/../../../../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/bin/tsserver" "$@"
|
|
19
|
+
else
|
|
20
|
+
exec node "$basedir/../../../../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/bin/tsserver" "$@"
|
|
21
|
+
fi
|