This commit is contained in:
Steven Milanese 2025-03-07 05:05:49 -05:00
parent 523576ce96
commit 666d4eb4c2
6 changed files with 10467 additions and 30 deletions

10435
package-lock.json generated Normal file

File diff suppressed because it is too large Load diff

View file

@ -25,7 +25,9 @@
"url": "https://github.com/developtheweb/n8n-tavily-nodes/issues"
},
"dependencies": {
"axios": "^1.6.0"
"axios": "^1.6.0",
"n8n-core": "^1.14.1",
"n8n-workflow": "^1.14.1"
},
"devDependencies": {
"@types/node": "^18.0.0",

View file

@ -1,11 +1,12 @@
import { IExecuteFunctions } from 'n8n-core';
import {
IExecuteFunctions,
NodeApiError,
INodeExecutionData,
INodeType,
INodeTypeDescription,
INodeProperties,
NodeApiError,
} from 'n8n-workflow';
// REMOVED import { IExecuteFunctions } from 'n8n-core';
import { tavilyApiRequest } from './tavilyApi.utils';
@ -87,7 +88,7 @@ export class TavilyExtract implements INodeType {
const credentials = await this.getCredentials('tavilyApi');
if (!credentials?.apiKey) {
throw new NodeApiError(this.getNode(), new Error('Missing Tavily API key in credentials.'));
throw new NodeApiError(this.getNode(), { message: 'Missing Tavily API key in credentials.' });
}
const apiKey = credentials.apiKey as string;
@ -97,9 +98,8 @@ export class TavilyExtract implements INodeType {
const includeImages = this.getNodeParameter('includeImages', i) as boolean;
const extractDepth = this.getNodeParameter('extractDepth', i) as string;
// Validate input parameters
if (!Array.isArray(urls) || urls.length === 0) {
throw new NodeApiError(this.getNode(), new Error('At least one URL is required.'));
throw new NodeApiError(this.getNode(), { message: 'At least one URL is required.' });
}
const body = {
@ -121,7 +121,7 @@ export class TavilyExtract implements INodeType {
if (error instanceof NodeApiError) {
throw error;
}
throw new NodeApiError(this.getNode(), error as Error);
throw new NodeApiError(this.getNode(), { message: String(error) });
}
}

View file

@ -1,15 +1,16 @@
import { IExecuteFunctions } from 'n8n-core';
import {
IExecuteFunctions,
NodeApiError,
INodeExecutionData,
INodeType,
INodeTypeDescription,
INodeProperties,
NodeApiError,
} from 'n8n-workflow';
// REMOVED import { IExecuteFunctions } from 'n8n-core';
import { tavilyApiRequest } from './tavilyApi.utils';
// NEW: maintain a constant array for valid time ranges
// For older n8n usage, ALLOWED_TIME_RANGES is fine here
const ALLOWED_TIME_RANGES = ['', 'day', 'week', 'month', 'year', 'd', 'w', 'm', 'y'];
export class TavilySearch implements INodeType {
@ -205,8 +206,7 @@ export class TavilySearch implements INodeType {
const credentials = await this.getCredentials('tavilyApi');
if (!credentials?.apiKey) {
// Standardize NodeApiError usage
throw new NodeApiError(this.getNode(), new Error('Missing Tavily API key in credentials.'));
throw new NodeApiError(this.getNode(), { message: 'Missing Tavily API key in credentials.' });
}
const apiKey = credentials.apiKey as string;
@ -225,21 +225,21 @@ export class TavilySearch implements INodeType {
const includeDomains = this.getNodeParameter('includeDomains', i, []) as string[];
const excludeDomains = this.getNodeParameter('excludeDomains', i, []) as string[];
// --- Validate input parameters ---
// Validate parameters
if (!query?.trim()) {
throw new NodeApiError(this.getNode(), new Error('Query parameter cannot be empty.'));
throw new NodeApiError(this.getNode(), { message: 'Query parameter cannot be empty.' });
}
if (maxResults < 0 || maxResults > 20) {
throw new NodeApiError(this.getNode(), new Error('Max Results must be between 0 and 20.'));
throw new NodeApiError(this.getNode(), { message: 'Max Results must be between 0 and 20.' });
}
// Use ALLOWED_TIME_RANGES constant
if (!ALLOWED_TIME_RANGES.includes(timeRange)) {
throw new NodeApiError(this.getNode(), new Error(`Invalid timeRange value. Allowed: ${ALLOWED_TIME_RANGES.join(', ')}`));
throw new NodeApiError(this.getNode(), {
message: `Invalid timeRange value. Allowed: ${ALLOWED_TIME_RANGES.join(', ')}`,
});
}
if (topic === 'news' && days < 0) {
throw new NodeApiError(this.getNode(), new Error('Days must be >= 0 when topic is "news".'));
throw new NodeApiError(this.getNode(), { message: 'Days must be >= 0 when topic is "news".' });
}
// ----------------------------------
const body: Record<string, any> = {
query,
@ -267,7 +267,6 @@ export class TavilySearch implements INodeType {
body.exclude_domains = excludeDomains;
}
// Make request via the shared utility
const result = await tavilyApiRequest.call(
this,
'POST',
@ -278,11 +277,10 @@ export class TavilySearch implements INodeType {
returnData.push({ json: result });
} catch (error) {
// Ensure consistent error wrapping
if (error instanceof NodeApiError) {
throw error;
}
throw new NodeApiError(this.getNode(), error as Error);
throw new NodeApiError(this.getNode(), { message: String(error) });
}
}

View file

@ -1,6 +1,6 @@
import axios, { AxiosError, AxiosResponse } from 'axios';
import { NodeApiError } from 'n8n-workflow';
import { IExecuteFunctions } from 'n8n-core';
import { NodeApiError, IExecuteFunctions } from 'n8n-workflow'; // CHANGED
// import { IExecuteFunctions } from 'n8n-core'; // REMOVED
/**
* Common function to call the Tavily API.
@ -30,6 +30,7 @@ export async function tavilyApiRequest(
if (axios.isAxiosError(error)) {
const status = error.response?.status;
let message = `Tavily API error: ${error.message}`;
if (status) {
switch (status) {
case 400:
@ -65,19 +66,19 @@ export async function tavilyApiRequest(
additionalMsgParts.push(`error_message: ${data.error_message}`);
}
if (!data.error_code && !data.error_message) {
// Fall back to a full JSON dump if no known fields
additionalMsgParts.push(JSON.stringify(data));
}
// Append to main message
if (additionalMsgParts.length > 0) {
message += ` | ${additionalMsgParts.join(' | ')}`;
}
}
throw new NodeApiError(this.getNode(), new Error(message));
// PASS A JsonObject
throw new NodeApiError(this.getNode(), { message });
} else {
throw new NodeApiError(this.getNode(), error as Error);
// If not an AxiosError, wrap it
throw new NodeApiError(this.getNode(), { message: String(error) });
}
}

View file

@ -8,7 +8,8 @@
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true
"forceConsistentCasingInFileNames": true,
"useUnknownInCatchVariables": false
},
"include": ["src/**/*.ts"],
"exclude": ["node_modules", "dist"]