#
tokens: 36473/50000 2/653 files (page 51/67)
lines: on (toggle) GitHub
raw markdown copy reset
This is page 51 of 67. Use http://codebase.md/czlonkowski/n8n-mcp?lines=true&page={x} to view the full context.

# Directory Structure

```
├── _config.yml
├── .claude
│   └── agents
│       ├── code-reviewer.md
│       ├── context-manager.md
│       ├── debugger.md
│       ├── deployment-engineer.md
│       ├── mcp-backend-engineer.md
│       ├── n8n-mcp-tester.md
│       ├── technical-researcher.md
│       └── test-automator.md
├── .dockerignore
├── .env.docker
├── .env.example
├── .env.n8n.example
├── .env.test
├── .env.test.example
├── .github
│   ├── ABOUT.md
│   ├── BENCHMARK_THRESHOLDS.md
│   ├── FUNDING.yml
│   ├── gh-pages.yml
│   ├── secret_scanning.yml
│   └── workflows
│       ├── benchmark-pr.yml
│       ├── benchmark.yml
│       ├── dependency-check.yml
│       ├── docker-build-fast.yml
│       ├── docker-build-n8n.yml
│       ├── docker-build.yml
│       ├── release.yml
│       ├── test.yml
│       └── update-n8n-deps.yml
├── .gitignore
├── .npmignore
├── ANALYSIS_QUICK_REFERENCE.md
├── ATTRIBUTION.md
├── CHANGELOG.md
├── CLAUDE.md
├── codecov.yml
├── coverage.json
├── data
│   ├── .gitkeep
│   ├── nodes.db
│   ├── nodes.db-shm
│   ├── nodes.db-wal
│   └── templates.db
├── deploy
│   └── quick-deploy-n8n.sh
├── docker
│   ├── docker-entrypoint.sh
│   ├── n8n-mcp
│   ├── parse-config.js
│   └── README.md
├── docker-compose.buildkit.yml
├── docker-compose.extract.yml
├── docker-compose.n8n.yml
├── docker-compose.override.yml.example
├── docker-compose.test-n8n.yml
├── docker-compose.yml
├── Dockerfile
├── Dockerfile.railway
├── Dockerfile.test
├── docs
│   ├── ANTIGRAVITY_SETUP.md
│   ├── AUTOMATED_RELEASES.md
│   ├── BENCHMARKS.md
│   ├── CHANGELOG.md
│   ├── CI_TEST_INFRASTRUCTURE.md
│   ├── CLAUDE_CODE_SETUP.md
│   ├── CLAUDE_INTERVIEW.md
│   ├── CODECOV_SETUP.md
│   ├── CODEX_SETUP.md
│   ├── CURSOR_SETUP.md
│   ├── DEPENDENCY_UPDATES.md
│   ├── DOCKER_README.md
│   ├── DOCKER_TROUBLESHOOTING.md
│   ├── FINAL_AI_VALIDATION_SPEC.md
│   ├── FLEXIBLE_INSTANCE_CONFIGURATION.md
│   ├── HTTP_DEPLOYMENT.md
│   ├── img
│   │   ├── cc_command.png
│   │   ├── cc_connected.png
│   │   ├── codex_connected.png
│   │   ├── cursor_tut.png
│   │   ├── Railway_api.png
│   │   ├── Railway_server_address.png
│   │   ├── skills.png
│   │   ├── vsc_ghcp_chat_agent_mode.png
│   │   ├── vsc_ghcp_chat_instruction_files.png
│   │   ├── vsc_ghcp_chat_thinking_tool.png
│   │   └── windsurf_tut.png
│   ├── INSTALLATION.md
│   ├── LIBRARY_USAGE.md
│   ├── local
│   │   ├── DEEP_DIVE_ANALYSIS_2025-10-02.md
│   │   ├── DEEP_DIVE_ANALYSIS_README.md
│   │   ├── Deep_dive_p1_p2.md
│   │   ├── integration-testing-plan.md
│   │   ├── integration-tests-phase1-summary.md
│   │   ├── N8N_AI_WORKFLOW_BUILDER_ANALYSIS.md
│   │   ├── P0_IMPLEMENTATION_PLAN.md
│   │   └── TEMPLATE_MINING_ANALYSIS.md
│   ├── MCP_ESSENTIALS_README.md
│   ├── MCP_QUICK_START_GUIDE.md
│   ├── N8N_DEPLOYMENT.md
│   ├── RAILWAY_DEPLOYMENT.md
│   ├── README_CLAUDE_SETUP.md
│   ├── README.md
│   ├── SESSION_PERSISTENCE.md
│   ├── tools-documentation-usage.md
│   ├── TYPE_STRUCTURE_VALIDATION.md
│   ├── VS_CODE_PROJECT_SETUP.md
│   ├── WINDSURF_SETUP.md
│   └── workflow-diff-examples.md
├── examples
│   └── enhanced-documentation-demo.js
├── fetch_log.txt
├── LICENSE
├── MEMORY_N8N_UPDATE.md
├── MEMORY_TEMPLATE_UPDATE.md
├── monitor_fetch.sh
├── N8N_HTTP_STREAMABLE_SETUP.md
├── n8n-nodes.db
├── P0-R3-TEST-PLAN.md
├── package-lock.json
├── package.json
├── package.runtime.json
├── PRIVACY.md
├── railway.json
├── README_ANALYSIS.md
├── README.md
├── renovate.json
├── scripts
│   ├── analyze-optimization.sh
│   ├── audit-schema-coverage.ts
│   ├── backfill-mutation-hashes.ts
│   ├── build-optimized.sh
│   ├── compare-benchmarks.js
│   ├── demo-optimization.sh
│   ├── deploy-http.sh
│   ├── deploy-to-vm.sh
│   ├── export-webhook-workflows.ts
│   ├── extract-changelog.js
│   ├── extract-from-docker.js
│   ├── extract-nodes-docker.sh
│   ├── extract-nodes-simple.sh
│   ├── format-benchmark-results.js
│   ├── generate-benchmark-stub.js
│   ├── generate-detailed-reports.js
│   ├── generate-initial-release-notes.js
│   ├── generate-release-notes.js
│   ├── generate-test-summary.js
│   ├── http-bridge.js
│   ├── mcp-http-client.js
│   ├── migrate-nodes-fts.ts
│   ├── migrate-tool-docs.ts
│   ├── n8n-docs-mcp.service
│   ├── nginx-n8n-mcp.conf
│   ├── prebuild-fts5.ts
│   ├── prepare-release.js
│   ├── process-batch-metadata.ts
│   ├── publish-npm-quick.sh
│   ├── publish-npm.sh
│   ├── quick-test.ts
│   ├── run-benchmarks-ci.js
│   ├── sync-runtime-version.js
│   ├── test-ai-validation-debug.ts
│   ├── test-code-node-enhancements.ts
│   ├── test-code-node-fixes.ts
│   ├── test-docker-config.sh
│   ├── test-docker-fingerprint.ts
│   ├── test-docker-optimization.sh
│   ├── test-docker.sh
│   ├── test-empty-connection-validation.ts
│   ├── test-error-message-tracking.ts
│   ├── test-error-output-validation.ts
│   ├── test-error-validation.js
│   ├── test-essentials.ts
│   ├── test-expression-code-validation.ts
│   ├── test-expression-format-validation.js
│   ├── test-fts5-search.ts
│   ├── test-fuzzy-fix.ts
│   ├── test-fuzzy-simple.ts
│   ├── test-helpers-validation.ts
│   ├── test-http-search.ts
│   ├── test-http.sh
│   ├── test-jmespath-validation.ts
│   ├── test-multi-tenant-simple.ts
│   ├── test-multi-tenant.ts
│   ├── test-n8n-integration.sh
│   ├── test-node-info.js
│   ├── test-node-type-validation.ts
│   ├── test-nodes-base-prefix.ts
│   ├── test-operation-validation.ts
│   ├── test-optimized-docker.sh
│   ├── test-release-automation.js
│   ├── test-search-improvements.ts
│   ├── test-security.ts
│   ├── test-single-session.sh
│   ├── test-sqljs-triggers.ts
│   ├── test-structure-validation.ts
│   ├── test-telemetry-debug.ts
│   ├── test-telemetry-direct.ts
│   ├── test-telemetry-env.ts
│   ├── test-telemetry-integration.ts
│   ├── test-telemetry-no-select.ts
│   ├── test-telemetry-security.ts
│   ├── test-telemetry-simple.ts
│   ├── test-typeversion-validation.ts
│   ├── test-url-configuration.ts
│   ├── test-user-id-persistence.ts
│   ├── test-webhook-validation.ts
│   ├── test-workflow-insert.ts
│   ├── test-workflow-sanitizer.ts
│   ├── test-workflow-tracking-debug.ts
│   ├── test-workflow-versioning.ts
│   ├── update-and-publish-prep.sh
│   ├── update-n8n-deps.js
│   ├── update-readme-version.js
│   ├── vitest-benchmark-json-reporter.js
│   └── vitest-benchmark-reporter.ts
├── SECURITY.md
├── src
│   ├── config
│   │   └── n8n-api.ts
│   ├── constants
│   │   └── type-structures.ts
│   ├── data
│   │   └── canonical-ai-tool-examples.json
│   ├── database
│   │   ├── database-adapter.ts
│   │   ├── migrations
│   │   │   └── add-template-node-configs.sql
│   │   ├── node-repository.ts
│   │   ├── nodes.db
│   │   ├── schema-optimized.sql
│   │   └── schema.sql
│   ├── errors
│   │   └── validation-service-error.ts
│   ├── http-server-single-session.ts
│   ├── http-server.ts
│   ├── index.ts
│   ├── loaders
│   │   └── node-loader.ts
│   ├── mappers
│   │   └── docs-mapper.ts
│   ├── mcp
│   │   ├── handlers-n8n-manager.ts
│   │   ├── handlers-workflow-diff.ts
│   │   ├── index.ts
│   │   ├── server.ts
│   │   ├── stdio-wrapper.ts
│   │   ├── tool-docs
│   │   │   ├── configuration
│   │   │   │   ├── get-node.ts
│   │   │   │   └── index.ts
│   │   │   ├── discovery
│   │   │   │   ├── index.ts
│   │   │   │   └── search-nodes.ts
│   │   │   ├── guides
│   │   │   │   ├── ai-agents-guide.ts
│   │   │   │   └── index.ts
│   │   │   ├── index.ts
│   │   │   ├── system
│   │   │   │   ├── index.ts
│   │   │   │   ├── n8n-diagnostic.ts
│   │   │   │   ├── n8n-health-check.ts
│   │   │   │   ├── n8n-list-available-tools.ts
│   │   │   │   └── tools-documentation.ts
│   │   │   ├── templates
│   │   │   │   ├── get-template.ts
│   │   │   │   ├── index.ts
│   │   │   │   └── search-templates.ts
│   │   │   ├── types.ts
│   │   │   ├── validation
│   │   │   │   ├── index.ts
│   │   │   │   ├── validate-node.ts
│   │   │   │   └── validate-workflow.ts
│   │   │   └── workflow_management
│   │   │       ├── index.ts
│   │   │       ├── n8n-autofix-workflow.ts
│   │   │       ├── n8n-create-workflow.ts
│   │   │       ├── n8n-delete-workflow.ts
│   │   │       ├── n8n-deploy-template.ts
│   │   │       ├── n8n-executions.ts
│   │   │       ├── n8n-get-workflow.ts
│   │   │       ├── n8n-list-workflows.ts
│   │   │       ├── n8n-trigger-webhook-workflow.ts
│   │   │       ├── n8n-update-full-workflow.ts
│   │   │       ├── n8n-update-partial-workflow.ts
│   │   │       ├── n8n-validate-workflow.ts
│   │   │       └── n8n-workflow-versions.ts
│   │   ├── tools-documentation.ts
│   │   ├── tools-n8n-friendly.ts
│   │   ├── tools-n8n-manager.ts
│   │   ├── tools.ts
│   │   └── workflow-examples.ts
│   ├── mcp-engine.ts
│   ├── mcp-tools-engine.ts
│   ├── n8n
│   │   ├── MCPApi.credentials.ts
│   │   └── MCPNode.node.ts
│   ├── parsers
│   │   ├── node-parser.ts
│   │   ├── property-extractor.ts
│   │   └── simple-parser.ts
│   ├── scripts
│   │   ├── debug-http-search.ts
│   │   ├── extract-from-docker.ts
│   │   ├── fetch-templates-robust.ts
│   │   ├── fetch-templates.ts
│   │   ├── rebuild-database.ts
│   │   ├── rebuild-optimized.ts
│   │   ├── rebuild.ts
│   │   ├── sanitize-templates.ts
│   │   ├── seed-canonical-ai-examples.ts
│   │   ├── test-autofix-documentation.ts
│   │   ├── test-autofix-workflow.ts
│   │   ├── test-execution-filtering.ts
│   │   ├── test-node-suggestions.ts
│   │   ├── test-protocol-negotiation.ts
│   │   ├── test-summary.ts
│   │   ├── test-telemetry-mutations-verbose.ts
│   │   ├── test-telemetry-mutations.ts
│   │   ├── test-webhook-autofix.ts
│   │   ├── validate.ts
│   │   └── validation-summary.ts
│   ├── services
│   │   ├── ai-node-validator.ts
│   │   ├── ai-tool-validators.ts
│   │   ├── breaking-change-detector.ts
│   │   ├── breaking-changes-registry.ts
│   │   ├── confidence-scorer.ts
│   │   ├── config-validator.ts
│   │   ├── enhanced-config-validator.ts
│   │   ├── example-generator.ts
│   │   ├── execution-processor.ts
│   │   ├── expression-format-validator.ts
│   │   ├── expression-validator.ts
│   │   ├── n8n-api-client.ts
│   │   ├── n8n-validation.ts
│   │   ├── node-documentation-service.ts
│   │   ├── node-migration-service.ts
│   │   ├── node-sanitizer.ts
│   │   ├── node-similarity-service.ts
│   │   ├── node-specific-validators.ts
│   │   ├── node-version-service.ts
│   │   ├── operation-similarity-service.ts
│   │   ├── post-update-validator.ts
│   │   ├── property-dependencies.ts
│   │   ├── property-filter.ts
│   │   ├── resource-similarity-service.ts
│   │   ├── sqlite-storage-service.ts
│   │   ├── task-templates.ts
│   │   ├── type-structure-service.ts
│   │   ├── universal-expression-validator.ts
│   │   ├── workflow-auto-fixer.ts
│   │   ├── workflow-diff-engine.ts
│   │   ├── workflow-validator.ts
│   │   └── workflow-versioning-service.ts
│   ├── telemetry
│   │   ├── batch-processor.ts
│   │   ├── config-manager.ts
│   │   ├── early-error-logger.ts
│   │   ├── error-sanitization-utils.ts
│   │   ├── error-sanitizer.ts
│   │   ├── event-tracker.ts
│   │   ├── event-validator.ts
│   │   ├── index.ts
│   │   ├── intent-classifier.ts
│   │   ├── intent-sanitizer.ts
│   │   ├── mutation-tracker.ts
│   │   ├── mutation-types.ts
│   │   ├── mutation-validator.ts
│   │   ├── performance-monitor.ts
│   │   ├── rate-limiter.ts
│   │   ├── startup-checkpoints.ts
│   │   ├── telemetry-error.ts
│   │   ├── telemetry-manager.ts
│   │   ├── telemetry-types.ts
│   │   └── workflow-sanitizer.ts
│   ├── templates
│   │   ├── batch-processor.ts
│   │   ├── metadata-generator.ts
│   │   ├── README.md
│   │   ├── template-fetcher.ts
│   │   ├── template-repository.ts
│   │   └── template-service.ts
│   ├── types
│   │   ├── index.ts
│   │   ├── instance-context.ts
│   │   ├── n8n-api.ts
│   │   ├── node-types.ts
│   │   ├── session-state.ts
│   │   ├── type-structures.ts
│   │   └── workflow-diff.ts
│   └── utils
│       ├── auth.ts
│       ├── bridge.ts
│       ├── cache-utils.ts
│       ├── console-manager.ts
│       ├── documentation-fetcher.ts
│       ├── enhanced-documentation-fetcher.ts
│       ├── error-handler.ts
│       ├── example-generator.ts
│       ├── expression-utils.ts
│       ├── fixed-collection-validator.ts
│       ├── logger.ts
│       ├── mcp-client.ts
│       ├── n8n-errors.ts
│       ├── node-classification.ts
│       ├── node-source-extractor.ts
│       ├── node-type-normalizer.ts
│       ├── node-type-utils.ts
│       ├── node-utils.ts
│       ├── npm-version-checker.ts
│       ├── protocol-version.ts
│       ├── simple-cache.ts
│       ├── ssrf-protection.ts
│       ├── template-node-resolver.ts
│       ├── template-sanitizer.ts
│       ├── url-detector.ts
│       ├── validation-schemas.ts
│       └── version.ts
├── test-output.txt
├── test-reinit-fix.sh
├── tests
│   ├── __snapshots__
│   │   └── .gitkeep
│   ├── auth.test.ts
│   ├── benchmarks
│   │   ├── database-queries.bench.ts
│   │   ├── index.ts
│   │   ├── mcp-tools.bench.ts
│   │   ├── mcp-tools.bench.ts.disabled
│   │   ├── mcp-tools.bench.ts.skip
│   │   ├── node-loading.bench.ts.disabled
│   │   ├── README.md
│   │   ├── search-operations.bench.ts.disabled
│   │   └── validation-performance.bench.ts.disabled
│   ├── bridge.test.ts
│   ├── comprehensive-extraction-test.js
│   ├── data
│   │   └── .gitkeep
│   ├── debug-slack-doc.js
│   ├── demo-enhanced-documentation.js
│   ├── docker-tests-README.md
│   ├── error-handler.test.ts
│   ├── examples
│   │   └── using-database-utils.test.ts
│   ├── extracted-nodes-db
│   │   ├── database-import.json
│   │   ├── extraction-report.json
│   │   ├── insert-nodes.sql
│   │   ├── n8n-nodes-base__Airtable.json
│   │   ├── n8n-nodes-base__Discord.json
│   │   ├── n8n-nodes-base__Function.json
│   │   ├── n8n-nodes-base__HttpRequest.json
│   │   ├── n8n-nodes-base__If.json
│   │   ├── n8n-nodes-base__Slack.json
│   │   ├── n8n-nodes-base__SplitInBatches.json
│   │   └── n8n-nodes-base__Webhook.json
│   ├── factories
│   │   ├── node-factory.ts
│   │   └── property-definition-factory.ts
│   ├── fixtures
│   │   ├── .gitkeep
│   │   ├── database
│   │   │   └── test-nodes.json
│   │   ├── factories
│   │   │   ├── node.factory.ts
│   │   │   └── parser-node.factory.ts
│   │   └── template-configs.ts
│   ├── helpers
│   │   └── env-helpers.ts
│   ├── http-server-auth.test.ts
│   ├── integration
│   │   ├── ai-validation
│   │   │   ├── ai-agent-validation.test.ts
│   │   │   ├── ai-tool-validation.test.ts
│   │   │   ├── chat-trigger-validation.test.ts
│   │   │   ├── e2e-validation.test.ts
│   │   │   ├── helpers.ts
│   │   │   ├── llm-chain-validation.test.ts
│   │   │   ├── README.md
│   │   │   └── TEST_REPORT.md
│   │   ├── ci
│   │   │   └── database-population.test.ts
│   │   ├── database
│   │   │   ├── connection-management.test.ts
│   │   │   ├── empty-database.test.ts
│   │   │   ├── fts5-search.test.ts
│   │   │   ├── node-fts5-search.test.ts
│   │   │   ├── node-repository.test.ts
│   │   │   ├── performance.test.ts
│   │   │   ├── sqljs-memory-leak.test.ts
│   │   │   ├── template-node-configs.test.ts
│   │   │   ├── template-repository.test.ts
│   │   │   ├── test-utils.ts
│   │   │   └── transactions.test.ts
│   │   ├── database-integration.test.ts
│   │   ├── docker
│   │   │   ├── docker-config.test.ts
│   │   │   ├── docker-entrypoint.test.ts
│   │   │   └── test-helpers.ts
│   │   ├── flexible-instance-config.test.ts
│   │   ├── mcp
│   │   │   └── template-examples-e2e.test.ts
│   │   ├── mcp-protocol
│   │   │   ├── basic-connection.test.ts
│   │   │   ├── error-handling.test.ts
│   │   │   ├── performance.test.ts
│   │   │   ├── protocol-compliance.test.ts
│   │   │   ├── README.md
│   │   │   ├── session-management.test.ts
│   │   │   ├── test-helpers.ts
│   │   │   ├── tool-invocation.test.ts
│   │   │   └── workflow-error-validation.test.ts
│   │   ├── msw-setup.test.ts
│   │   ├── n8n-api
│   │   │   ├── executions
│   │   │   │   ├── delete-execution.test.ts
│   │   │   │   ├── get-execution.test.ts
│   │   │   │   ├── list-executions.test.ts
│   │   │   │   └── trigger-webhook.test.ts
│   │   │   ├── scripts
│   │   │   │   └── cleanup-orphans.ts
│   │   │   ├── system
│   │   │   │   ├── diagnostic.test.ts
│   │   │   │   └── health-check.test.ts
│   │   │   ├── test-connection.ts
│   │   │   ├── types
│   │   │   │   └── mcp-responses.ts
│   │   │   ├── utils
│   │   │   │   ├── cleanup-helpers.ts
│   │   │   │   ├── credentials.ts
│   │   │   │   ├── factories.ts
│   │   │   │   ├── fixtures.ts
│   │   │   │   ├── mcp-context.ts
│   │   │   │   ├── n8n-client.ts
│   │   │   │   ├── node-repository.ts
│   │   │   │   ├── response-types.ts
│   │   │   │   ├── test-context.ts
│   │   │   │   └── webhook-workflows.ts
│   │   │   └── workflows
│   │   │       ├── autofix-workflow.test.ts
│   │   │       ├── create-workflow.test.ts
│   │   │       ├── delete-workflow.test.ts
│   │   │       ├── get-workflow-details.test.ts
│   │   │       ├── get-workflow-minimal.test.ts
│   │   │       ├── get-workflow-structure.test.ts
│   │   │       ├── get-workflow.test.ts
│   │   │       ├── list-workflows.test.ts
│   │   │       ├── smart-parameters.test.ts
│   │   │       ├── update-partial-workflow.test.ts
│   │   │       ├── update-workflow.test.ts
│   │   │       └── validate-workflow.test.ts
│   │   ├── security
│   │   │   ├── command-injection-prevention.test.ts
│   │   │   └── rate-limiting.test.ts
│   │   ├── setup
│   │   │   ├── integration-setup.ts
│   │   │   └── msw-test-server.ts
│   │   ├── telemetry
│   │   │   ├── docker-user-id-stability.test.ts
│   │   │   └── mcp-telemetry.test.ts
│   │   ├── templates
│   │   │   └── metadata-operations.test.ts
│   │   ├── validation
│   │   │   └── real-world-structure-validation.test.ts
│   │   ├── workflow-creation-node-type-format.test.ts
│   │   └── workflow-diff
│   │       ├── ai-node-connection-validation.test.ts
│   │       └── node-rename-integration.test.ts
│   ├── logger.test.ts
│   ├── MOCKING_STRATEGY.md
│   ├── mocks
│   │   ├── n8n-api
│   │   │   ├── data
│   │   │   │   ├── credentials.ts
│   │   │   │   ├── executions.ts
│   │   │   │   └── workflows.ts
│   │   │   ├── handlers.ts
│   │   │   └── index.ts
│   │   └── README.md
│   ├── node-storage-export.json
│   ├── setup
│   │   ├── global-setup.ts
│   │   ├── msw-setup.ts
│   │   ├── TEST_ENV_DOCUMENTATION.md
│   │   └── test-env.ts
│   ├── test-database-extraction.js
│   ├── test-direct-extraction.js
│   ├── test-enhanced-documentation.js
│   ├── test-enhanced-integration.js
│   ├── test-mcp-extraction.js
│   ├── test-mcp-server-extraction.js
│   ├── test-mcp-tools-integration.js
│   ├── test-node-documentation-service.js
│   ├── test-node-list.js
│   ├── test-package-info.js
│   ├── test-parsing-operations.js
│   ├── test-slack-node-complete.js
│   ├── test-small-rebuild.js
│   ├── test-sqlite-search.js
│   ├── test-storage-system.js
│   ├── unit
│   │   ├── __mocks__
│   │   │   ├── n8n-nodes-base.test.ts
│   │   │   ├── n8n-nodes-base.ts
│   │   │   └── README.md
│   │   ├── constants
│   │   │   └── type-structures.test.ts
│   │   ├── database
│   │   │   ├── __mocks__
│   │   │   │   └── better-sqlite3.ts
│   │   │   ├── database-adapter-unit.test.ts
│   │   │   ├── node-repository-core.test.ts
│   │   │   ├── node-repository-operations.test.ts
│   │   │   ├── node-repository-outputs.test.ts
│   │   │   ├── README.md
│   │   │   └── template-repository-core.test.ts
│   │   ├── docker
│   │   │   ├── config-security.test.ts
│   │   │   ├── edge-cases.test.ts
│   │   │   ├── parse-config.test.ts
│   │   │   └── serve-command.test.ts
│   │   ├── errors
│   │   │   └── validation-service-error.test.ts
│   │   ├── examples
│   │   │   └── using-n8n-nodes-base-mock.test.ts
│   │   ├── flexible-instance-security-advanced.test.ts
│   │   ├── flexible-instance-security.test.ts
│   │   ├── http-server
│   │   │   ├── multi-tenant-support.test.ts
│   │   │   └── session-persistence.test.ts
│   │   ├── http-server-n8n-mode.test.ts
│   │   ├── http-server-n8n-reinit.test.ts
│   │   ├── http-server-session-management.test.ts
│   │   ├── loaders
│   │   │   └── node-loader.test.ts
│   │   ├── mappers
│   │   │   └── docs-mapper.test.ts
│   │   ├── mcp
│   │   │   ├── disabled-tools-additional.test.ts
│   │   │   ├── disabled-tools.test.ts
│   │   │   ├── get-node-essentials-examples.test.ts
│   │   │   ├── get-node-unified.test.ts
│   │   │   ├── handlers-deploy-template.test.ts
│   │   │   ├── handlers-n8n-manager-simple.test.ts
│   │   │   ├── handlers-n8n-manager.test.ts
│   │   │   ├── handlers-workflow-diff.test.ts
│   │   │   ├── lru-cache-behavior.test.ts
│   │   │   ├── multi-tenant-tool-listing.test.ts.disabled
│   │   │   ├── parameter-validation.test.ts
│   │   │   ├── search-nodes-examples.test.ts
│   │   │   ├── tools-documentation.test.ts
│   │   │   └── tools.test.ts
│   │   ├── mcp-engine
│   │   │   └── session-persistence.test.ts
│   │   ├── monitoring
│   │   │   └── cache-metrics.test.ts
│   │   ├── MULTI_TENANT_TEST_COVERAGE.md
│   │   ├── multi-tenant-integration.test.ts
│   │   ├── parsers
│   │   │   ├── node-parser-outputs.test.ts
│   │   │   ├── node-parser.test.ts
│   │   │   ├── property-extractor.test.ts
│   │   │   └── simple-parser.test.ts
│   │   ├── scripts
│   │   │   └── fetch-templates-extraction.test.ts
│   │   ├── services
│   │   │   ├── ai-node-validator.test.ts
│   │   │   ├── ai-tool-validators.test.ts
│   │   │   ├── breaking-change-detector.test.ts
│   │   │   ├── confidence-scorer.test.ts
│   │   │   ├── config-validator-basic.test.ts
│   │   │   ├── config-validator-edge-cases.test.ts
│   │   │   ├── config-validator-node-specific.test.ts
│   │   │   ├── config-validator-security.test.ts
│   │   │   ├── debug-validator.test.ts
│   │   │   ├── enhanced-config-validator-integration.test.ts
│   │   │   ├── enhanced-config-validator-operations.test.ts
│   │   │   ├── enhanced-config-validator-type-structures.test.ts
│   │   │   ├── enhanced-config-validator.test.ts
│   │   │   ├── example-generator.test.ts
│   │   │   ├── execution-processor.test.ts
│   │   │   ├── expression-format-validator.test.ts
│   │   │   ├── expression-validator-edge-cases.test.ts
│   │   │   ├── expression-validator.test.ts
│   │   │   ├── fixed-collection-validation.test.ts
│   │   │   ├── loop-output-edge-cases.test.ts
│   │   │   ├── n8n-api-client.test.ts
│   │   │   ├── n8n-validation-sticky-notes.test.ts
│   │   │   ├── n8n-validation.test.ts
│   │   │   ├── node-migration-service.test.ts
│   │   │   ├── node-sanitizer.test.ts
│   │   │   ├── node-similarity-service.test.ts
│   │   │   ├── node-specific-validators.test.ts
│   │   │   ├── node-version-service.test.ts
│   │   │   ├── operation-similarity-service-comprehensive.test.ts
│   │   │   ├── operation-similarity-service.test.ts
│   │   │   ├── post-update-validator.test.ts
│   │   │   ├── property-dependencies.test.ts
│   │   │   ├── property-filter-edge-cases.test.ts
│   │   │   ├── property-filter.test.ts
│   │   │   ├── resource-similarity-service-comprehensive.test.ts
│   │   │   ├── resource-similarity-service.test.ts
│   │   │   ├── task-templates.test.ts
│   │   │   ├── template-service.test.ts
│   │   │   ├── type-structure-service.test.ts
│   │   │   ├── universal-expression-validator.test.ts
│   │   │   ├── validation-fixes.test.ts
│   │   │   ├── workflow-auto-fixer.test.ts
│   │   │   ├── workflow-diff-engine.test.ts
│   │   │   ├── workflow-diff-node-rename.test.ts
│   │   │   ├── workflow-fixed-collection-validation.test.ts
│   │   │   ├── workflow-validator-comprehensive.test.ts
│   │   │   ├── workflow-validator-edge-cases.test.ts
│   │   │   ├── workflow-validator-error-outputs.test.ts
│   │   │   ├── workflow-validator-expression-format.test.ts
│   │   │   ├── workflow-validator-loops-simple.test.ts
│   │   │   ├── workflow-validator-loops.test.ts
│   │   │   ├── workflow-validator-mocks.test.ts
│   │   │   ├── workflow-validator-performance.test.ts
│   │   │   ├── workflow-validator-with-mocks.test.ts
│   │   │   ├── workflow-validator.test.ts
│   │   │   └── workflow-versioning-service.test.ts
│   │   ├── telemetry
│   │   │   ├── batch-processor.test.ts
│   │   │   ├── config-manager.test.ts
│   │   │   ├── event-tracker.test.ts
│   │   │   ├── event-validator.test.ts
│   │   │   ├── mutation-tracker.test.ts
│   │   │   ├── mutation-validator.test.ts
│   │   │   ├── rate-limiter.test.ts
│   │   │   ├── telemetry-error.test.ts
│   │   │   ├── telemetry-manager.test.ts
│   │   │   ├── v2.18.3-fixes-verification.test.ts
│   │   │   └── workflow-sanitizer.test.ts
│   │   ├── templates
│   │   │   ├── batch-processor.test.ts
│   │   │   ├── metadata-generator.test.ts
│   │   │   ├── template-repository-metadata.test.ts
│   │   │   └── template-repository-security.test.ts
│   │   ├── test-env-example.test.ts
│   │   ├── test-infrastructure.test.ts
│   │   ├── types
│   │   │   ├── instance-context-coverage.test.ts
│   │   │   ├── instance-context-multi-tenant.test.ts
│   │   │   └── type-structures.test.ts
│   │   ├── utils
│   │   │   ├── auth-timing-safe.test.ts
│   │   │   ├── cache-utils.test.ts
│   │   │   ├── console-manager.test.ts
│   │   │   ├── database-utils.test.ts
│   │   │   ├── expression-utils.test.ts
│   │   │   ├── fixed-collection-validator.test.ts
│   │   │   ├── n8n-errors.test.ts
│   │   │   ├── node-classification.test.ts
│   │   │   ├── node-type-normalizer.test.ts
│   │   │   ├── node-type-utils.test.ts
│   │   │   ├── node-utils.test.ts
│   │   │   ├── simple-cache-memory-leak-fix.test.ts
│   │   │   ├── ssrf-protection.test.ts
│   │   │   └── template-node-resolver.test.ts
│   │   └── validation-fixes.test.ts
│   └── utils
│       ├── assertions.ts
│       ├── builders
│       │   └── workflow.builder.ts
│       ├── data-generators.ts
│       ├── database-utils.ts
│       ├── README.md
│       └── test-helpers.ts
├── thumbnail.png
├── tsconfig.build.json
├── tsconfig.json
├── types
│   ├── mcp.d.ts
│   └── test-env.d.ts
├── versioned-nodes.md
├── vitest.config.benchmark.ts
├── vitest.config.integration.ts
└── vitest.config.ts
```

# Files

--------------------------------------------------------------------------------
/tests/extracted-nodes-db/n8n-nodes-base__HttpRequest.json:
--------------------------------------------------------------------------------

```json
  1 | {
  2 |   "node_type": "n8n-nodes-base.HttpRequest",
  3 |   "name": "HttpRequest",
  4 |   "package_name": "n8n-nodes-base",
  5 |   "code_hash": "5b5e2328474b7e85361c940dfe942e167b3f0057f38062f56d6b693f0a7ffe7e",
  6 |   "code_length": 1343,
  7 |   "source_location": "node_modules/n8n-nodes-base/dist/nodes/HttpRequest/HttpRequest.node.js",
  8 |   "has_credentials": false,
  9 |   "source_code": "\"use strict\";\nObject.defineProperty(exports, \"__esModule\", { value: true });\nexports.HttpRequest = void 0;\nconst n8n_workflow_1 = require(\"n8n-workflow\");\nconst HttpRequestV1_node_1 = require(\"./V1/HttpRequestV1.node\");\nconst HttpRequestV2_node_1 = require(\"./V2/HttpRequestV2.node\");\nconst HttpRequestV3_node_1 = require(\"./V3/HttpRequestV3.node\");\nclass HttpRequest extends n8n_workflow_1.VersionedNodeType {\n    constructor() {\n        const baseDescription = {\n            displayName: 'HTTP Request',\n            name: 'httpRequest',\n            icon: 'fa:at',\n            group: ['output'],\n            subtitle: '={{$parameter[\"requestMethod\"] + \": \" + $parameter[\"url\"]}}',\n            description: 'Makes an HTTP request and returns the response data',\n            defaultVersion: 4.1,\n        };\n        const nodeVersions = {\n            1: new HttpRequestV1_node_1.HttpRequestV1(baseDescription),\n            2: new HttpRequestV2_node_1.HttpRequestV2(baseDescription),\n            3: new HttpRequestV3_node_1.HttpRequestV3(baseDescription),\n            4: new HttpRequestV3_node_1.HttpRequestV3(baseDescription),\n            4.1: new HttpRequestV3_node_1.HttpRequestV3(baseDescription),\n        };\n        super(nodeVersions, baseDescription);\n    }\n}\nexports.HttpRequest = HttpRequest;\n//# sourceMappingURL=HttpRequest.node.js.map",
 10 |   "package_info": {
 11 |     "name": "n8n-nodes-base",
 12 |     "version": "1.14.1",
 13 |     "description": "Base nodes of n8n",
 14 |     "license": "SEE LICENSE IN LICENSE.md",
 15 |     "homepage": "https://n8n.io",
 16 |     "author": {
 17 |       "name": "Jan Oberhauser",
 18 |       "email": "[email protected]"
 19 |     },
 20 |     "main": "index.js",
 21 |     "repository": {
 22 |       "type": "git",
 23 |       "url": "git+https://github.com/n8n-io/n8n.git"
 24 |     },
 25 |     "files": [
 26 |       "dist"
 27 |     ],
 28 |     "n8n": {
 29 |       "credentials": [
 30 |         "dist/credentials/ActionNetworkApi.credentials.js",
 31 |         "dist/credentials/ActiveCampaignApi.credentials.js",
 32 |         "dist/credentials/AcuitySchedulingApi.credentials.js",
 33 |         "dist/credentials/AcuitySchedulingOAuth2Api.credentials.js",
 34 |         "dist/credentials/AdaloApi.credentials.js",
 35 |         "dist/credentials/AffinityApi.credentials.js",
 36 |         "dist/credentials/AgileCrmApi.credentials.js",
 37 |         "dist/credentials/AirtableApi.credentials.js",
 38 |         "dist/credentials/AirtableOAuth2Api.credentials.js",
 39 |         "dist/credentials/AirtableTokenApi.credentials.js",
 40 |         "dist/credentials/AlienVaultApi.credentials.js",
 41 |         "dist/credentials/Amqp.credentials.js",
 42 |         "dist/credentials/ApiTemplateIoApi.credentials.js",
 43 |         "dist/credentials/AsanaApi.credentials.js",
 44 |         "dist/credentials/AsanaOAuth2Api.credentials.js",
 45 |         "dist/credentials/Auth0ManagementApi.credentials.js",
 46 |         "dist/credentials/AutomizyApi.credentials.js",
 47 |         "dist/credentials/AutopilotApi.credentials.js",
 48 |         "dist/credentials/Aws.credentials.js",
 49 |         "dist/credentials/BambooHrApi.credentials.js",
 50 |         "dist/credentials/BannerbearApi.credentials.js",
 51 |         "dist/credentials/BaserowApi.credentials.js",
 52 |         "dist/credentials/BeeminderApi.credentials.js",
 53 |         "dist/credentials/BitbucketApi.credentials.js",
 54 |         "dist/credentials/BitlyApi.credentials.js",
 55 |         "dist/credentials/BitlyOAuth2Api.credentials.js",
 56 |         "dist/credentials/BitwardenApi.credentials.js",
 57 |         "dist/credentials/BoxOAuth2Api.credentials.js",
 58 |         "dist/credentials/BrandfetchApi.credentials.js",
 59 |         "dist/credentials/BubbleApi.credentials.js",
 60 |         "dist/credentials/CalApi.credentials.js",
 61 |         "dist/credentials/CalendlyApi.credentials.js",
 62 |         "dist/credentials/CarbonBlackApi.credentials.js",
 63 |         "dist/credentials/ChargebeeApi.credentials.js",
 64 |         "dist/credentials/CircleCiApi.credentials.js",
 65 |         "dist/credentials/CiscoMerakiApi.credentials.js",
 66 |         "dist/credentials/CiscoSecureEndpointApi.credentials.js",
 67 |         "dist/credentials/CiscoWebexOAuth2Api.credentials.js",
 68 |         "dist/credentials/CiscoUmbrellaApi.credentials.js",
 69 |         "dist/credentials/CitrixAdcApi.credentials.js",
 70 |         "dist/credentials/CloudflareApi.credentials.js",
 71 |         "dist/credentials/ClearbitApi.credentials.js",
 72 |         "dist/credentials/ClickUpApi.credentials.js",
 73 |         "dist/credentials/ClickUpOAuth2Api.credentials.js",
 74 |         "dist/credentials/ClockifyApi.credentials.js",
 75 |         "dist/credentials/CockpitApi.credentials.js",
 76 |         "dist/credentials/CodaApi.credentials.js",
 77 |         "dist/credentials/ContentfulApi.credentials.js",
 78 |         "dist/credentials/ConvertKitApi.credentials.js",
 79 |         "dist/credentials/CopperApi.credentials.js",
 80 |         "dist/credentials/CortexApi.credentials.js",
 81 |         "dist/credentials/CrateDb.credentials.js",
 82 |         "dist/credentials/CrowdStrikeOAuth2Api.credentials.js",
 83 |         "dist/credentials/CrowdDevApi.credentials.js",
 84 |         "dist/credentials/CustomerIoApi.credentials.js",
 85 |         "dist/credentials/DeepLApi.credentials.js",
 86 |         "dist/credentials/DemioApi.credentials.js",
 87 |         "dist/credentials/DhlApi.credentials.js",
 88 |         "dist/credentials/DiscourseApi.credentials.js",
 89 |         "dist/credentials/DisqusApi.credentials.js",
 90 |         "dist/credentials/DriftApi.credentials.js",
 91 |         "dist/credentials/DriftOAuth2Api.credentials.js",
 92 |         "dist/credentials/DropboxApi.credentials.js",
 93 |         "dist/credentials/DropboxOAuth2Api.credentials.js",
 94 |         "dist/credentials/DropcontactApi.credentials.js",
 95 |         "dist/credentials/EgoiApi.credentials.js",
 96 |         "dist/credentials/ElasticsearchApi.credentials.js",
 97 |         "dist/credentials/ElasticSecurityApi.credentials.js",
 98 |         "dist/credentials/EmeliaApi.credentials.js",
 99 |         "dist/credentials/ERPNextApi.credentials.js",
100 |         "dist/credentials/EventbriteApi.credentials.js",
101 |         "dist/credentials/EventbriteOAuth2Api.credentials.js",
102 |         "dist/credentials/F5BigIpApi.credentials.js",
103 |         "dist/credentials/FacebookGraphApi.credentials.js",
104 |         "dist/credentials/FacebookGraphAppApi.credentials.js",
105 |         "dist/credentials/FacebookLeadAdsOAuth2Api.credentials.js",
106 |         "dist/credentials/FigmaApi.credentials.js",
107 |         "dist/credentials/FileMaker.credentials.js",
108 |         "dist/credentials/FlowApi.credentials.js",
109 |         "dist/credentials/FormIoApi.credentials.js",
110 |         "dist/credentials/FormstackApi.credentials.js",
111 |         "dist/credentials/FormstackOAuth2Api.credentials.js",
112 |         "dist/credentials/FortiGateApi.credentials.js",
113 |         "dist/credentials/FreshdeskApi.credentials.js",
114 |         "dist/credentials/FreshserviceApi.credentials.js",
115 |         "dist/credentials/FreshworksCrmApi.credentials.js",
116 |         "dist/credentials/Ftp.credentials.js",
117 |         "dist/credentials/GetResponseApi.credentials.js",
118 |         "dist/credentials/GetResponseOAuth2Api.credentials.js",
119 |         "dist/credentials/GhostAdminApi.credentials.js",
120 |         "dist/credentials/GhostContentApi.credentials.js",
121 |         "dist/credentials/GithubApi.credentials.js",
122 |         "dist/credentials/GithubOAuth2Api.credentials.js",
123 |         "dist/credentials/GitlabApi.credentials.js",
124 |         "dist/credentials/GitlabOAuth2Api.credentials.js",
125 |         "dist/credentials/GitPassword.credentials.js",
126 |         "dist/credentials/GmailOAuth2Api.credentials.js",
127 |         "dist/credentials/GoogleAdsOAuth2Api.credentials.js",
128 |         "dist/credentials/GoogleAnalyticsOAuth2Api.credentials.js",
129 |         "dist/credentials/GoogleApi.credentials.js",
130 |         "dist/credentials/GoogleBigQueryOAuth2Api.credentials.js",
131 |         "dist/credentials/GoogleBooksOAuth2Api.credentials.js",
132 |         "dist/credentials/GoogleCalendarOAuth2Api.credentials.js",
133 |         "dist/credentials/GoogleCloudNaturalLanguageOAuth2Api.credentials.js",
134 |         "dist/credentials/GoogleCloudStorageOAuth2Api.credentials.js",
135 |         "dist/credentials/GoogleContactsOAuth2Api.credentials.js",
136 |         "dist/credentials/GoogleDocsOAuth2Api.credentials.js",
137 |         "dist/credentials/GoogleDriveOAuth2Api.credentials.js",
138 |         "dist/credentials/GoogleFirebaseCloudFirestoreOAuth2Api.credentials.js",
139 |         "dist/credentials/GoogleFirebaseRealtimeDatabaseOAuth2Api.credentials.js",
140 |         "dist/credentials/GoogleOAuth2Api.credentials.js",
141 |         "dist/credentials/GooglePerspectiveOAuth2Api.credentials.js",
142 |         "dist/credentials/GoogleSheetsOAuth2Api.credentials.js",
143 |         "dist/credentials/GoogleSheetsTriggerOAuth2Api.credentials.js",
144 |         "dist/credentials/GoogleSlidesOAuth2Api.credentials.js",
145 |         "dist/credentials/GoogleTasksOAuth2Api.credentials.js",
146 |         "dist/credentials/GoogleTranslateOAuth2Api.credentials.js",
147 |         "dist/credentials/GotifyApi.credentials.js",
148 |         "dist/credentials/GoToWebinarOAuth2Api.credentials.js",
149 |         "dist/credentials/GristApi.credentials.js",
150 |         "dist/credentials/GrafanaApi.credentials.js",
151 |         "dist/credentials/GSuiteAdminOAuth2Api.credentials.js",
152 |         "dist/credentials/GumroadApi.credentials.js",
153 |         "dist/credentials/HaloPSAApi.credentials.js",
154 |         "dist/credentials/HarvestApi.credentials.js",
155 |         "dist/credentials/HarvestOAuth2Api.credentials.js",
156 |         "dist/credentials/HelpScoutOAuth2Api.credentials.js",
157 |         "dist/credentials/HighLevelApi.credentials.js",
158 |         "dist/credentials/HomeAssistantApi.credentials.js",
159 |         "dist/credentials/HttpBasicAuth.credentials.js",
160 |         "dist/credentials/HttpDigestAuth.credentials.js",
161 |         "dist/credentials/HttpHeaderAuth.credentials.js",
162 |         "dist/credentials/HttpCustomAuth.credentials.js",
163 |         "dist/credentials/HttpQueryAuth.credentials.js",
164 |         "dist/credentials/HubspotApi.credentials.js",
165 |         "dist/credentials/HubspotAppToken.credentials.js",
166 |         "dist/credentials/HubspotDeveloperApi.credentials.js",
167 |         "dist/credentials/HubspotOAuth2Api.credentials.js",
168 |         "dist/credentials/HumanticAiApi.credentials.js",
169 |         "dist/credentials/HunterApi.credentials.js",
170 |         "dist/credentials/HybridAnalysisApi.credentials.js",
171 |         "dist/credentials/Imap.credentials.js",
172 |         "dist/credentials/ImpervaWafApi.credentials.js",
173 |         "dist/credentials/IntercomApi.credentials.js",
174 |         "dist/credentials/InvoiceNinjaApi.credentials.js",
175 |         "dist/credentials/IterableApi.credentials.js",
176 |         "dist/credentials/JenkinsApi.credentials.js",
177 |         "dist/credentials/JiraSoftwareCloudApi.credentials.js",
178 |         "dist/credentials/JiraSoftwareServerApi.credentials.js",
179 |         "dist/credentials/JotFormApi.credentials.js",
180 |         "dist/credentials/Kafka.credentials.js",
181 |         "dist/credentials/KeapOAuth2Api.credentials.js",
182 |         "dist/credentials/KibanaApi.credentials.js",
183 |         "dist/credentials/KitemakerApi.credentials.js",
184 |         "dist/credentials/KoBoToolboxApi.credentials.js",
185 |         "dist/credentials/Ldap.credentials.js",
186 |         "dist/credentials/LemlistApi.credentials.js",
187 |         "dist/credentials/LinearApi.credentials.js",
188 |         "dist/credentials/LinearOAuth2Api.credentials.js",
189 |         "dist/credentials/LineNotifyOAuth2Api.credentials.js",
190 |         "dist/credentials/LingvaNexApi.credentials.js",
191 |         "dist/credentials/LinkedInOAuth2Api.credentials.js",
192 |         "dist/credentials/LoneScaleApi.credentials.js",
193 |         "dist/credentials/Magento2Api.credentials.js",
194 |         "dist/credentials/MailcheckApi.credentials.js",
195 |         "dist/credentials/MailchimpApi.credentials.js",
196 |         "dist/credentials/MailchimpOAuth2Api.credentials.js",
197 |         "dist/credentials/MailerLiteApi.credentials.js",
198 |         "dist/credentials/MailgunApi.credentials.js",
199 |         "dist/credentials/MailjetEmailApi.credentials.js",
200 |         "dist/credentials/MailjetSmsApi.credentials.js",
201 |         "dist/credentials/MandrillApi.credentials.js",
202 |         "dist/credentials/MarketstackApi.credentials.js",
203 |         "dist/credentials/MatrixApi.credentials.js",
204 |         "dist/credentials/MattermostApi.credentials.js",
205 |         "dist/credentials/MauticApi.credentials.js",
206 |         "dist/credentials/MauticOAuth2Api.credentials.js",
207 |         "dist/credentials/MediumApi.credentials.js",
208 |         "dist/credentials/MediumOAuth2Api.credentials.js",
209 |         "dist/credentials/MetabaseApi.credentials.js",
210 |         "dist/credentials/MessageBirdApi.credentials.js",
211 |         "dist/credentials/MetabaseApi.credentials.js",
212 |         "dist/credentials/MicrosoftDynamicsOAuth2Api.credentials.js",
213 |         "dist/credentials/MicrosoftEntraOAuth2Api.credentials.js",
214 |         "dist/credentials/MicrosoftExcelOAuth2Api.credentials.js",
215 |         "dist/credentials/MicrosoftGraphSecurityOAuth2Api.credentials.js",
216 |         "dist/credentials/MicrosoftOAuth2Api.credentials.js",
217 |         "dist/credentials/MicrosoftOneDriveOAuth2Api.credentials.js",
218 |         "dist/credentials/MicrosoftOutlookOAuth2Api.credentials.js",
219 |         "dist/credentials/MicrosoftSql.credentials.js",
220 |         "dist/credentials/MicrosoftTeamsOAuth2Api.credentials.js",
221 |         "dist/credentials/MicrosoftToDoOAuth2Api.credentials.js",
222 |         "dist/credentials/MindeeInvoiceApi.credentials.js",
223 |         "dist/credentials/MindeeReceiptApi.credentials.js",
224 |         "dist/credentials/MispApi.credentials.js",
225 |         "dist/credentials/MistApi.credentials.js",
226 |         "dist/credentials/MoceanApi.credentials.js",
227 |         "dist/credentials/MondayComApi.credentials.js",
228 |         "dist/credentials/MondayComOAuth2Api.credentials.js",
229 |         "dist/credentials/MongoDb.credentials.js",
230 |         "dist/credentials/MonicaCrmApi.credentials.js",
231 |         "dist/credentials/Mqtt.credentials.js",
232 |         "dist/credentials/Msg91Api.credentials.js",
233 |         "dist/credentials/MySql.credentials.js",
234 |         "dist/credentials/N8nApi.credentials.js",
235 |         "dist/credentials/NasaApi.credentials.js",
236 |         "dist/credentials/NetlifyApi.credentials.js",
237 |         "dist/credentials/NextCloudApi.credentials.js",
238 |         "dist/credentials/NextCloudOAuth2Api.credentials.js",
239 |         "dist/credentials/NocoDb.credentials.js",
240 |         "dist/credentials/NocoDbApiToken.credentials.js",
241 |         "dist/credentials/NotionApi.credentials.js",
242 |         "dist/credentials/NotionOAuth2Api.credentials.js",
243 |         "dist/credentials/NpmApi.credentials.js",
244 |         "dist/credentials/OAuth1Api.credentials.js",
245 |         "dist/credentials/OAuth2Api.credentials.js",
246 |         "dist/credentials/OdooApi.credentials.js",
247 |         "dist/credentials/OktaApi.credentials.js",
248 |         "dist/credentials/OneSimpleApi.credentials.js",
249 |         "dist/credentials/OnfleetApi.credentials.js",
250 |         "dist/credentials/OpenAiApi.credentials.js",
251 |         "dist/credentials/OpenCTIApi.credentials.js",
252 |         "dist/credentials/OpenWeatherMapApi.credentials.js",
253 |         "dist/credentials/OrbitApi.credentials.js",
254 |         "dist/credentials/OuraApi.credentials.js",
255 |         "dist/credentials/PaddleApi.credentials.js",
256 |         "dist/credentials/PagerDutyApi.credentials.js",
257 |         "dist/credentials/PagerDutyOAuth2Api.credentials.js",
258 |         "dist/credentials/PayPalApi.credentials.js",
259 |         "dist/credentials/PeekalinkApi.credentials.js",
260 |         "dist/credentials/PhantombusterApi.credentials.js",
261 |         "dist/credentials/PhilipsHueOAuth2Api.credentials.js",
262 |         "dist/credentials/PipedriveApi.credentials.js",
263 |         "dist/credentials/PipedriveOAuth2Api.credentials.js",
264 |         "dist/credentials/PlivoApi.credentials.js",
265 |         "dist/credentials/Postgres.credentials.js",
266 |         "dist/credentials/PostHogApi.credentials.js",
267 |         "dist/credentials/PostmarkApi.credentials.js",
268 |         "dist/credentials/ProfitWellApi.credentials.js",
269 |         "dist/credentials/PushbulletOAuth2Api.credentials.js",
270 |         "dist/credentials/PushcutApi.credentials.js",
271 |         "dist/credentials/PushoverApi.credentials.js",
272 |         "dist/credentials/QRadarApi.credentials.js",
273 |         "dist/credentials/QualysApi.credentials.js",
274 |         "dist/credentials/QuestDb.credentials.js",
275 |         "dist/credentials/QuickBaseApi.credentials.js",
276 |         "dist/credentials/QuickBooksOAuth2Api.credentials.js",
277 |         "dist/credentials/RabbitMQ.credentials.js",
278 |         "dist/credentials/RaindropOAuth2Api.credentials.js",
279 |         "dist/credentials/RecordedFutureApi.credentials.js",
280 |         "dist/credentials/RedditOAuth2Api.credentials.js",
281 |         "dist/credentials/Redis.credentials.js",
282 |         "dist/credentials/RocketchatApi.credentials.js",
283 |         "dist/credentials/RundeckApi.credentials.js",
284 |         "dist/credentials/S3.credentials.js",
285 |         "dist/credentials/SalesforceJwtApi.credentials.js",
286 |         "dist/credentials/SalesforceOAuth2Api.credentials.js",
287 |         "dist/credentials/SalesmateApi.credentials.js",
288 |         "dist/credentials/SeaTableApi.credentials.js",
289 |         "dist/credentials/SecurityScorecardApi.credentials.js",
290 |         "dist/credentials/SegmentApi.credentials.js",
291 |         "dist/credentials/SekoiaApi.credentials.js",
292 |         "dist/credentials/SendGridApi.credentials.js",
293 |         "dist/credentials/BrevoApi.credentials.js",
294 |         "dist/credentials/SendyApi.credentials.js",
295 |         "dist/credentials/SentryIoApi.credentials.js",
296 |         "dist/credentials/SentryIoOAuth2Api.credentials.js",
297 |         "dist/credentials/SentryIoServerApi.credentials.js",
298 |         "dist/credentials/ServiceNowOAuth2Api.credentials.js",
299 |         "dist/credentials/ServiceNowBasicApi.credentials.js",
300 |         "dist/credentials/Sftp.credentials.js",
301 |         "dist/credentials/ShopifyApi.credentials.js",
302 |         "dist/credentials/ShopifyAccessTokenApi.credentials.js",
303 |         "dist/credentials/ShopifyOAuth2Api.credentials.js",
304 |         "dist/credentials/Signl4Api.credentials.js",
305 |         "dist/credentials/SlackApi.credentials.js",
306 |         "dist/credentials/SlackOAuth2Api.credentials.js",
307 |         "dist/credentials/Sms77Api.credentials.js",
308 |         "dist/credentials/Smtp.credentials.js",
309 |         "dist/credentials/Snowflake.credentials.js",
310 |         "dist/credentials/SplunkApi.credentials.js",
311 |         "dist/credentials/SpontitApi.credentials.js",
312 |         "dist/credentials/SpotifyOAuth2Api.credentials.js",
313 |         "dist/credentials/ShufflerApi.credentials.js",
314 |         "dist/credentials/SshPassword.credentials.js",
315 |         "dist/credentials/SshPrivateKey.credentials.js",
316 |         "dist/credentials/StackbyApi.credentials.js",
317 |         "dist/credentials/StoryblokContentApi.credentials.js",
318 |         "dist/credentials/StoryblokManagementApi.credentials.js",
319 |         "dist/credentials/StrapiApi.credentials.js",
320 |         "dist/credentials/StrapiTokenApi.credentials.js",
321 |         "dist/credentials/StravaOAuth2Api.credentials.js",
322 |         "dist/credentials/StripeApi.credentials.js",
323 |         "dist/credentials/SupabaseApi.credentials.js",
324 |         "dist/credentials/SurveyMonkeyApi.credentials.js",
325 |         "dist/credentials/SurveyMonkeyOAuth2Api.credentials.js",
326 |         "dist/credentials/SyncroMspApi.credentials.js",
327 |         "dist/credentials/TaigaApi.credentials.js",
328 |         "dist/credentials/TapfiliateApi.credentials.js",
329 |         "dist/credentials/TelegramApi.credentials.js",
330 |         "dist/credentials/TheHiveProjectApi.credentials.js",
331 |         "dist/credentials/TheHiveApi.credentials.js",
332 |         "dist/credentials/TimescaleDb.credentials.js",
333 |         "dist/credentials/TodoistApi.credentials.js",
334 |         "dist/credentials/TodoistOAuth2Api.credentials.js",
335 |         "dist/credentials/TogglApi.credentials.js",
336 |         "dist/credentials/TotpApi.credentials.js",
337 |         "dist/credentials/TravisCiApi.credentials.js",
338 |         "dist/credentials/TrellixEpoApi.credentials.js",
339 |         "dist/credentials/TrelloApi.credentials.js",
340 |         "dist/credentials/TwakeCloudApi.credentials.js",
341 |         "dist/credentials/TwakeServerApi.credentials.js",
342 |         "dist/credentials/TwilioApi.credentials.js",
343 |         "dist/credentials/TwistOAuth2Api.credentials.js",
344 |         "dist/credentials/TwitterOAuth1Api.credentials.js",
345 |         "dist/credentials/TwitterOAuth2Api.credentials.js",
346 |         "dist/credentials/TypeformApi.credentials.js",
347 |         "dist/credentials/TypeformOAuth2Api.credentials.js",
348 |         "dist/credentials/UnleashedSoftwareApi.credentials.js",
349 |         "dist/credentials/UpleadApi.credentials.js",
350 |         "dist/credentials/UProcApi.credentials.js",
351 |         "dist/credentials/UptimeRobotApi.credentials.js",
352 |         "dist/credentials/UrlScanIoApi.credentials.js",
353 |         "dist/credentials/VeroApi.credentials.js",
354 |         "dist/credentials/VirusTotalApi.credentials.js",
355 |         "dist/credentials/VonageApi.credentials.js",
356 |         "dist/credentials/VenafiTlsProtectCloudApi.credentials.js",
357 |         "dist/credentials/VenafiTlsProtectDatacenterApi.credentials.js",
358 |         "dist/credentials/WebflowApi.credentials.js",
359 |         "dist/credentials/WebflowOAuth2Api.credentials.js",
360 |         "dist/credentials/WekanApi.credentials.js",
361 |         "dist/credentials/WhatsAppApi.credentials.js",
362 |         "dist/credentials/WiseApi.credentials.js",
363 |         "dist/credentials/WooCommerceApi.credentials.js",
364 |         "dist/credentials/WordpressApi.credentials.js",
365 |         "dist/credentials/WorkableApi.credentials.js",
366 |         "dist/credentials/WufooApi.credentials.js",
367 |         "dist/credentials/XeroOAuth2Api.credentials.js",
368 |         "dist/credentials/YourlsApi.credentials.js",
369 |         "dist/credentials/YouTubeOAuth2Api.credentials.js",
370 |         "dist/credentials/ZammadBasicAuthApi.credentials.js",
371 |         "dist/credentials/ZammadTokenAuthApi.credentials.js",
372 |         "dist/credentials/ZendeskApi.credentials.js",
373 |         "dist/credentials/ZendeskOAuth2Api.credentials.js",
374 |         "dist/credentials/ZohoOAuth2Api.credentials.js",
375 |         "dist/credentials/ZoomApi.credentials.js",
376 |         "dist/credentials/ZoomOAuth2Api.credentials.js",
377 |         "dist/credentials/ZscalerZiaApi.credentials.js",
378 |         "dist/credentials/ZulipApi.credentials.js"
379 |       ],
380 |       "nodes": [
381 |         "dist/nodes/ActionNetwork/ActionNetwork.node.js",
382 |         "dist/nodes/ActiveCampaign/ActiveCampaign.node.js",
383 |         "dist/nodes/ActiveCampaign/ActiveCampaignTrigger.node.js",
384 |         "dist/nodes/AcuityScheduling/AcuitySchedulingTrigger.node.js",
385 |         "dist/nodes/Adalo/Adalo.node.js",
386 |         "dist/nodes/Affinity/Affinity.node.js",
387 |         "dist/nodes/Affinity/AffinityTrigger.node.js",
388 |         "dist/nodes/AgileCrm/AgileCrm.node.js",
389 |         "dist/nodes/Airtable/Airtable.node.js",
390 |         "dist/nodes/Airtable/AirtableTrigger.node.js",
391 |         "dist/nodes/Amqp/Amqp.node.js",
392 |         "dist/nodes/Amqp/AmqpTrigger.node.js",
393 |         "dist/nodes/ApiTemplateIo/ApiTemplateIo.node.js",
394 |         "dist/nodes/Asana/Asana.node.js",
395 |         "dist/nodes/Asana/AsanaTrigger.node.js",
396 |         "dist/nodes/Automizy/Automizy.node.js",
397 |         "dist/nodes/Autopilot/Autopilot.node.js",
398 |         "dist/nodes/Autopilot/AutopilotTrigger.node.js",
399 |         "dist/nodes/Aws/AwsLambda.node.js",
400 |         "dist/nodes/Aws/AwsSns.node.js",
401 |         "dist/nodes/Aws/AwsSnsTrigger.node.js",
402 |         "dist/nodes/Aws/CertificateManager/AwsCertificateManager.node.js",
403 |         "dist/nodes/Aws/Comprehend/AwsComprehend.node.js",
404 |         "dist/nodes/Aws/DynamoDB/AwsDynamoDB.node.js",
405 |         "dist/nodes/Aws/ELB/AwsElb.node.js",
406 |         "dist/nodes/Aws/Rekognition/AwsRekognition.node.js",
407 |         "dist/nodes/Aws/S3/AwsS3.node.js",
408 |         "dist/nodes/Aws/SES/AwsSes.node.js",
409 |         "dist/nodes/Aws/SQS/AwsSqs.node.js",
410 |         "dist/nodes/Aws/Textract/AwsTextract.node.js",
411 |         "dist/nodes/Aws/Transcribe/AwsTranscribe.node.js",
412 |         "dist/nodes/BambooHr/BambooHr.node.js",
413 |         "dist/nodes/Bannerbear/Bannerbear.node.js",
414 |         "dist/nodes/Baserow/Baserow.node.js",
415 |         "dist/nodes/Beeminder/Beeminder.node.js",
416 |         "dist/nodes/Bitbucket/BitbucketTrigger.node.js",
417 |         "dist/nodes/Bitly/Bitly.node.js",
418 |         "dist/nodes/Bitwarden/Bitwarden.node.js",
419 |         "dist/nodes/Box/Box.node.js",
420 |         "dist/nodes/Box/BoxTrigger.node.js",
421 |         "dist/nodes/Brandfetch/Brandfetch.node.js",
422 |         "dist/nodes/Bubble/Bubble.node.js",
423 |         "dist/nodes/Cal/CalTrigger.node.js",
424 |         "dist/nodes/Calendly/CalendlyTrigger.node.js",
425 |         "dist/nodes/Chargebee/Chargebee.node.js",
426 |         "dist/nodes/Chargebee/ChargebeeTrigger.node.js",
427 |         "dist/nodes/CircleCi/CircleCi.node.js",
428 |         "dist/nodes/Cisco/Webex/CiscoWebex.node.js",
429 |         "dist/nodes/Citrix/ADC/CitrixAdc.node.js",
430 |         "dist/nodes/Cisco/Webex/CiscoWebexTrigger.node.js",
431 |         "dist/nodes/Cloudflare/Cloudflare.node.js",
432 |         "dist/nodes/Clearbit/Clearbit.node.js",
433 |         "dist/nodes/ClickUp/ClickUp.node.js",
434 |         "dist/nodes/ClickUp/ClickUpTrigger.node.js",
435 |         "dist/nodes/Clockify/Clockify.node.js",
436 |         "dist/nodes/Clockify/ClockifyTrigger.node.js",
437 |         "dist/nodes/Cockpit/Cockpit.node.js",
438 |         "dist/nodes/Coda/Coda.node.js",
439 |         "dist/nodes/Code/Code.node.js",
440 |         "dist/nodes/CoinGecko/CoinGecko.node.js",
441 |         "dist/nodes/CompareDatasets/CompareDatasets.node.js",
442 |         "dist/nodes/Compression/Compression.node.js",
443 |         "dist/nodes/Contentful/Contentful.node.js",
444 |         "dist/nodes/ConvertKit/ConvertKit.node.js",
445 |         "dist/nodes/ConvertKit/ConvertKitTrigger.node.js",
446 |         "dist/nodes/Copper/Copper.node.js",
447 |         "dist/nodes/Copper/CopperTrigger.node.js",
448 |         "dist/nodes/Cortex/Cortex.node.js",
449 |         "dist/nodes/CrateDb/CrateDb.node.js",
450 |         "dist/nodes/Cron/Cron.node.js",
451 |         "dist/nodes/CrowdDev/CrowdDev.node.js",
452 |         "dist/nodes/CrowdDev/CrowdDevTrigger.node.js",
453 |         "dist/nodes/Crypto/Crypto.node.js",
454 |         "dist/nodes/CustomerIo/CustomerIo.node.js",
455 |         "dist/nodes/CustomerIo/CustomerIoTrigger.node.js",
456 |         "dist/nodes/DateTime/DateTime.node.js",
457 |         "dist/nodes/DebugHelper/DebugHelper.node.js",
458 |         "dist/nodes/DeepL/DeepL.node.js",
459 |         "dist/nodes/Demio/Demio.node.js",
460 |         "dist/nodes/Dhl/Dhl.node.js",
461 |         "dist/nodes/Discord/Discord.node.js",
462 |         "dist/nodes/Discourse/Discourse.node.js",
463 |         "dist/nodes/Disqus/Disqus.node.js",
464 |         "dist/nodes/Drift/Drift.node.js",
465 |         "dist/nodes/Dropbox/Dropbox.node.js",
466 |         "dist/nodes/Dropcontact/Dropcontact.node.js",
467 |         "dist/nodes/EditImage/EditImage.node.js",
468 |         "dist/nodes/E2eTest/E2eTest.node.js",
469 |         "dist/nodes/Egoi/Egoi.node.js",
470 |         "dist/nodes/Elastic/Elasticsearch/Elasticsearch.node.js",
471 |         "dist/nodes/Elastic/ElasticSecurity/ElasticSecurity.node.js",
472 |         "dist/nodes/EmailReadImap/EmailReadImap.node.js",
473 |         "dist/nodes/EmailSend/EmailSend.node.js",
474 |         "dist/nodes/Emelia/Emelia.node.js",
475 |         "dist/nodes/Emelia/EmeliaTrigger.node.js",
476 |         "dist/nodes/ERPNext/ERPNext.node.js",
477 |         "dist/nodes/ErrorTrigger/ErrorTrigger.node.js",
478 |         "dist/nodes/Eventbrite/EventbriteTrigger.node.js",
479 |         "dist/nodes/ExecuteCommand/ExecuteCommand.node.js",
480 |         "dist/nodes/ExecuteWorkflow/ExecuteWorkflow.node.js",
481 |         "dist/nodes/ExecuteWorkflowTrigger/ExecuteWorkflowTrigger.node.js",
482 |         "dist/nodes/ExecutionData/ExecutionData.node.js",
483 |         "dist/nodes/Facebook/FacebookGraphApi.node.js",
484 |         "dist/nodes/Facebook/FacebookTrigger.node.js",
485 |         "dist/nodes/FacebookLeadAds/FacebookLeadAdsTrigger.node.js",
486 |         "dist/nodes/Figma/FigmaTrigger.node.js",
487 |         "dist/nodes/FileMaker/FileMaker.node.js",
488 |         "dist/nodes/Filter/Filter.node.js",
489 |         "dist/nodes/Flow/Flow.node.js",
490 |         "dist/nodes/Flow/FlowTrigger.node.js",
491 |         "dist/nodes/Form/FormTrigger.node.js",
492 |         "dist/nodes/FormIo/FormIoTrigger.node.js",
493 |         "dist/nodes/Formstack/FormstackTrigger.node.js",
494 |         "dist/nodes/Freshdesk/Freshdesk.node.js",
495 |         "dist/nodes/Freshservice/Freshservice.node.js",
496 |         "dist/nodes/FreshworksCrm/FreshworksCrm.node.js",
497 |         "dist/nodes/Ftp/Ftp.node.js",
498 |         "dist/nodes/Function/Function.node.js",
499 |         "dist/nodes/FunctionItem/FunctionItem.node.js",
500 |         "dist/nodes/GetResponse/GetResponse.node.js",
501 |         "dist/nodes/GetResponse/GetResponseTrigger.node.js",
502 |         "dist/nodes/Ghost/Ghost.node.js",
503 |         "dist/nodes/Git/Git.node.js",
504 |         "dist/nodes/Github/Github.node.js",
505 |         "dist/nodes/Github/GithubTrigger.node.js",
506 |         "dist/nodes/Gitlab/Gitlab.node.js",
507 |         "dist/nodes/Gitlab/GitlabTrigger.node.js",
508 |         "dist/nodes/Google/Ads/GoogleAds.node.js",
509 |         "dist/nodes/Google/Analytics/GoogleAnalytics.node.js",
510 |         "dist/nodes/Google/BigQuery/GoogleBigQuery.node.js",
511 |         "dist/nodes/Google/Books/GoogleBooks.node.js",
512 |         "dist/nodes/Google/Calendar/GoogleCalendar.node.js",
513 |         "dist/nodes/Google/Calendar/GoogleCalendarTrigger.node.js",
514 |         "dist/nodes/Google/Chat/GoogleChat.node.js",
515 |         "dist/nodes/Google/CloudNaturalLanguage/GoogleCloudNaturalLanguage.node.js",
516 |         "dist/nodes/Google/CloudStorage/GoogleCloudStorage.node.js",
517 |         "dist/nodes/Google/Contacts/GoogleContacts.node.js",
518 |         "dist/nodes/Google/Docs/GoogleDocs.node.js",
519 |         "dist/nodes/Google/Drive/GoogleDrive.node.js",
520 |         "dist/nodes/Google/Drive/GoogleDriveTrigger.node.js",
521 |         "dist/nodes/Google/Firebase/CloudFirestore/GoogleFirebaseCloudFirestore.node.js",
522 |         "dist/nodes/Google/Firebase/RealtimeDatabase/GoogleFirebaseRealtimeDatabase.node.js",
523 |         "dist/nodes/Google/Gmail/Gmail.node.js",
524 |         "dist/nodes/Google/Gmail/GmailTrigger.node.js",
525 |         "dist/nodes/Google/GSuiteAdmin/GSuiteAdmin.node.js",
526 |         "dist/nodes/Google/Perspective/GooglePerspective.node.js",
527 |         "dist/nodes/Google/Sheet/GoogleSheets.node.js",
528 |         "dist/nodes/Google/Sheet/GoogleSheetsTrigger.node.js",
529 |         "dist/nodes/Google/Slides/GoogleSlides.node.js",
530 |         "dist/nodes/Google/Task/GoogleTasks.node.js",
531 |         "dist/nodes/Google/Translate/GoogleTranslate.node.js",
532 |         "dist/nodes/Google/YouTube/YouTube.node.js",
533 |         "dist/nodes/Gotify/Gotify.node.js",
534 |         "dist/nodes/GoToWebinar/GoToWebinar.node.js",
535 |         "dist/nodes/Grafana/Grafana.node.js",
536 |         "dist/nodes/GraphQL/GraphQL.node.js",
537 |         "dist/nodes/Grist/Grist.node.js",
538 |         "dist/nodes/Gumroad/GumroadTrigger.node.js",
539 |         "dist/nodes/HackerNews/HackerNews.node.js",
540 |         "dist/nodes/HaloPSA/HaloPSA.node.js",
541 |         "dist/nodes/Harvest/Harvest.node.js",
542 |         "dist/nodes/HelpScout/HelpScout.node.js",
543 |         "dist/nodes/HelpScout/HelpScoutTrigger.node.js",
544 |         "dist/nodes/HighLevel/HighLevel.node.js",
545 |         "dist/nodes/HomeAssistant/HomeAssistant.node.js",
546 |         "dist/nodes/HtmlExtract/HtmlExtract.node.js",
547 |         "dist/nodes/Html/Html.node.js",
548 |         "dist/nodes/HttpRequest/HttpRequest.node.js",
549 |         "dist/nodes/Hubspot/Hubspot.node.js",
550 |         "dist/nodes/Hubspot/HubspotTrigger.node.js",
551 |         "dist/nodes/HumanticAI/HumanticAi.node.js",
552 |         "dist/nodes/Hunter/Hunter.node.js",
553 |         "dist/nodes/ICalendar/ICalendar.node.js",
554 |         "dist/nodes/If/If.node.js",
555 |         "dist/nodes/Intercom/Intercom.node.js",
556 |         "dist/nodes/Interval/Interval.node.js",
557 |         "dist/nodes/InvoiceNinja/InvoiceNinja.node.js",
558 |         "dist/nodes/InvoiceNinja/InvoiceNinjaTrigger.node.js",
559 |         "dist/nodes/ItemLists/ItemLists.node.js",
560 |         "dist/nodes/Iterable/Iterable.node.js",
561 |         "dist/nodes/Jenkins/Jenkins.node.js",
562 |         "dist/nodes/Jira/Jira.node.js",
563 |         "dist/nodes/Jira/JiraTrigger.node.js",
564 |         "dist/nodes/JotForm/JotFormTrigger.node.js",
565 |         "dist/nodes/Kafka/Kafka.node.js",
566 |         "dist/nodes/Kafka/KafkaTrigger.node.js",
567 |         "dist/nodes/Keap/Keap.node.js",
568 |         "dist/nodes/Keap/KeapTrigger.node.js",
569 |         "dist/nodes/Kitemaker/Kitemaker.node.js",
570 |         "dist/nodes/KoBoToolbox/KoBoToolbox.node.js",
571 |         "dist/nodes/KoBoToolbox/KoBoToolboxTrigger.node.js",
572 |         "dist/nodes/Ldap/Ldap.node.js",
573 |         "dist/nodes/Lemlist/Lemlist.node.js",
574 |         "dist/nodes/Lemlist/LemlistTrigger.node.js",
575 |         "dist/nodes/Line/Line.node.js",
576 |         "dist/nodes/Linear/Linear.node.js",
577 |         "dist/nodes/Linear/LinearTrigger.node.js",
578 |         "dist/nodes/LingvaNex/LingvaNex.node.js",
579 |         "dist/nodes/LinkedIn/LinkedIn.node.js",
580 |         "dist/nodes/LocalFileTrigger/LocalFileTrigger.node.js",
581 |         "dist/nodes/LoneScale/LoneScaleTrigger.node.js",
582 |         "dist/nodes/LoneScale/LoneScale.node.js",
583 |         "dist/nodes/Magento/Magento2.node.js",
584 |         "dist/nodes/Mailcheck/Mailcheck.node.js",
585 |         "dist/nodes/Mailchimp/Mailchimp.node.js",
586 |         "dist/nodes/Mailchimp/MailchimpTrigger.node.js",
587 |         "dist/nodes/MailerLite/MailerLite.node.js",
588 |         "dist/nodes/MailerLite/MailerLiteTrigger.node.js",
589 |         "dist/nodes/Mailgun/Mailgun.node.js",
590 |         "dist/nodes/Mailjet/Mailjet.node.js",
591 |         "dist/nodes/Mailjet/MailjetTrigger.node.js",
592 |         "dist/nodes/Mandrill/Mandrill.node.js",
593 |         "dist/nodes/ManualTrigger/ManualTrigger.node.js",
594 |         "dist/nodes/Markdown/Markdown.node.js",
595 |         "dist/nodes/Marketstack/Marketstack.node.js",
596 |         "dist/nodes/Matrix/Matrix.node.js",
597 |         "dist/nodes/Mattermost/Mattermost.node.js",
598 |         "dist/nodes/Mautic/Mautic.node.js",
599 |         "dist/nodes/Mautic/MauticTrigger.node.js",
600 |         "dist/nodes/Medium/Medium.node.js",
601 |         "dist/nodes/Merge/Merge.node.js",
602 |         "dist/nodes/MessageBird/MessageBird.node.js",
603 |         "dist/nodes/Metabase/Metabase.node.js",
604 |         "dist/nodes/Microsoft/Dynamics/MicrosoftDynamicsCrm.node.js",
605 |         "dist/nodes/Microsoft/Excel/MicrosoftExcel.node.js",
606 |         "dist/nodes/Microsoft/GraphSecurity/MicrosoftGraphSecurity.node.js",
607 |         "dist/nodes/Microsoft/OneDrive/MicrosoftOneDrive.node.js",
608 |         "dist/nodes/Microsoft/Outlook/MicrosoftOutlook.node.js",
609 |         "dist/nodes/Microsoft/Sql/MicrosoftSql.node.js",
610 |         "dist/nodes/Microsoft/Teams/MicrosoftTeams.node.js",
611 |         "dist/nodes/Microsoft/ToDo/MicrosoftToDo.node.js",
612 |         "dist/nodes/Mindee/Mindee.node.js",
613 |         "dist/nodes/Misp/Misp.node.js",
614 |         "dist/nodes/Mocean/Mocean.node.js",
615 |         "dist/nodes/MondayCom/MondayCom.node.js",
616 |         "dist/nodes/MongoDb/MongoDb.node.js",
617 |         "dist/nodes/MonicaCrm/MonicaCrm.node.js",
618 |         "dist/nodes/MoveBinaryData/MoveBinaryData.node.js",
619 |         "dist/nodes/MQTT/Mqtt.node.js",
620 |         "dist/nodes/MQTT/MqttTrigger.node.js",
621 |         "dist/nodes/Msg91/Msg91.node.js",
622 |         "dist/nodes/MySql/MySql.node.js",
623 |         "dist/nodes/N8n/N8n.node.js",
624 |         "dist/nodes/N8nTrainingCustomerDatastore/N8nTrainingCustomerDatastore.node.js",
625 |         "dist/nodes/N8nTrainingCustomerMessenger/N8nTrainingCustomerMessenger.node.js",
626 |         "dist/nodes/N8nTrigger/N8nTrigger.node.js",
627 |         "dist/nodes/Nasa/Nasa.node.js",
628 |         "dist/nodes/Netlify/Netlify.node.js",
629 |         "dist/nodes/Netlify/NetlifyTrigger.node.js",
630 |         "dist/nodes/NextCloud/NextCloud.node.js",
631 |         "dist/nodes/NocoDB/NocoDB.node.js",
632 |         "dist/nodes/Brevo/Brevo.node.js",
633 |         "dist/nodes/Brevo/BrevoTrigger.node.js",
634 |         "dist/nodes/StickyNote/StickyNote.node.js",
635 |         "dist/nodes/NoOp/NoOp.node.js",
636 |         "dist/nodes/Onfleet/Onfleet.node.js",
637 |         "dist/nodes/Onfleet/OnfleetTrigger.node.js",
638 |         "dist/nodes/Notion/Notion.node.js",
639 |         "dist/nodes/Notion/NotionTrigger.node.js",
640 |         "dist/nodes/Npm/Npm.node.js",
641 |         "dist/nodes/Odoo/Odoo.node.js",
642 |         "dist/nodes/OneSimpleApi/OneSimpleApi.node.js",
643 |         "dist/nodes/OpenAi/OpenAi.node.js",
644 |         "dist/nodes/OpenThesaurus/OpenThesaurus.node.js",
645 |         "dist/nodes/OpenWeatherMap/OpenWeatherMap.node.js",
646 |         "dist/nodes/Orbit/Orbit.node.js",
647 |         "dist/nodes/Oura/Oura.node.js",
648 |         "dist/nodes/Paddle/Paddle.node.js",
649 |         "dist/nodes/PagerDuty/PagerDuty.node.js",
650 |         "dist/nodes/PayPal/PayPal.node.js",
651 |         "dist/nodes/PayPal/PayPalTrigger.node.js",
652 |         "dist/nodes/Peekalink/Peekalink.node.js",
653 |         "dist/nodes/Phantombuster/Phantombuster.node.js",
654 |         "dist/nodes/PhilipsHue/PhilipsHue.node.js",
655 |         "dist/nodes/Pipedrive/Pipedrive.node.js",
656 |         "dist/nodes/Pipedrive/PipedriveTrigger.node.js",
657 |         "dist/nodes/Plivo/Plivo.node.js",
658 |         "dist/nodes/PostBin/PostBin.node.js",
659 |         "dist/nodes/Postgres/Postgres.node.js",
660 |         "dist/nodes/Postgres/PostgresTrigger.node.js",
661 |         "dist/nodes/PostHog/PostHog.node.js",
662 |         "dist/nodes/Postmark/PostmarkTrigger.node.js",
663 |         "dist/nodes/ProfitWell/ProfitWell.node.js",
664 |         "dist/nodes/Pushbullet/Pushbullet.node.js",
665 |         "dist/nodes/Pushcut/Pushcut.node.js",
666 |         "dist/nodes/Pushcut/PushcutTrigger.node.js",
667 |         "dist/nodes/Pushover/Pushover.node.js",
668 |         "dist/nodes/QuestDb/QuestDb.node.js",
669 |         "dist/nodes/QuickBase/QuickBase.node.js",
670 |         "dist/nodes/QuickBooks/QuickBooks.node.js",
671 |         "dist/nodes/QuickChart/QuickChart.node.js",
672 |         "dist/nodes/RabbitMQ/RabbitMQ.node.js",
673 |         "dist/nodes/RabbitMQ/RabbitMQTrigger.node.js",
674 |         "dist/nodes/Raindrop/Raindrop.node.js",
675 |         "dist/nodes/ReadBinaryFile/ReadBinaryFile.node.js",
676 |         "dist/nodes/ReadBinaryFiles/ReadBinaryFiles.node.js",
677 |         "dist/nodes/ReadPdf/ReadPDF.node.js",
678 |         "dist/nodes/Reddit/Reddit.node.js",
679 |         "dist/nodes/Redis/Redis.node.js",
680 |         "dist/nodes/Redis/RedisTrigger.node.js",
681 |         "dist/nodes/RenameKeys/RenameKeys.node.js",
682 |         "dist/nodes/RespondToWebhook/RespondToWebhook.node.js",
683 |         "dist/nodes/Rocketchat/Rocketchat.node.js",
684 |         "dist/nodes/RssFeedRead/RssFeedRead.node.js",
685 |         "dist/nodes/RssFeedRead/RssFeedReadTrigger.node.js",
686 |         "dist/nodes/Rundeck/Rundeck.node.js",
687 |         "dist/nodes/S3/S3.node.js",
688 |         "dist/nodes/Salesforce/Salesforce.node.js",
689 |         "dist/nodes/Salesmate/Salesmate.node.js",
690 |         "dist/nodes/Schedule/ScheduleTrigger.node.js",
691 |         "dist/nodes/SeaTable/SeaTable.node.js",
692 |         "dist/nodes/SeaTable/SeaTableTrigger.node.js",
693 |         "dist/nodes/SecurityScorecard/SecurityScorecard.node.js",
694 |         "dist/nodes/Segment/Segment.node.js",
695 |         "dist/nodes/SendGrid/SendGrid.node.js",
696 |         "dist/nodes/Sendy/Sendy.node.js",
697 |         "dist/nodes/SentryIo/SentryIo.node.js",
698 |         "dist/nodes/ServiceNow/ServiceNow.node.js",
699 |         "dist/nodes/Set/Set.node.js",
700 |         "dist/nodes/Shopify/Shopify.node.js",
701 |         "dist/nodes/Shopify/ShopifyTrigger.node.js",
702 |         "dist/nodes/Signl4/Signl4.node.js",
703 |         "dist/nodes/Slack/Slack.node.js",
704 |         "dist/nodes/Sms77/Sms77.node.js",
705 |         "dist/nodes/Snowflake/Snowflake.node.js",
706 |         "dist/nodes/SplitInBatches/SplitInBatches.node.js",
707 |         "dist/nodes/Splunk/Splunk.node.js",
708 |         "dist/nodes/Spontit/Spontit.node.js",
709 |         "dist/nodes/Spotify/Spotify.node.js",
710 |         "dist/nodes/SpreadsheetFile/SpreadsheetFile.node.js",
711 |         "dist/nodes/SseTrigger/SseTrigger.node.js",
712 |         "dist/nodes/Ssh/Ssh.node.js",
713 |         "dist/nodes/Stackby/Stackby.node.js",
714 |         "dist/nodes/Start/Start.node.js",
715 |         "dist/nodes/StopAndError/StopAndError.node.js",
716 |         "dist/nodes/Storyblok/Storyblok.node.js",
717 |         "dist/nodes/Strapi/Strapi.node.js",
718 |         "dist/nodes/Strava/Strava.node.js",
719 |         "dist/nodes/Strava/StravaTrigger.node.js",
720 |         "dist/nodes/Stripe/Stripe.node.js",
721 |         "dist/nodes/Stripe/StripeTrigger.node.js",
722 |         "dist/nodes/Supabase/Supabase.node.js",
723 |         "dist/nodes/SurveyMonkey/SurveyMonkeyTrigger.node.js",
724 |         "dist/nodes/Switch/Switch.node.js",
725 |         "dist/nodes/SyncroMSP/SyncroMsp.node.js",
726 |         "dist/nodes/Taiga/Taiga.node.js",
727 |         "dist/nodes/Taiga/TaigaTrigger.node.js",
728 |         "dist/nodes/Tapfiliate/Tapfiliate.node.js",
729 |         "dist/nodes/Telegram/Telegram.node.js",
730 |         "dist/nodes/Telegram/TelegramTrigger.node.js",
731 |         "dist/nodes/TheHiveProject/TheHiveProject.node.js",
732 |         "dist/nodes/TheHiveProject/TheHiveProjectTrigger.node.js",
733 |         "dist/nodes/TheHive/TheHive.node.js",
734 |         "dist/nodes/TheHive/TheHiveTrigger.node.js",
735 |         "dist/nodes/TimescaleDb/TimescaleDb.node.js",
736 |         "dist/nodes/Todoist/Todoist.node.js",
737 |         "dist/nodes/Toggl/TogglTrigger.node.js",
738 |         "dist/nodes/Totp/Totp.node.js",
739 |         "dist/nodes/TravisCi/TravisCi.node.js",
740 |         "dist/nodes/Trello/Trello.node.js",
741 |         "dist/nodes/Trello/TrelloTrigger.node.js",
742 |         "dist/nodes/Twake/Twake.node.js",
743 |         "dist/nodes/Twilio/Twilio.node.js",
744 |         "dist/nodes/Twist/Twist.node.js",
745 |         "dist/nodes/Twitter/Twitter.node.js",
746 |         "dist/nodes/Typeform/TypeformTrigger.node.js",
747 |         "dist/nodes/UnleashedSoftware/UnleashedSoftware.node.js",
748 |         "dist/nodes/Uplead/Uplead.node.js",
749 |         "dist/nodes/UProc/UProc.node.js",
750 |         "dist/nodes/UptimeRobot/UptimeRobot.node.js",
751 |         "dist/nodes/UrlScanIo/UrlScanIo.node.js",
752 |         "dist/nodes/Vero/Vero.node.js",
753 |         "dist/nodes/Venafi/ProtectCloud/VenafiTlsProtectCloud.node.js",
754 |         "dist/nodes/Venafi/ProtectCloud/VenafiTlsProtectCloudTrigger.node.js",
755 |         "dist/nodes/Venafi/Datacenter/VenafiTlsProtectDatacenter.node.js",
756 |         "dist/nodes/Vonage/Vonage.node.js",
757 |         "dist/nodes/Wait/Wait.node.js",
758 |         "dist/nodes/Webflow/Webflow.node.js",
759 |         "dist/nodes/Webflow/WebflowTrigger.node.js",
760 |         "dist/nodes/Webhook/Webhook.node.js",
761 |         "dist/nodes/Wekan/Wekan.node.js",
762 |         "dist/nodes/WhatsApp/WhatsApp.node.js",
763 |         "dist/nodes/Wise/Wise.node.js",
764 |         "dist/nodes/Wise/WiseTrigger.node.js",
765 |         "dist/nodes/WooCommerce/WooCommerce.node.js",
766 |         "dist/nodes/WooCommerce/WooCommerceTrigger.node.js",
767 |         "dist/nodes/Wordpress/Wordpress.node.js",
768 |         "dist/nodes/Workable/WorkableTrigger.node.js",
769 |         "dist/nodes/WorkflowTrigger/WorkflowTrigger.node.js",
770 |         "dist/nodes/WriteBinaryFile/WriteBinaryFile.node.js",
771 |         "dist/nodes/Wufoo/WufooTrigger.node.js",
772 |         "dist/nodes/Xero/Xero.node.js",
773 |         "dist/nodes/Xml/Xml.node.js",
774 |         "dist/nodes/Yourls/Yourls.node.js",
775 |         "dist/nodes/Zammad/Zammad.node.js",
776 |         "dist/nodes/Zendesk/Zendesk.node.js",
777 |         "dist/nodes/Zendesk/ZendeskTrigger.node.js",
778 |         "dist/nodes/Zoho/ZohoCrm.node.js",
779 |         "dist/nodes/Zoom/Zoom.node.js",
780 |         "dist/nodes/Zulip/Zulip.node.js"
781 |       ]
782 |     },
783 |     "devDependencies": {
784 |       "@types/amqplib": "^0.10.1",
785 |       "@types/aws4": "^1.5.1",
786 |       "@types/basic-auth": "^1.1.3",
787 |       "@types/cheerio": "^0.22.15",
788 |       "@types/cron": "~1.7.1",
789 |       "@types/eventsource": "^1.1.2",
790 |       "@types/express": "^4.17.6",
791 |       "@types/gm": "^1.25.0",
792 |       "@types/imap-simple": "^4.2.0",
793 |       "@types/js-nacl": "^1.3.0",
794 |       "@types/jsonwebtoken": "^9.0.1",
795 |       "@types/lodash": "^4.14.195",
796 |       "@types/lossless-json": "^1.0.0",
797 |       "@types/mailparser": "^2.7.3",
798 |       "@types/mime-types": "^2.1.0",
799 |       "@types/mssql": "^6.0.2",
800 |       "@types/node-ssh": "^7.0.1",
801 |       "@types/nodemailer": "^6.4.0",
802 |       "@types/promise-ftp": "^1.3.4",
803 |       "@types/redis": "^2.8.11",
804 |       "@types/request-promise-native": "~1.0.15",
805 |       "@types/rfc2047": "^2.0.1",
806 |       "@types/showdown": "^1.9.4",
807 |       "@types/snowflake-sdk": "^1.6.12",
808 |       "@types/ssh2-sftp-client": "^5.1.0",
809 |       "@types/tmp": "^0.2.0",
810 |       "@types/uuid": "^8.3.2",
811 |       "@types/xml2js": "^0.4.11",
812 |       "eslint-plugin-n8n-nodes-base": "^1.16.0",
813 |       "gulp": "^4.0.0",
814 |       "n8n-core": "1.14.1"
815 |     },
816 |     "dependencies": {
817 |       "@kafkajs/confluent-schema-registry": "1.0.6",
818 |       "@n8n/vm2": "^3.9.20",
819 |       "amqplib": "^0.10.3",
820 |       "aws4": "^1.8.0",
821 |       "basic-auth": "^2.0.1",
822 |       "change-case": "^4.1.1",
823 |       "cheerio": "1.0.0-rc.6",
824 |       "chokidar": "3.5.2",
825 |       "cron": "~1.7.2",
826 |       "csv-parse": "^5.5.0",
827 |       "currency-codes": "^2.1.0",
828 |       "eventsource": "^2.0.2",
829 |       "fast-glob": "^3.2.5",
830 |       "fflate": "^0.7.0",
831 |       "get-system-fonts": "^2.0.2",
832 |       "gm": "^1.25.0",
833 |       "iconv-lite": "^0.6.2",
834 |       "ics": "^2.27.0",
835 |       "imap-simple": "^4.3.0",
836 |       "isbot": "^3.6.13",
837 |       "iso-639-1": "^2.1.3",
838 |       "js-nacl": "^1.4.0",
839 |       "jsonwebtoken": "^9.0.0",
840 |       "kafkajs": "^1.14.0",
841 |       "ldapts": "^4.2.6",
842 |       "lodash": "^4.17.21",
843 |       "lossless-json": "^1.0.4",
844 |       "luxon": "^3.3.0",
845 |       "mailparser": "^3.2.0",
846 |       "minifaker": "^1.34.1",
847 |       "moment": "~2.29.2",
848 |       "moment-timezone": "^0.5.28",
849 |       "mongodb": "^4.17.1",
850 |       "mqtt": "^5.0.2",
851 |       "mssql": "^8.1.2",
852 |       "mysql2": "~2.3.0",
853 |       "nanoid": "^3.3.6",
854 |       "node-html-markdown": "^1.1.3",
855 |       "node-ssh": "^12.0.0",
856 |       "nodemailer": "^6.7.1",
857 |       "otpauth": "^9.1.1",
858 |       "pdfjs-dist": "^2.16.105",
859 |       "pg": "^8.3.0",
860 |       "pg-promise": "^10.5.8",
861 |       "pretty-bytes": "^5.6.0",
862 |       "promise-ftp": "^1.3.5",
863 |       "pyodide": "^0.23.4",
864 |       "redis": "^3.1.1",
865 |       "rfc2047": "^4.0.1",
866 |       "rhea": "^1.0.11",
867 |       "rss-parser": "^3.7.0",
868 |       "semver": "^7.5.4",
869 |       "showdown": "^2.0.3",
870 |       "simple-git": "^3.17.0",
871 |       "snowflake-sdk": "^1.8.0",
872 |       "ssh2-sftp-client": "^7.0.0",
873 |       "tmp-promise": "^3.0.2",
874 |       "typedi": "^0.10.0",
875 |       "uuid": "^8.3.2",
876 |       "xlsx": "https://cdn.sheetjs.com/xlsx-0.19.3/xlsx-0.19.3.tgz",
877 |       "xml2js": "^0.5.0",
878 |       "n8n-workflow": "1.14.1"
879 |     },
880 |     "scripts": {
881 |       "clean": "rimraf dist .turbo",
882 |       "dev": "pnpm watch",
883 |       "typecheck": "tsc",
884 |       "build": "tsc -p tsconfig.build.json && tsc-alias -p tsconfig.build.json && gulp build:icons && gulp build:translations && pnpm build:metadata",
885 |       "build:translations": "gulp build:translations",
886 |       "build:metadata": "pnpm n8n-generate-known && pnpm n8n-generate-ui-types",
887 |       "format": "prettier --write . --ignore-path ../../.prettierignore",
888 |       "lint": "eslint . --quiet && node ./scripts/validate-load-options-methods.js",
889 |       "lintfix": "eslint . --fix",
890 |       "watch": "tsc-watch -p tsconfig.build.json --onCompilationComplete \"tsc-alias -p tsconfig.build.json\" --onSuccess \"pnpm n8n-generate-ui-types\"",
891 |       "test": "jest"
892 |     }
893 |   },
894 |   "extraction_time_ms": 7,
895 |   "extracted_at": "2025-06-07T17:49:22.717Z"
896 | }
```

--------------------------------------------------------------------------------
/src/services/enhanced-config-validator.ts:
--------------------------------------------------------------------------------

```typescript
   1 | /**
   2 |  * Enhanced Configuration Validator Service
   3 |  * 
   4 |  * Provides operation-aware validation for n8n nodes with reduced false positives.
   5 |  * Supports multiple validation modes and node-specific logic.
   6 |  */
   7 | 
   8 | import { ConfigValidator, ValidationResult, ValidationError, ValidationWarning } from './config-validator';
   9 | import { NodeSpecificValidators, NodeValidationContext } from './node-specific-validators';
  10 | import { FixedCollectionValidator } from '../utils/fixed-collection-validator';
  11 | import { OperationSimilarityService } from './operation-similarity-service';
  12 | import { ResourceSimilarityService } from './resource-similarity-service';
  13 | import { NodeRepository } from '../database/node-repository';
  14 | import { DatabaseAdapter } from '../database/database-adapter';
  15 | import { NodeTypeNormalizer } from '../utils/node-type-normalizer';
  16 | import { TypeStructureService } from './type-structure-service';
  17 | import type { NodePropertyTypes } from 'n8n-workflow';
  18 | 
  19 | export type ValidationMode = 'full' | 'operation' | 'minimal';
  20 | export type ValidationProfile = 'strict' | 'runtime' | 'ai-friendly' | 'minimal';
  21 | 
  22 | export interface EnhancedValidationResult extends ValidationResult {
  23 |   mode: ValidationMode;
  24 |   profile?: ValidationProfile;
  25 |   operation?: {
  26 |     resource?: string;
  27 |     operation?: string;
  28 |     action?: string;
  29 |   };
  30 |   examples?: Array<{
  31 |     description: string;
  32 |     config: Record<string, any>;
  33 |   }>;
  34 |   nextSteps?: string[];
  35 | }
  36 | 
  37 | export interface OperationContext {
  38 |   resource?: string;
  39 |   operation?: string;
  40 |   action?: string;
  41 |   mode?: string;
  42 | }
  43 | 
  44 | export class EnhancedConfigValidator extends ConfigValidator {
  45 |   private static operationSimilarityService: OperationSimilarityService | null = null;
  46 |   private static resourceSimilarityService: ResourceSimilarityService | null = null;
  47 |   private static nodeRepository: NodeRepository | null = null;
  48 | 
  49 |   /**
  50 |    * Initialize similarity services (called once at startup)
  51 |    */
  52 |   static initializeSimilarityServices(repository: NodeRepository): void {
  53 |     this.nodeRepository = repository;
  54 |     this.operationSimilarityService = new OperationSimilarityService(repository);
  55 |     this.resourceSimilarityService = new ResourceSimilarityService(repository);
  56 |   }
  57 |   /**
  58 |    * Validate with operation awareness
  59 |    */
  60 |   static validateWithMode(
  61 |     nodeType: string,
  62 |     config: Record<string, any>,
  63 |     properties: any[],
  64 |     mode: ValidationMode = 'operation',
  65 |     profile: ValidationProfile = 'ai-friendly'
  66 |   ): EnhancedValidationResult {
  67 |     // Input validation - ensure parameters are valid
  68 |     if (typeof nodeType !== 'string') {
  69 |       throw new Error(`Invalid nodeType: expected string, got ${typeof nodeType}`);
  70 |     }
  71 |     
  72 |     if (!config || typeof config !== 'object') {
  73 |       throw new Error(`Invalid config: expected object, got ${typeof config}`);
  74 |     }
  75 |     
  76 |     if (!Array.isArray(properties)) {
  77 |       throw new Error(`Invalid properties: expected array, got ${typeof properties}`);
  78 |     }
  79 |     
  80 |     // Extract operation context from config
  81 |     const operationContext = this.extractOperationContext(config);
  82 | 
  83 |     // Extract user-provided keys before applying defaults (CRITICAL FIX for warning system)
  84 |     const userProvidedKeys = new Set(Object.keys(config));
  85 | 
  86 |     // Filter properties based on mode and operation, and get config with defaults
  87 |     const { properties: filteredProperties, configWithDefaults } = this.filterPropertiesByMode(
  88 |       properties,
  89 |       config,
  90 |       mode,
  91 |       operationContext
  92 |     );
  93 | 
  94 |     // Perform base validation on filtered properties with defaults applied
  95 |     // Pass userProvidedKeys to prevent warnings about default values
  96 |     const baseResult = super.validate(nodeType, configWithDefaults, filteredProperties, userProvidedKeys);
  97 |     
  98 |     // Enhance the result
  99 |     const enhancedResult: EnhancedValidationResult = {
 100 |       ...baseResult,
 101 |       mode,
 102 |       profile,
 103 |       operation: operationContext,
 104 |       examples: [],
 105 |       nextSteps: [],
 106 |       // Ensure arrays are initialized (in case baseResult doesn't have them)
 107 |       errors: baseResult.errors || [],
 108 |       warnings: baseResult.warnings || [],
 109 |       suggestions: baseResult.suggestions || []
 110 |     };
 111 |     
 112 |     // Apply profile-based filtering
 113 |     this.applyProfileFilters(enhancedResult, profile);
 114 |     
 115 |     // Add operation-specific enhancements
 116 |     this.addOperationSpecificEnhancements(nodeType, config, filteredProperties, enhancedResult);
 117 |     
 118 |     // Deduplicate errors
 119 |     enhancedResult.errors = this.deduplicateErrors(enhancedResult.errors);
 120 |     
 121 |     // Examples removed - use validate_node_operation for configuration guidance
 122 |     
 123 |     // Generate next steps based on errors
 124 |     enhancedResult.nextSteps = this.generateNextSteps(enhancedResult);
 125 |     
 126 |     // Recalculate validity after all enhancements (crucial for fixedCollection validation)
 127 |     enhancedResult.valid = enhancedResult.errors.length === 0;
 128 |     
 129 |     return enhancedResult;
 130 |   }
 131 |   
 132 |   /**
 133 |    * Extract operation context from configuration
 134 |    */
 135 |   private static extractOperationContext(config: Record<string, any>): OperationContext {
 136 |     return {
 137 |       resource: config.resource,
 138 |       operation: config.operation,
 139 |       action: config.action,
 140 |       mode: config.mode
 141 |     };
 142 |   }
 143 |   
 144 |   /**
 145 |    * Filter properties based on validation mode and operation
 146 |    * Returns both filtered properties and config with defaults
 147 |    */
 148 |   private static filterPropertiesByMode(
 149 |     properties: any[],
 150 |     config: Record<string, any>,
 151 |     mode: ValidationMode,
 152 |     operation: OperationContext
 153 |   ): { properties: any[], configWithDefaults: Record<string, any> } {
 154 |     // Apply defaults for visibility checking
 155 |     const configWithDefaults = this.applyNodeDefaults(properties, config);
 156 | 
 157 |     let filteredProperties: any[];
 158 |     switch (mode) {
 159 |       case 'minimal':
 160 |         // Only required properties that are visible
 161 |         filteredProperties = properties.filter(prop =>
 162 |           prop.required && this.isPropertyVisible(prop, configWithDefaults)
 163 |         );
 164 |         break;
 165 | 
 166 |       case 'operation':
 167 |         // Only properties relevant to the current operation
 168 |         filteredProperties = properties.filter(prop =>
 169 |           this.isPropertyRelevantToOperation(prop, configWithDefaults, operation)
 170 |         );
 171 |         break;
 172 | 
 173 |       case 'full':
 174 |       default:
 175 |         // All properties (current behavior)
 176 |         filteredProperties = properties;
 177 |         break;
 178 |     }
 179 | 
 180 |     return { properties: filteredProperties, configWithDefaults };
 181 |   }
 182 | 
 183 |   /**
 184 |    * Apply node defaults to configuration for accurate visibility checking
 185 |    */
 186 |   private static applyNodeDefaults(properties: any[], config: Record<string, any>): Record<string, any> {
 187 |     const result = { ...config };
 188 | 
 189 |     for (const prop of properties) {
 190 |       if (prop.name && prop.default !== undefined && result[prop.name] === undefined) {
 191 |         result[prop.name] = prop.default;
 192 |       }
 193 |     }
 194 | 
 195 |     return result;
 196 |   }
 197 |   
 198 |   /**
 199 |    * Check if property is relevant to current operation
 200 |    */
 201 |   private static isPropertyRelevantToOperation(
 202 |     prop: any,
 203 |     config: Record<string, any>,
 204 |     operation: OperationContext
 205 |   ): boolean {
 206 |     // First check if visible
 207 |     if (!this.isPropertyVisible(prop, config)) {
 208 |       return false;
 209 |     }
 210 |     
 211 |     // If no operation context, include all visible
 212 |     if (!operation.resource && !operation.operation && !operation.action) {
 213 |       return true;
 214 |     }
 215 |     
 216 |     // Check if property has operation-specific display options
 217 |     if (prop.displayOptions?.show) {
 218 |       const show = prop.displayOptions.show;
 219 |       
 220 |       // Check each operation field
 221 |       if (operation.resource && show.resource) {
 222 |         const expectedResources = Array.isArray(show.resource) ? show.resource : [show.resource];
 223 |         if (!expectedResources.includes(operation.resource)) {
 224 |           return false;
 225 |         }
 226 |       }
 227 |       
 228 |       if (operation.operation && show.operation) {
 229 |         const expectedOps = Array.isArray(show.operation) ? show.operation : [show.operation];
 230 |         if (!expectedOps.includes(operation.operation)) {
 231 |           return false;
 232 |         }
 233 |       }
 234 |       
 235 |       if (operation.action && show.action) {
 236 |         const expectedActions = Array.isArray(show.action) ? show.action : [show.action];
 237 |         if (!expectedActions.includes(operation.action)) {
 238 |           return false;
 239 |         }
 240 |       }
 241 |     }
 242 |     
 243 |     return true;
 244 |   }
 245 |   
 246 |   /**
 247 |    * Add operation-specific enhancements to validation result
 248 |    */
 249 |   private static addOperationSpecificEnhancements(
 250 |     nodeType: string,
 251 |     config: Record<string, any>,
 252 |     properties: any[],
 253 |     result: EnhancedValidationResult
 254 |   ): void {
 255 |     // Type safety check - this should never happen with proper validation
 256 |     if (typeof nodeType !== 'string') {
 257 |       result.errors.push({
 258 |         type: 'invalid_type',
 259 |         property: 'nodeType',
 260 |         message: `Invalid nodeType: expected string, got ${typeof nodeType}`,
 261 |         fix: 'Provide a valid node type string (e.g., "nodes-base.webhook")'
 262 |       });
 263 |       return;
 264 |     }
 265 | 
 266 |     // Validate resource and operation using similarity services
 267 |     this.validateResourceAndOperation(nodeType, config, result);
 268 | 
 269 |     // Validate special type structures (filter, resourceMapper, assignmentCollection, resourceLocator)
 270 |     this.validateSpecialTypeStructures(config, properties, result);
 271 | 
 272 |     // First, validate fixedCollection properties for known problematic nodes
 273 |     this.validateFixedCollectionStructures(nodeType, config, result);
 274 |     
 275 |     // Create context for node-specific validators
 276 |     const context: NodeValidationContext = {
 277 |       config,
 278 |       errors: result.errors,
 279 |       warnings: result.warnings,
 280 |       suggestions: result.suggestions,
 281 |       autofix: result.autofix || {}
 282 |     };
 283 |     
 284 |     // Normalize node type (handle both 'n8n-nodes-base.x' and 'nodes-base.x' formats)
 285 |     const normalizedNodeType = nodeType.replace('n8n-nodes-base.', 'nodes-base.');
 286 |     
 287 |     // Use node-specific validators
 288 |     switch (normalizedNodeType) {
 289 |       case 'nodes-base.slack':
 290 |         NodeSpecificValidators.validateSlack(context);
 291 |         this.enhanceSlackValidation(config, result);
 292 |         break;
 293 |         
 294 |       case 'nodes-base.googleSheets':
 295 |         NodeSpecificValidators.validateGoogleSheets(context);
 296 |         this.enhanceGoogleSheetsValidation(config, result);
 297 |         break;
 298 |         
 299 |       case 'nodes-base.httpRequest':
 300 |         // Use existing HTTP validation from base class
 301 |         this.enhanceHttpRequestValidation(config, result);
 302 |         break;
 303 |         
 304 |       case 'nodes-base.code':
 305 |         NodeSpecificValidators.validateCode(context);
 306 |         break;
 307 |         
 308 |       case 'nodes-base.openAi':
 309 |         NodeSpecificValidators.validateOpenAI(context);
 310 |         break;
 311 |         
 312 |       case 'nodes-base.mongoDb':
 313 |         NodeSpecificValidators.validateMongoDB(context);
 314 |         break;
 315 |         
 316 |       case 'nodes-base.webhook':
 317 |         NodeSpecificValidators.validateWebhook(context);
 318 |         break;
 319 |         
 320 |       case 'nodes-base.postgres':
 321 |         NodeSpecificValidators.validatePostgres(context);
 322 |         break;
 323 |         
 324 |       case 'nodes-base.mysql':
 325 |         NodeSpecificValidators.validateMySQL(context);
 326 |         break;
 327 | 
 328 |       case 'nodes-langchain.agent':
 329 |         NodeSpecificValidators.validateAIAgent(context);
 330 |         break;
 331 | 
 332 |       case 'nodes-base.set':
 333 |         NodeSpecificValidators.validateSet(context);
 334 |         break;
 335 | 
 336 |       case 'nodes-base.switch':
 337 |         this.validateSwitchNodeStructure(config, result);
 338 |         break;
 339 |         
 340 |       case 'nodes-base.if':
 341 |         this.validateIfNodeStructure(config, result);
 342 |         break;
 343 |         
 344 |       case 'nodes-base.filter':
 345 |         this.validateFilterNodeStructure(config, result);
 346 |         break;
 347 |         
 348 |       // Additional nodes handled by FixedCollectionValidator
 349 |       // No need for specific validators as the generic utility handles them
 350 |     }
 351 |     
 352 |     // Update autofix if changes were made
 353 |     if (Object.keys(context.autofix).length > 0) {
 354 |       result.autofix = context.autofix;
 355 |     }
 356 |   }
 357 |   
 358 |   /**
 359 |    * Enhanced Slack validation with operation awareness
 360 |    */
 361 |   private static enhanceSlackValidation(
 362 |     config: Record<string, any>,
 363 |     result: EnhancedValidationResult
 364 |   ): void {
 365 |     const { resource, operation } = result.operation || {};
 366 |     
 367 |     if (resource === 'message' && operation === 'send') {
 368 |       // Examples removed - validation focuses on error detection
 369 |       
 370 |       // Check for common issues
 371 |       if (!config.channel && !config.channelId) {
 372 |         const channelError = result.errors.find(e => 
 373 |           e.property === 'channel' || e.property === 'channelId'
 374 |         );
 375 |         if (channelError) {
 376 |           channelError.message = 'To send a Slack message, specify either a channel name (e.g., "#general") or channel ID';
 377 |           channelError.fix = 'Add channel: "#general" or use a channel ID like "C1234567890"';
 378 |         }
 379 |       }
 380 |     }
 381 |   }
 382 |   
 383 |   /**
 384 |    * Enhanced Google Sheets validation
 385 |    */
 386 |   private static enhanceGoogleSheetsValidation(
 387 |     config: Record<string, any>,
 388 |     result: EnhancedValidationResult
 389 |   ): void {
 390 |     const { operation } = result.operation || {};
 391 |     
 392 |     if (operation === 'append') {
 393 |       // Examples removed - validation focuses on configuration correctness
 394 |       
 395 |       // Validate range format
 396 |       if (config.range && !config.range.includes('!')) {
 397 |         result.warnings.push({
 398 |           type: 'inefficient',
 399 |           property: 'range',
 400 |           message: 'Range should include sheet name (e.g., "Sheet1!A:B")',
 401 |           suggestion: 'Format: "SheetName!A1:B10" or "SheetName!A:B" for entire columns'
 402 |         });
 403 |       }
 404 |     }
 405 |   }
 406 |   
 407 |   /**
 408 |    * Enhanced HTTP Request validation
 409 |    */
 410 |   private static enhanceHttpRequestValidation(
 411 |     config: Record<string, any>,
 412 |     result: EnhancedValidationResult
 413 |   ): void {
 414 |     const url = String(config.url || '');
 415 |     const options = config.options || {};
 416 | 
 417 |     // 1. Suggest alwaysOutputData for better error handling (node-level property)
 418 |     // Note: We can't check if it exists (it's node-level, not in parameters),
 419 |     // but we can suggest it as a best practice
 420 |     if (!result.suggestions.some(s => typeof s === 'string' && s.includes('alwaysOutputData'))) {
 421 |       result.suggestions.push(
 422 |         'Consider adding alwaysOutputData: true at node level (not in parameters) for better error handling. ' +
 423 |         'This ensures the node produces output even when HTTP requests fail, allowing downstream error handling.'
 424 |       );
 425 |     }
 426 | 
 427 |     // 2. Suggest responseFormat for API endpoints
 428 |     const lowerUrl = url.toLowerCase();
 429 |     const isApiEndpoint =
 430 |       // Subdomain patterns (api.example.com)
 431 |       /^https?:\/\/api\./i.test(url) ||
 432 |       // Path patterns with word boundaries to prevent false positives like "therapist", "restaurant"
 433 |       /\/api[\/\?]|\/api$/i.test(url) ||
 434 |       /\/rest[\/\?]|\/rest$/i.test(url) ||
 435 |       // Known API service domains
 436 |       lowerUrl.includes('supabase.co') ||
 437 |       lowerUrl.includes('firebase') ||
 438 |       lowerUrl.includes('googleapis.com') ||
 439 |       // Versioned API paths (e.g., example.com/v1, example.com/v2)
 440 |       /\.com\/v\d+/i.test(url);
 441 | 
 442 |     if (isApiEndpoint && !options.response?.response?.responseFormat) {
 443 |       result.suggestions.push(
 444 |         'API endpoints should explicitly set options.response.response.responseFormat to "json" or "text" ' +
 445 |         'to prevent confusion about response parsing. Example: ' +
 446 |         '{ "options": { "response": { "response": { "responseFormat": "json" } } } }'
 447 |       );
 448 |     }
 449 | 
 450 |     // 3. Enhanced URL protocol validation for expressions
 451 |     if (url && url.startsWith('=')) {
 452 |       // Expression-based URL - check for common protocol issues
 453 |       const expressionContent = url.slice(1); // Remove = prefix
 454 |       const lowerExpression = expressionContent.toLowerCase();
 455 | 
 456 |       // Check for missing protocol in expression (case-insensitive)
 457 |       if (expressionContent.startsWith('www.') ||
 458 |           (expressionContent.includes('{{') && !lowerExpression.includes('http'))) {
 459 |         result.warnings.push({
 460 |           type: 'invalid_value',
 461 |           property: 'url',
 462 |           message: 'URL expression appears to be missing http:// or https:// protocol',
 463 |           suggestion: 'Include protocol in your expression. Example: ={{ "https://" + $json.domain + ".com" }}'
 464 |         });
 465 |       }
 466 |     }
 467 |   }
 468 |   
 469 |   /**
 470 |    * Generate actionable next steps based on validation results
 471 |    */
 472 |   private static generateNextSteps(result: EnhancedValidationResult): string[] {
 473 |     const steps: string[] = [];
 474 |     
 475 |     // Group errors by type
 476 |     const requiredErrors = result.errors.filter(e => e.type === 'missing_required');
 477 |     const typeErrors = result.errors.filter(e => e.type === 'invalid_type');
 478 |     const valueErrors = result.errors.filter(e => e.type === 'invalid_value');
 479 |     
 480 |     if (requiredErrors.length > 0) {
 481 |       steps.push(`Add required fields: ${requiredErrors.map(e => e.property).join(', ')}`);
 482 |     }
 483 |     
 484 |     if (typeErrors.length > 0) {
 485 |       steps.push(`Fix type mismatches: ${typeErrors.map(e => `${e.property} should be ${e.fix}`).join(', ')}`);
 486 |     }
 487 |     
 488 |     if (valueErrors.length > 0) {
 489 |       steps.push(`Correct invalid values: ${valueErrors.map(e => e.property).join(', ')}`);
 490 |     }
 491 |     
 492 |     if (result.warnings.length > 0 && result.errors.length === 0) {
 493 |       steps.push('Consider addressing warnings for better reliability');
 494 |     }
 495 |     
 496 |     if (result.errors.length > 0) {
 497 |       steps.push('Fix the errors above following the provided suggestions');
 498 |     }
 499 |     
 500 |     return steps;
 501 |   }
 502 |   
 503 |   
 504 |   /**
 505 |    * Deduplicate errors based on property and type
 506 |    * Prefers more specific error messages over generic ones
 507 |    */
 508 |   private static deduplicateErrors(errors: ValidationError[]): ValidationError[] {
 509 |     const seen = new Map<string, ValidationError>();
 510 |     
 511 |     for (const error of errors) {
 512 |       const key = `${error.property}-${error.type}`;
 513 |       const existing = seen.get(key);
 514 |       
 515 |       if (!existing) {
 516 |         seen.set(key, error);
 517 |       } else {
 518 |         // Keep the error with more specific message or fix
 519 |         const existingLength = (existing.message?.length || 0) + (existing.fix?.length || 0);
 520 |         const newLength = (error.message?.length || 0) + (error.fix?.length || 0);
 521 |         
 522 |         if (newLength > existingLength) {
 523 |           seen.set(key, error);
 524 |         }
 525 |       }
 526 |     }
 527 |     
 528 |     return Array.from(seen.values());
 529 |   }
 530 |   
 531 |   /**
 532 |    * Check if a warning should be filtered out (hardcoded credentials shown only in strict mode)
 533 |    */
 534 |   private static shouldFilterCredentialWarning(warning: ValidationWarning): boolean {
 535 |     return warning.type === 'security' &&
 536 |            warning.message !== undefined &&
 537 |            warning.message.includes('Hardcoded nodeCredentialType');
 538 |   }
 539 | 
 540 |   /**
 541 |    * Apply profile-based filtering to validation results
 542 |    */
 543 |   private static applyProfileFilters(
 544 |     result: EnhancedValidationResult,
 545 |     profile: ValidationProfile
 546 |   ): void {
 547 |     switch (profile) {
 548 |       case 'minimal':
 549 |         // Only keep missing required errors
 550 |         result.errors = result.errors.filter(e => e.type === 'missing_required');
 551 |         // Keep ONLY critical warnings (security and deprecated)
 552 |         // But filter out hardcoded credential type warnings (only show in strict mode)
 553 |         result.warnings = result.warnings.filter(w => {
 554 |           if (this.shouldFilterCredentialWarning(w)) {
 555 |             return false;
 556 |           }
 557 |           return w.type === 'security' || w.type === 'deprecated';
 558 |         });
 559 |         result.suggestions = [];
 560 |         break;
 561 | 
 562 |       case 'runtime':
 563 |         // Keep critical runtime errors only
 564 |         result.errors = result.errors.filter(e =>
 565 |           e.type === 'missing_required' ||
 566 |           e.type === 'invalid_value' ||
 567 |           (e.type === 'invalid_type' && e.message.includes('undefined'))
 568 |         );
 569 |         // Keep security and deprecated warnings, REMOVE property visibility warnings
 570 |         result.warnings = result.warnings.filter(w => {
 571 |           // Filter out hardcoded credential type warnings (only show in strict mode)
 572 |           if (this.shouldFilterCredentialWarning(w)) {
 573 |             return false;
 574 |           }
 575 |           if (w.type === 'security' || w.type === 'deprecated') return true;
 576 |           // FILTER OUT property visibility warnings (too noisy)
 577 |           if (w.type === 'inefficient' && w.message && w.message.includes('not visible')) {
 578 |             return false;
 579 |           }
 580 |           return false;
 581 |         });
 582 |         result.suggestions = [];
 583 |         break;
 584 | 
 585 |       case 'strict':
 586 |         // Keep everything, add more suggestions
 587 |         if (result.warnings.length === 0 && result.errors.length === 0) {
 588 |           result.suggestions.push('Consider adding error handling with onError property and timeout configuration');
 589 |           result.suggestions.push('Add authentication if connecting to external services');
 590 |         }
 591 |         // Require error handling for external service nodes
 592 |         this.enforceErrorHandlingForProfile(result, profile);
 593 |         break;
 594 | 
 595 |       case 'ai-friendly':
 596 |       default:
 597 |         // Current behavior - balanced for AI agents
 598 |         // Filter out noise but keep helpful warnings
 599 |         result.warnings = result.warnings.filter(w => {
 600 |           // Filter out hardcoded credential type warnings (only show in strict mode)
 601 |           if (this.shouldFilterCredentialWarning(w)) {
 602 |             return false;
 603 |           }
 604 |           // Keep security and deprecated warnings
 605 |           if (w.type === 'security' || w.type === 'deprecated') return true;
 606 |           // Keep missing common properties
 607 |           if (w.type === 'missing_common') return true;
 608 |           // Keep best practice warnings
 609 |           if (w.type === 'best_practice') return true;
 610 |           // FILTER OUT inefficient warnings about property visibility (now fixed at source)
 611 |           if (w.type === 'inefficient' && w.message && w.message.includes('not visible')) {
 612 |             return false; // These are now rare due to userProvidedKeys fix
 613 |           }
 614 |           // Filter out internal property warnings
 615 |           if (w.type === 'inefficient' && w.property?.startsWith('_')) {
 616 |             return false;
 617 |           }
 618 |           return true;
 619 |         });
 620 |         // Add error handling suggestions for AI-friendly profile
 621 |         this.addErrorHandlingSuggestions(result);
 622 |         break;
 623 |     }
 624 |   }
 625 |   
 626 |   /**
 627 |    * Enforce error handling requirements based on profile
 628 |    */
 629 |   private static enforceErrorHandlingForProfile(
 630 |     result: EnhancedValidationResult,
 631 |     profile: ValidationProfile
 632 |   ): void {
 633 |     // Only enforce for strict profile on external service nodes
 634 |     if (profile !== 'strict') return;
 635 |     
 636 |     const nodeType = result.operation?.resource || '';
 637 |     const errorProneTypes = ['httpRequest', 'webhook', 'database', 'api', 'slack', 'email', 'openai'];
 638 |     
 639 |     if (errorProneTypes.some(type => nodeType.toLowerCase().includes(type))) {
 640 |       // Add general warning for strict profile
 641 |       // The actual error handling validation is done in node-specific validators
 642 |       result.warnings.push({
 643 |         type: 'best_practice',
 644 |         property: 'errorHandling',
 645 |         message: 'External service nodes should have error handling configured',
 646 |         suggestion: 'Add onError: "continueRegularOutput" or "stopWorkflow" with retryOnFail: true for resilience'
 647 |       });
 648 |     }
 649 |   }
 650 |   
 651 |   /**
 652 |    * Add error handling suggestions for AI-friendly profile
 653 |    */
 654 |   private static addErrorHandlingSuggestions(
 655 |     result: EnhancedValidationResult
 656 |   ): void {
 657 |     // Check if there are any network/API related errors
 658 |     const hasNetworkErrors = result.errors.some(e => 
 659 |       e.message.toLowerCase().includes('url') || 
 660 |       e.message.toLowerCase().includes('endpoint') ||
 661 |       e.message.toLowerCase().includes('api')
 662 |     );
 663 |     
 664 |     if (hasNetworkErrors) {
 665 |       result.suggestions.push(
 666 |         'For API calls, consider adding onError: "continueRegularOutput" with retryOnFail: true and maxTries: 3'
 667 |       );
 668 |     }
 669 |     
 670 |     // Check for webhook configurations
 671 |     const isWebhook = result.operation?.resource === 'webhook' || 
 672 |                      result.errors.some(e => e.message.toLowerCase().includes('webhook'));
 673 |     
 674 |     if (isWebhook) {
 675 |       result.suggestions.push(
 676 |         'Webhooks should use onError: "continueRegularOutput" to ensure responses are always sent'
 677 |       );
 678 |     }
 679 |   }
 680 |   
 681 |   /**
 682 |    * Validate fixedCollection structures for known problematic nodes
 683 |    * This prevents the "propertyValues[itemName] is not iterable" error
 684 |    */
 685 |   private static validateFixedCollectionStructures(
 686 |     nodeType: string,
 687 |     config: Record<string, any>,
 688 |     result: EnhancedValidationResult
 689 |   ): void {
 690 |     // Use the generic FixedCollectionValidator
 691 |     const validationResult = FixedCollectionValidator.validate(nodeType, config);
 692 |     
 693 |     if (!validationResult.isValid) {
 694 |       // Add errors to the result
 695 |       for (const error of validationResult.errors) {
 696 |         result.errors.push({
 697 |           type: 'invalid_value',
 698 |           property: error.pattern.split('.')[0], // Get the root property
 699 |           message: error.message,
 700 |           fix: error.fix
 701 |         });
 702 |       }
 703 |       
 704 |       // Apply autofix if available
 705 |       if (validationResult.autofix) {
 706 |         // For nodes like If/Filter where the entire config might be replaced,
 707 |         // we need to handle it specially
 708 |         if (typeof validationResult.autofix === 'object' && !Array.isArray(validationResult.autofix)) {
 709 |           result.autofix = {
 710 |             ...result.autofix,
 711 |             ...validationResult.autofix
 712 |           };
 713 |         } else {
 714 |           // If the autofix is an array (like for If/Filter nodes), wrap it properly
 715 |           const firstError = validationResult.errors[0];
 716 |           if (firstError) {
 717 |             const rootProperty = firstError.pattern.split('.')[0];
 718 |             result.autofix = {
 719 |               ...result.autofix,
 720 |               [rootProperty]: validationResult.autofix
 721 |             };
 722 |           }
 723 |         }
 724 |       }
 725 |     }
 726 |   }
 727 |   
 728 |   
 729 |   /**
 730 |    * Validate Switch node structure specifically
 731 |    */
 732 |   private static validateSwitchNodeStructure(
 733 |     config: Record<string, any>,
 734 |     result: EnhancedValidationResult
 735 |   ): void {
 736 |     if (!config.rules) return;
 737 |     
 738 |     // Skip if already caught by validateFixedCollectionStructures
 739 |     const hasFixedCollectionError = result.errors.some(e => 
 740 |       e.property === 'rules' && e.message.includes('propertyValues[itemName] is not iterable')
 741 |     );
 742 |     
 743 |     if (hasFixedCollectionError) return;
 744 |     
 745 |     // Validate rules.values structure if present
 746 |     if (config.rules.values && Array.isArray(config.rules.values)) {
 747 |       config.rules.values.forEach((rule: any, index: number) => {
 748 |         if (!rule.conditions) {
 749 |           result.warnings.push({
 750 |             type: 'missing_common',
 751 |             property: 'rules',
 752 |             message: `Switch rule ${index + 1} is missing "conditions" property`,
 753 |             suggestion: 'Each rule in the values array should have a "conditions" property'
 754 |           });
 755 |         }
 756 |         if (!rule.outputKey && rule.renameOutput !== false) {
 757 |           result.warnings.push({
 758 |             type: 'missing_common',
 759 |             property: 'rules',
 760 |             message: `Switch rule ${index + 1} is missing "outputKey" property`,
 761 |             suggestion: 'Add "outputKey" to specify which output to use when this rule matches'
 762 |           });
 763 |         }
 764 |       });
 765 |     }
 766 |   }
 767 |   
 768 |   /**
 769 |    * Validate If node structure specifically
 770 |    */
 771 |   private static validateIfNodeStructure(
 772 |     config: Record<string, any>,
 773 |     result: EnhancedValidationResult
 774 |   ): void {
 775 |     if (!config.conditions) return;
 776 |     
 777 |     // Skip if already caught by validateFixedCollectionStructures
 778 |     const hasFixedCollectionError = result.errors.some(e => 
 779 |       e.property === 'conditions' && e.message.includes('propertyValues[itemName] is not iterable')
 780 |     );
 781 |     
 782 |     if (hasFixedCollectionError) return;
 783 |     
 784 |     // Add any If-node-specific validation here in the future
 785 |   }
 786 |   
 787 |   /**
 788 |    * Validate Filter node structure specifically
 789 |    */
 790 |   private static validateFilterNodeStructure(
 791 |     config: Record<string, any>,
 792 |     result: EnhancedValidationResult
 793 |   ): void {
 794 |     if (!config.conditions) return;
 795 |     
 796 |     // Skip if already caught by validateFixedCollectionStructures
 797 |     const hasFixedCollectionError = result.errors.some(e => 
 798 |       e.property === 'conditions' && e.message.includes('propertyValues[itemName] is not iterable')
 799 |     );
 800 |     
 801 |     if (hasFixedCollectionError) return;
 802 |     
 803 |     // Add any Filter-node-specific validation here in the future
 804 |   }
 805 | 
 806 |   /**
 807 |    * Validate resource and operation values using similarity services
 808 |    */
 809 |   private static validateResourceAndOperation(
 810 |     nodeType: string,
 811 |     config: Record<string, any>,
 812 |     result: EnhancedValidationResult
 813 |   ): void {
 814 |     // Skip if similarity services not initialized
 815 |     if (!this.operationSimilarityService || !this.resourceSimilarityService || !this.nodeRepository) {
 816 |       return;
 817 |     }
 818 | 
 819 |     // Normalize the node type for repository lookups
 820 |     const normalizedNodeType = NodeTypeNormalizer.normalizeToFullForm(nodeType);
 821 | 
 822 |     // Apply defaults for validation
 823 |     const configWithDefaults = { ...config };
 824 | 
 825 |     // If operation is undefined but resource is set, get the default operation for that resource
 826 |     if (configWithDefaults.operation === undefined && configWithDefaults.resource !== undefined) {
 827 |       const defaultOperation = this.nodeRepository.getDefaultOperationForResource(normalizedNodeType, configWithDefaults.resource);
 828 |       if (defaultOperation !== undefined) {
 829 |         configWithDefaults.operation = defaultOperation;
 830 |       }
 831 |     }
 832 | 
 833 |     // Validate resource field if present
 834 |     if (config.resource !== undefined) {
 835 |       // Remove any existing resource error from base validator to replace with our enhanced version
 836 |       result.errors = result.errors.filter(e => e.property !== 'resource');
 837 |       const validResources = this.nodeRepository.getNodeResources(normalizedNodeType);
 838 |       const resourceIsValid = validResources.some(r => {
 839 |         const resourceValue = typeof r === 'string' ? r : r.value;
 840 |         return resourceValue === config.resource;
 841 |       });
 842 | 
 843 |       if (!resourceIsValid && config.resource !== '') {
 844 |         // Find similar resources
 845 |         let suggestions: any[] = [];
 846 |         try {
 847 |           suggestions = this.resourceSimilarityService.findSimilarResources(
 848 |             normalizedNodeType,
 849 |             config.resource,
 850 |             3
 851 |           );
 852 |         } catch (error) {
 853 |           // If similarity service fails, continue with validation without suggestions
 854 |           console.error('Resource similarity service error:', error);
 855 |         }
 856 | 
 857 |         // Build error message with suggestions
 858 |         let errorMessage = `Invalid resource "${config.resource}" for node ${nodeType}.`;
 859 |         let fix = '';
 860 | 
 861 |         if (suggestions.length > 0) {
 862 |           const topSuggestion = suggestions[0];
 863 |           // Always use "Did you mean" for the top suggestion
 864 |           errorMessage += ` Did you mean "${topSuggestion.value}"?`;
 865 |           if (topSuggestion.confidence >= 0.8) {
 866 |             fix = `Change resource to "${topSuggestion.value}". ${topSuggestion.reason}`;
 867 |           } else {
 868 |             // For lower confidence, still show valid resources in the fix
 869 |             fix = `Valid resources: ${validResources.slice(0, 5).map(r => {
 870 |               const val = typeof r === 'string' ? r : r.value;
 871 |               return `"${val}"`;
 872 |             }).join(', ')}${validResources.length > 5 ? '...' : ''}`;
 873 |           }
 874 |         } else {
 875 |           // No similar resources found, list valid ones
 876 |           fix = `Valid resources: ${validResources.slice(0, 5).map(r => {
 877 |             const val = typeof r === 'string' ? r : r.value;
 878 |             return `"${val}"`;
 879 |           }).join(', ')}${validResources.length > 5 ? '...' : ''}`;
 880 |         }
 881 | 
 882 |         const error: any = {
 883 |           type: 'invalid_value',
 884 |           property: 'resource',
 885 |           message: errorMessage,
 886 |           fix
 887 |         };
 888 | 
 889 |         // Add suggestion property if we have high confidence suggestions
 890 |         if (suggestions.length > 0 && suggestions[0].confidence >= 0.5) {
 891 |           error.suggestion = `Did you mean "${suggestions[0].value}"? ${suggestions[0].reason}`;
 892 |         }
 893 | 
 894 |         result.errors.push(error);
 895 | 
 896 |         // Add suggestions to result.suggestions array
 897 |         if (suggestions.length > 0) {
 898 |           for (const suggestion of suggestions) {
 899 |             result.suggestions.push(
 900 |               `Resource "${config.resource}" not found. Did you mean "${suggestion.value}"? ${suggestion.reason}`
 901 |             );
 902 |           }
 903 |         }
 904 |       }
 905 |     }
 906 | 
 907 |     // Validate operation field - now we check configWithDefaults which has defaults applied
 908 |     // Only validate if operation was explicitly set (not undefined) OR if we're using a default
 909 |     if (config.operation !== undefined || configWithDefaults.operation !== undefined) {
 910 |       // Remove any existing operation error from base validator to replace with our enhanced version
 911 |       result.errors = result.errors.filter(e => e.property !== 'operation');
 912 | 
 913 |       // Use the operation from configWithDefaults for validation (which includes the default if applied)
 914 |       const operationToValidate = configWithDefaults.operation || config.operation;
 915 |       const validOperations = this.nodeRepository.getNodeOperations(normalizedNodeType, config.resource);
 916 |       const operationIsValid = validOperations.some(op => {
 917 |         const opValue = op.operation || op.value || op;
 918 |         return opValue === operationToValidate;
 919 |       });
 920 | 
 921 |       // Only report error if the explicit operation is invalid (not for defaults)
 922 |       if (!operationIsValid && config.operation !== undefined && config.operation !== '') {
 923 |         // Find similar operations
 924 |         let suggestions: any[] = [];
 925 |         try {
 926 |           suggestions = this.operationSimilarityService.findSimilarOperations(
 927 |             normalizedNodeType,
 928 |             config.operation,
 929 |             config.resource,
 930 |             3
 931 |           );
 932 |         } catch (error) {
 933 |           // If similarity service fails, continue with validation without suggestions
 934 |           console.error('Operation similarity service error:', error);
 935 |         }
 936 | 
 937 |         // Build error message with suggestions
 938 |         let errorMessage = `Invalid operation "${config.operation}" for node ${nodeType}`;
 939 |         if (config.resource) {
 940 |           errorMessage += ` with resource "${config.resource}"`;
 941 |         }
 942 |         errorMessage += '.';
 943 | 
 944 |         let fix = '';
 945 | 
 946 |         if (suggestions.length > 0) {
 947 |           const topSuggestion = suggestions[0];
 948 |           if (topSuggestion.confidence >= 0.8) {
 949 |             errorMessage += ` Did you mean "${topSuggestion.value}"?`;
 950 |             fix = `Change operation to "${topSuggestion.value}". ${topSuggestion.reason}`;
 951 |           } else {
 952 |             errorMessage += ` Similar operations: ${suggestions.map(s => `"${s.value}"`).join(', ')}`;
 953 |             fix = `Valid operations${config.resource ? ` for resource "${config.resource}"` : ''}: ${validOperations.slice(0, 5).map(op => {
 954 |               const val = op.operation || op.value || op;
 955 |               return `"${val}"`;
 956 |             }).join(', ')}${validOperations.length > 5 ? '...' : ''}`;
 957 |           }
 958 |         } else {
 959 |           // No similar operations found, list valid ones
 960 |           fix = `Valid operations${config.resource ? ` for resource "${config.resource}"` : ''}: ${validOperations.slice(0, 5).map(op => {
 961 |             const val = op.operation || op.value || op;
 962 |             return `"${val}"`;
 963 |           }).join(', ')}${validOperations.length > 5 ? '...' : ''}`;
 964 |         }
 965 | 
 966 |         const error: any = {
 967 |           type: 'invalid_value',
 968 |           property: 'operation',
 969 |           message: errorMessage,
 970 |           fix
 971 |         };
 972 | 
 973 |         // Add suggestion property if we have high confidence suggestions
 974 |         if (suggestions.length > 0 && suggestions[0].confidence >= 0.5) {
 975 |           error.suggestion = `Did you mean "${suggestions[0].value}"? ${suggestions[0].reason}`;
 976 |         }
 977 | 
 978 |         result.errors.push(error);
 979 | 
 980 |         // Add suggestions to result.suggestions array
 981 |         if (suggestions.length > 0) {
 982 |           for (const suggestion of suggestions) {
 983 |             result.suggestions.push(
 984 |               `Operation "${config.operation}" not found. Did you mean "${suggestion.value}"? ${suggestion.reason}`
 985 |             );
 986 |           }
 987 |         }
 988 |       }
 989 |     }
 990 |   }
 991 | 
 992 |   /**
 993 |    * Validate special type structures (filter, resourceMapper, assignmentCollection, resourceLocator)
 994 |    *
 995 |    * Integrates TypeStructureService to validate complex property types against their
 996 |    * expected structures. This catches configuration errors for advanced node types.
 997 |    *
 998 |    * @param config - Node configuration to validate
 999 |    * @param properties - Property definitions from node schema
1000 |    * @param result - Validation result to populate with errors/warnings
1001 |    */
1002 |   private static validateSpecialTypeStructures(
1003 |     config: Record<string, any>,
1004 |     properties: any[],
1005 |     result: EnhancedValidationResult
1006 |   ): void {
1007 |     for (const [key, value] of Object.entries(config)) {
1008 |       if (value === undefined || value === null) continue;
1009 | 
1010 |       // Find property definition
1011 |       const propDef = properties.find(p => p.name === key);
1012 |       if (!propDef) continue;
1013 | 
1014 |       // Check if this property uses a special type
1015 |       let structureType: NodePropertyTypes | null = null;
1016 | 
1017 |       if (propDef.type === 'filter') {
1018 |         structureType = 'filter';
1019 |       } else if (propDef.type === 'resourceMapper') {
1020 |         structureType = 'resourceMapper';
1021 |       } else if (propDef.type === 'assignmentCollection') {
1022 |         structureType = 'assignmentCollection';
1023 |       } else if (propDef.type === 'resourceLocator') {
1024 |         structureType = 'resourceLocator';
1025 |       }
1026 | 
1027 |       if (!structureType) continue;
1028 | 
1029 |       // Get structure definition
1030 |       const structure = TypeStructureService.getStructure(structureType);
1031 |       if (!structure) {
1032 |         console.warn(`No structure definition found for type: ${structureType}`);
1033 |         continue;
1034 |       }
1035 | 
1036 |       // Validate using TypeStructureService for basic type checking
1037 |       const validationResult = TypeStructureService.validateTypeCompatibility(
1038 |         value,
1039 |         structureType
1040 |       );
1041 | 
1042 |       // Add errors from structure validation
1043 |       if (!validationResult.valid) {
1044 |         for (const error of validationResult.errors) {
1045 |           result.errors.push({
1046 |             type: 'invalid_configuration',
1047 |             property: key,
1048 |             message: error,
1049 |             fix: `Ensure ${key} follows the expected structure for ${structureType} type. Example: ${JSON.stringify(structure.example)}`
1050 |           });
1051 |         }
1052 |       }
1053 | 
1054 |       // Add warnings
1055 |       for (const warning of validationResult.warnings) {
1056 |         result.warnings.push({
1057 |           type: 'best_practice',
1058 |           property: key,
1059 |           message: warning
1060 |         });
1061 |       }
1062 | 
1063 |       // Perform deep structure validation for complex types
1064 |       if (typeof value === 'object' && value !== null) {
1065 |         this.validateComplexTypeStructure(key, value, structureType, structure, result);
1066 |       }
1067 | 
1068 |       // Special handling for filter operation validation
1069 |       if (structureType === 'filter' && value.conditions) {
1070 |         this.validateFilterOperations(value.conditions, key, result);
1071 |       }
1072 |     }
1073 |   }
1074 | 
1075 |   /**
1076 |    * Deep validation for complex type structures
1077 |    */
1078 |   private static validateComplexTypeStructure(
1079 |     propertyName: string,
1080 |     value: any,
1081 |     type: NodePropertyTypes,
1082 |     structure: any,
1083 |     result: EnhancedValidationResult
1084 |   ): void {
1085 |     switch (type) {
1086 |       case 'filter':
1087 |         // Validate filter structure: must have combinator and conditions
1088 |         if (!value.combinator) {
1089 |           result.errors.push({
1090 |             type: 'invalid_configuration',
1091 |             property: `${propertyName}.combinator`,
1092 |             message: 'Filter must have a combinator field',
1093 |             fix: 'Add combinator: "and" or combinator: "or" to the filter configuration'
1094 |           });
1095 |         } else if (value.combinator !== 'and' && value.combinator !== 'or') {
1096 |           result.errors.push({
1097 |             type: 'invalid_configuration',
1098 |             property: `${propertyName}.combinator`,
1099 |             message: `Invalid combinator value: ${value.combinator}. Must be "and" or "or"`,
1100 |             fix: 'Set combinator to either "and" or "or"'
1101 |           });
1102 |         }
1103 | 
1104 |         if (!value.conditions) {
1105 |           result.errors.push({
1106 |             type: 'invalid_configuration',
1107 |             property: `${propertyName}.conditions`,
1108 |             message: 'Filter must have a conditions field',
1109 |             fix: 'Add conditions array to the filter configuration'
1110 |           });
1111 |         } else if (!Array.isArray(value.conditions)) {
1112 |           result.errors.push({
1113 |             type: 'invalid_configuration',
1114 |             property: `${propertyName}.conditions`,
1115 |             message: 'Filter conditions must be an array',
1116 |             fix: 'Ensure conditions is an array of condition objects'
1117 |           });
1118 |         }
1119 |         break;
1120 | 
1121 |       case 'resourceLocator':
1122 |         // Validate resourceLocator structure: must have mode and value
1123 |         if (!value.mode) {
1124 |           result.errors.push({
1125 |             type: 'invalid_configuration',
1126 |             property: `${propertyName}.mode`,
1127 |             message: 'ResourceLocator must have a mode field',
1128 |             fix: 'Add mode: "id", mode: "url", or mode: "list" to the resourceLocator configuration'
1129 |           });
1130 |         } else if (!['id', 'url', 'list', 'name'].includes(value.mode)) {
1131 |           result.errors.push({
1132 |             type: 'invalid_configuration',
1133 |             property: `${propertyName}.mode`,
1134 |             message: `Invalid mode value: ${value.mode}. Must be "id", "url", "list", or "name"`,
1135 |             fix: 'Set mode to one of: "id", "url", "list", "name"'
1136 |           });
1137 |         }
1138 | 
1139 |         if (!value.hasOwnProperty('value')) {
1140 |           result.errors.push({
1141 |             type: 'invalid_configuration',
1142 |             property: `${propertyName}.value`,
1143 |             message: 'ResourceLocator must have a value field',
1144 |             fix: 'Add value field to the resourceLocator configuration'
1145 |           });
1146 |         }
1147 |         break;
1148 | 
1149 |       case 'assignmentCollection':
1150 |         // Validate assignmentCollection structure: must have assignments array
1151 |         if (!value.assignments) {
1152 |           result.errors.push({
1153 |             type: 'invalid_configuration',
1154 |             property: `${propertyName}.assignments`,
1155 |             message: 'AssignmentCollection must have an assignments field',
1156 |             fix: 'Add assignments array to the assignmentCollection configuration'
1157 |           });
1158 |         } else if (!Array.isArray(value.assignments)) {
1159 |           result.errors.push({
1160 |             type: 'invalid_configuration',
1161 |             property: `${propertyName}.assignments`,
1162 |             message: 'AssignmentCollection assignments must be an array',
1163 |             fix: 'Ensure assignments is an array of assignment objects'
1164 |           });
1165 |         }
1166 |         break;
1167 | 
1168 |       case 'resourceMapper':
1169 |         // Validate resourceMapper structure: must have mappingMode
1170 |         if (!value.mappingMode) {
1171 |           result.errors.push({
1172 |             type: 'invalid_configuration',
1173 |             property: `${propertyName}.mappingMode`,
1174 |             message: 'ResourceMapper must have a mappingMode field',
1175 |             fix: 'Add mappingMode: "defineBelow" or mappingMode: "autoMapInputData"'
1176 |           });
1177 |         } else if (!['defineBelow', 'autoMapInputData'].includes(value.mappingMode)) {
1178 |           result.errors.push({
1179 |             type: 'invalid_configuration',
1180 |             property: `${propertyName}.mappingMode`,
1181 |             message: `Invalid mappingMode: ${value.mappingMode}. Must be "defineBelow" or "autoMapInputData"`,
1182 |             fix: 'Set mappingMode to either "defineBelow" or "autoMapInputData"'
1183 |           });
1184 |         }
1185 |         break;
1186 |     }
1187 |   }
1188 | 
1189 |   /**
1190 |    * Validate filter operations match operator types
1191 |    *
1192 |    * Ensures that filter operations are compatible with their operator types.
1193 |    * For example, 'gt' (greater than) is only valid for numbers, not strings.
1194 |    *
1195 |    * @param conditions - Array of filter conditions to validate
1196 |    * @param propertyName - Name of the filter property (for error reporting)
1197 |    * @param result - Validation result to populate with errors
1198 |    */
1199 |   private static validateFilterOperations(
1200 |     conditions: any,
1201 |     propertyName: string,
1202 |     result: EnhancedValidationResult
1203 |   ): void {
1204 |     if (!Array.isArray(conditions)) return;
1205 | 
1206 |     // Operation validation rules based on n8n filter type definitions
1207 |     const VALID_OPERATIONS_BY_TYPE: Record<string, string[]> = {
1208 |       string: [
1209 |         'empty', 'notEmpty', 'equals', 'notEquals',
1210 |         'contains', 'notContains', 'startsWith', 'notStartsWith',
1211 |         'endsWith', 'notEndsWith', 'regex', 'notRegex',
1212 |         'exists', 'notExists', 'isNotEmpty' // exists checks field presence, isNotEmpty alias for notEmpty
1213 |       ],
1214 |       number: [
1215 |         'empty', 'notEmpty', 'equals', 'notEquals', 'gt', 'lt', 'gte', 'lte',
1216 |         'exists', 'notExists', 'isNotEmpty'
1217 |       ],
1218 |       dateTime: [
1219 |         'empty', 'notEmpty', 'equals', 'notEquals', 'after', 'before', 'afterOrEquals', 'beforeOrEquals',
1220 |         'exists', 'notExists', 'isNotEmpty'
1221 |       ],
1222 |       boolean: [
1223 |         'empty', 'notEmpty', 'true', 'false', 'equals', 'notEquals',
1224 |         'exists', 'notExists', 'isNotEmpty'
1225 |       ],
1226 |       array: [
1227 |         'contains', 'notContains', 'lengthEquals', 'lengthNotEquals',
1228 |         'lengthGt', 'lengthLt', 'lengthGte', 'lengthLte', 'empty', 'notEmpty',
1229 |         'exists', 'notExists', 'isNotEmpty'
1230 |       ],
1231 |       object: [
1232 |         'empty', 'notEmpty',
1233 |         'exists', 'notExists', 'isNotEmpty'
1234 |       ],
1235 |       any: ['exists', 'notExists', 'isNotEmpty']
1236 |     };
1237 | 
1238 |     for (let i = 0; i < conditions.length; i++) {
1239 |       const condition = conditions[i];
1240 |       if (!condition.operator || typeof condition.operator !== 'object') continue;
1241 | 
1242 |       const { type, operation } = condition.operator;
1243 |       if (!type || !operation) continue;
1244 | 
1245 |       // Get valid operations for this type
1246 |       const validOperations = VALID_OPERATIONS_BY_TYPE[type];
1247 |       if (!validOperations) {
1248 |         result.warnings.push({
1249 |           type: 'best_practice',
1250 |           property: `${propertyName}.conditions[${i}].operator.type`,
1251 |           message: `Unknown operator type: ${type}`
1252 |         });
1253 |         continue;
1254 |       }
1255 | 
1256 |       // Check if operation is valid for this type
1257 |       if (!validOperations.includes(operation)) {
1258 |         result.errors.push({
1259 |           type: 'invalid_value',
1260 |           property: `${propertyName}.conditions[${i}].operator.operation`,
1261 |           message: `Operation '${operation}' is not valid for type '${type}'`,
1262 |           fix: `Use one of the valid operations for ${type}: ${validOperations.join(', ')}`
1263 |         });
1264 |       }
1265 |     }
1266 |   }
1267 | }
1268 | 
```
Page 51/67FirstPrevNextLast