Files
n8n-mcp/src/scripts/fetch-community-nodes.ts
czlonkowski a571ad5ef5 chore: update n8n to 2.13.3 and bump version to 2.41.0
- Updated n8n from 2.12.3 to 2.13.3
- Updated n8n-core from 2.12.0 to 2.13.1
- Updated n8n-workflow from 2.12.0 to 2.13.1
- Updated @n8n/n8n-nodes-langchain from 2.12.0 to 2.13.1
- Rebuilt node database with 1,396 nodes (812 core + 584 community: 516 verified + 68 npm)
- Refreshed community nodes with 581 AI-generated documentation summaries
- Improved documentation generator: strip <think> tags, raw fetch for vLLM chat_template_kwargs
- Incremental community updates: saveNode uses ON CONFLICT DO UPDATE preserving READMEs/AI summaries
- fetch:community now upserts by default (use --rebuild for clean slate)
- Updated README badge and node counts
- Updated CHANGELOG and MEMORY_N8N_UPDATE.md

Conceived by Romuald Członkowski - https://www.aiadvisors.pl/en

Co-Authored-By: Claude <noreply@anthropic.com>
2026-03-26 09:39:57 +01:00

166 lines
5.3 KiB
JavaScript

#!/usr/bin/env node
/**
* Fetch community nodes from n8n Strapi API and npm registry.
*
* Usage:
* npm run fetch:community # Upsert all (preserves READMEs and AI summaries)
* 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
* --rebuild Delete all community nodes first (wipes READMEs/AI summaries!)
* --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;
rebuild: boolean;
npmLimit: number;
staging: boolean;
}
function parseArgs(): CliOptions {
const args = process.argv.slice(2);
const options: CliOptions = {
verifiedOnly: false,
update: false,
rebuild: 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 === '--rebuild') {
options.rebuild = 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.rebuild ? 'Rebuild (clean slate)' : cliOptions.update ? 'Update (skip existing)' : 'Upsert (preserves docs)'}`);
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);
// Only delete existing community nodes when --rebuild is explicitly requested
if (cliOptions.rebuild) {
console.log('\nClearing existing community nodes (--rebuild)...');
console.log(' WARNING: This wipes READMEs and AI summaries!');
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);
});