UNPKG

defarm-sdk

Version:

DeFarm SDK - Git for traceability with multi-role permissions and global item discovery for agriculture supply chain

987 lines (828 loc) 29.5 kB
const fs = require('fs').promises; const { ModuleSystem } = require('./lib/module-system'); const { DatabaseManager } = require('./lib/db-manager'); const { QueueManager } = require('./lib/queue-manager'); const { BlockchainEngine } = require('./lib/engines/blockchain-engine'); const { TokenizationEngine } = require('./lib/engines/tokenization-engine'); const { TokenizationRelay } = require('./lib/engines/tokenization-relay'); const { VerificationEngine } = require('./lib/engines/verification-engine'); const { ProvenanceEngine } = require('./lib/engines/provenance-engine'); const { APIKeyManager } = require('./lib/auth/api-key-manager'); // Enterprise adapters and services (mocks included for testing) const { PostgreSQLAdapter, OracleAdapter, SQLServerAdapter } = require('./lib/adapters'); const { ValidationService, PremiumAPIClient, ICPBrasilIntegration, DeFarmServicesClient, LivestockProcessor, CropsProcessor } = require('./lib/core'); // Import WASM processor when ready let wasmProcessor = null; let wasmProcessorWarningShown = false; function showWasmWarning() { if (!wasmProcessorWarningShown) { console.warn('⚠️ WASM processor not built yet. Run: npm run build:wasm'); wasmProcessorWarningShown = true; } } try { wasmProcessor = require('./pkg/defarm_processor.js'); } catch (e) { // Only show warning when WASM processor is actually needed if (!process.argv.includes('--version') && !process.argv.includes('-v')) { showWasmWarning(); } } /** * DeFarm SDK - Main entry point * * On-premise SDK for agriculture supply chain management with blockchain integration */ class DeFarmSDK { constructor(config = {}) { this.config = { environment: config.environment || process.env.DEFARM_ENV || 'production', apiKey: config.apiKey || process.env.DEFARM_API_KEY || this.loadAPIKeyFromConfig(), database: config.database || this.loadDatabaseConfig(), blockchain: config.blockchain || this.loadBlockchainConfig(), ipfs: config.ipfs || this.loadIPFSConfig(), queue: config.queue || { enabled: true, workers: 4 }, modules: config.modules || ['core', 'agriculture', 'blockchain', 'tokenization'], relay: config.relay || { enabled: true, url: process.env.DEFARM_RELAY_URL }, enterprise: config.enterprise || { enabled: true }, deploymentMode: config.deploymentMode || 'hybrid', // 'on-premise', 'cloud', 'hybrid' auth: config.auth || { required: false, offlineMode: true }, ...config }; // Initialize core systems this.moduleSystem = new ModuleSystem(); this.dbManager = null; this.queueManager = null; this.blockchainEngine = null; this.tokenizationEngine = null; this.tokenizationRelay = null; // Enterprise services this.validationService = null; this.premiumAPIClient = null; this.icpBrasilIntegration = null; this.servicesClient = null; // Core engines this.verificationEngine = null; this.provenanceEngine = null; // Enterprise processors this.processors = new Map(); // Enterprise database adapters this.dbAdapter = null; // API Key Manager for authentication this.authManager = null; this.initialized = false; } /** * Initialize the SDK */ async initialize() { if (this.initialized) return; console.log('🚀 Initializing DeFarm SDK...'); // Initialize authentication first if (this.config.auth.required || this.config.apiKey) { await this.initializeAuth(); } // Load modules await this.loadModules(); // Initialize database with appropriate adapter if (this.config.database.enabled !== false) { await this.initializeDatabase(); } // Initialize queue system if configured if (this.config.queue.enabled) { this.queueManager = new QueueManager(this.config.queue); await this.queueManager.initialize(); } // Initialize blockchain engine (optional) if (this.config.blockchain.enabled !== false) { try { this.blockchainEngine = new BlockchainEngine(this.config.blockchain); await this.blockchainEngine.initialize(); } catch (error) { console.warn(`⚠️ Blockchain engine initialization failed: ${error.message}`); this.blockchainEngine = null; } } // Initialize tokenization engines this.tokenizationEngine = new TokenizationEngine({ blockchain: this.blockchainEngine, database: this.dbManager }); // Initialize relay tokenization for gas-free operations if (this.config.relay.enabled) { this.tokenizationRelay = new TokenizationRelay({ relayUrl: this.config.relay.url, apiKey: this.config.relay.apiKey }); } // Initialize core engines this.verificationEngine = new VerificationEngine({ database: this.dbManager, strictMode: this.config.enterprise.strictValidation || true }); this.provenanceEngine = new ProvenanceEngine({ database: this.dbManager, blockchain: this.blockchainEngine, enableBlockchain: this.config.blockchain.enabled }); // Initialize provenance database tables await this.provenanceEngine.initializeDatabase(); // Initialize enterprise services if enabled if (this.config.enterprise.enabled) { await this.initializeEnterpriseServices(); } this.initialized = true; console.log('✅ DeFarm SDK initialized successfully'); } /** * Initialize authentication manager */ async initializeAuth() { this.authManager = new APIKeyManager({ apiEndpoint: this.config.auth.apiEndpoint, offlineMode: this.config.auth.offlineMode, cacheTimeout: this.config.auth.cacheTimeout }); // Validate API key if provided if (this.config.apiKey) { try { const validation = await this.authManager.validateAPIKey(this.config.apiKey); console.log(`✅ API Key validated - Plan: ${validation.plan}`); // Show usage stats const stats = await this.authManager.getUsageStats(this.config.apiKey); console.log(`📊 Usage: ${stats.usage.tokenizations.used}/${stats.usage.tokenizations.limit || '∞'} tokenizations`); } catch (error) { if (this.config.auth.required) { throw new Error(`API Key validation failed: ${error.message}`); } else { console.warn(`⚠️ API Key validation failed: ${error.message} - continuing in limited mode`); } } } else if (this.config.auth.required && this.config.deploymentMode !== 'on-premise') { console.warn('⚠️ No API key provided - some features will be limited'); console.log('💡 Get your API key at https://defarm.io/dashboard'); } } /** * Load configured modules */ async loadModules() { const modules = this.config.modules; for (const moduleName of modules) { try { const module = require(`./lib/modules/${moduleName}`); this.moduleSystem.register(moduleName, module); } catch (error) { console.warn(`⚠️ Module '${moduleName}' not found or failed to load`); } } console.log(`📦 Loaded ${this.moduleSystem.list().length} modules`); } /** * Process agricultural data with blockchain integration */ async processAgricultureData(data, options = {}) { await this.ensureInitialized(); // Check API key and usage limits if (this.authManager && this.config.apiKey) { await this.authManager.checkUsageLimit(this.config.apiKey, 'processings'); } const processOptions = { tokenize: options.tokenize !== false, blockchain: options.blockchain !== false, ipfs: options.ipfs !== false, validate: options.validate !== false, async: options.async || false, ...options }; // If async processing requested, queue the job if (processOptions.async && this.queueManager) { return await this.queueManager.addJob('process-agriculture', { data, options: processOptions }); } // Execute processing pipeline const pipeline = await this.createProcessingPipeline(processOptions); return await pipeline.execute(data); } /** * Create asset token on blockchain * Supports both direct (with private key) and relay (gas-free) modes */ async createAssetToken(assetData, options = {}) { await this.ensureInitialized(); // Check API key and tokenization limits if (this.authManager && this.config.apiKey) { await this.authManager.checkUsageLimit(this.config.apiKey, 'tokenizations'); // Check if tokenization feature is available const hasFeature = await this.authManager.hasFeature(this.config.apiKey, 'tokenization'); if (!hasFeature) { throw new Error('Tokenization not available in your plan. Upgrade at https://defarm.io/pricing'); } } else if (!this.config.auth.offlineMode) { throw new Error('API key required for tokenization. Get yours at https://defarm.io/dashboard'); } // Use relay for gas-free tokenization if configured if (this.config.relay.enabled && !options.directMode) { if (!this.tokenizationRelay) { throw new Error('Tokenization relay not initialized'); } return await this.tokenizationRelay.requestTokenization( assetData, options.clientWallet || assetData.owner_wallet, options ); } // Traditional tokenization with private key if (!this.tokenizationEngine) { throw new Error('Tokenization engine not initialized'); } return await this.tokenizationEngine.createToken(assetData, options); } /** * Track supply chain event */ async trackSupplyChainEvent(eventData, options = {}) { await this.ensureInitialized(); // Validate event data const validatedData = await this.validateEventData(eventData); // Store in local database if (this.dbManager) { await this.dbManager.storeEvent(validatedData); } // Record on blockchain if configured if (this.config.blockchain.enabled && options.blockchain !== false) { await this.blockchainEngine.recordEvent(validatedData); } // Store metadata on IPFS if configured if (this.config.ipfs.enabled && options.ipfs !== false) { const ipfsHash = await this.storeOnIPFS(validatedData); validatedData.ipfsHash = ipfsHash; } return validatedData; } /** * Query agriculture data */ async queryData(query, options = {}) { await this.ensureInitialized(); if (!this.dbManager) { throw new Error('Database not configured'); } return await this.dbManager.query(query, options); } /** * Get asset history from blockchain */ async getAssetHistory(assetId, options = {}) { await this.ensureInitialized(); const history = []; // Get from local database if (this.dbManager) { const dbHistory = await this.dbManager.getAssetHistory(assetId); history.push(...dbHistory); } // Get from blockchain if (this.blockchainEngine && options.blockchain !== false) { const blockchainHistory = await this.blockchainEngine.getAssetHistory(assetId); history.push(...blockchainHistory); } // Sort by timestamp history.sort((a, b) => a.timestamp - b.timestamp); return history; } /** * Verify data integrity */ async verifyIntegrity(data, hash, options = {}) { if (!wasmProcessor || !wasmProcessor.verify_hash) { throw new Error('WASM processor not available. Run: npm run build:wasm'); } return wasmProcessor.verify_hash(JSON.stringify(data), hash); } /** * Generate compliance report */ async generateComplianceReport(criteria, options = {}) { await this.ensureInitialized(); const report = { timestamp: new Date().toISOString(), criteria, results: {}, recommendations: [] }; // Run compliance checks through modules const complianceResults = await this.moduleSystem.executeHook('compliance:check', { criteria, options }); report.results = complianceResults; // Generate recommendations const recommendations = await this.moduleSystem.executeHook('compliance:recommend', { results: complianceResults, criteria }); report.recommendations = recommendations; return report; } /** * Export data in various formats */ async exportData(query, format = 'json', options = {}) { await this.ensureInitialized(); const data = await this.queryData(query, options); switch (format.toLowerCase()) { case 'json': return JSON.stringify(data, null, 2); case 'csv': return this.convertToCSV(data); case 'xml': return this.convertToXML(data); case 'blockchain': return await this.exportToBlockchain(data, options); default: throw new Error(`Unsupported export format: ${format}`); } } /** * Get SDK statistics */ async getStatistics() { await this.ensureInitialized(); const stats = { modules: this.moduleSystem.list(), database: this.dbManager ? await this.dbManager.getStats() : null, queue: this.queueManager ? await this.queueManager.getStats() : null, blockchain: this.blockchainEngine ? await this.blockchainEngine.getStats() : null, usage: null }; // Add usage statistics if authenticated if (this.authManager && this.config.apiKey) { try { stats.usage = await this.authManager.getUsageStats(this.config.apiKey); } catch (error) { stats.usage = { error: error.message }; } } return stats; } /** * Get current API key usage and limits */ async getUsage() { if (!this.authManager || !this.config.apiKey) { throw new Error('API key required to get usage statistics'); } return await this.authManager.getUsageStats(this.config.apiKey); } // Private helper methods async ensureInitialized() { if (!this.initialized) { await this.initialize(); } } loadDatabaseConfig() { const dbType = process.env.DEFARM_DB_TYPE || 'sqlite'; // Default to SQLite for easier setup and testing if (dbType === 'sqlite') { return { type: 'sqlite', database: process.env.DEFARM_DB_NAME || './defarm_sdk.db', // SQLite doesn't need host/port/user/password }; } // Configuration for other database types return { type: dbType, host: process.env.DEFARM_DB_HOST || 'localhost', port: process.env.DEFARM_DB_PORT || (dbType === 'postgresql' ? 5432 : dbType === 'mysql' ? 3306 : 1433), database: process.env.DEFARM_DB_NAME || 'defarm_sdk', user: process.env.DEFARM_DB_USER || 'defarm', password: process.env.DEFARM_DB_PASSWORD || '', ssl: process.env.DEFARM_DB_SSL === 'true' }; } loadBlockchainConfig() { return { enabled: process.env.DEFARM_BLOCKCHAIN_ENABLED !== 'false', network: process.env.DEFARM_BLOCKCHAIN_NETWORK || 'polygon', rpcUrl: process.env.DEFARM_RPC_URL, privateKey: process.env.DEFARM_PRIVATE_KEY, contractAddress: process.env.DEFARM_CONTRACT_ADDRESS }; } loadIPFSConfig() { return { enabled: process.env.DEFARM_IPFS_ENABLED !== 'false', host: process.env.DEFARM_IPFS_HOST || 'ipfs.infura.io', port: process.env.DEFARM_IPFS_PORT || 5001, protocol: process.env.DEFARM_IPFS_PROTOCOL || 'https' }; } loadAPIKeyFromConfig() { try { const os = require('os'); const path = require('path'); const fs = require('fs'); const configPath = path.join(os.homedir(), '.defarm', 'config.json'); if (fs.existsSync(configPath)) { const config = JSON.parse(fs.readFileSync(configPath, 'utf-8')); return config.apiKey || null; } } catch (e) { // Ignore errors, will use without API key } return null; } async createProcessingPipeline(options) { const pipeline = { steps: [], execute: async function(data) { let result = data; for (const step of this.steps) { result = await step(result); } return result; } }; // Add validation step if (options.validate) { pipeline.steps.push(async (data) => { return await this.validateAgricultureData(data); }); } // Add tokenization step if (options.tokenize) { pipeline.steps.push(async (data) => { data.token = await this.tokenizationEngine.generateToken(data); return data; }); } // Add blockchain step if (options.blockchain) { pipeline.steps.push(async (data) => { data.blockchainTx = await this.blockchainEngine.recordData(data); return data; }); } // Add IPFS step if (options.ipfs) { pipeline.steps.push(async (data) => { data.ipfsHash = await this.storeOnIPFS(data); return data; }); } return pipeline; } async validateAgricultureData(data) { // Run validation through WASM processor if available if (wasmProcessor && wasmProcessor.validate_agriculture_data) { const validationResult = wasmProcessor.validate_agriculture_data(JSON.stringify(data)); const result = JSON.parse(validationResult); if (!result.valid) { throw new Error(`Validation failed: ${result.errors.join(', ')}`); } } // Run module validations return await this.moduleSystem.executeHook('validate:agriculture', data); } async validateEventData(eventData) { // Basic validation if (!eventData.type) throw new Error('Event type is required'); if (!eventData.timestamp) eventData.timestamp = Date.now(); if (!eventData.id) eventData.id = this.generateId(); // Module-specific validation return await this.moduleSystem.executeHook('validate:event', eventData); } async storeOnIPFS(data) { // IPFS storage implementation would go here // For now, return a mock hash const crypto = require('crypto'); return crypto.createHash('sha256').update(JSON.stringify(data)).digest('hex'); } convertToCSV(data) { if (!Array.isArray(data) || data.length === 0) return ''; const headers = Object.keys(data[0]); const rows = data.map(item => headers.map(header => { const value = item[header]; return typeof value === 'string' && value.includes(',') ? `"${value}"` : value; }).join(',') ); return [headers.join(','), ...rows].join('\n'); } convertToXML(data) { const toXML = (obj, rootName = 'root') => { let xml = `<?xml version="1.0" encoding="UTF-8"?>\n<${rootName}>`; const convertObject = (o, indent = ' ') => { let result = ''; for (const [key, value] of Object.entries(o)) { if (value === null || value === undefined) continue; result += `\n${indent}<${key}>`; if (typeof value === 'object' && !Array.isArray(value)) { result += convertObject(value, indent + ' '); result += `\n${indent}`; } else if (Array.isArray(value)) { for (const item of value) { result += `\n${indent} <item>`; if (typeof item === 'object') { result += convertObject(item, indent + ' '); result += `\n${indent} `; } else { result += item; } result += `</item>`; } result += `\n${indent}`; } else { result += value; } result += `</${key}>`; } return result; }; if (Array.isArray(data)) { for (const item of data) { xml += '\n <item>'; xml += convertObject(item, ' '); xml += '\n </item>'; } } else { xml += convertObject(data); } xml += `\n</${rootName}>`; return xml; }; return toXML(data, 'defarm-data'); } async exportToBlockchain(data, options) { if (!this.blockchainEngine) { throw new Error('Blockchain engine not initialized'); } const batchSize = options.batchSize || 100; const results = []; // Process in batches to avoid gas limits for (let i = 0; i < data.length; i += batchSize) { const batch = data.slice(i, i + batchSize); const tx = await this.blockchainEngine.batchRecord(batch); results.push(tx); } return results; } generateId() { return require('uuid').v4(); } /** * Initialize database with appropriate adapter based on config */ async initializeDatabase() { const dbType = this.config.database.type; switch (dbType) { case 'postgresql': this.dbAdapter = new PostgreSQLAdapter(this.config.database); await this.dbAdapter.connect(); this.dbManager = new DatabaseManager({ ...this.config.database, adapter: this.dbAdapter }); break; case 'oracle': this.dbAdapter = new OracleAdapter(this.config.database); await this.dbAdapter.connect(); this.dbManager = new DatabaseManager({ ...this.config.database, adapter: this.dbAdapter }); break; case 'sqlserver': this.dbAdapter = new SQLServerAdapter(this.config.database); await this.dbAdapter.connect(); this.dbManager = new DatabaseManager({ ...this.config.database, adapter: this.dbAdapter }); break; case 'sqlite': default: // Use default database manager for SQLite and other types (includes SQLite support) this.dbManager = new DatabaseManager(this.config.database); break; } await this.dbManager.initialize(); } /** * Initialize enterprise services */ async initializeEnterpriseServices() { // Validation service this.validationService = new ValidationService({ strict: this.config.enterprise.strictValidation || true, schemas: this.config.enterprise.validationSchemas }); // Premium API client for cloud features if (this.config.enterprise.premiumAPI) { this.premiumAPIClient = new PremiumAPIClient({ apiKey: this.config.enterprise.apiKey, endpoint: this.config.enterprise.apiEndpoint }); } // ICP-Brasil integration for Brazilian compliance if (this.config.enterprise.icpBrasil) { this.icpBrasilIntegration = new ICPBrasilIntegration({ certificatePath: this.config.enterprise.icpCertPath }); } // DeFarm services client if (this.config.enterprise.servicesEnabled) { this.servicesClient = new DeFarmServicesClient({ apiKey: this.config.enterprise.apiKey, environment: this.config.environment }); } // Initialize processors this.processors.set('livestock', new LivestockProcessor()); this.processors.set('crops', new CropsProcessor()); console.log('✅ Enterprise services initialized'); } /** * Process data with specific processor */ async processWithProcessor(type, data, options = {}) { await this.ensureInitialized(); const processor = this.processors.get(type.toLowerCase()); if (!processor) { throw new Error(`Processor for type '${type}' not found`); } return await processor.process(data, options); } /** * Validate data with enterprise validation service */ async validateWithSchema(data, schema, options = {}) { if (!this.validationService) { throw new Error('Validation service not initialized'); } return await this.validationService.validate(data, schema, options); } /** * Validate asset data with WASM-protected algorithms */ async validateAsset(assetData, options = {}) { if (!this.verificationEngine) { throw new Error('Verification engine not initialized'); } // Record validation attempt in provenance if (this.provenanceEngine && options.recordProvenance !== false) { await this.provenanceEngine.recordEvent( assetData.asset_id || assetData.id, 'validation_attempt', { validation_type: 'asset_data' }, { actor: options.actor || 'system' } ); } return await this.verificationEngine.validateAsset(assetData); } /** * Check for duplicates using protected ML algorithms */ async checkForDuplicates(newAsset, options = {}) { if (!this.verificationEngine) { throw new Error('Verification engine not initialized'); } // Get existing assets from database if not provided let existingAssets = options.existingAssets || []; if (existingAssets.length === 0 && this.dbManager) { existingAssets = await this.dbManager.query( 'SELECT * FROM assets WHERE organization_id = $1 AND asset_type = $2', [options.organizationId || newAsset.organization_id, newAsset.asset_type] ); } const result = await this.verificationEngine.checkDuplicates(newAsset, existingAssets); // Record duplicate check in provenance if (this.provenanceEngine && options.recordProvenance !== false) { await this.provenanceEngine.recordEvent( newAsset.asset_id || newAsset.id, 'duplicate_check', { isDuplicate: result.isDuplicate, confidence: result.confidence, matches: result.exactMatches.length + result.potentialMatches.length }, { actor: options.actor || 'system' } ); } return result; } /** * Get complete provenance chain for asset */ async getProvenanceChain(assetId, options = {}) { if (!this.provenanceEngine) { throw new Error('Provenance engine not initialized'); } return await this.provenanceEngine.getProvenanceChain(assetId, options); } /** * Record provenance event */ async recordProvenanceEvent(assetId, eventType, eventData, options = {}) { if (!this.provenanceEngine) { throw new Error('Provenance engine not initialized'); } return await this.provenanceEngine.recordEvent(assetId, eventType, eventData, options); } /** * Check for duplicates using DeFarm services */ async checkDuplicates(data, options = {}) { if (!this.servicesClient) { throw new Error('Services client not initialized'); } return await this.servicesClient.checkDuplicates(data, options); } /** * Sign data with ICP-Brasil certificate */ async signWithICPBrasil(data, options = {}) { if (!this.icpBrasilIntegration) { throw new Error('ICP-Brasil integration not initialized'); } return await this.icpBrasilIntegration.sign(data, options); } /** * Get enhanced analytics using premium API */ async getAnalytics(query, options = {}) { if (!this.premiumAPIClient) { throw new Error('Premium API client not initialized'); } return await this.premiumAPIClient.getAnalytics(query, options); } /** * Switch between deployment modes */ async setDeploymentMode(mode) { if (!['on-premise', 'cloud', 'hybrid'].includes(mode)) { throw new Error('Invalid deployment mode. Use: on-premise, cloud, or hybrid'); } this.config.deploymentMode = mode; // Adjust services based on mode if (mode === 'on-premise') { this.config.relay.enabled = false; this.config.enterprise.premiumAPI = false; } else if (mode === 'cloud') { this.config.relay.enabled = true; this.config.enterprise.premiumAPI = true; } // Reinitialize if needed if (this.initialized) { await this.shutdown(); await this.initialize(); } } /** * Cleanup and shutdown */ async shutdown() { console.log('🔄 Shutting down DeFarm SDK...'); if (this.queueManager) { await this.queueManager.shutdown(); } if (this.dbManager) { await this.dbManager.close(); } if (this.blockchainEngine) { await this.blockchainEngine.disconnect(); } console.log('👋 DeFarm SDK shutdown complete'); } } // Export singleton instance and class const defaultSDK = new DeFarmSDK(); module.exports = { DeFarmSDK, sdk: defaultSDK, initialize: (config) => { Object.assign(defaultSDK.config, config); return defaultSDK.initialize(); }, processAgricultureData: (...args) => defaultSDK.processAgricultureData(...args), createAssetToken: (...args) => defaultSDK.createAssetToken(...args), trackSupplyChainEvent: (...args) => defaultSDK.trackSupplyChainEvent(...args), queryData: (...args) => defaultSDK.queryData(...args), getAssetHistory: (...args) => defaultSDK.getAssetHistory(...args), verifyIntegrity: (...args) => defaultSDK.verifyIntegrity(...args), generateComplianceReport: (...args) => defaultSDK.generateComplianceReport(...args), exportData: (...args) => defaultSDK.exportData(...args), getStatistics: (...args) => defaultSDK.getStatistics(...args) };