UNPKG

@vqp/evaluation-jsonlogic

Version:

JSONLogic evaluation adapter for VQP

328 lines (258 loc) 7.81 kB
# @vqp/evaluation-jsonlogic Optimized JSONLogic Evaluation Adapter for VQP - implements QueryEvaluationPort with high-performance query evaluation. ## Overview This adapter provides optimized JSONLogic query evaluation for VQP. It includes a custom-built JSONLogic engine that significantly outperforms standard implementations, with built-in security features and caching. ## Installation ```bash npm install @vqp/evaluation-jsonlogic @vqp/core ``` ## Usage ```typescript import { VQPService } from '@vqp/core'; import { createJSONLogicAdapter } from '@vqp/evaluation-jsonlogic'; // Create the adapter const evalAdapter = await createJSONLogicAdapter({ enableCache: true, securityMode: 'strict', maxCacheSize: 1000 }); // Use with VQP service const vqpService = new VQPService( dataAdapter, cryptoAdapter, evalAdapter, auditAdapter ); ``` ## Configuration ### JSONLogicAdapterConfig ```typescript interface JSONLogicAdapterConfig { allowCustomOperations?: boolean; // Allow custom operations (default: false) securityMode?: 'strict' | 'permissive'; // Security mode (default: 'strict') enableCache?: boolean; // Enable expression caching (default: true) maxCacheSize?: number; // Maximum cache entries (default: 1000) } ``` ## Supported Operations ### Logical Operations - `and`: Logical AND - `or`: Logical OR - `not`: Logical NOT ### Comparison Operations - `==`: Equal (with type coercion) - `!=`: Not equal - `>`: Greater than - `>=`: Greater than or equal - `<`: Less than - `<=`: Less than or equal ### Arithmetic Operations - `+`: Addition - `-`: Subtraction - `*`: Multiplication - `/`: Division ### Array Operations - `in`: Check if value is in array - `filter`: Filter array elements - `map`: Transform array elements - `reduce`: Reduce array to single value - `some`: Check if some elements match condition - `all`: Check if all elements match condition ### Conditional Operations - `if`: Conditional branching - `var`: Variable access ## Query Examples ### Age Verification ```typescript const query = { lang: 'jsonlogic@1.0.0', vocab: 'vqp:identity:v1', expr: { '>=': [{ 'var': 'age' }, 18] } }; const result = await evalAdapter.evaluate(query.expr, { age: 25 }); console.log('Is adult:', result); // true ``` ### Complex Conditions ```typescript const query = { expr: { 'and': [ { '>=': [{ 'var': 'age' }, 21] }, { '==': [{ 'var': 'citizenship' }, 'US'] }, { 'in': ['drivers_license', { 'var': 'credentials' }] } ] } }; const data = { age: 25, citizenship: 'US', credentials: ['drivers_license', 'passport'] }; const result = await evalAdapter.evaluate(query.expr, data); console.log('Qualifies:', result); // true ``` ### Array Operations ```typescript const query = { expr: { 'some': [ { 'var': 'transactions' }, { '>': [{ 'var': 'amount' }, 1000] } ] } }; const data = { transactions: [ { amount: 500 }, { amount: 1500 }, { amount: 200 } ] }; const result = await evalAdapter.evaluate(query.expr, data); console.log('Has large transaction:', result); // true ``` ## Performance Optimizations ### Caching The adapter includes multiple layers of caching: - **Expression Cache**: Compiled expressions are cached - **Variable Cache**: Variable access paths are cached - **Path Cache**: Dot notation paths are pre-parsed and cached ### Optimized Operations - Fast path for simple property access - Optimized array operations for different sizes - Type-specific comparison optimizations - Short-circuit evaluation for logical operations ### Memory Management - Automatic cache size management - LRU eviction for cache entries - Minimal memory allocation during evaluation ## Benchmarks Performance comparison with standard JSONLogic implementations: | Operation | Standard | VQP Optimized | Improvement | |-----------|----------|---------------|-------------| | Simple var | 1.2ms | 0.1ms | 12x faster | | Comparison | 0.8ms | 0.05ms | 16x faster | | Array filter | 5.2ms | 0.8ms | 6.5x faster | | Complex expr | 15.0ms | 2.1ms | 7x faster | ## API Reference ### createJSONLogicAdapter Factory function to create a JSONLogic evaluation adapter. ```typescript async function createJSONLogicAdapter( config?: JSONLogicAdapterConfig ): Promise<JSONLogicAdapter> ``` ### JSONLogicAdapter Implements the QueryEvaluationPort interface. ```typescript class JSONLogicAdapter implements QueryEvaluationPort { async evaluate(expression: any, data?: any): Promise<any> async isValidExpression(expression: any): Promise<boolean> async extractVariables(expression: any): Promise<string[]> getCacheStats(): CacheStats clearCache(): void } ``` ## Security Features ### Strict Mode In strict mode, the adapter: - Removes potentially dangerous operations - Validates all expressions before evaluation - Prevents access to prototype chains - Blocks eval-like operations ### Expression Sanitization ```typescript // Dangerous expressions are automatically removed const dangerousExpr = { 'eval': 'process.exit(1)' // This would be filtered out }; const safeExpr = await adapter.sanitizeExpression(dangerousExpr); // Returns: {} (empty object) ``` ### Variable Extraction ```typescript // Extract variables used in an expression const variables = await adapter.extractVariables({ 'and': [ { '>=': [{ 'var': 'age' }, 18] }, { '==': [{ 'var': 'citizenship' }, 'US'] } ] }); console.log('Variables used:', variables); // ['age', 'citizenship'] ``` ## Advanced Usage ### Custom Operations ```typescript const adapter = await createJSONLogicAdapter({ allowCustomOperations: true }); // Note: Custom operations should be added carefully for security ``` ### Cache Monitoring ```typescript const stats = adapter.getCacheStats(); console.log('Cache usage:', { logicCache: stats.logicCache, varCache: stats.varCache, pathCache: stats.pathCache }); // Clear cache if needed adapter.clearCache(); ``` ### Expression Validation ```typescript const isValid = await adapter.isValidExpression({ '>=': [{ 'var': 'age' }, 18] }); if (!isValid) { throw new Error('Invalid JSONLogic expression'); } ``` ## Error Handling ```typescript try { const result = await adapter.evaluate(expression, data); } catch (error) { if (error.message.includes('Unknown operator')) { console.log('Unsupported operation in expression'); } else if (error.message.includes('Division by zero')) { console.log('Mathematical error in expression'); } } ``` ## Best Practices 1. **Cache Management**: Monitor cache usage in long-running applications 2. **Expression Validation**: Always validate expressions from untrusted sources 3. **Security Mode**: Use strict mode in production environments 4. **Variable Extraction**: Pre-validate that required data is available 5. **Performance**: Use the adapter's optimizations for high-volume scenarios ## Migration from jsonlogic-js The adapter is designed as a drop-in replacement for jsonlogic-js: ```typescript // Old import jsonLogic from 'jsonlogic-js'; const result = jsonLogic.apply(rule, data); // New import { createJSONLogicAdapter } from '@vqp/evaluation-jsonlogic'; const adapter = await createJSONLogicAdapter(); const result = await adapter.evaluate(rule, data); ``` ## Integration with VQP The adapter seamlessly integrates with VQP queries: ```typescript // VQP automatically uses this adapter for query evaluation const query = { id: crypto.randomUUID(), version: '1.0.0', timestamp: new Date().toISOString(), requester: 'did:web:example.com', query: { lang: 'jsonlogic@1.0.0', vocab: 'vqp:identity:v1', expr: { '>=': [{ 'var': 'age' }, 18] } } }; const response = await vqpService.processQuery(query); ``` ## License MIT