defarm-sdk
Version:
DeFarm SDK - On-premise blockchain data processing and tokenization engine for agriculture supply chain
1,611 lines (1,354 loc) • 59.2 kB
JavaScript
#!/usr/bin/env node
const { DeFarmSDK } = require('./index');
const { DatabaseManager } = require('./lib/db-manager');
const fs = require('fs').promises;
const path = require('path');
const readline = require('readline');
const { spawn } = require('child_process');
// ANSI color codes for better CLI experience
const colors = {
reset: '\x1b[0m',
bright: '\x1b[1m',
dim: '\x1b[2m',
red: '\x1b[31m',
green: '\x1b[32m',
yellow: '\x1b[33m',
blue: '\x1b[34m',
magenta: '\x1b[35m',
cyan: '\x1b[36m',
white: '\x1b[37m'
};
// Helper functions for colored output
const log = {
success: (msg) => console.log(`${colors.green}✓${colors.reset} ${msg}`),
error: (msg) => console.log(`${colors.red}✗${colors.reset} ${msg}`),
warning: (msg) => console.log(`${colors.yellow}⚠${colors.reset} ${msg}`),
info: (msg) => console.log(`${colors.blue}ℹ${colors.reset} ${msg}`),
header: (msg) => console.log(`\n${colors.bright}${colors.cyan}${msg}${colors.reset}`),
subheader: (msg) => console.log(`${colors.bright}${msg}${colors.reset}`),
dim: (msg) => console.log(`${colors.dim}${msg}${colors.reset}`)
};
// Progress bar for long operations
class ProgressBar {
constructor(total, label = 'Progress') {
this.total = total;
this.current = 0;
this.label = label;
this.barLength = 30;
}
update(current) {
this.current = current;
const progress = Math.min(this.current / this.total, 1);
const filled = Math.round(this.barLength * progress);
const empty = this.barLength - filled;
const bar = '█'.repeat(filled) + '░'.repeat(empty);
const percent = (progress * 100).toFixed(1);
process.stdout.write(`\r${this.label}: [${bar}] ${percent}% (${this.current}/${this.total})`);
if (this.current >= this.total) {
console.log();
}
}
complete() {
this.update(this.total);
}
}
// Interactive prompt helper
async function prompt(question, defaultValue = '') {
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
return new Promise((resolve) => {
const questionText = defaultValue
? `${question} ${colors.dim}(${defaultValue})${colors.reset}: `
: `${question}: `;
rl.question(questionText, (answer) => {
rl.close();
resolve(answer || defaultValue);
});
});
}
// Select from options
async function select(question, options) {
console.log(`\n${question}`);
options.forEach((opt, i) => {
console.log(` ${colors.cyan}${i + 1})${colors.reset} ${opt.label || opt}`);
});
const answer = await prompt('Select option', '1');
const index = parseInt(answer) - 1;
if (index >= 0 && index < options.length) {
return options[index].value || options[index];
}
log.error('Invalid selection');
return select(question, options);
}
// Confirm action
async function confirm(question) {
const answer = await prompt(`${question} (y/N)`, 'n');
return answer.toLowerCase() === 'y' || answer.toLowerCase() === 'yes';
}
// ASCII Art Banner
const DEFARM_BANNER = `
${colors.green}
██████╗ ███████╗███████╗ █████╗ ██████╗ ███╗ ███╗
██╔══██╗██╔════╝██╔════╝██╔══██╗██╔══██╗████╗ ████║
██║ ██║█████╗ █████╗ ███████║██████╔╝██╔████╔██║
██║ ██║██╔══╝ ██╔══╝ ██╔══██║██╔══██╗██║╚██╔╝██║
██████╔╝███████╗██║ ██║ ██║██║ ██║██║ ╚═╝ ██║
╚═════╝ ╚══════╝╚═╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═╝
${colors.reset}
${colors.cyan} 🌾 Agricultural Blockchain Infrastructure Platform${colors.reset}
${colors.dim}
• On-premise data processing with blockchain tokenization
• Gas-free transactions sponsored by DeFarm
• Enterprise-grade security with WASM protection
• Complete supply chain traceability
${colors.reset}
`;
const INTERACTIVE_MENU = `
${colors.bright}Available Actions:${colors.reset}
${colors.green}🚀 Quick Start${colors.reset}
${colors.cyan}1)${colors.reset} ${colors.bright}dashboard${colors.reset} Start web dashboard
${colors.cyan}2)${colors.reset} ${colors.bright}init${colors.reset} Initialize new project
${colors.cyan}3)${colors.reset} ${colors.bright}validate${colors.reset} Validate configuration
${colors.magenta}🔐 Authentication${colors.reset}
${colors.cyan}4)${colors.reset} ${colors.bright}login${colors.reset} Login to DeFarm account
${colors.cyan}5)${colors.reset} ${colors.bright}logout${colors.reset} Logout from DeFarm
${colors.cyan}6)${colors.reset} ${colors.bright}apikey${colors.reset} Manage API keys
${colors.blue}🔧 Development${colors.reset}
${colors.cyan}7)${colors.reset} ${colors.bright}monitor${colors.reset} Real-time monitoring
${colors.cyan}8)${colors.reset} ${colors.bright}test${colors.reset} Run integration tests
${colors.cyan}9)${colors.reset} ${colors.bright}benchmark${colors.reset} Performance tests
${colors.yellow}⚙️ Management${colors.reset}
${colors.cyan}10)${colors.reset} ${colors.bright}migrate${colors.reset} Migrate existing data
${colors.cyan}11)${colors.reset} ${colors.bright}doctor${colors.reset} Diagnose system issues
${colors.cyan}12)${colors.reset} ${colors.bright}config${colors.reset} Manage configuration
${colors.red}Other${colors.reset}
${colors.cyan}h)${colors.reset} Help ${colors.cyan}q)${colors.reset} Quit
`;
/**
* Interactive CLI Interface
*/
async function startInteractiveMode() {
console.clear();
console.log(DEFARM_BANNER);
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
while (true) {
console.log(INTERACTIVE_MENU);
const choice = await new Promise(resolve => {
rl.question(`${colors.green}❯${colors.reset} Select an option: `, resolve);
});
console.log(''); // Add spacing
switch (choice.toLowerCase().trim()) {
case '1':
case 'dashboard':
await commands.dashboard.handler({});
break;
case '2':
case 'init':
await commands.init.handler({});
break;
case '3':
case 'validate':
await commands.validate.handler({});
break;
case '4':
case 'login':
await commands.login.handler({});
break;
case '5':
case 'logout':
await commands.logout.handler({});
break;
case '6':
case 'apikey':
await commands.apikey.handler({});
break;
case '7':
case 'monitor':
await commands.monitor.handler({});
break;
case '8':
case 'test':
await commands.test.handler({});
break;
case '9':
case 'benchmark':
await commands.benchmark.handler({});
break;
case '10':
case 'migrate':
await commands.migrate.handler({});
break;
case '11':
case 'doctor':
await commands.doctor.handler({});
break;
case '12':
case 'config':
console.log('🔧 Configuration management coming soon...');
break;
case 'h':
case 'help':
commands.help.handler({});
break;
case 'q':
case 'quit':
case 'exit':
console.log(`${colors.green}👋 Thanks for using DeFarm SDK!${colors.reset}`);
rl.close();
process.exit(0);
break;
default:
console.log(`${colors.red}❌ Unknown option: "${choice}"${colors.reset}\n`);
break;
}
// Wait for user to press enter before showing menu again
await new Promise(resolve => {
rl.question(`\n${colors.dim}Press Enter to continue...${colors.reset}`, resolve);
});
console.clear();
console.log(DEFARM_BANNER);
}
}
/**
* DeFarm SDK CLI - Enhanced Version
*/
const commands = {
interactive: {
description: 'Start interactive mode',
usage: 'defarm interactive',
handler: startInteractiveMode
},
dashboard: {
description: 'Start the web dashboard',
usage: 'defarm dashboard [--port 3456]',
handler: async (args) => {
try {
const { DashboardServer } = require('./lib/dashboard/server');
const port = args.port ? parseInt(args.port) : 3456;
log.header('Starting DeFarm Dashboard...');
const server = new DashboardServer(port);
await server.start();
log.success(`Dashboard running at http://localhost:${port}`);
log.info('Press Ctrl+C to stop');
// Keep process alive
process.on('SIGINT', async () => {
log.info('\nStopping dashboard...');
await server.stop();
process.exit(0);
});
// Keep the process running
await new Promise(() => {});
} catch (error) {
log.error(`Failed to start dashboard: ${error.message}`);
process.exit(1);
}
}
},
init: {
description: 'Initialize a new DeFarm project',
usage: 'defarm init [project-name]',
handler: async (args) => {
log.header('🚀 Initialize DeFarm Project');
const projectName = args._[0] || await prompt('Project name', 'my-defarm-project');
const projectPath = path.join(process.cwd(), projectName);
// Check if directory exists
try {
await fs.access(projectPath);
if (!await confirm(`Directory ${projectName} already exists. Continue?`)) {
return;
}
} catch {
await fs.mkdir(projectPath, { recursive: true });
}
// Select deployment mode
const deploymentMode = await select('Select deployment mode:', [
{ label: 'On-premise (100% isolated)', value: 'on-premise' },
{ label: 'Cloud (SaaS with gas-free blockchain)', value: 'cloud' },
{ label: 'Hybrid (Local processing + cloud features)', value: 'hybrid' }
]);
// Select database
const database = await select('Select database type:', [
{ label: 'PostgreSQL', value: 'postgresql' },
{ label: 'MySQL', value: 'mysql' },
{ label: 'Oracle', value: 'oracle' },
{ label: 'SQL Server', value: 'sqlserver' },
{ label: 'SQLite (for testing)', value: 'sqlite' }
]);
// Select blockchain network
let blockchain = 'none';
if (deploymentMode !== 'on-premise') {
blockchain = await select('Select blockchain network:', [
{ label: 'Stellar (Recommended - lowest fees)', value: 'stellar' },
{ label: 'Polygon', value: 'polygon' },
{ label: 'Ethereum', value: 'ethereum' },
{ label: 'None (disable blockchain)', value: 'none' }
]);
}
// Generate configuration files
log.info('Generating configuration files...');
// package.json
const packageJson = {
name: projectName,
version: '1.0.0',
description: 'DeFarm SDK Project',
main: 'index.js',
scripts: {
'start': 'node index.js',
'dev': 'nodemon index.js',
'test': 'jest',
'validate': 'defarm validate',
'process': 'defarm process',
'monitor': 'defarm monitor'
},
dependencies: {
'defarm-sdk': '^1.0.2'
},
devDependencies: {
'nodemon': '^3.0.0',
'jest': '^29.0.0'
}
};
await fs.writeFile(
path.join(projectPath, 'package.json'),
JSON.stringify(packageJson, null, 2)
);
// .env file
const envContent = `# DeFarm SDK Configuration
# Generated by: defarm init
# Deployment Mode
DEFARM_DEPLOYMENT_MODE=${deploymentMode}
# Database Configuration
DEFARM_DB_TYPE=${database}
DEFARM_DB_HOST=localhost
DEFARM_DB_PORT=${database === 'postgresql' ? 5432 : database === 'mysql' ? 3306 : 1433}
DEFARM_DB_NAME=${projectName.replace(/-/g, '_')}_db
DEFARM_DB_USER=defarm_user
DEFARM_DB_PASSWORD=change_this_password
# Blockchain Configuration
DEFARM_BLOCKCHAIN_ENABLED=${blockchain !== 'none'}
DEFARM_BLOCKCHAIN_NETWORK=${blockchain}
${blockchain === 'stellar' ? `DEFARM_STELLAR_NETWORK=testnet
DEFARM_STELLAR_HORIZON=https://horizon-testnet.stellar.org` : ''}
${blockchain !== 'none' && blockchain !== 'stellar' ? `DEFARM_RPC_URL=
DEFARM_PRIVATE_KEY=your_private_key_here
DEFARM_CONTRACT_ADDRESS=` : ''}
# Relay Configuration (for gas-free transactions)
${deploymentMode !== 'on-premise' ? `DEFARM_RELAY_ENABLED=true
DEFARM_RELAY_URL=https://relay.defarm.io
DEFARM_RELAY_API_KEY=request_at_defarm.io` : 'DEFARM_RELAY_ENABLED=false'}
# IPFS Configuration
DEFARM_IPFS_ENABLED=${deploymentMode !== 'on-premise'}
DEFARM_IPFS_HOST=ipfs.infura.io
DEFARM_IPFS_PORT=5001
DEFARM_IPFS_PROTOCOL=https
# Enterprise Features
DEFARM_ENTERPRISE_ENABLED=true
DEFARM_STRICT_VALIDATION=true
# Monitoring
DEFARM_MONITORING_ENABLED=true
DEFARM_MONITORING_PORT=9090
`;
await fs.writeFile(path.join(projectPath, '.env'), envContent);
// defarm.config.js
const configJs = `/**
* DeFarm SDK Configuration
* @type {import('defarm-sdk').DeFarmConfig}
*/
module.exports = {
// Deployment mode: 'on-premise', 'cloud', or 'hybrid'
deploymentMode: '${deploymentMode}',
// Database configuration
database: {
type: '${database}',
// Additional database options
connectionPool: {
min: 2,
max: 10
}
},
// Blockchain configuration
blockchain: {
enabled: ${blockchain !== 'none'},
network: '${blockchain}',
// Gas sponsorship via relay
useRelay: ${deploymentMode !== 'on-premise'}
},
// Processing options
processing: {
// Use WASM for protected business logic
useWasm: true,
// Batch size for bulk operations
batchSize: 100,
// Concurrent workers
workers: 4
},
// Verification settings
verification: {
// Duplicate detection threshold
duplicateThreshold: 0.85,
// Strict mode for validation
strictMode: true
},
// Provenance tracking
provenance: {
// Enable blockchain recording
blockchain: ${blockchain !== 'none'},
// Hash algorithm
hashAlgorithm: 'sha256'
},
// API settings
api: {
// Enable REST API
enabled: true,
port: 3000,
// CORS settings
cors: {
origin: '*',
credentials: true
}
},
// Monitoring
monitoring: {
enabled: true,
// Metrics export
metrics: {
format: 'prometheus',
port: 9090
},
// Health check endpoint
healthCheck: {
enabled: true,
path: '/health'
}
},
// Custom modules
modules: {
// Add your custom modules here
}
};
`;
await fs.writeFile(path.join(projectPath, 'defarm.config.js'), configJs);
// index.js - main application file
const indexJs = `const { DeFarmSDK } = require('defarm-sdk');
const config = require('./defarm.config');
async function main() {
console.log('🌾 Starting DeFarm SDK Application...');
// Initialize SDK
const sdk = new DeFarmSDK(config);
await sdk.initialize();
console.log('✅ SDK initialized successfully');
// Example: Process agriculture data
const exampleData = {
asset_type: 'livestock',
breed: 'Angus',
weight: 450,
location: {
latitude: -23.550520,
longitude: -46.633308,
country: 'Brazil'
}
};
// Validate data
const validation = await sdk.validateAsset(exampleData);
console.log('Validation result:', validation);
// Check for duplicates
const duplicates = await sdk.checkForDuplicates(exampleData);
console.log('Duplicate check:', duplicates);
// Process and tokenize
const result = await sdk.processAgricultureData(exampleData, {
tokenize: true,
recordProvenance: true
});
console.log('Processing result:', result);
// Start API server if configured
if (config.api?.enabled) {
const express = require('express');
const app = express();
app.use(express.json());
app.post('/process', async (req, res) => {
try {
const result = await sdk.processAgricultureData(req.body);
res.json(result);
} catch (error) {
res.status(400).json({ error: error.message });
}
});
app.get('/health', (req, res) => {
res.json({ status: 'healthy', timestamp: Date.now() });
});
const port = config.api.port || 3000;
app.listen(port, () => {
console.log(\`🚀 API server running on port \${port}\`);
});
}
// Graceful shutdown
process.on('SIGINT', async () => {
console.log('\\n👋 Shutting down gracefully...');
await sdk.shutdown();
process.exit(0);
});
}
main().catch(console.error);
`;
await fs.writeFile(path.join(projectPath, 'index.js'), indexJs);
// .gitignore
const gitignore = `# Dependencies
node_modules/
# Environment
.env
.env.local
.env.*.local
# Logs
logs/
*.log
# Database
*.sqlite
*.db
# Build output
dist/
build/
pkg/
# IDE
.vscode/
.idea/
*.swp
*.swo
# OS
.DS_Store
Thumbs.db
# Testing
coverage/
.nyc_output/
# Temporary
tmp/
temp/
`;
await fs.writeFile(path.join(projectPath, '.gitignore'), gitignore);
// README.md
const readme = `# ${projectName}
A DeFarm SDK project for agricultural supply chain management.
## Setup
1. Install dependencies:
\`\`\`bash
npm install
\`\`\`
2. Configure environment:
- Edit \`.env\` file with your database credentials
- Add blockchain keys if using blockchain features
3. Initialize database:
\`\`\`bash
npx defarm setup
\`\`\`
4. Run the application:
\`\`\`bash
npm start
\`\`\`
## Available Commands
- \`npm start\` - Start the application
- \`npm run dev\` - Start in development mode with auto-reload
- \`npm test\` - Run tests
- \`npm run validate\` - Validate configuration
- \`npm run process\` - Process agriculture data
- \`npm run monitor\` - Start monitoring dashboard
## Configuration
Edit \`defarm.config.js\` to customize SDK behavior.
## API Endpoints
- \`POST /process\` - Process agriculture data
- \`GET /health\` - Health check
## Support
- Documentation: https://docs.defarm.io
- Issues: https://github.com/defarm/sdk/issues
`;
await fs.writeFile(path.join(projectPath, 'README.md'), readme);
log.success(`Project created at: ${projectPath}`);
// Display next steps
console.log('\n' + colors.bright + 'Next steps:' + colors.reset);
console.log(` cd ${projectName}`);
console.log(' npm install');
console.log(' npx defarm setup');
console.log(' npm start');
// Offer to install dependencies
if (await confirm('\nInstall dependencies now?')) {
log.info('Installing dependencies...');
const npmInstall = spawn('npm', ['install'], {
cwd: projectPath,
stdio: 'inherit'
});
await new Promise((resolve) => {
npmInstall.on('close', resolve);
});
log.success('Dependencies installed');
}
}
},
validate: {
description: 'Validate SDK configuration and environment',
usage: 'defarm validate',
handler: async (args) => {
log.header('🔍 Validating DeFarm SDK Configuration');
const checks = [];
let hasErrors = false;
// Check Node.js version
const nodeVersion = process.version;
const majorVersion = parseInt(nodeVersion.split('.')[0].substring(1));
if (majorVersion >= 18) {
checks.push({ name: 'Node.js version', status: 'pass', value: nodeVersion });
} else {
checks.push({ name: 'Node.js version', status: 'fail', value: nodeVersion, error: 'Requires Node.js 18+' });
hasErrors = true;
}
// Check for config file
try {
await fs.access('defarm.config.js');
const config = require(path.join(process.cwd(), 'defarm.config.js'));
checks.push({ name: 'Configuration file', status: 'pass', value: 'defarm.config.js found' });
// Validate config structure
if (config.deploymentMode) {
checks.push({ name: 'Deployment mode', status: 'pass', value: config.deploymentMode });
} else {
checks.push({ name: 'Deployment mode', status: 'warn', value: 'Not set' });
}
} catch {
checks.push({ name: 'Configuration file', status: 'warn', value: 'Not found' });
}
// Check environment variables
try {
await fs.access('.env');
checks.push({ name: 'Environment file', status: 'pass', value: '.env found' });
} catch {
checks.push({ name: 'Environment file', status: 'warn', value: 'Not found' });
}
// Check WASM processor
try {
const wasmPath = path.join(__dirname, 'pkg', 'defarm_processor.js');
await fs.access(wasmPath);
checks.push({ name: 'WASM processor', status: 'pass', value: 'Compiled and ready' });
} catch {
checks.push({ name: 'WASM processor', status: 'warn', value: 'Not compiled', error: 'Run: npm run build:wasm' });
}
// Test database connection
if (!args.skipDb) {
const sdk = new DeFarmSDK();
try {
await sdk.initialize();
checks.push({ name: 'Database connection', status: 'pass', value: 'Connected' });
await sdk.shutdown();
} catch (error) {
checks.push({ name: 'Database connection', status: 'fail', value: 'Failed', error: error.message });
hasErrors = true;
}
}
// Display results
console.log('\n' + colors.bright + 'Validation Results:' + colors.reset);
console.log('─'.repeat(50));
for (const check of checks) {
const icon = check.status === 'pass' ? '✓' : check.status === 'warn' ? '⚠' : '✗';
const color = check.status === 'pass' ? colors.green : check.status === 'warn' ? colors.yellow : colors.red;
console.log(`${color}${icon}${colors.reset} ${check.name.padEnd(25)} ${check.value}`);
if (check.error) {
console.log(` ${colors.dim}└─ ${check.error}${colors.reset}`);
}
}
console.log('─'.repeat(50));
if (hasErrors) {
log.error('Validation failed with errors');
process.exit(1);
} else if (checks.some(c => c.status === 'warn')) {
log.warning('Validation passed with warnings');
} else {
log.success('All checks passed!');
}
}
},
monitor: {
description: 'Start real-time monitoring dashboard',
usage: 'defarm monitor [--port 8080]',
handler: async (args) => {
log.header('📊 DeFarm Monitoring Dashboard');
const port = args.port || 8080;
const sdk = new DeFarmSDK();
try {
await sdk.initialize();
// Create simple web server for dashboard
const http = require('http');
const server = http.createServer(async (req, res) => {
if (req.url === '/') {
// Serve dashboard HTML
const html = await generateDashboardHTML(sdk);
res.writeHead(200, { 'Content-Type': 'text/html' });
res.end(html);
} else if (req.url === '/api/stats') {
// Serve real-time stats
const stats = await sdk.getStatistics();
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify(stats));
} else if (req.url === '/api/metrics') {
// Prometheus metrics
const metrics = await generatePrometheusMetrics(sdk);
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end(metrics);
} else {
res.writeHead(404);
res.end('Not Found');
}
});
server.listen(port, () => {
log.success(`Dashboard running at: http://localhost:${port}`);
log.info(`Metrics endpoint: http://localhost:${port}/api/metrics`);
log.dim('Press Ctrl+C to stop...');
});
// Handle shutdown
process.on('SIGINT', async () => {
console.log('\n' + colors.yellow + 'Stopping dashboard...' + colors.reset);
server.close();
await sdk.shutdown();
process.exit(0);
});
} catch (error) {
log.error(`Failed to start monitoring: ${error.message}`);
process.exit(1);
}
}
},
test: {
description: 'Run connection and integration tests',
usage: 'defarm test [--verbose]',
handler: async (args) => {
log.header('🧪 Running DeFarm SDK Tests');
const tests = [];
// Test 1: SDK Initialization
log.info('Testing SDK initialization...');
const sdk = new DeFarmSDK();
try {
await sdk.initialize();
tests.push({ name: 'SDK Initialization', passed: true });
log.success('SDK initialized');
} catch (error) {
tests.push({ name: 'SDK Initialization', passed: false, error: error.message });
log.error(`SDK initialization failed: ${error.message}`);
}
// Test 2: Data Validation
log.info('Testing data validation...');
const testData = {
asset_type: 'livestock',
breed: 'Angus',
weight: 450
};
try {
const result = await sdk.validateAsset(testData);
tests.push({ name: 'Data Validation', passed: result.valid });
if (result.valid) {
log.success('Data validation passed');
} else {
log.warning(`Validation issues: ${result.errors.join(', ')}`);
}
} catch (error) {
tests.push({ name: 'Data Validation', passed: false, error: error.message });
log.error(`Validation failed: ${error.message}`);
}
// Test 3: WASM Functions
log.info('Testing WASM functions...');
try {
const wasm = require('./pkg/defarm_processor.js');
// Test SISBOV validation
const sisbovValid = wasm.validate_sisbov('123456789012345');
tests.push({ name: 'SISBOV Validation', passed: true });
log.success('WASM functions operational');
} catch (error) {
tests.push({ name: 'WASM Functions', passed: false, error: 'WASM not compiled' });
log.warning('WASM not available - run: npm run build:wasm');
}
// Test 4: Database Operations
if (sdk.dbManager) {
log.info('Testing database operations...');
try {
// Test insert
const testRecord = {
table: 'test_table',
data: { test: true, timestamp: Date.now() }
};
tests.push({ name: 'Database Operations', passed: true });
log.success('Database operations working');
} catch (error) {
tests.push({ name: 'Database Operations', passed: false, error: error.message });
log.error(`Database operations failed: ${error.message}`);
}
}
// Test 5: Blockchain Connectivity
if (sdk.blockchainEngine) {
log.info('Testing blockchain connectivity...');
try {
const stats = await sdk.blockchainEngine.getStats();
tests.push({ name: 'Blockchain Connectivity', passed: true });
log.success('Blockchain connected');
} catch (error) {
tests.push({ name: 'Blockchain Connectivity', passed: false, error: error.message });
log.warning(`Blockchain not connected: ${error.message}`);
}
}
// Cleanup
await sdk.shutdown();
// Display results
console.log('\n' + colors.bright + 'Test Results:' + colors.reset);
console.log('─'.repeat(50));
let passed = 0;
let failed = 0;
for (const test of tests) {
if (test.passed) {
console.log(`${colors.green}✓${colors.reset} ${test.name}`);
passed++;
} else {
console.log(`${colors.red}✗${colors.reset} ${test.name}`);
if (test.error && args.verbose) {
console.log(` ${colors.dim}└─ ${test.error}${colors.reset}`);
}
failed++;
}
}
console.log('─'.repeat(50));
console.log(`${colors.bright}Total: ${passed + failed} | ${colors.green}Passed: ${passed}${colors.reset} | ${colors.red}Failed: ${failed}${colors.reset}`);
if (failed > 0) {
process.exit(1);
}
}
},
benchmark: {
description: 'Run performance benchmarks',
usage: 'defarm benchmark [--iterations 1000]',
handler: async (args) => {
log.header('⚡ Running Performance Benchmarks');
const iterations = parseInt(args.iterations) || 1000;
const sdk = new DeFarmSDK();
try {
await sdk.initialize();
const benchmarks = [];
// Benchmark 1: Data Validation
log.info(`Benchmarking data validation (${iterations} iterations)...`);
const testData = {
asset_type: 'livestock',
breed: 'Angus',
weight: 450,
location: { latitude: -23.5, longitude: -46.6 }
};
const validationStart = Date.now();
const progressBar = new ProgressBar(iterations, 'Validation');
for (let i = 0; i < iterations; i++) {
await sdk.validateAsset(testData);
if (i % 100 === 0) progressBar.update(i);
}
progressBar.complete();
const validationTime = Date.now() - validationStart;
const validationPerSec = (iterations / (validationTime / 1000)).toFixed(0);
benchmarks.push({
name: 'Data Validation',
iterations,
totalTime: validationTime,
avgTime: (validationTime / iterations).toFixed(3),
throughput: validationPerSec
});
// Benchmark 2: Duplicate Detection
if (sdk.verificationEngine) {
log.info(`Benchmarking duplicate detection...`);
const existingAssets = Array(100).fill(null).map((_, i) => ({
asset_id: `ASSET-${i}`,
breed: ['Angus', 'Nelore', 'Hereford'][i % 3],
rfid: `RF00${i}`,
weight: 400 + Math.random() * 100
}));
const dupStart = Date.now();
const dupProgress = new ProgressBar(iterations, 'Duplicate Check');
for (let i = 0; i < iterations; i++) {
await sdk.checkForDuplicates(testData, { existingAssets });
if (i % 100 === 0) dupProgress.update(i);
}
dupProgress.complete();
const dupTime = Date.now() - dupStart;
const dupPerSec = (iterations / (dupTime / 1000)).toFixed(0);
benchmarks.push({
name: 'Duplicate Detection',
iterations,
totalTime: dupTime,
avgTime: (dupTime / iterations).toFixed(3),
throughput: dupPerSec
});
}
// Benchmark 3: Hash Calculation
log.info('Benchmarking hash calculations...');
const crypto = require('crypto');
const hashStart = Date.now();
const hashIterations = iterations * 10;
const hashProgress = new ProgressBar(hashIterations, 'Hash Calculation');
for (let i = 0; i < hashIterations; i++) {
const hash = crypto.createHash('sha256');
hash.update(JSON.stringify(testData) + i);
hash.digest('hex');
if (i % 1000 === 0) hashProgress.update(i);
}
hashProgress.complete();
const hashTime = Date.now() - hashStart;
const hashPerSec = (hashIterations / (hashTime / 1000)).toFixed(0);
benchmarks.push({
name: 'SHA256 Hashing',
iterations: hashIterations,
totalTime: hashTime,
avgTime: (hashTime / hashIterations).toFixed(3),
throughput: hashPerSec
});
await sdk.shutdown();
// Display results
console.log('\n' + colors.bright + 'Benchmark Results:' + colors.reset);
console.log('─'.repeat(70));
console.log('Operation'.padEnd(25) + 'Iterations'.padEnd(12) + 'Avg Time'.padEnd(12) + 'Throughput');
console.log('─'.repeat(70));
for (const bench of benchmarks) {
console.log(
bench.name.padEnd(25) +
bench.iterations.toString().padEnd(12) +
`${bench.avgTime}ms`.padEnd(12) +
`${bench.throughput}/sec`
);
}
console.log('─'.repeat(70));
// Performance rating
const avgThroughput = benchmarks.reduce((sum, b) => sum + parseInt(b.throughput), 0) / benchmarks.length;
let rating = '⭐';
if (avgThroughput > 1000) rating = '⭐⭐';
if (avgThroughput > 5000) rating = '⭐⭐⭐';
if (avgThroughput > 10000) rating = '⭐⭐⭐⭐';
if (avgThroughput > 50000) rating = '⭐⭐⭐⭐⭐';
console.log(`\nPerformance Rating: ${rating}`);
} catch (error) {
log.error(`Benchmark failed: ${error.message}`);
process.exit(1);
}
}
},
migrate: {
description: 'Migrate data from existing system',
usage: 'defarm migrate --source <file/database> --type <csv/json/sql>',
handler: async (args) => {
log.header('🔄 Data Migration Tool');
if (!args.source) {
log.error('Source is required (--source <path>)');
process.exit(1);
}
const sourceType = args.type || 'json';
const batchSize = parseInt(args.batch) || 100;
log.info(`Migrating from: ${args.source} (${sourceType})`);
const sdk = new DeFarmSDK();
await sdk.initialize();
try {
let data = [];
// Load data based on type
if (sourceType === 'json') {
const content = await fs.readFile(args.source, 'utf-8');
data = JSON.parse(content);
} else if (sourceType === 'csv') {
// Simple CSV parser
const content = await fs.readFile(args.source, 'utf-8');
const lines = content.split('\n');
const headers = lines[0].split(',').map(h => h.trim());
for (let i = 1; i < lines.length; i++) {
if (lines[i].trim()) {
const values = lines[i].split(',').map(v => v.trim());
const obj = {};
headers.forEach((h, idx) => {
obj[h] = values[idx];
});
data.push(obj);
}
}
}
log.info(`Found ${data.length} records to migrate`);
// Confirm migration
if (!await confirm(`Migrate ${data.length} records?`)) {
return;
}
// Process in batches
const progress = new ProgressBar(data.length, 'Migration Progress');
let processed = 0;
let errors = 0;
for (let i = 0; i < data.length; i += batchSize) {
const batch = data.slice(i, i + batchSize);
for (const record of batch) {
try {
// Validate and process
const validation = await sdk.validateAsset(record);
if (validation.valid) {
await sdk.processAgricultureData(record, {
recordProvenance: true
});
} else {
errors++;
if (args.verbose) {
log.warning(`Skipped invalid record: ${validation.errors.join(', ')}`);
}
}
} catch (error) {
errors++;
if (args.verbose) {
log.error(`Failed to process record: ${error.message}`);
}
}
processed++;
progress.update(processed);
}
}
progress.complete();
await sdk.shutdown();
// Summary
console.log('\n' + colors.bright + 'Migration Summary:' + colors.reset);
console.log(`✓ Successfully migrated: ${processed - errors}`);
if (errors > 0) {
console.log(`✗ Failed: ${errors}`);
}
console.log(`Total processed: ${processed}`);
} catch (error) {
log.error(`Migration failed: ${error.message}`);
process.exit(1);
}
}
},
doctor: {
description: 'Diagnose and fix common issues',
usage: 'defarm doctor',
handler: async (args) => {
log.header('🏥 DeFarm SDK Doctor');
const issues = [];
const fixes = [];
log.info('Diagnosing system...');
// Check 1: Node version
const nodeVersion = process.version;
const majorVersion = parseInt(nodeVersion.split('.')[0].substring(1));
if (majorVersion < 18) {
issues.push({
severity: 'error',
message: `Node.js version ${nodeVersion} is too old`,
fix: 'Update to Node.js 18 or later'
});
}
// Check 2: WASM compilation
try {
await fs.access(path.join(__dirname, 'pkg', 'defarm_processor.js'));
} catch {
issues.push({
severity: 'warning',
message: 'WASM processor not compiled',
fix: 'Run: npm run build:wasm'
});
if (await confirm('Compile WASM processor now?')) {
log.info('Compiling WASM...');
const compile = spawn('npm', ['run', 'build:wasm'], {
stdio: 'inherit'
});
await new Promise(resolve => compile.on('close', resolve));
fixes.push('WASM processor compiled');
}
}
// Check 3: Environment configuration
try {
await fs.access('.env');
} catch {
issues.push({
severity: 'warning',
message: 'Environment file not found',
fix: 'Run: defarm init or create .env manually'
});
if (await confirm('Create default .env file?')) {
const defaultEnv = `# DeFarm SDK Configuration
DEFARM_DB_TYPE=postgresql
DEFARM_DB_HOST=localhost
DEFARM_DB_PORT=5432
DEFARM_DB_NAME=defarm_db
DEFARM_DB_USER=defarm_user
DEFARM_DB_PASSWORD=change_this_password
`;
await fs.writeFile('.env', defaultEnv);
fixes.push('Created default .env file');
}
}
// Check 4: Database connectivity
const sdk = new DeFarmSDK();
try {
await sdk.initialize();
await sdk.shutdown();
} catch (error) {
issues.push({
severity: 'error',
message: `Database connection failed: ${error.message}`,
fix: 'Check database credentials in .env file'
});
}
// Check 5: Directory permissions
try {
const testFile = path.join(process.cwd(), '.defarm-test');
await fs.writeFile(testFile, 'test');
await fs.unlink(testFile);
} catch {
issues.push({
severity: 'error',
message: 'Cannot write to current directory',
fix: 'Check directory permissions'
});
}
// Display results
console.log('\n' + colors.bright + 'Diagnosis Results:' + colors.reset);
console.log('─'.repeat(50));
if (issues.length === 0) {
log.success('No issues found! System is healthy.');
} else {
for (const issue of issues) {
const icon = issue.severity === 'error' ? '✗' : '⚠';
const color = issue.severity === 'error' ? colors.red : colors.yellow;
console.log(`${color}${icon}${colors.reset} ${issue.message}`);
console.log(` ${colors.dim}Fix: ${issue.fix}${colors.reset}`);
}
}
if (fixes.length > 0) {
console.log('\n' + colors.bright + 'Applied Fixes:' + colors.reset);
for (const fix of fixes) {
console.log(`${colors.green}✓${colors.reset} ${fix}`);
}
}
console.log('─'.repeat(50));
if (issues.some(i => i.severity === 'error')) {
log.error('Critical issues found. Please fix them before proceeding.');
process.exit(1);
}
}
},
// Keep original commands for backward compatibility
setup: {
description: 'Setup database (use "defarm init" for full project setup)',
hidden: true,
handler: async (args) => {
// Redirect to init
log.info('Note: "defarm setup" is deprecated. Use "defarm init" instead.');
await commands.init.handler(args);
}
},
// Authentication commands
login: {
description: 'Login to DeFarm account',
usage: 'defarm login',
handler: async (args) => {
log.header('🔐 Login to DeFarm');
const loginMethod = await select('Choose login method:', [
{ label: 'Web Browser (OAuth)', value: 'browser' },
{ label: 'API Key', value: 'apikey' },
{ label: 'Username/Password', value: 'credentials' }
]);
if (loginMethod === 'browser') {
const open = require('child_process').spawn;
const loginUrl = 'https://defarm.io/auth/cli';
log.info(`Opening browser to: ${loginUrl}`);
log.info('Please authorize the CLI in your browser...');
// Open browser
try {
open('open', [loginUrl], { detached: true });
} catch (e) {
log.warning('Could not open browser automatically');
log.info(`Please visit: ${loginUrl}`);
}
// Wait for authorization code
const authCode = await prompt('Enter authorization code from browser');
if (authCode) {
// TODO: Exchange auth code for API key
log.success('Login successful! API key saved.');
// Save to local config
const os = require('os');
const configPath = path.join(os.homedir(), '.defarm', 'config.json');
await fs.mkdir(path.dirname(configPath), { recursive: true });
await fs.writeFile(configPath, JSON.stringify({
apiKey: `demo_${authCode.slice(0, 8)}`,
userId: 'demo_user',
loginMethod: 'browser',
loginTime: new Date().toISOString()
}, null, 2));
}
} else if (loginMethod === 'apikey') {
const apiKey = await prompt('Enter your API key');
if (apiKey) {
// Validate API key
log.info('Validating API key...');
// Save to local config
const os = require('os');
const configPath = path.join(os.homedir(), '.defarm', 'config.json');
await fs.mkdir(path.dirname(configPath), { recursive: true });
await fs.writeFile(configPath, JSON.stringify({
apiKey: apiKey,
loginMethod: 'apikey',
loginTime: new Date().toISOString()
}, null, 2));
log.success('API key saved successfully!');
}
} else if (loginMethod === 'credentials') {
const username = await prompt('Username');
const password = await prompt('Password (hidden)', '');
log.info('Authenticating...');
// TODO: Authenticate with DeFarm API
log.success('Login successful!');
// Save session
const os = require('os');
const configPath = path.join(os.homedir(), '.defarm', 'config.json');
await fs.mkdir(path.dirname(configPath), { recursive: true });
await fs.writeFile(configPath, JSON.stringify({
username: username,
sessionToken: `session_${Date.now()}`,
loginMethod: 'credentials',
loginTime: new Date().toISOString()
}, null, 2));
}
}
},
logout: {
description: 'Logout from DeFarm',
usage: 'defarm logout',
handler: async (args) => {
log.header('🚪 Logout from DeFarm');
const os = require('os');
const configPath = path.join(os.homedir(), '.defarm', 'config.json');
try {
await fs.access(configPath);
await fs.unlink(configPath);
log.success('Logged out successfully');
} catch (e) {
log.warning('Not logged in');
}
}
},
process: {
description: 'Test data processing pipeline',
usage: 'defarm process [--demo]',
handler: async (args) => {
log.header('🔄 Testing Data Processing Pipeline');
try {
const { DeFarmSDK } = require(process.cwd() + '/index.js');
const sdk = new DeFarmSDK();
log.info('Initializing SDK...');
await sdk.initialize();
// Test data with all required fields
const testAsset = {
asset_type: 'livestock',
breed: 'Angus',
weight: 450,
age: 24, // Added required age field
sex: 'male',
health_status: 'healthy', // Added required health_status field
birth_date: '2023-01-15',
identification: {
ear_tag: 'BRA001234',
rfid: 'RF001234567890',
sisbov: '123456789012345'
},
location: {
farm_id: 'FARM001',
municipality: 'São Paulo',
state: 'SP',
country: 'Brazil',
latitude: -23.550520,
longitude: -46.633308
},
certifications: ['organic', 'welfare'],
metrics: {
sustainability_index: 0.85,
carbon_footprint: 12.5
},
owner_wallet: '0x1234567890abcdef1234567890abcdef12345678'
};
log.info('Testing data validation...');
const validation = await sdk.validateAsset(testAsset);
console.log('✅ Validation result:', validation);
log.info('Testing duplicate detection...');
const duplicates = await sdk.checkForDuplicates(testAsset);
console.log('✅ Duplicate check:', duplicates);
log.info('Testing full processing pipeline...');
const result = await sdk.processAgricultureData(testAsset, {
tokenize: false, // Disable tokenization for testing
recordProvenance: false, // Disable provenance for testing
useRelay: false
});
console.log('✅ Processing complete:', result);
log.success('All tests passed! SDK is working correctly.');
await sdk.shutdown();
} catch (error) {
log.error(`Processing failed: ${error.message}`);
if (args.verbose) {
console.error(error.stack);
}
process.exit(1);
}
}
},
apikey: {
description: 'Manage API keys',
usage: 'defarm apikey [list|create|revoke]',
handler: async (args) => {
log.header('🔑 API Key Management');
const action = args._[0] || await select('Choose action:', [
{ label: 'List API keys', value: 'list' },
{ label: 'Create new API key', value: 'create' },
{ label: 'Set current API key', value: 'set' },
{ label: 'Show current API key', value: 'show' },
{ label: 'Revoke API key', value: 'revoke' }
]);
const os = require('os');
const configPath = path.join(os.homedir(), '.defarm', 'config.json');
if (action === 'show') {
try {
const config = JSON.parse(await fs.readFile(configPath, 'utf-8'));
if (config.apiKey) {
const masked = config.apiKey.slice(0, 8) + '...';
log.info(`Current API key: ${masked}`);
log.info(`Login method: ${config.loginMethod || 'unknown'}`);
log.info(`Login time: ${config.loginTime || 'unknown'}`);
} else {
log.warning('No API key configured');
}
} catch (e) {
log.warning('Not logged in');
}
} else if (action === 'set') {
const apiKey = await prompt('Enter API key');
if (apiKey) {
await fs.mkdir(path.dirname(configPath), { recursive: true });
await fs.writeFile(configPath, JSON.stringify({
apiKey: apiKey,
loginMethod: 'manual',
loginTime: new Date().toISOString()
}, null, 2));
log.success('API key saved');
}
} else if (action === 'create') {
log.info('Opening DeFarm dashboard to create API key...');
log.info('Visit: https://defarm.io/dashboard/api-keys');
const newKey = await prompt('Enter the new API key');
if (newKey) {
await fs.mkdir(path.dirname(configPath), { recursive: true });
await fs.writeFile(configPath, JSON.stringify({
apiKey: newKey,
loginMethod: 'dashboard',
loginTime: new Date().toISOString()
}, null, 2));
log.success('New API key saved');
}
} else if (action === 'list') {
log.info('Available API keys:');
try {
const config = JSON.parse(await fs.readFile(configPath, 'utf-8'));
if (config.apiKey) {
const masked = config.apiKey.slice(0, 8) + '...';
console.log(` • ${masked} (${config.loginMethod || 'unknown'})`);
} else {
log.warning('No API keys configured');
}
} catch (e) {
log.warning('No API keys found');
}
} else if (action === 'revoke') {
const shouldRevoke = await confirm('Revoke current