UNPKG

n8n-nodes-duckduckgo-search

Version:

AI Agent-ready n8n community node for DuckDuckGo search. Search the web, images, news, and videos with no API key required and no outbound telemetry. Optionally fetch and extract the main text of result pages or any URL, and get DuckDuckGo Instant Answers

1,024 lines 101 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.DuckDuckGo = void 0; const n8n_workflow_1 = require("n8n-workflow"); const duck_duck_scrape_1 = require("duck-duck-scrape"); const directSearch_1 = require("./directSearch"); const types_1 = require("./types"); const processors_1 = require("./processors"); const constants_1 = require("./constants"); const utils_1 = require("./utils"); const cache_1 = require("./cache"); const searchOperators_1 = require("./searchOperators"); const vqdPagination_1 = require("./vqdPagination"); const fallbackSearch_1 = require("./fallbackSearch"); const pageContent_1 = require("./pageContent"); const instantAnswer_1 = require("./instantAnswer"); function sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } function getSafeSearchType(value) { switch (value) { case 0: return duck_duck_scrape_1.SafeSearchType.STRICT; case -1: return duck_duck_scrape_1.SafeSearchType.MODERATE; case -2: return duck_duck_scrape_1.SafeSearchType.OFF; default: return duck_duck_scrape_1.SafeSearchType.MODERATE; } } function getSearchTimeType(value) { switch (value) { case 'pastDay': case 'd': return duck_duck_scrape_1.SearchTimeType.DAY; case 'pastWeek': case 'w': return duck_duck_scrape_1.SearchTimeType.WEEK; case 'pastMonth': case 'm': return duck_duck_scrape_1.SearchTimeType.MONTH; case 'pastYear': case 'y': return duck_duck_scrape_1.SearchTimeType.YEAR; case 'anyTime': case 'a': default: return duck_duck_scrape_1.SearchTimeType.ALL; } } function enhanceSearchQuery(query, searchType = 'web') { const enhancedQuery = query.trim(); void searchType; return enhancedQuery; } async function enrichWithPageContent(results, pageOpts, debugMode, operation) { var _a, _b, _c; if (!pageOpts.fetchPageContent || results.length === 0) { return; } const count = Math.min((_a = pageOpts.pageContentMaxResults) !== null && _a !== void 0 ? _a : 3, results.length); const pcOptions = { timeout: (_b = pageOpts.pageContentTimeout) !== null && _b !== void 0 ? _b : 8000, maxLength: (_c = pageOpts.pageContentMaxLength) !== null && _c !== void 0 ? _c : 2000, }; for (const r of results) { r.json.pageContent = ''; } const targets = results.slice(0, count); const pcResults = await (0, pageContent_1.fetchPageContents)(targets.map(r => (typeof r.json.url === 'string' ? r.json.url : '')), pcOptions); targets.forEach((r, i) => { const pc = pcResults[i]; r.json.pageContent = pc.content; if (pc.truncated) { r.json.pageContentTruncated = true; } if (pc.error) { r.json.pageContentError = pc.error; } if (pageOpts.includePageMetadata && pc.meta) { if (pc.meta.title) r.json.pageTitle = pc.meta.title; if (pc.meta.author) r.json.pageAuthor = pc.meta.author; if (pc.meta.published) r.json.pagePublished = pc.meta.published; if (pc.meta.excerpt) r.json.pageExcerpt = pc.meta.excerpt; if (pc.meta.siteName) r.json.pageSiteName = pc.meta.siteName; } }); if (debugMode) { console.log(JSON.stringify((0, utils_1.createLogEntry)(utils_1.LogLevel.INFO, `Fetched page content for ${count} of ${results.length} ${operation} results`, operation, { count, pageContentOptions: pcOptions }))); } } class DuckDuckGo { constructor() { this.description = { displayName: constants_1.NODE_INFO.DISPLAY_NAME, name: constants_1.NODE_INFO.NAME, icon: 'file:duckduckgo.svg', group: ['transform'], version: constants_1.NODE_INFO.VERSION, subtitle: '={{$parameter["operation"]}}', description: constants_1.NODE_INFO.DESCRIPTION, defaults: { name: constants_1.NODE_INFO.DISPLAY_NAME, }, inputs: ['main'], outputs: ['main'], usableAsTool: true, credentials: [], properties: [ { displayName: 'Operation', name: 'operation', type: 'options', default: types_1.DuckDuckGoOperation.Search, noDataExpression: true, required: true, description: 'Type of search to perform with DuckDuckGo', options: [ { name: 'Web Search', value: types_1.DuckDuckGoOperation.Search, description: 'Search websites and web content', action: 'Search the web', }, { name: 'Image Search', value: types_1.DuckDuckGoOperation.SearchImages, description: 'Find images across the web', action: 'Search for images', }, { name: 'News Search', value: types_1.DuckDuckGoOperation.SearchNews, description: 'Discover news articles and updates', action: 'Search for news', }, { name: 'Video Search', value: types_1.DuckDuckGoOperation.SearchVideos, description: 'Find videos from various sources', action: 'Search for videos', }, { name: 'Extract Page Content', value: types_1.DuckDuckGoOperation.ExtractContent, description: 'Fetch any URL and extract its main text and metadata', action: 'Extract page content from a URL', }, { name: 'Instant Answer', value: types_1.DuckDuckGoOperation.InstantAnswer, description: 'Get a direct answer, abstract, or definition from DuckDuckGo', action: 'Get an instant answer', } ], }, { displayName: 'URL', name: 'url', type: 'string', required: true, default: '', description: 'The URL of the page to fetch and extract text from', placeholder: 'https://example.com/article', displayOptions: { show: { operation: [ types_1.DuckDuckGoOperation.ExtractContent, ], }, }, }, { displayName: 'Options', name: 'extractOptions', type: 'collection', placeholder: 'Add Option', default: {}, displayOptions: { show: { operation: [ types_1.DuckDuckGoOperation.ExtractContent, ], }, }, options: [ { displayName: 'Max Content Length', name: 'pageContentMaxLength', type: 'number', default: 2000, description: 'Maximum number of characters of extracted text to keep, or 0 for no limit', typeOptions: { minValue: 0, }, }, { displayName: 'Page Fetch Timeout', name: 'pageContentTimeout', type: 'number', default: 8000, description: 'Maximum time in milliseconds to wait for the page to load', typeOptions: { minValue: 1000, maxValue: 60000, }, }, { displayName: 'Include Page Metadata', name: 'includePageMetadata', type: 'boolean', default: false, description: 'Whether to also return page metadata (title, author, published, excerpt, siteName) when the page is an article', }, ], }, { displayName: 'Query', name: 'instantAnswerQuery', type: 'string', required: true, default: '', description: 'The term or question to get an instant answer for (e.g. a person, place, or concept)', placeholder: 'e.g. DuckDuckGo', displayOptions: { show: { operation: [ types_1.DuckDuckGoOperation.InstantAnswer, ], }, }, }, { displayName: 'Search Query', name: 'query', type: 'string', required: true, default: '', description: 'The search terms to look for on the web', placeholder: 'Enter your search query', displayOptions: { show: { operation: [ types_1.DuckDuckGoOperation.Search, ], }, }, typeOptions: { minLength: 1, }, }, { displayName: 'Web Search Options', name: 'webSearchOptions', type: 'collection', placeholder: 'Add Option', default: { maxResults: constants_1.DEFAULT_PARAMETERS.MAX_RESULTS, region: constants_1.DEFAULT_PARAMETERS.REGION, safeSearch: constants_1.DEFAULT_PARAMETERS.SAFE_SEARCH, }, displayOptions: { show: { operation: [ types_1.DuckDuckGoOperation.Search, ], }, }, options: [ { displayName: 'Maximum Results', name: 'maxResults', type: 'number', default: constants_1.DEFAULT_PARAMETERS.MAX_RESULTS, description: 'Maximum number of search results to return', typeOptions: { minValue: 1, maxValue: 100, }, }, { displayName: 'Region', name: 'region', type: 'options', default: constants_1.DEFAULT_PARAMETERS.REGION, description: 'The region to target for web search results', options: constants_1.REGIONS, }, { displayName: 'Safe Search', name: 'safeSearch', type: 'options', default: constants_1.DEFAULT_PARAMETERS.SAFE_SEARCH, description: 'Content filtering level for web search', options: [ { name: 'Strict', value: types_1.SafeSearchLevel.Strict, description: 'Filter explicit content', }, { name: 'Moderate', value: types_1.SafeSearchLevel.Moderate, description: 'Default filtering level', }, { name: 'Off', value: types_1.SafeSearchLevel.Off, description: 'No content filtering', } ], }, { displayName: 'Return Raw Results', name: 'returnRawResults', type: 'boolean', default: false, description: 'Whether to return the raw API response instead of processed results', }, { displayName: 'Fetch Page Content', name: 'fetchPageContent', type: 'boolean', default: false, description: 'Whether to fetch each result page and extract its main text into a pageContent field (makes extra requests to third-party sites, so it is slower and not limited to DuckDuckGo)', }, { displayName: 'Number of Results to Fetch', name: 'pageContentMaxResults', type: 'number', default: 3, description: 'How many of the top results to fetch and extract page content for', typeOptions: { minValue: 1, maxValue: 20, }, displayOptions: { show: { fetchPageContent: [true], }, }, }, { displayName: 'Max Content Length', name: 'pageContentMaxLength', type: 'number', default: 2000, description: 'Maximum number of characters of extracted text to keep, or 0 for no limit', typeOptions: { minValue: 0, }, displayOptions: { show: { fetchPageContent: [true], }, }, }, { displayName: 'Page Fetch Timeout', name: 'pageContentTimeout', type: 'number', default: 8000, description: 'Maximum time in milliseconds to wait for each page to load', typeOptions: { minValue: 1000, maxValue: 60000, }, displayOptions: { show: { fetchPageContent: [true], }, }, }, { displayName: 'Include Page Metadata', name: 'includePageMetadata', type: 'boolean', default: false, description: 'Whether to also add page metadata (pageTitle, pageAuthor, pagePublished, pageExcerpt, pageSiteName) when the page is an article', displayOptions: { show: { fetchPageContent: [true], }, }, }, { displayName: 'Use Search Operators', name: 'useSearchOperators', type: 'boolean', default: false, description: 'Whether to enable advanced search operators', }, { displayName: 'Search Operators', name: 'searchOperators', type: 'collection', placeholder: 'Add Search Operator', default: {}, displayOptions: { show: { useSearchOperators: [true], }, }, description: 'Advanced search operators to refine your search', options: [ { displayName: 'Site', name: 'site', type: 'string', default: '', placeholder: searchOperators_1.OPERATOR_INFO.site.placeholder, description: `${searchOperators_1.OPERATOR_INFO.site.description}. Example: ${searchOperators_1.OPERATOR_INFO.site.example}.`, }, { displayName: 'File Type', name: 'filetype', type: 'string', default: '', placeholder: searchOperators_1.OPERATOR_INFO.filetype.placeholder, description: `${searchOperators_1.OPERATOR_INFO.filetype.description}. Example: ${searchOperators_1.OPERATOR_INFO.filetype.example}.`, }, { displayName: 'In Title', name: 'intitle', type: 'string', default: '', placeholder: searchOperators_1.OPERATOR_INFO.intitle.placeholder, description: `${searchOperators_1.OPERATOR_INFO.intitle.description}. Example: ${searchOperators_1.OPERATOR_INFO.intitle.example}.`, }, { displayName: 'In URL', name: 'inurl', type: 'string', default: '', placeholder: searchOperators_1.OPERATOR_INFO.inurl.placeholder, description: `${searchOperators_1.OPERATOR_INFO.inurl.description}. Example: ${searchOperators_1.OPERATOR_INFO.inurl.example}.`, }, { displayName: 'In Body', name: 'inbody', type: 'string', default: '', placeholder: searchOperators_1.OPERATOR_INFO.inbody.placeholder, description: `${searchOperators_1.OPERATOR_INFO.inbody.description}. Example: ${searchOperators_1.OPERATOR_INFO.inbody.example}.`, }, { displayName: 'Exclude Words', name: 'exclude', type: 'string', default: '', placeholder: searchOperators_1.OPERATOR_INFO.exclude.placeholder, description: `${searchOperators_1.OPERATOR_INFO.exclude.description}. Example: ${searchOperators_1.OPERATOR_INFO.exclude.example}.`, }, { displayName: 'Exact Phrase', name: 'exact', type: 'string', default: '', placeholder: searchOperators_1.OPERATOR_INFO.exact.placeholder, description: `${searchOperators_1.OPERATOR_INFO.exact.description}. Example: ${searchOperators_1.OPERATOR_INFO.exact.example}.`, }, { displayName: 'OR Terms', name: 'or', type: 'string', default: '', placeholder: 'term1, term2, term3', description: 'Search for any of these terms (comma-separated). Example: python, javascript, typescript.', }, { displayName: 'Related', name: 'related', type: 'string', default: '', placeholder: searchOperators_1.OPERATOR_INFO.related.placeholder, description: `${searchOperators_1.OPERATOR_INFO.related.description}. Example: ${searchOperators_1.OPERATOR_INFO.related.example}.`, }, { displayName: 'Cache', name: 'cache', type: 'string', default: '', placeholder: searchOperators_1.OPERATOR_INFO.cache.placeholder, description: `${searchOperators_1.OPERATOR_INFO.cache.description}. Example: ${searchOperators_1.OPERATOR_INFO.cache.example}.`, }, { displayName: 'Define', name: 'define', type: 'string', default: '', placeholder: searchOperators_1.OPERATOR_INFO.define.placeholder, description: `${searchOperators_1.OPERATOR_INFO.define.description}. Example: ${searchOperators_1.OPERATOR_INFO.define.example}.`, }, { displayName: 'All In Title', name: 'allintitle', type: 'string', default: '', placeholder: searchOperators_1.OPERATOR_INFO.allintitle.placeholder, description: `${searchOperators_1.OPERATOR_INFO.allintitle.description}. Example: ${searchOperators_1.OPERATOR_INFO.allintitle.example}.`, }, { displayName: 'All In URL', name: 'allinurl', type: 'string', default: '', placeholder: searchOperators_1.OPERATOR_INFO.allinurl.placeholder, description: `${searchOperators_1.OPERATOR_INFO.allinurl.description}. Example: ${searchOperators_1.OPERATOR_INFO.allinurl.example}.`, }, { displayName: 'All In Text', name: 'allintext', type: 'string', default: '', placeholder: searchOperators_1.OPERATOR_INFO.allintext.placeholder, description: `${searchOperators_1.OPERATOR_INFO.allintext.description}. Example: ${searchOperators_1.OPERATOR_INFO.allintext.example}.`, }, { displayName: 'Location', name: 'location', type: 'string', default: '', placeholder: searchOperators_1.OPERATOR_INFO.location.placeholder, description: `${searchOperators_1.OPERATOR_INFO.location.description}. Example: ${searchOperators_1.OPERATOR_INFO.location.example}.`, }, { displayName: 'Language Code', name: 'language', type: 'string', default: '', placeholder: searchOperators_1.OPERATOR_INFO.language.placeholder, description: `${searchOperators_1.OPERATOR_INFO.language.description}. Example: ${searchOperators_1.OPERATOR_INFO.language.example}.`, }, ], }, ], }, { displayName: 'Image Search Query', name: 'imageQuery', type: 'string', required: true, default: '', description: 'The search terms to find images for', placeholder: 'Enter image search query', displayOptions: { show: { operation: [ types_1.DuckDuckGoOperation.SearchImages, ], }, }, typeOptions: { minLength: 1, }, }, { displayName: 'Image Search Options', name: 'imageSearchOptions', type: 'collection', placeholder: 'Add Option', default: { maxResults: constants_1.DEFAULT_PARAMETERS.MAX_RESULTS, region: constants_1.DEFAULT_PARAMETERS.REGION, safeSearch: constants_1.DEFAULT_PARAMETERS.SAFE_SEARCH, }, displayOptions: { show: { operation: [ types_1.DuckDuckGoOperation.SearchImages, ], }, }, options: [ { displayName: 'Maximum Results', name: 'maxResults', type: 'number', default: constants_1.DEFAULT_PARAMETERS.MAX_RESULTS, description: 'Maximum number of image results to return', typeOptions: { minValue: 1, maxValue: 100, }, }, { displayName: 'Region', name: 'region', type: 'options', default: constants_1.DEFAULT_PARAMETERS.REGION, description: 'The region to target for image search', options: constants_1.REGIONS, }, { displayName: 'Safe Search', name: 'safeSearch', type: 'options', default: constants_1.DEFAULT_PARAMETERS.SAFE_SEARCH, description: 'Content filtering level for images', options: [ { name: 'Strict', value: types_1.SafeSearchLevel.Strict, description: 'Filter explicit images', }, { name: 'Moderate', value: types_1.SafeSearchLevel.Moderate, description: 'Default filtering level', }, { name: 'Off', value: types_1.SafeSearchLevel.Off, description: 'No image filtering', } ], }, { displayName: 'Return Raw Results', name: 'returnRawResults', type: 'boolean', default: false, description: 'Whether to return the raw API response instead of processed results', }, ], }, { displayName: 'News Search Query', name: 'newsQuery', type: 'string', required: true, default: '', description: 'The search terms to find news articles for', placeholder: 'Enter news search query', displayOptions: { show: { operation: [ types_1.DuckDuckGoOperation.SearchNews, ], }, }, typeOptions: { minLength: 1, }, }, { displayName: 'News Search Options', name: 'newsSearchOptions', type: 'collection', placeholder: 'Add Option', default: { maxResults: constants_1.DEFAULT_PARAMETERS.MAX_RESULTS, region: constants_1.DEFAULT_PARAMETERS.REGION, safeSearch: constants_1.DEFAULT_PARAMETERS.SAFE_SEARCH, }, displayOptions: { show: { operation: [ types_1.DuckDuckGoOperation.SearchNews, ], }, }, options: [ { displayName: 'Maximum Results', name: 'maxResults', type: 'number', default: constants_1.DEFAULT_PARAMETERS.MAX_RESULTS, description: 'Maximum number of news articles to return', typeOptions: { minValue: 1, maxValue: 100, }, }, { displayName: 'Region', name: 'region', type: 'options', default: constants_1.DEFAULT_PARAMETERS.REGION, description: 'The region to target for news', options: constants_1.REGIONS, }, { displayName: 'Safe Search', name: 'safeSearch', type: 'options', default: constants_1.DEFAULT_PARAMETERS.SAFE_SEARCH, description: 'Content filtering level for news articles', options: [ { name: 'Strict', value: types_1.SafeSearchLevel.Strict, description: 'Filter explicit content', }, { name: 'Moderate', value: types_1.SafeSearchLevel.Moderate, description: 'Default filtering level', }, { name: 'Off', value: types_1.SafeSearchLevel.Off, description: 'No content filtering', } ], }, { displayName: 'Time Period', name: 'timePeriod', type: 'options', default: types_1.TimePeriod.PastWeek, description: 'Time range for news articles', options: [ { name: 'All Time', value: types_1.TimePeriod.AllTime, description: 'No time restriction', }, { name: 'Past Day', value: types_1.TimePeriod.PastDay, description: 'Last 24 hours', }, { name: 'Past Week', value: types_1.TimePeriod.PastWeek, description: 'Last 7 days', }, { name: 'Past Month', value: types_1.TimePeriod.PastMonth, description: 'Last 30 days', }, { name: 'Past Year', value: types_1.TimePeriod.PastYear, description: 'Last 365 days', }, ], }, { displayName: 'Return Raw Results', name: 'returnRawResults', type: 'boolean', default: false, description: 'Whether to return the raw API response instead of processed results', }, { displayName: 'Fetch Page Content', name: 'fetchPageContent', type: 'boolean', default: false, description: 'Whether to fetch each article page and extract its main text into a pageContent field (makes extra requests to third-party sites, so it is slower and not limited to DuckDuckGo)', }, { displayName: 'Number of Results to Fetch', name: 'pageContentMaxResults', type: 'number', default: 3, description: 'How many of the top results to fetch and extract page content for', typeOptions: { minValue: 1, maxValue: 20, }, displayOptions: { show: { fetchPageContent: [true], }, }, }, { displayName: 'Max Content Length', name: 'pageContentMaxLength', type: 'number', default: 2000, description: 'Maximum number of characters of extracted text to keep, or 0 for no limit', typeOptions: { minValue: 0, }, displayOptions: { show: { fetchPageContent: [true], }, }, }, { displayName: 'Page Fetch Timeout', name: 'pageContentTimeout', type: 'number', default: 8000, description: 'Maximum time in milliseconds to wait for each page to load', typeOptions: { minValue: 1000, maxValue: 60000, }, displayOptions: { show: { fetchPageContent: [true], }, }, }, { displayName: 'Include Page Metadata', name: 'includePageMetadata', type: 'boolean', default: false, description: 'Whether to also add page metadata (pageTitle, pageAuthor, pagePublished, pageExcerpt, pageSiteName) when the page is an article', displayOptions: { show: { fetchPageContent: [true], }, }, }, ], }, { displayName: 'Video Search Query', name: 'videoQuery', type: 'string', required: true, default: '', description: 'The search terms to find videos for', placeholder: 'Enter video search query', displayOptions: { show: { operation: [ types_1.DuckDuckGoOperation.SearchVideos, ], }, }, typeOptions: { minLength: 1, }, }, { displayName: 'Video Search Options', name: 'videoSearchOptions', type: 'collection', placeholder: 'Add Option', default: { maxResults: constants_1.DEFAULT_PARAMETERS.MAX_RESULTS, region: constants_1.DEFAULT_PARAMETERS.REGION, safeSearch: constants_1.DEFAULT_PARAMETERS.SAFE_SEARCH, }, displayOptions: { show: { operation: [ types_1.DuckDuckGoOperation.SearchVideos, ], }, }, options: [ { displayName: 'Maximum Results', name: 'maxResults', type: 'number', default: constants_1.DEFAULT_PARAMETERS.MAX_RESULTS, description: 'Maximum number of videos to return', typeOptions: { minValue: 1, maxValue: 100, }, }, { displayName: 'Region', name: 'region', type: 'options', default: constants_1.DEFAULT_PARAMETERS.REGION, description: 'The region to target for videos', options: constants_1.REGIONS, }, { displayName: 'Safe Search', name: 'safeSearch', type: 'options', default: constants_1.DEFAULT_PARAMETERS.SAFE_SEARCH, description: 'Content filtering level for videos', options: [ { name: 'Strict', value: types_1.SafeSearchLevel.Strict, description: 'Filter explicit videos', }, { name: 'Moderate', value: types_1.SafeSearchLevel.Moderate, description: 'Default filtering level', }, { name: 'Off', value: types_1.SafeSearchLevel.Off, description: 'No video filtering', } ], }, { displayName: 'Return Raw Results', name: 'returnRawResults', type: 'boolean', default: false, description: 'Whether to return the raw API response instead of processed results', }, ], }, { displayName: 'Error Handling', name: 'errorHandling', type: 'options', default: 'continueOnFail', description: 'How errors should be handled', options: [ { name: 'Break on Error', value: 'breakOnError', description: 'Stop executing when an error occurs', }, { name: 'Continue on Error', value: 'continueOnFail', description: 'Continue execution even when errors occur', }, ], }, { displayName: 'Debug Mode', name: 'debugMode', type: 'boolean', default: false, description: 'Whether to include detailed request and response information for troubleshooting', }, { displayName: 'Cache Settings', name: 'cacheSettings', type: 'collection', placeholder: 'Add Cache Setting', default: { cacheTTL: 300, enableCache: true, }, options: [ { displayName: 'Enable Cache', name: 'enableCache', type: 'boolean', default: true, description: 'Whether to cache search results to improve performance for repeated queries', }, { displayName: 'Cache TTL', name: 'cacheTTL', type: 'number', default: 300, description: 'Time in seconds to keep results in cache (Time-To-Live)', typeOptions: { minValue: 60, maxValue: 86400, }, }, ], }, ], }; } async _webSearchWithSuperPagination(query, options) { const debugMode = this.getNodeParameter('debugMode', 0, false); const paginationResult = await (0, vqdPagination_1.paginateWithVqd)(query, { safeSearch: getSafeSearchType(options.safeSearch), locale: options.locale, time: options.timePeriod, }, { maxResults: options.maxResults, pageSize: vqdPagination_1.DEFAULT_PAGINATION_CONFIG.pageSize, maxPages: Math.min(vqdPagination_1.DEFAULT_PAGINATION_CONFIG.maxPages, Math.ceil(options.maxResults / vqdPagination_1.DEFAULT_PAGINATION_CONFIG.pageSize)), delayBetweenRequests: vqdPagination_1.DEFAULT_PAGINATION_CONFIG.delayBetweenRequests, debugMode, }); if (paginationResult.results.length < options.maxResults && paginationResult.totalFetched < options.maxResults) { const { parseHtmlResults } = await Promise.resolve().then(() => __importStar(require('./htmlParser'))); const remainingNeeded = options.maxResults - paginationResult.results.length; const htmlResults = []; let offsetHtml = 0; let hasMoreHtml = true; const pageSizeHtml = 10; while (htmlResults.length < remainingNeeded && hasMoreHtml) { cons