#!/usr/bin/env node
/**
* Fetch community nodes from n8n Strapi API and npm registry.
*
* Usage:
* npm run fetch:community # Full rebuild (verified + top 100 npm)
* npm run fetch:community:verified # Verified nodes only (fast)
* npm run fetch:community:update # Incremental update (skip existing)
*
* Options:
* --verified-only Only fetch verified nodes from Strapi API
* --update Skip nodes that already exist in database
* --npm-limit=N Maximum number of npm packages to fetch (default: 100)
* --staging Use staging Strapi API instead of production
*/
import path from 'path';
import { CommunityNodeService, SyncOptions } from '../community';
import { NodeRepository } from '../database/node-repository';
import { createDatabaseAdapter } from '../database/database-adapter';
interface CliOptions {
verifiedOnly: boolean;
update: boolean;
npmLimit: number;
staging: boolean;
}
function parseArgs(): CliOptions {
const args = process.argv.slice(2);
const options: CliOptions = {
verifiedOnly: false,
update: false,
npmLimit: 100,
staging: false,
};
for (const arg of args) {
if (arg === '--verified-only') {
options.verifiedOnly = true;
} else if (arg === '--update') {
options.update = true;
} else if (arg === '--staging') {
options.staging = true;
} else if (arg.startsWith('--npm-limit=')) {
const value = parseInt(arg.split('=')[1], 10);
if (!isNaN(value) && value > 0) {
options.npmLimit = value;
}
}
}
return options;
}
function printProgress(message: string, current: number, total: number): void {
const percent = total > 0 ? Math.round((current / total) * 100) : 0;
const bar = '='.repeat(Math.floor(percent / 2)) + ' '.repeat(50 - Math.floor(percent / 2));
process.stdout.write(`\r[${bar}] ${percent}% - ${message} (${current}/${total})`);
if (current === total) {
console.log(); // New line at completion
}
}
async function main(): Promise<void> {
const cliOptions = parseArgs();
console.log('='.repeat(60));
console.log(' n8n-mcp Community Node Fetcher');
console.log('='.repeat(60));
console.log();
// Print options
console.log('Options:');
console.log(` - Mode: ${cliOptions.update ? 'Update (incremental)' : 'Rebuild'}`);
console.log(` - Verified only: ${cliOptions.verifiedOnly ? 'Yes' : 'No'}`);
if (!cliOptions.verifiedOnly) {
console.log(` - npm package limit: ${cliOptions.npmLimit}`);
}
console.log(` - API environment: ${cliOptions.staging ? 'staging' : 'production'}`);
console.log();
// Initialize database
const dbPath = path.join(__dirname, '../../data/nodes.db');
console.log(`Database: ${dbPath}`);
const db = await createDatabaseAdapter(dbPath);
const repository = new NodeRepository(db);
// Create service
const environment = cliOptions.staging ? 'staging' : 'production';
const service = new CommunityNodeService(repository, environment);
// If not updating, delete existing community nodes
if (!cliOptions.update) {
console.log('\nClearing existing community nodes...');
const deleted = service.deleteCommunityNodes();
console.log(` Deleted ${deleted} existing community nodes`);
}
// Sync options
const syncOptions: SyncOptions = {
verifiedOnly: cliOptions.verifiedOnly,
npmLimit: cliOptions.npmLimit,
skipExisting: cliOptions.update,
environment,
};
// Run sync
console.log('\nFetching community nodes...\n');
const result = await service.syncCommunityNodes(syncOptions, printProgress);
// Print results
console.log('\n' + '='.repeat(60));
console.log(' Results');
console.log('='.repeat(60));
console.log();
console.log('Verified nodes (Strapi API):');
console.log(` - Fetched: ${result.verified.fetched}`);
console.log(` - Saved: ${result.verified.saved}`);
console.log(` - Skipped: ${result.verified.skipped}`);
if (result.verified.errors.length > 0) {
console.log(` - Errors: ${result.verified.errors.length}`);
result.verified.errors.forEach((e) => console.log(` ! ${e}`));
}
if (!cliOptions.verifiedOnly) {
console.log('\nnpm packages:');
console.log(` - Fetched: ${result.npm.fetched}`);
console.log(` - Saved: ${result.npm.saved}`);
console.log(` - Skipped: ${result.npm.skipped}`);
if (result.npm.errors.length > 0) {
console.log(` - Errors: ${result.npm.errors.length}`);
result.npm.errors.forEach((e) => console.log(` ! ${e}`));
}
}
// Get final stats
const stats = service.getCommunityStats();
console.log('\nDatabase statistics:');
console.log(` - Total community nodes: ${stats.total}`);
console.log(` - Verified: ${stats.verified}`);
console.log(` - Unverified: ${stats.unverified}`);
console.log(`\nCompleted in ${(result.duration / 1000).toFixed(1)} seconds`);
console.log('='.repeat(60));
// Close database
db.close();
}
// Run
main().catch((error) => {
console.error('Fatal error:', error);
process.exit(1);
});