UNPKG

n8n-nodes-neuronwriter

Version:

n8n community node for NeuronWriter API integration - SEO content analysis and optimization

678 lines (677 loc) 29.6 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.NeuronWriter = void 0; const n8n_workflow_1 = require("n8n-workflow"); class NeuronWriter { constructor() { this.description = { displayName: 'NeuronWriter', name: 'neuronWriter', icon: 'file:neuronwriter.svg', group: ['transform'], version: 1, subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}', description: 'Interact with NeuronWriter API for SEO content analysis and optimization', defaults: { name: 'NeuronWriter', }, inputs: ["main" /* NodeConnectionType.Main */], outputs: ["main" /* NodeConnectionType.Main */], credentials: [ { name: 'neuronWriterApi', required: true, }, ], requestDefaults: { headers: { 'X-API-KEY': '={{$credentials.apiKey}}', 'Accept': 'application/json', 'Content-Type': 'application/json', }, }, properties: [ // Resource selector { displayName: 'Resource', name: 'resource', type: 'options', noDataExpression: true, options: [ { name: 'Project', value: 'project', description: 'Operations on NeuronWriter projects', }, { name: 'Query', value: 'query', description: 'SEO analysis queries and results', }, { name: 'Content', value: 'content', description: 'Content management operations', }, ], default: 'query', }, // PROJECT OPERATIONS { displayName: 'Operation', name: 'operation', type: 'options', noDataExpression: true, displayOptions: { show: { resource: ['project'], }, }, options: [ { name: 'List', value: 'list', description: 'Get all projects in your account', action: 'List all projects', }, ], default: 'list', }, // QUERY OPERATIONS { displayName: 'Operation', name: 'operation', type: 'options', noDataExpression: true, displayOptions: { show: { resource: ['query'], }, }, options: [ { name: 'Create', value: 'create', description: 'Create a new SEO analysis query for a keyword', action: 'Create a new query', }, { name: 'Get', value: 'get', description: 'Get analysis results and recommendations for a query', action: 'Get query results', }, { name: 'List', value: 'list', description: 'List all queries in a project with filters', action: 'List queries', }, ], default: 'create', }, // CONTENT OPERATIONS { displayName: 'Operation', name: 'operation', type: 'options', noDataExpression: true, displayOptions: { show: { resource: ['content'], }, }, options: [ { name: 'Get', value: 'get', description: 'Get saved content for a query', action: 'Get saved content', }, { name: 'Import', value: 'import', description: 'Import HTML content and save it to a query', action: 'Import content', }, { name: 'Evaluate', value: 'evaluate', description: 'Evaluate content and get SEO score without saving', action: 'Evaluate content', }, ], default: 'get', }, // QUERY CREATE FIELDS { displayName: 'Project ID', name: 'projectId', type: 'string', required: true, displayOptions: { show: { resource: ['query'], operation: ['create', 'list'], }, }, default: '', description: 'The ID of your NeuronWriter project. You can get this from the project URL or by using the "List Projects" operation.', placeholder: 'e.g., c2fe46bce8019bff', }, { displayName: 'Keyword', name: 'keyword', type: 'string', required: true, displayOptions: { show: { resource: ['query'], operation: ['create'], }, }, default: '', description: 'Main keyword for SEO analysis and content optimization', placeholder: 'e.g., best running shoes 2024', }, { displayName: 'Search Engine', name: 'engine', type: 'options', displayOptions: { show: { resource: ['query'], operation: ['create'], }, }, options: [ { name: 'Google.com (Global)', value: 'google.com', }, { name: 'Google.co.uk (United Kingdom)', value: 'google.co.uk', }, { name: 'Google.fr (France)', value: 'google.fr', }, { name: 'Google.de (Germany)', value: 'google.de', }, { name: 'Google.es (Spain)', value: 'google.es', }, { name: 'Google.it (Italy)', value: 'google.it', }, { name: 'Google.ca (Canada)', value: 'google.ca', }, { name: 'Google.com.au (Australia)', value: 'google.com.au', }, ], default: 'google.com', description: 'Search engine to use for SERP analysis', }, { displayName: 'Language', name: 'language', type: 'options', displayOptions: { show: { resource: ['query'], operation: ['create'], }, }, options: [ { name: 'English', value: 'English', }, { name: 'French', value: 'French', }, { name: 'Spanish', value: 'Spanish', }, { name: 'German', value: 'German', }, { name: 'Italian', value: 'Italian', }, { name: 'Portuguese', value: 'Portuguese', }, { name: 'Dutch', value: 'Dutch', }, { name: 'Polish', value: 'Polish', }, ], default: 'English', description: 'Content language for analysis', }, { displayName: 'Additional Keywords', name: 'additionalKeywords', type: 'string', displayOptions: { show: { resource: ['query'], operation: ['create'], }, }, default: '', description: 'Optional: Comma-separated list of supporting keywords to include in the analysis', placeholder: 'e.g., running shoes, athletic footwear, sport shoes', }, // QUERY GET FIELDS { displayName: 'Query ID', name: 'queryId', type: 'string', required: true, displayOptions: { show: { resource: ['query', 'content'], operation: ['get'], }, }, default: '', description: 'The ID of the query to retrieve. This is returned when creating a query.', placeholder: 'e.g., 79ca6b6b45fb9d67', }, // QUERY LIST FIELDS { displayName: 'Additional Options', name: 'additionalOptions', type: 'collection', placeholder: 'Add Option', displayOptions: { show: { resource: ['query'], operation: ['list'], }, }, default: {}, options: [ { displayName: 'Status', name: 'status', type: 'options', options: [ { name: 'All', value: '', }, { name: 'Waiting', value: 'waiting', }, { name: 'In Progress', value: 'in progress', }, { name: 'Ready', value: 'ready', }, ], default: 'ready', description: 'Filter queries by their analysis status', }, { displayName: 'Source', name: 'source', type: 'options', options: [ { name: 'All', value: '', }, { name: 'NeuronWriter Interface', value: 'neuron', }, { name: 'API', value: 'neuron-api', }, ], default: '', description: 'Filter by how the query was created', }, { displayName: 'Tags', name: 'tags', type: 'string', default: '', description: 'Comma-separated list of tags to filter by', placeholder: 'e.g., Done, Published', }, ], }, // CONTENT FIELDS { displayName: 'Query ID', name: 'queryId', type: 'string', required: true, displayOptions: { show: { resource: ['content'], operation: ['import', 'evaluate'], }, }, default: '', description: 'The ID of the query to associate content with', placeholder: 'e.g., 79ca6b6b45fb9d67', }, { displayName: 'HTML Content', name: 'html', type: 'string', typeOptions: { alwaysOpenEditWindow: true, editor: 'htmlEditor', rows: 10, }, displayOptions: { show: { resource: ['content'], operation: ['import', 'evaluate'], }, }, default: '', description: 'HTML content to import or evaluate for SEO optimization', placeholder: '<h1>Your Article Title</h1><p>Your content here...</p>', }, { displayName: 'Title', name: 'title', type: 'string', displayOptions: { show: { resource: ['content'], operation: ['import', 'evaluate'], }, }, default: '', description: 'Article title (will override any <title> in HTML)', placeholder: 'e.g., The Ultimate Guide to Running Shoes', }, { displayName: 'Meta Description', name: 'description', type: 'string', typeOptions: { rows: 3, }, displayOptions: { show: { resource: ['content'], operation: ['import', 'evaluate'], }, }, default: '', description: 'Meta description for SEO (will override any meta description in HTML)', placeholder: 'e.g., Discover the best running shoes of 2024 with our comprehensive guide...', }, // CONTENT IMPORT OPTIONS { displayName: 'Import Options', name: 'importOptions', type: 'collection', placeholder: 'Add Option', displayOptions: { show: { resource: ['content'], operation: ['import', 'evaluate'], }, }, default: {}, options: [ { displayName: 'Import from URL', name: 'url', type: 'string', default: '', description: 'URL to import content from (alternative to providing HTML directly)', placeholder: 'https://example.com/article', }, { displayName: 'Container ID', name: 'id', type: 'string', default: '', description: 'ID of the HTML container that contains the main content (when importing from URL)', placeholder: 'e.g., main-content', }, { displayName: 'Container Class', name: 'class', type: 'string', default: '', description: 'CSS class of the HTML container that contains the main content (when importing from URL)', placeholder: 'e.g., article-content', }, ], }, // CONTENT GET OPTIONS { displayName: 'Revision Type', name: 'revisionType', type: 'options', displayOptions: { show: { resource: ['content'], operation: ['get'], }, }, options: [ { name: 'Manual Saves Only', value: 'manual', }, { name: 'All (Including Autosaves)', value: 'all', }, ], default: 'all', description: 'Type of content revisions to retrieve', }, ], }; } async execute() { var _a; const items = this.getInputData(); const returnData = []; for (let i = 0; i < items.length; i++) { try { const resource = this.getNodeParameter('resource', i); const operation = this.getNodeParameter('operation', i); let responseData; if (resource === 'project') { if (operation === 'list') { responseData = await this.helpers.httpRequestWithAuthentication.call(this, 'neuronWriterApi', { method: 'POST', url: 'https://app.neuronwriter.com/neuron-api/0.5/writer/list-projects', body: {}, json: true, }); } } else if (resource === 'query') { if (operation === 'create') { const projectId = this.getNodeParameter('projectId', i); const keyword = this.getNodeParameter('keyword', i); const engine = this.getNodeParameter('engine', i); const language = this.getNodeParameter('language', i); const additionalKeywords = this.getNodeParameter('additionalKeywords', i); const body = { project: projectId, keyword, engine, language, }; if (additionalKeywords) { body.additional_keywords = additionalKeywords.split(',').map(k => k.trim()).filter(k => k); } responseData = await this.helpers.httpRequestWithAuthentication.call(this, 'neuronWriterApi', { method: 'POST', url: 'https://app.neuronwriter.com/neuron-api/0.5/writer/new-query', body, json: true, }); } else if (operation === 'get') { const queryId = this.getNodeParameter('queryId', i); responseData = await this.helpers.httpRequestWithAuthentication.call(this, 'neuronWriterApi', { method: 'POST', url: 'https://app.neuronwriter.com/neuron-api/0.5/writer/get-query', body: { query: queryId }, json: true, }); } else if (operation === 'list') { const projectId = this.getNodeParameter('projectId', i); const additionalOptions = this.getNodeParameter('additionalOptions', i); const body = { project: projectId, }; if (additionalOptions.status) { body.status = additionalOptions.status; } if (additionalOptions.source) { body.source = additionalOptions.source; } if (additionalOptions.tags) { const tags = additionalOptions.tags.split(',').map(t => t.trim()).filter(t => t); if (tags.length > 0) { body.tags = tags; } } responseData = await this.helpers.httpRequestWithAuthentication.call(this, 'neuronWriterApi', { method: 'POST', url: 'https://app.neuronwriter.com/neuron-api/0.5/writer/list-queries', body, json: true, }); } } else if (resource === 'content') { if (operation === 'get') { const queryId = this.getNodeParameter('queryId', i); const revisionType = this.getNodeParameter('revisionType', i); responseData = await this.helpers.httpRequestWithAuthentication.call(this, 'neuronWriterApi', { method: 'POST', url: 'https://app.neuronwriter.com/neuron-api/0.5/writer/get-content', body: { query: queryId, revision_type: revisionType }, json: true, }); } else if (operation === 'import' || operation === 'evaluate') { const queryId = this.getNodeParameter('queryId', i); const html = this.getNodeParameter('html', i); const title = this.getNodeParameter('title', i); const description = this.getNodeParameter('description', i); const importOptions = this.getNodeParameter('importOptions', i); const endpoint = operation === 'import' ? '/import-content' : '/evaluate-content'; const body = { query: queryId, }; // If URL is provided, use it instead of HTML if (importOptions.url) { body.url = importOptions.url; if (importOptions.id) body.id = importOptions.id; if (importOptions.class) body.class = importOptions.class; } else if (html) { body.html = html; } else { throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Either HTML content or URL must be provided', { itemIndex: i }); } if (title) body.title = title; if (description) body.description = description; responseData = await this.helpers.httpRequestWithAuthentication.call(this, 'neuronWriterApi', { method: 'POST', url: endpoint, body, json: true, }); } } // Enhanced response data with metadata const enhancedResponse = { ...responseData, _metadata: { resource, operation, timestamp: new Date().toISOString(), nodeVersion: 1, } }; returnData.push({ json: enhancedResponse, pairedItem: { item: i }, }); } catch (error) { // Enhanced error handling if (this.continueOnFail()) { const errorData = { error: (error === null || error === void 0 ? void 0 : error.message) || 'Unknown error', resource: this.getNodeParameter('resource', i), operation: this.getNodeParameter('operation', i), timestamp: new Date().toISOString(), }; returnData.push({ json: errorData, pairedItem: { item: i }, }); continue; } // Provide more specific error messages if ((error === null || error === void 0 ? void 0 : error.httpCode) === '401') { throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Invalid API key. Please check your NeuronWriter API credentials.', { itemIndex: i }); } else if ((error === null || error === void 0 ? void 0 : error.httpCode) === '404') { throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Resource not found. Please check your Project ID or Query ID.', { itemIndex: i }); } else if ((_a = error === null || error === void 0 ? void 0 : error.message) === null || _a === void 0 ? void 0 : _a.includes('project')) { throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Project error: ${error.message}. Make sure the Project ID exists and you have access to it.`, { itemIndex: i }); } throw new n8n_workflow_1.NodeOperationError(this.getNode(), error, { itemIndex: i }); } } return [returnData]; } } exports.NeuronWriter = NeuronWriter;