Compare commits

..

15 Commits

Author SHA1 Message Date
czlonkowski
657d5ab60c fix: relax SQL assertion in outputs test to match ON CONFLICT pattern
Conceived by Romuald Członkowski - https://www.aiadvisors.pl/en

Co-Authored-By: Claude <noreply@anthropic.com>
2026-03-26 12:50:58 +01:00
czlonkowski
7e314f8ff2 chore: remove documentation generator tests
These tests mocked the OpenAI SDK which was replaced with raw fetch.
Documentation generation is a local LLM utility, not core functionality.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2026-03-26 10:43:48 +01:00
czlonkowski
3cc09b4f07 fix: update test assertions for ON CONFLICT saveNode SQL
Tests expected old INSERT OR REPLACE SQL, updated to match new
INSERT INTO ... ON CONFLICT(node_type) DO UPDATE SET pattern.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2026-03-26 10:24:01 +01:00
czlonkowski
537e701610 chore: update MCP SDK from 1.27.1 to 1.28.0
- Pinned @modelcontextprotocol/sdk to 1.28.0 (was ^1.27.1)
- Updated CI dependency check to expect 1.28.0
- SDK 1.28.0 includes: loopback port relaxation, inputSchema fix,
  timeout cleanup fix, OAuth scope improvements
- All 15 MCP tool tests pass with no regressions

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

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

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

Co-Authored-By: Claude <noreply@anthropic.com>
2026-03-26 09:39:57 +01:00
Romuald Członkowski
1f0738e637 fix: auto-inject webhookId on webhook nodes during create/update (#643) (#657)
n8n 2.10+ requires webhookId (UUID) on webhook-type nodes for proper
webhook URL registration. Without it, webhooks silently fail with 404.
The n8n UI always generates webhookId but programmatic creation via
n8n-mcp did not.

Add ensureWebhookIds() helper that injects crypto.randomUUID() on
webhook, webhookTrigger, formTrigger, and chatTrigger nodes when
webhookId is missing. Called from both cleanWorkflowForCreate() and
cleanWorkflowForUpdate(). Existing webhookId values are preserved.

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

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-22 23:20:34 +01:00
Romuald Członkowski
93816fce30 fix: data tables available on all n8n plans, remove redundant pitfalls (#656)
Data tables are available on self-hosted n8n too, not just enterprise/cloud.
Removed incorrect availability restriction from tool description and docs.
Removed redundant pitfalls (API key requirement implicit, plan restriction wrong).

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

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-22 22:29:19 +01:00
Romuald Członkowski
ec19c9dade fix: return 202 for stale-session notifications, warn on updateTable columns (#654) (#655) 2026-03-22 19:59:57 +01:00
Romuald Członkowski
6f6668acc4 fix: resolve double URL-encoding in datatable filter/sortBy query params (#652) 2026-03-22 15:59:34 +01:00
Romuald Członkowski
c5665632af fix: resolve 5 bugs in n8n_manage_datatable (#651) 2026-03-22 00:12:39 +01:00
Romuald Członkowski
be3d07dbdc feat: add n8n_manage_datatable MCP tool with full CRUD (#640) (#650)
* feat: add n8n_create_data_table MCP tool and projectId for create workflow (#640)

Add new MCP tool to create n8n data tables via the REST API:
- n8n_create_data_table tool definition with name + columns schema
- handleCreateDataTable handler with Zod validation and N8nApiError handling
- N8nApiClient.createDataTable() calling POST /data-tables
- DataTable, DataTableColumn, DataTableColumnResponse types per OpenAPI spec
- Column types: string | number | boolean | date | json
- Input validation: .min(1) on table name and column names
- Tool documentation with examples, use cases, and pitfalls

Also adds projectId parameter to n8n_create_workflow for enterprise
project support, and fixes stale management tool count in health check.

Based on work by @djakielski in PR #646.
Co-Authored-By: Dominik Jakielski <dominik.jakielski@urlaubsguru.de>

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

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: replace n8n_create_data_table with n8n_manage_datatable (10 actions)

Replaces the single-purpose n8n_create_data_table tool with a comprehensive
n8n_manage_datatable tool covering all 10 n8n data table API endpoints:

Table operations: createTable, listTables, getTable, updateTable, deleteTable
Row operations: getRows, insertRows, updateRows, upsertRows, deleteRows

- Filter system with and/or logic and 8 condition operators
- Dry-run support for updateRows, upsertRows, deleteRows
- Pagination, sorting, and full-text search for row listing
- 9 new N8nApiClient methods for all data table endpoints
- Shared error handler and consolidated Zod schemas
- Comprehensive tool documentation with examples per action
- 36 handler tests + 18 API client tests

BREAKING: n8n_create_data_table removed. Use n8n_manage_datatable with
action="createTable" instead.

Based on work by @djakielski in PR #646.
Co-Authored-By: Dominik Jakielski <dominik.jakielski@urlaubsguru.de>

Conceived by Romuald Członkowski - https://www.aiadvisors.pl/en
2026-03-21 19:06:22 +01:00
Romuald Członkowski
47a1cb135d feat: implement transferWorkflow operation in n8n_update_partial_workflow (#644) (#649)
Add transferWorkflow diff operation to move workflows between n8n projects:
- TransferWorkflowOperation type with destinationProjectId field
- WorkflowDiffEngine validates and tracks transfer intent
- Handler calls PUT /workflows/{id}/transfer after update
- N8nApiClient.transferWorkflow() method
- Zod schema validates destinationProjectId is non-empty
- Tool description and documentation updated
- inferIntentFromOperations case for transfer

Also fixes two pre-existing bugs found during review:
- continueOnError path now properly extracts/propagates activation flags
- Debug log in updateConnectionReferences shows correct old name

Based on work by @djakielski in PR #645.


Conceived by Romuald Członkowski - https://www.aiadvisors.pl/en
2026-03-20 17:50:00 +01:00
Romuald Członkowski
14962a39b6 chore: update n8n to 2.12.3 and bump version to 2.37.4 (#647) 2026-03-18 17:01:25 +01:00
Romuald Członkowski
f7a1cfe8bf fix: field normalization, AI connection validation, autofix filter (#581) (#638)
- Normalize name→nodeName and id→nodeId for node-targeting operations in
  the Zod schema transform, so LLMs using natural field names no longer
  get "Node not found" errors
- Replace hardcoded ALL_CONNECTION_TYPES with dynamic iteration so AI
  sub-nodes (ai_outputParser, ai_document, ai_textSplitter, etc.) are
  not flagged as disconnected during save
- Add .catchall() to workflowConnectionSchema and extend connection
  reference validation to cover all connection types, not just main
- Fix filterOperationsByFixes ID-vs-name mismatch: typeversion-upgrade
  operations now include nodeName alongside nodeId, and the filter checks
  both fields

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

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-15 14:32:14 +01:00
Romuald Członkowski
65ab94deb2 fix: code validator false positives and null property removal (#294, #293, #611) (#637)
- Fix $() node reference triggering "Invalid $ usage" warning by adding ( and _ to regex lookahead
- Fix helper function primitive returns triggering "Cannot return primitive values" error
- Fix null values in diff engine causing Zod validation errors — null now deletes properties
- Update property removal docs from undefined to null

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

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-15 11:26:44 +01:00
108 changed files with 7076 additions and 4853 deletions

View File

@@ -77,15 +77,15 @@ jobs:
echo "Zod version: $ZOD_VERSION"
echo ""
# Check MCP SDK version - must be exactly 1.27.1
# Check MCP SDK version - must be exactly 1.28.0
if [[ "$SDK_VERSION" == "not found" ]]; then
echo "❌ FAILED: Could not determine MCP SDK version!"
echo " The dependency may not have been installed correctly."
exit 1
fi
if [[ "$SDK_VERSION" != "1.27.1" ]]; then
if [[ "$SDK_VERSION" != "1.28.0" ]]; then
echo "❌ FAILED: MCP SDK version mismatch!"
echo " Expected: 1.27.1"
echo " Expected: 1.28.0"
echo " Got: $SDK_VERSION"
echo ""
echo "This can cause runtime errors. See issues #440, #444, #446, #447, #450"

View File

@@ -7,6 +7,132 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
## [2.41.0] - 2026-03-25
### Changed
- **Updated n8n dependencies**: n8n 2.12.3 → 2.13.3, n8n-core 2.12.0 → 2.13.1, n8n-workflow 2.12.0 → 2.13.1, @n8n/n8n-nodes-langchain 2.12.0 → 2.13.1
- **Rebuilt node database**: 1,396 nodes (812 from n8n-nodes-base/langchain + 584 community: 516 verified + 68 npm)
- **Refreshed community nodes**: 584 total (up from 430), with 581 AI-generated documentation summaries
- **Improved documentation generator**: Strip `<think>` tags from thinking-model responses; use raw fetch for vLLM `chat_template_kwargs` support
- **Incremental community node updates**: `fetch:community` now upserts by default, preserving existing READMEs and AI summaries. Use `--rebuild` for clean slate
Conceived by Romuald Czlonkowski - https://www.aiadvisors.pl/en
## [2.40.5] - 2026-03-22
### Fixed
- **Webhook workflows created via MCP get 404 errors** (Issue #643): Auto-inject `webhookId` (UUID) on webhook-type nodes (`webhook`, `webhookTrigger`, `formTrigger`, `chatTrigger`) during `cleanWorkflowForCreate()` and `cleanWorkflowForUpdate()`. n8n 2.10+ requires this field for proper webhook URL registration; without it, webhooks silently fail with 404. Existing `webhookId` values are preserved.
Conceived by Romuald Członkowski - https://www.aiadvisors.pl/en
## [2.40.4] - 2026-03-22
### Fixed
- **Incorrect data tables availability info**: Removed "enterprise/cloud only" restriction from tool description and documentation — data tables are available on all n8n plans including self-hosted
- **Redundant pitfalls removed**: Removed "Requires N8N_API_URL and N8N_API_KEY" and "enterprise or cloud plans" pitfalls — the first is implicit for all n8n management tools, the second was incorrect
Conceived by Romuald Członkowski - https://www.aiadvisors.pl/en
## [2.40.3] - 2026-03-22
### Fixed
- **Notification 400 disconnect storms (#654)**: `handleRequest()` now returns 202 Accepted for JSON-RPC notifications with stale/expired session IDs instead of 400. Per JSON-RPC 2.0 spec, notifications don't expect responses — returning 400 caused Claude's proxy to trigger reconnection storms (930 errors/day, 216 users affected)
- **TOCTOU race in session lookup**: Added null guard after transport assignment to handle sessions removed between the existence check and use
- **`updateTable` silently ignoring `columns` parameter**: Now returns a warning message when `columns` is passed to `updateTable`, clarifying that table schema is immutable after creation via the public API
- **Tool schema descriptions clarified**: `name` and `columns` parameter descriptions now explicitly document that `updateTable` is rename-only and columns are for `createTable` only
Conceived by Romuald Członkowski - https://www.aiadvisors.pl/en
## [2.40.2] - 2026-03-22
### Fixed
- **Double URL-encoding of `filter` and `sortBy` in `getRows`/`deleteRows`**: Moved `encodeURIComponent()` from handler layer to a custom `paramsSerializer` in the API client. Handlers were encoding values before passing them as Axios params, causing double-encoding (`%257B` instead of `%7B`). Handlers now pass raw values; the API client encodes once via `serializeDataTableParams()`
- **`updateTable` documentation clarified**: Explicitly notes that only renaming is supported (no column modifications via public API)
Conceived by Romuald Członkowski - https://www.aiadvisors.pl/en
## [2.40.1] - 2026-03-21
### Fixed
- **`n8n_manage_datatable` row operations broken by MCP transport serialization**: `data` parameter received as string instead of JSON — added `z.preprocess` coercers for array/object/filter params
- **`n8n_manage_datatable` filter/sortBy URL encoding**: n8n API requires URL-encoded query params — added `encodeURIComponent()` for filter and sortBy in getRows and deleteRows (revised in 2.40.2 to move encoding to API client layer)
- **`json` column type rejected by n8n API**: Removed `json` from column type enum (n8n only accepts string/number/boolean/date)
- **Garbled 404 error messages**: Fixed `N8nNotFoundError` constructor — API error messages are now passed through cleanly instead of being wrapped in "Resource with ID ... not found"
Conceived by Romuald Członkowski - https://www.aiadvisors.pl/en
## [2.40.0] - 2026-03-21
### Changed
- **`n8n_manage_datatable` MCP tool** (replaces `n8n_create_data_table`): Full data table management covering all 10 n8n data table API endpoints
- **Table operations**: createTable, listTables, getTable, updateTable, deleteTable
- **Row operations**: getRows, insertRows, updateRows, upsertRows, deleteRows
- Filter system with and/or logic and 8 condition operators (eq, neq, like, ilike, gt, gte, lt, lte)
- Dry-run support for updateRows, upsertRows, deleteRows
- Pagination, sorting, and full-text search for row listing
- Shared error handler and consolidated Zod schemas for consistency
- 9 new `N8nApiClient` methods for all data table endpoints
- **`projectId` parameter for `n8n_create_workflow`**: Create workflows directly in a specific team project (enterprise feature)
### Breaking
- `n8n_create_data_table` tool replaced by `n8n_manage_datatable` with `action: "createTable"`
Conceived by Romuald Członkowski - https://www.aiadvisors.pl/en
## [2.38.0] - 2026-03-20
### Added
- **`transferWorkflow` diff operation** (Issue #644): Move workflows between projects via `n8n_update_partial_workflow`
- New `transferWorkflow` operation type with `destinationProjectId` parameter
- Calls `PUT /workflows/{id}/transfer` via dedicated API after workflow update
- Proper error handling: returns `{ success: false, saved: true }` when transfer fails after update
- Transfer executes before activation so workflow is in target project first
- Zod schema validates `destinationProjectId` is non-empty
- Updated tool description and documentation to list the new operation
- `inferIntentFromOperations` returns descriptive intent for transfer operations
- `N8nApiClient.transferWorkflow()` method added
Conceived by Romuald Członkowski - https://www.aiadvisors.pl/en
## [2.37.4] - 2026-03-18
### Changed
- **Updated n8n dependencies**: n8n 2.11.4 → 2.12.3, n8n-core 2.11.1 → 2.12.0, n8n-workflow 2.11.1 → 2.12.0, @n8n/n8n-nodes-langchain 2.11.2 → 2.12.0
- **Rebuilt node database**: 1,239 nodes (809 from n8n-nodes-base and @n8n/n8n-nodes-langchain, 430 community)
Conceived by Romuald Członkowski - https://www.aiadvisors.pl/en
## [2.37.3] - 2026-03-15
### Fixed
- **updateNode `name`/`id` field normalization**: LLMs sending `{type: "updateNode", name: "Code", ...}` instead of `nodeName` no longer get "Node not found" errors. The Zod schema now normalizes `name``nodeName` and `id``nodeId` for node-targeting operations (updateNode, removeNode, moveNode, enableNode, disableNode)
- **AI connection types in disconnected-node detection** (Issue #581): Replaced hardcoded 7-type list with dynamic iteration over all connection types present in workflow data. Nodes connected via `ai_outputParser`, `ai_document`, `ai_textSplitter`, `ai_agent`, `ai_chain`, `ai_retriever` are no longer falsely flagged as disconnected during save
- **Connection schema and reference validation** (Issue #581): Added `.catchall()` to `workflowConnectionSchema` for unknown AI connection types, and extended connection reference validation to check all connection types (not just `main`)
- **autofix `filterOperationsByFixes` ID-vs-name mismatch**: Typeversion-upgrade operations now include `nodeName` alongside `nodeId`, and the filter checks both fields. Previously, `applyFixes=true` silently dropped all typeversion fixes because `fixedNodes` contained names but the filter only checked `nodeId` (UUID)
Conceived by Romuald Członkowski - https://www.aiadvisors.pl/en
## [2.37.2] - 2026-03-15
### Fixed
- **Code validator `$()` false positive** (Issue #294): `$('Previous Node').first().json` no longer triggers "Invalid $ usage detected" warning. Added `(` and `_` to the regex negative lookahead to support standard n8n cross-node references and valid JS identifiers like `$_var`
- **Code validator helper function return false positive** (Issue #293): `function isValid(item) { return false; }` no longer triggers "Cannot return primitive values directly" error. Added helper function detection to skip primitive return checks when named functions or arrow function assignments are present
- **Null property removal in diff engine** (Issue #611): `{continueOnFail: null}` no longer causes Zod validation error "Expected boolean, received null". The diff engine now treats `null` values as property deletion (`delete` operator), and documentation updated from `undefined` to `null` for property removal
Conceived by Romuald Członkowski - https://www.aiadvisors.pl/en
## [2.37.1] - 2026-03-14
### Fixed

View File

@@ -1,9 +1,16 @@
# n8n Update Process - Quick Reference
## ⚡ Recommended Fast Workflow (2025-11-04)
## ⚡ Recommended Fast Workflow (2026-03-25)
**CRITICAL FIRST STEP**: Check existing releases to avoid version conflicts!
**IMPORTANT: Community nodes are preserved incrementally!**
- `npm run update:n8n` rebuilds the base node DB (wipes community nodes temporarily)
- Community nodes must be backed up BEFORE and restored AFTER the base rebuild
- `npm run fetch:community` now upserts by default (preserves READMEs + AI summaries)
- `npm run generate:docs:incremental` only processes nodes missing docs
- Use `generate:docs:readme-only` first, then `generate:docs:summary-only` with a local LLM
```bash
# 1. CHECK EXISTING RELEASES FIRST (prevents version conflicts!)
gh release list | head -5
@@ -15,14 +22,29 @@ git checkout main && git pull
# 3. Check for updates (dry run)
npm run update:n8n:check
# 4. Run update and skip tests (we'll test in CI)
# 4. Back up community nodes BEFORE update (update:n8n rebuilds base DB!)
sqlite3 data/nodes.db ".mode insert nodes" "SELECT * FROM nodes WHERE is_community = 1;" > /tmp/n8n_community_backup.sql
# 5. Run update and skip tests (we'll test in CI)
yes y | npm run update:n8n
# 5. Refresh community nodes (standard practice!)
npm run fetch:community
npm run generate:docs
# 6. Restore community nodes after rebuild
sqlite3 data/nodes.db < /tmp/n8n_community_backup.sql
# 6. Create feature branch
# 7. Refresh community nodes (upserts - preserves existing READMEs + AI summaries!)
npm run fetch:community
# NOTE: Default mode is now "upsert" - no deletion. Use --rebuild for clean slate.
# 8. Generate docs incrementally (only for new/missing nodes)
npm run generate:docs:readme-only # Fetch READMEs from npm (no LLM needed)
# Then with a local LLM server running (LM Studio, vLLM, Ollama):
N8N_MCP_LLM_BASE_URL="http://YOUR_SERVER:PORT/v1" \
N8N_MCP_LLM_MODEL="your-model-name" \
node dist/scripts/generate-community-docs.js --summary-only --skip-existing-summary --llm-concurrency=11
# For vLLM with thinking models, the code auto-sends chat_template_kwargs: {enable_thinking: false}
# Context length needed: 8K minimum (README truncated to 6000 chars, output max 2000 tokens)
# 9. Create feature branch
git checkout -b update/n8n-X.X.X
# 7. Update version in package.json (must be HIGHER than latest release!)

View File

@@ -5,17 +5,17 @@
[![npm version](https://img.shields.io/npm/v/n8n-mcp.svg)](https://www.npmjs.com/package/n8n-mcp)
[![codecov](https://codecov.io/gh/czlonkowski/n8n-mcp/graph/badge.svg?token=YOUR_TOKEN)](https://codecov.io/gh/czlonkowski/n8n-mcp)
[![Tests](https://img.shields.io/badge/tests-3336%20passing-brightgreen.svg)](https://github.com/czlonkowski/n8n-mcp/actions)
[![n8n version](https://img.shields.io/badge/n8n-2.11.4-orange.svg)](https://github.com/n8n-io/n8n)
[![n8n version](https://img.shields.io/badge/n8n-2.13.3-orange.svg)](https://github.com/n8n-io/n8n)
[![Docker](https://img.shields.io/badge/docker-ghcr.io%2Fczlonkowski%2Fn8n--mcp-green.svg)](https://github.com/czlonkowski/n8n-mcp/pkgs/container/n8n-mcp)
[![Deploy on Railway](https://railway.com/button.svg)](https://railway.com/deploy/n8n-mcp?referralCode=n8n-mcp)
A Model Context Protocol (MCP) server that provides AI assistants with comprehensive access to n8n node documentation, properties, and operations. Deploy in minutes to give Claude and other AI assistants deep knowledge about n8n's 1,239 workflow automation nodes (809 core + 430 community).
A Model Context Protocol (MCP) server that provides AI assistants with comprehensive access to n8n node documentation, properties, and operations. Deploy in minutes to give Claude and other AI assistants deep knowledge about n8n's 1,396 workflow automation nodes (812 core + 584 community).
## Overview
n8n-MCP serves as a bridge between n8n's workflow automation platform and AI models, enabling them to understand and work with n8n nodes effectively. It provides structured access to:
- 📚 **1,084 n8n nodes** - 537 core nodes + 547 community nodes (301 verified)
- 📚 **1,396 n8n nodes** - 812 core nodes + 584 community nodes (516 verified)
- 🔧 **Node properties** - 99% coverage with detailed schemas
-**Node operations** - 63.6% coverage of available actions
- 📄 **Documentation** - 87% coverage from official n8n docs (including AI nodes)

Binary file not shown.

View File

@@ -1 +1 @@
{"version":3,"file":"node-repository.d.ts","sourceRoot":"","sources":["../../src/database/node-repository.ts"],"names":[],"mappings":"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"}
{"version":3,"file":"node-repository.d.ts","sourceRoot":"","sources":["../../src/database/node-repository.ts"],"names":[],"mappings":"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"}

View File

@@ -13,7 +13,7 @@ class NodeRepository {
}
saveNode(node) {
const stmt = this.db.prepare(`
INSERT OR REPLACE INTO nodes (
INSERT INTO nodes (
node_type, package_name, display_name, description,
category, development_style, is_ai_tool, is_trigger,
is_webhook, is_versioned, is_tool_variant, tool_variant_of,
@@ -23,6 +23,35 @@ class NodeRepository {
is_community, is_verified, author_name, author_github_url,
npm_package_name, npm_version, npm_downloads, community_fetched_at
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
ON CONFLICT(node_type) DO UPDATE SET
package_name = excluded.package_name,
display_name = excluded.display_name,
description = excluded.description,
category = excluded.category,
development_style = excluded.development_style,
is_ai_tool = excluded.is_ai_tool,
is_trigger = excluded.is_trigger,
is_webhook = excluded.is_webhook,
is_versioned = excluded.is_versioned,
is_tool_variant = excluded.is_tool_variant,
tool_variant_of = excluded.tool_variant_of,
has_tool_variant = excluded.has_tool_variant,
version = excluded.version,
documentation = excluded.documentation,
properties_schema = excluded.properties_schema,
operations = excluded.operations,
credentials_required = excluded.credentials_required,
outputs = excluded.outputs,
output_names = excluded.output_names,
is_community = excluded.is_community,
is_verified = excluded.is_verified,
author_name = excluded.author_name,
author_github_url = excluded.author_github_url,
npm_package_name = excluded.npm_package_name,
npm_version = excluded.npm_version,
npm_downloads = excluded.npm_downloads,
community_fetched_at = excluded.community_fetched_at,
updated_at = CURRENT_TIMESTAMP
`);
stmt.run(node.nodeType, node.packageName, node.displayName, node.description, node.category, node.style, node.isAITool ? 1 : 0, node.isTrigger ? 1 : 0, node.isWebhook ? 1 : 0, node.isVersioned ? 1 : 0, node.isToolVariant ? 1 : 0, node.toolVariantOf || null, node.hasToolVariant ? 1 : 0, node.version, node.documentation || null, JSON.stringify(node.properties, null, 2), JSON.stringify(node.operations, null, 2), JSON.stringify(node.credentials, null, 2), node.outputs ? JSON.stringify(node.outputs, null, 2) : null, node.outputNames ? JSON.stringify(node.outputNames, null, 2) : null, node.isCommunity ? 1 : 0, node.isVerified ? 1 : 0, node.authorName || null, node.authorGithubUrl || null, node.npmPackageName || null, node.npmVersion || null, node.npmDownloads || 0, node.communityFetchedAt || null);
}

File diff suppressed because one or more lines are too long

View File

@@ -21,6 +21,7 @@ export declare class SingleSessionHTTPServer {
private getActiveSessionCount;
private canCreateSession;
private isValidSessionId;
private isJsonRpcNotification;
private sanitizeErrorForClient;
private updateSessionAccess;
private switchSessionContext;

View File

@@ -1 +1 @@
{"version":3,"file":"http-server-single-session.d.ts","sourceRoot":"","sources":["../src/http-server-single-session.ts"],"names":[],"mappings":";AAMA,OAAO,OAAO,MAAM,SAAS,CAAC;AAoB9B,OAAO,EAAE,eAAe,EAA2B,MAAM,0BAA0B,CAAC;AACpF,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAwErD,qBAAa,uBAAuB;IAElC,OAAO,CAAC,UAAU,CAA8D;IAChF,OAAO,CAAC,OAAO,CAA0D;IACzE,OAAO,CAAC,eAAe,CAAsE;IAC7F,OAAO,CAAC,eAAe,CAA4D;IACnF,OAAO,CAAC,kBAAkB,CAAyC;IACnE,OAAO,CAAC,OAAO,CAAwB;IACvC,OAAO,CAAC,cAAc,CAAwB;IAC9C,OAAO,CAAC,aAAa,CAAM;IAI3B,OAAO,CAAC,cAAc,CAER;IACd,OAAO,CAAC,SAAS,CAAuB;IACxC,OAAO,CAAC,YAAY,CAA+B;;IAcnD,OAAO,CAAC,mBAAmB;IAmB3B,OAAO,CAAC,sBAAsB;YAqChB,aAAa;IAuC3B,OAAO,CAAC,qBAAqB;IAO7B,OAAO,CAAC,gBAAgB;IAkBxB,OAAO,CAAC,gBAAgB;IASxB,OAAO,CAAC,sBAAsB;IAkC9B,OAAO,CAAC,mBAAmB;YASb,oBAAoB;YAwBpB,oBAAoB;IAwBlC,OAAO,CAAC,iBAAiB;IAsBzB,OAAO,CAAC,aAAa;IA2BrB,OAAO,CAAC,mBAAmB;IAoDrB,aAAa,CACjB,GAAG,EAAE,OAAO,CAAC,OAAO,EACpB,GAAG,EAAE,OAAO,CAAC,QAAQ,EACrB,eAAe,CAAC,EAAE,eAAe,GAChC,OAAO,CAAC,IAAI,CAAC;YA0PF,eAAe;IA4D7B,OAAO,CAAC,SAAS;IAYjB,OAAO,CAAC,gBAAgB;IASlB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAgnBtB,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IA2D/B,cAAc,IAAI;QAChB,MAAM,EAAE,OAAO,CAAC;QAChB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,GAAG,CAAC,EAAE,MAAM,CAAC;QACb,QAAQ,CAAC,EAAE;YACT,KAAK,EAAE,MAAM,CAAC;YACd,MAAM,EAAE,MAAM,CAAC;YACf,OAAO,EAAE,MAAM,CAAC;YAChB,GAAG,EAAE,MAAM,CAAC;YACZ,UAAU,EAAE,MAAM,EAAE,CAAC;SACtB,CAAC;KACH;IAmDM,kBAAkB,IAAI,YAAY,EAAE;IAoEpC,mBAAmB,CAAC,QAAQ,EAAE,YAAY,EAAE,GAAG,MAAM;CAsG7D"}
{"version":3,"file":"http-server-single-session.d.ts","sourceRoot":"","sources":["../src/http-server-single-session.ts"],"names":[],"mappings":";AAMA,OAAO,OAAO,MAAM,SAAS,CAAC;AAoB9B,OAAO,EAAE,eAAe,EAA2B,MAAM,0BAA0B,CAAC;AACpF,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAwErD,qBAAa,uBAAuB;IAElC,OAAO,CAAC,UAAU,CAA8D;IAChF,OAAO,CAAC,OAAO,CAA0D;IACzE,OAAO,CAAC,eAAe,CAAsE;IAC7F,OAAO,CAAC,eAAe,CAA4D;IACnF,OAAO,CAAC,kBAAkB,CAAyC;IACnE,OAAO,CAAC,OAAO,CAAwB;IACvC,OAAO,CAAC,cAAc,CAAwB;IAC9C,OAAO,CAAC,aAAa,CAAM;IAI3B,OAAO,CAAC,cAAc,CAER;IACd,OAAO,CAAC,SAAS,CAAuB;IACxC,OAAO,CAAC,YAAY,CAA+B;;IAcnD,OAAO,CAAC,mBAAmB;IAmB3B,OAAO,CAAC,sBAAsB;YAqChB,aAAa;IAuC3B,OAAO,CAAC,qBAAqB;IAO7B,OAAO,CAAC,gBAAgB;IAkBxB,OAAO,CAAC,gBAAgB;IAYxB,OAAO,CAAC,qBAAqB;IAa7B,OAAO,CAAC,sBAAsB;IAkC9B,OAAO,CAAC,mBAAmB;YASb,oBAAoB;YAwBpB,oBAAoB;IAwBlC,OAAO,CAAC,iBAAiB;IAsBzB,OAAO,CAAC,aAAa;IA2BrB,OAAO,CAAC,mBAAmB;IAoDrB,aAAa,CACjB,GAAG,EAAE,OAAO,CAAC,OAAO,EACpB,GAAG,EAAE,OAAO,CAAC,QAAQ,EACrB,eAAe,CAAC,EAAE,eAAe,GAChC,OAAO,CAAC,IAAI,CAAC;YAoRF,eAAe;IA4D7B,OAAO,CAAC,SAAS;IAYjB,OAAO,CAAC,gBAAgB;IASlB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAgnBtB,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IA2D/B,cAAc,IAAI;QAChB,MAAM,EAAE,OAAO,CAAC;QAChB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,GAAG,CAAC,EAAE,MAAM,CAAC;QACb,QAAQ,CAAC,EAAE;YACT,KAAK,EAAE,MAAM,CAAC;YACd,MAAM,EAAE,MAAM,CAAC;YACf,OAAO,EAAE,MAAM,CAAC;YAChB,GAAG,EAAE,MAAM,CAAC;YACZ,UAAU,EAAE,MAAM,EAAE,CAAC;SACtB,CAAC;KACH;IAmDM,kBAAkB,IAAI,YAAY,EAAE;IAoEpC,mBAAmB,CAAC,QAAQ,EAAE,YAAY,EAAE,GAAG,MAAM;CAsG7D"}

View File

@@ -133,6 +133,15 @@ class SingleSessionHTTPServer {
isValidSessionId(sessionId) {
return Boolean(sessionId && sessionId.length > 0);
}
isJsonRpcNotification(body) {
if (!body || typeof body !== 'object')
return false;
const isSingleNotification = (msg) => msg && typeof msg.method === 'string' && !('id' in msg);
if (Array.isArray(body)) {
return body.length > 0 && body.every(isSingleNotification);
}
return isSingleNotification(body);
}
sanitizeErrorForClient(error) {
const isProduction = process.env.NODE_ENV === 'production';
if (error instanceof Error) {
@@ -381,6 +390,20 @@ class SingleSessionHTTPServer {
}
logger_1.logger.info('handleRequest: Reusing existing transport for session', { sessionId });
transport = this.transports[sessionId];
if (!transport) {
if (this.isJsonRpcNotification(req.body)) {
logger_1.logger.info('handleRequest: Session removed during lookup, accepting notification', { sessionId });
res.status(202).end();
return;
}
logger_1.logger.warn('handleRequest: Session removed between check and use (TOCTOU)', { sessionId });
res.status(400).json({
jsonrpc: '2.0',
error: { code: -32000, message: 'Bad Request: Session not found or expired' },
id: req.body?.id || null,
});
return;
}
const isMultiTenantEnabled = process.env.ENABLE_MULTI_TENANT === 'true';
const sessionStrategy = process.env.MULTI_TENANT_SESSION_STRATEGY || 'instance';
if (isMultiTenantEnabled && sessionStrategy === 'shared' && instanceContext) {
@@ -389,6 +412,14 @@ class SingleSessionHTTPServer {
this.updateSessionAccess(sessionId);
}
else {
if (this.isJsonRpcNotification(req.body)) {
logger_1.logger.info('handleRequest: Accepting notification for stale/missing session', {
method: req.body?.method,
sessionId: sessionId || 'none',
});
res.status(202).end();
return;
}
const errorDetails = {
hasSessionId: !!sessionId,
isInitialize: isInitialize,

File diff suppressed because one or more lines are too long

View File

@@ -26,4 +26,14 @@ export declare function handleDiagnostic(request: any, context?: InstanceContext
export declare function handleWorkflowVersions(args: unknown, repository: NodeRepository, context?: InstanceContext): Promise<McpToolResponse>;
export declare function handleDeployTemplate(args: unknown, templateService: TemplateService, repository: NodeRepository, context?: InstanceContext): Promise<McpToolResponse>;
export declare function handleTriggerWebhookWorkflow(args: unknown, context?: InstanceContext): Promise<McpToolResponse>;
export declare function handleCreateTable(args: unknown, context?: InstanceContext): Promise<McpToolResponse>;
export declare function handleListTables(args: unknown, context?: InstanceContext): Promise<McpToolResponse>;
export declare function handleGetTable(args: unknown, context?: InstanceContext): Promise<McpToolResponse>;
export declare function handleUpdateTable(args: unknown, context?: InstanceContext): Promise<McpToolResponse>;
export declare function handleDeleteTable(args: unknown, context?: InstanceContext): Promise<McpToolResponse>;
export declare function handleGetRows(args: unknown, context?: InstanceContext): Promise<McpToolResponse>;
export declare function handleInsertRows(args: unknown, context?: InstanceContext): Promise<McpToolResponse>;
export declare function handleUpdateRows(args: unknown, context?: InstanceContext): Promise<McpToolResponse>;
export declare function handleUpsertRows(args: unknown, context?: InstanceContext): Promise<McpToolResponse>;
export declare function handleDeleteRows(args: unknown, context?: InstanceContext): Promise<McpToolResponse>;
//# sourceMappingURL=handlers-n8n-manager.d.ts.map

View File

@@ -1 +1 @@
{"version":3,"file":"handlers-n8n-manager.d.ts","sourceRoot":"","sources":["../../src/mcp/handlers-n8n-manager.ts"],"names":[],"mappings":"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"}
{"version":3,"file":"handlers-n8n-manager.d.ts","sourceRoot":"","sources":["../../src/mcp/handlers-n8n-manager.ts"],"names":[],"mappings":"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"}

View File

@@ -56,6 +56,16 @@ exports.handleDiagnostic = handleDiagnostic;
exports.handleWorkflowVersions = handleWorkflowVersions;
exports.handleDeployTemplate = handleDeployTemplate;
exports.handleTriggerWebhookWorkflow = handleTriggerWebhookWorkflow;
exports.handleCreateTable = handleCreateTable;
exports.handleListTables = handleListTables;
exports.handleGetTable = handleGetTable;
exports.handleUpdateTable = handleUpdateTable;
exports.handleDeleteTable = handleDeleteTable;
exports.handleGetRows = handleGetRows;
exports.handleInsertRows = handleInsertRows;
exports.handleUpdateRows = handleUpdateRows;
exports.handleUpsertRows = handleUpsertRows;
exports.handleDeleteRows = handleDeleteRows;
const n8n_api_client_1 = require("../services/n8n-api-client");
const n8n_api_1 = require("../config/n8n-api");
const n8n_api_2 = require("../types/n8n-api");
@@ -175,6 +185,7 @@ const createWorkflowSchema = zod_1.z.object({
executionTimeout: zod_1.z.number().optional(),
errorWorkflow: zod_1.z.string().optional(),
}).optional(),
projectId: zod_1.z.string().optional(),
});
const updateWorkflowSchema = zod_1.z.object({
id: zod_1.z.string(),
@@ -288,6 +299,15 @@ async function handleCreateWorkflow(args, context) {
};
}
const workflow = await client.createWorkflow(input);
if (!workflow || !workflow.id) {
return {
success: false,
error: 'Workflow creation failed: n8n API returned an empty or invalid response. Verify your N8N_API_URL points to the correct /api/v1 endpoint and that the n8n instance supports workflow creation.',
details: {
response: workflow ? { keys: Object.keys(workflow) } : null
}
};
}
telemetry_1.telemetry.trackWorkflowCreation(workflow, true);
return {
success: true,
@@ -1461,7 +1481,7 @@ async function handleDiagnostic(request, context) {
}
}
const documentationTools = 7;
const managementTools = apiConfigured ? 13 : 0;
const managementTools = apiConfigured ? 14 : 0;
const totalTools = documentationTools + managementTools;
const versionCheck = await (0, npm_version_checker_1.checkNpmVersion)();
const cacheMetricsData = getInstanceCacheMetrics();
@@ -2029,4 +2049,244 @@ async function handleTriggerWebhookWorkflow(args, context) {
};
}
}
const dataTableFilterConditionSchema = zod_1.z.object({
columnName: zod_1.z.string().min(1),
condition: zod_1.z.enum(['eq', 'neq', 'like', 'ilike', 'gt', 'gte', 'lt', 'lte']),
value: zod_1.z.any(),
});
const dataTableFilterSchema = zod_1.z.object({
type: zod_1.z.enum(['and', 'or']).optional().default('and'),
filters: zod_1.z.array(dataTableFilterConditionSchema).min(1, 'At least one filter condition is required'),
});
const tableIdSchema = zod_1.z.object({
tableId: zod_1.z.string().min(1, 'tableId is required'),
});
const createTableSchema = zod_1.z.object({
name: zod_1.z.string().min(1, 'Table name cannot be empty'),
columns: zod_1.z.array(zod_1.z.object({
name: zod_1.z.string().min(1, 'Column name cannot be empty'),
type: zod_1.z.enum(['string', 'number', 'boolean', 'date']).optional(),
})).optional(),
});
const listTablesSchema = zod_1.z.object({
limit: zod_1.z.number().min(1).max(100).optional(),
cursor: zod_1.z.string().optional(),
});
const updateTableSchema = tableIdSchema.extend({
name: zod_1.z.string().min(1, 'New table name cannot be empty'),
});
function tryParseJson(val) {
if (typeof val !== 'string')
return val;
try {
return JSON.parse(val);
}
catch {
return val;
}
}
const coerceJsonArray = zod_1.z.preprocess(tryParseJson, zod_1.z.array(zod_1.z.record(zod_1.z.unknown())));
const coerceJsonObject = zod_1.z.preprocess(tryParseJson, zod_1.z.record(zod_1.z.unknown()));
const coerceJsonFilter = zod_1.z.preprocess(tryParseJson, dataTableFilterSchema);
const getRowsSchema = tableIdSchema.extend({
limit: zod_1.z.number().min(1).max(100).optional(),
cursor: zod_1.z.string().optional(),
filter: zod_1.z.union([coerceJsonFilter, zod_1.z.string()]).optional(),
sortBy: zod_1.z.string().optional(),
search: zod_1.z.string().optional(),
});
const insertRowsSchema = tableIdSchema.extend({
data: coerceJsonArray.pipe(zod_1.z.array(zod_1.z.record(zod_1.z.unknown())).min(1, 'At least one row is required')),
returnType: zod_1.z.enum(['count', 'id', 'all']).optional(),
});
const mutateRowsSchema = tableIdSchema.extend({
filter: coerceJsonFilter,
data: coerceJsonObject,
returnData: zod_1.z.boolean().optional(),
dryRun: zod_1.z.boolean().optional(),
});
const deleteRowsSchema = tableIdSchema.extend({
filter: coerceJsonFilter,
returnData: zod_1.z.boolean().optional(),
dryRun: zod_1.z.boolean().optional(),
});
function handleDataTableError(error) {
if (error instanceof zod_1.z.ZodError) {
return { success: false, error: 'Invalid input', details: { errors: error.errors } };
}
if (error instanceof n8n_errors_1.N8nApiError) {
return {
success: false,
error: (0, n8n_errors_1.getUserFriendlyErrorMessage)(error),
code: error.code,
details: error.details,
};
}
return { success: false, error: error instanceof Error ? error.message : 'Unknown error occurred' };
}
async function handleCreateTable(args, context) {
try {
const client = ensureApiConfigured(context);
const input = createTableSchema.parse(args);
const dataTable = await client.createDataTable(input);
if (!dataTable || !dataTable.id) {
return { success: false, error: 'Data table creation failed: n8n API returned an empty or invalid response' };
}
return {
success: true,
data: { id: dataTable.id, name: dataTable.name },
message: `Data table "${dataTable.name}" created with ID: ${dataTable.id}`,
};
}
catch (error) {
return handleDataTableError(error);
}
}
async function handleListTables(args, context) {
try {
const client = ensureApiConfigured(context);
const input = listTablesSchema.parse(args || {});
const result = await client.listDataTables(input);
return {
success: true,
data: {
tables: result.data,
count: result.data.length,
nextCursor: result.nextCursor || undefined,
},
};
}
catch (error) {
return handleDataTableError(error);
}
}
async function handleGetTable(args, context) {
try {
const client = ensureApiConfigured(context);
const { tableId } = tableIdSchema.parse(args);
const dataTable = await client.getDataTable(tableId);
return { success: true, data: dataTable };
}
catch (error) {
return handleDataTableError(error);
}
}
async function handleUpdateTable(args, context) {
try {
const client = ensureApiConfigured(context);
const { tableId, name } = updateTableSchema.parse(args);
const dataTable = await client.updateDataTable(tableId, { name });
const rawArgs = args;
const hasColumns = rawArgs && typeof rawArgs === 'object' && 'columns' in rawArgs;
return {
success: true,
data: dataTable,
message: `Data table renamed to "${dataTable.name}"` +
(hasColumns ? '. Note: columns parameter was ignored — table schema is immutable after creation via the public API' : ''),
};
}
catch (error) {
return handleDataTableError(error);
}
}
async function handleDeleteTable(args, context) {
try {
const client = ensureApiConfigured(context);
const { tableId } = tableIdSchema.parse(args);
await client.deleteDataTable(tableId);
return { success: true, message: `Data table ${tableId} deleted successfully` };
}
catch (error) {
return handleDataTableError(error);
}
}
async function handleGetRows(args, context) {
try {
const client = ensureApiConfigured(context);
const { tableId, filter, sortBy, ...params } = getRowsSchema.parse(args);
const queryParams = { ...params };
if (filter) {
queryParams.filter = typeof filter === 'string' ? filter : JSON.stringify(filter);
}
if (sortBy) {
queryParams.sortBy = sortBy;
}
const result = await client.getDataTableRows(tableId, queryParams);
return {
success: true,
data: {
rows: result.data,
count: result.data.length,
nextCursor: result.nextCursor || undefined,
},
};
}
catch (error) {
return handleDataTableError(error);
}
}
async function handleInsertRows(args, context) {
try {
const client = ensureApiConfigured(context);
const { tableId, ...params } = insertRowsSchema.parse(args);
const result = await client.insertDataTableRows(tableId, params);
return {
success: true,
data: result,
message: `Rows inserted into data table ${tableId}`,
};
}
catch (error) {
return handleDataTableError(error);
}
}
async function handleUpdateRows(args, context) {
try {
const client = ensureApiConfigured(context);
const { tableId, ...params } = mutateRowsSchema.parse(args);
const result = await client.updateDataTableRows(tableId, params);
return {
success: true,
data: result,
message: params.dryRun ? 'Dry run: rows matched (no changes applied)' : 'Rows updated successfully',
};
}
catch (error) {
return handleDataTableError(error);
}
}
async function handleUpsertRows(args, context) {
try {
const client = ensureApiConfigured(context);
const { tableId, ...params } = mutateRowsSchema.parse(args);
const result = await client.upsertDataTableRow(tableId, params);
return {
success: true,
data: result,
message: params.dryRun ? 'Dry run: upsert previewed (no changes applied)' : 'Row upserted successfully',
};
}
catch (error) {
return handleDataTableError(error);
}
}
async function handleDeleteRows(args, context) {
try {
const client = ensureApiConfigured(context);
const { tableId, filter, ...params } = deleteRowsSchema.parse(args);
const queryParams = {
filter: JSON.stringify(filter),
...params,
};
const result = await client.deleteDataTableRows(tableId, queryParams);
return {
success: true,
data: result,
message: params.dryRun ? 'Dry run: rows matched for deletion (no changes applied)' : 'Rows deleted successfully',
};
}
catch (error) {
return handleDataTableError(error);
}
}
//# sourceMappingURL=handlers-n8n-manager.js.map

File diff suppressed because one or more lines are too long

View File

@@ -1 +1 @@
{"version":3,"file":"handlers-workflow-diff.d.ts","sourceRoot":"","sources":["../../src/mcp/handlers-workflow-diff.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAMnD,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAE5D,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AA0D7D,wBAAsB,2BAA2B,CAC/C,IAAI,EAAE,OAAO,EACb,UAAU,EAAE,cAAc,EAC1B,OAAO,CAAC,EAAE,eAAe,GACxB,OAAO,CAAC,eAAe,CAAC,CA6V1B"}
{"version":3,"file":"handlers-workflow-diff.d.ts","sourceRoot":"","sources":["../../src/mcp/handlers-workflow-diff.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAMnD,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAE5D,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAkF7D,wBAAsB,2BAA2B,CAC/C,IAAI,EAAE,OAAO,EACb,UAAU,EAAE,cAAc,EAC1B,OAAO,CAAC,EAAE,eAAe,GACxB,OAAO,CAAC,eAAe,CAAC,CAib1B"}

View File

@@ -50,6 +50,9 @@ function getValidator(repository) {
}
return cachedValidator;
}
const NODE_TARGETING_OPERATIONS = new Set([
'updateNode', 'removeNode', 'moveNode', 'enableNode', 'disableNode'
]);
const workflowDiffSchema = zod_1.z.object({
id: zod_1.z.string(),
operations: zod_1.z.array(zod_1.z.object({
@@ -64,8 +67,8 @@ const workflowDiffSchema = zod_1.z.object({
target: zod_1.z.string().optional(),
from: zod_1.z.string().optional(),
to: zod_1.z.string().optional(),
sourceOutput: zod_1.z.string().optional(),
targetInput: zod_1.z.string().optional(),
sourceOutput: zod_1.z.union([zod_1.z.string(), zod_1.z.number()]).transform(String).optional(),
targetInput: zod_1.z.union([zod_1.z.string(), zod_1.z.number()]).transform(String).optional(),
sourceIndex: zod_1.z.number().optional(),
targetIndex: zod_1.z.number().optional(),
branch: zod_1.z.enum(['true', 'false']).optional(),
@@ -76,6 +79,20 @@ const workflowDiffSchema = zod_1.z.object({
settings: zod_1.z.any().optional(),
name: zod_1.z.string().optional(),
tag: zod_1.z.string().optional(),
destinationProjectId: zod_1.z.string().min(1).optional(),
id: zod_1.z.string().optional(),
}).transform((op) => {
if (NODE_TARGETING_OPERATIONS.has(op.type)) {
if (!op.nodeName && !op.nodeId && op.name) {
op.nodeName = op.name;
op.name = undefined;
}
if (!op.nodeId && op.id) {
op.nodeId = op.id;
op.id = undefined;
}
}
return op;
})),
validateOnly: zod_1.z.boolean().optional(),
continueOnError: zod_1.z.boolean().optional(),
@@ -167,11 +184,12 @@ async function handleUpdatePartialWorkflow(args, repository, context) {
else {
return {
success: false,
saved: false,
error: 'Failed to apply diff operations',
operationsApplied: diffResult.operationsApplied,
details: {
errors: diffResult.errors,
warnings: diffResult.warnings,
operationsApplied: diffResult.operationsApplied,
applied: diffResult.applied,
failed: diffResult.failed
}
@@ -239,6 +257,7 @@ async function handleUpdatePartialWorkflow(args, repository, context) {
if (!skipValidation) {
return {
success: false,
saved: false,
error: errorMessage,
details: {
errors: structureErrors,
@@ -247,7 +266,7 @@ async function handleUpdatePartialWorkflow(args, repository, context) {
applied: diffResult.applied,
recoveryGuidance: recoverySteps,
note: 'Operations were applied but created an invalid workflow structure. The workflow was NOT saved to n8n to prevent UI rendering errors.',
autoSanitizationNote: 'Auto-sanitization runs on all nodes during updates to fix operator structures and add missing metadata. However, it cannot fix all issues (e.g., broken connections, branch mismatches). Use the recovery guidance above to resolve remaining issues.'
autoSanitizationNote: 'Auto-sanitization runs on modified nodes during updates to fix operator structures and add missing metadata. However, it cannot fix all issues (e.g., broken connections, branch mismatches). Use the recovery guidance above to resolve remaining issues.'
}
};
}
@@ -259,6 +278,77 @@ async function handleUpdatePartialWorkflow(args, repository, context) {
}
try {
const updatedWorkflow = await client.updateWorkflow(input.id, diffResult.workflow);
let tagWarnings = [];
if (diffResult.tagsToAdd?.length || diffResult.tagsToRemove?.length) {
try {
const existingTags = Array.isArray(updatedWorkflow.tags)
? updatedWorkflow.tags.map((t) => typeof t === 'object' ? { id: t.id, name: t.name } : { id: '', name: t })
: [];
const allTags = await client.listTags();
const tagMap = new Map();
for (const t of allTags.data) {
if (t.id)
tagMap.set(t.name.toLowerCase(), t.id);
}
for (const tagName of (diffResult.tagsToAdd || [])) {
if (!tagMap.has(tagName.toLowerCase())) {
try {
const newTag = await client.createTag({ name: tagName });
if (newTag.id)
tagMap.set(tagName.toLowerCase(), newTag.id);
}
catch (createErr) {
tagWarnings.push(`Failed to create tag "${tagName}": ${createErr instanceof Error ? createErr.message : 'Unknown error'}`);
}
}
}
const currentTagIds = new Set();
for (const et of existingTags) {
if (et.id) {
currentTagIds.add(et.id);
}
else {
const resolved = tagMap.get(et.name.toLowerCase());
if (resolved)
currentTagIds.add(resolved);
}
}
for (const tagName of (diffResult.tagsToAdd || [])) {
const tagId = tagMap.get(tagName.toLowerCase());
if (tagId)
currentTagIds.add(tagId);
}
for (const tagName of (diffResult.tagsToRemove || [])) {
const tagId = tagMap.get(tagName.toLowerCase());
if (tagId)
currentTagIds.delete(tagId);
}
await client.updateWorkflowTags(input.id, Array.from(currentTagIds));
}
catch (tagError) {
tagWarnings.push(`Tag update failed: ${tagError instanceof Error ? tagError.message : 'Unknown error'}`);
logger_1.logger.warn('Tag operations failed (non-blocking)', tagError);
}
}
let transferMessage = '';
if (diffResult.transferToProjectId) {
try {
await client.transferWorkflow(input.id, diffResult.transferToProjectId);
transferMessage = ` Workflow transferred to project ${diffResult.transferToProjectId}.`;
}
catch (transferError) {
logger_1.logger.error('Failed to transfer workflow to project', transferError);
return {
success: false,
saved: true,
error: 'Workflow updated successfully but project transfer failed',
details: {
workflowUpdated: true,
transferError: transferError instanceof Error ? transferError.message : 'Unknown error'
}
};
}
}
let finalWorkflow = updatedWorkflow;
let activationMessage = '';
try {
@@ -286,6 +376,7 @@ async function handleUpdatePartialWorkflow(args, repository, context) {
logger_1.logger.error('Failed to activate workflow after update', activationError);
return {
success: false,
saved: true,
error: 'Workflow updated successfully but activation failed',
details: {
workflowUpdated: true,
@@ -303,6 +394,7 @@ async function handleUpdatePartialWorkflow(args, repository, context) {
logger_1.logger.error('Failed to deactivate workflow after update', deactivationError);
return {
success: false,
saved: true,
error: 'Workflow updated successfully but deactivation failed',
details: {
workflowUpdated: true,
@@ -329,6 +421,7 @@ async function handleUpdatePartialWorkflow(args, repository, context) {
}
return {
success: true,
saved: true,
data: {
id: finalWorkflow.id,
name: finalWorkflow.name,
@@ -336,12 +429,12 @@ async function handleUpdatePartialWorkflow(args, repository, context) {
nodeCount: finalWorkflow.nodes?.length || 0,
operationsApplied: diffResult.operationsApplied
},
message: `Workflow "${finalWorkflow.name}" updated successfully. Applied ${diffResult.operationsApplied} operations.${activationMessage} Use n8n_get_workflow with mode 'structure' to verify current state.`,
message: `Workflow "${finalWorkflow.name}" updated successfully. Applied ${diffResult.operationsApplied} operations.${transferMessage}${activationMessage} Use n8n_get_workflow with mode 'structure' to verify current state.`,
details: {
applied: diffResult.applied,
failed: diffResult.failed,
errors: diffResult.errors,
warnings: diffResult.warnings
warnings: mergeWarnings(diffResult.warnings, tagWarnings)
}
};
}
@@ -379,7 +472,9 @@ async function handleUpdatePartialWorkflow(args, repository, context) {
return {
success: false,
error: 'Invalid input',
details: { errors: error.errors }
details: {
errors: error.errors.map(e => `${e.path.join('.')}: ${e.message}`)
}
};
}
logger_1.logger.error('Failed to update partial workflow', error);
@@ -389,6 +484,13 @@ async function handleUpdatePartialWorkflow(args, repository, context) {
};
}
}
function mergeWarnings(diffWarnings, tagWarnings) {
const merged = [
...(diffWarnings || []),
...tagWarnings.map(w => ({ operation: -1, message: w }))
];
return merged.length > 0 ? merged : undefined;
}
function inferIntentFromOperations(operations) {
if (!operations || operations.length === 0) {
return 'Partial workflow update';
@@ -416,6 +518,8 @@ function inferIntentFromOperations(operations) {
return 'Activate workflow';
case 'deactivateWorkflow':
return 'Deactivate workflow';
case 'transferWorkflow':
return `Transfer workflow to project ${op.destinationProjectId || ''}`.trim();
default:
return `Workflow ${op.type}`;
}

File diff suppressed because one or more lines are too long

View File

@@ -1 +1 @@
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/mcp/server.ts"],"names":[],"mappings":"AA0CA,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAE5D,OAAO,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AAmGnE,qBAAa,yBAAyB;IACpC,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,EAAE,CAAgC;IAC1C,OAAO,CAAC,UAAU,CAA+B;IACjD,OAAO,CAAC,eAAe,CAAgC;IACvD,OAAO,CAAC,WAAW,CAAgB;IACnC,OAAO,CAAC,KAAK,CAAqB;IAClC,OAAO,CAAC,UAAU,CAAa;IAC/B,OAAO,CAAC,eAAe,CAAC,CAAkB;IAC1C,OAAO,CAAC,YAAY,CAAuB;IAC3C,OAAO,CAAC,qBAAqB,CAAsB;IACnD,OAAO,CAAC,WAAW,CAAiC;IACpD,OAAO,CAAC,kBAAkB,CAA4B;IACtD,OAAO,CAAC,iBAAiB,CAAkB;IAC3C,OAAO,CAAC,aAAa,CAAoC;IACzD,OAAO,CAAC,UAAU,CAAkB;gBAExB,eAAe,CAAC,EAAE,eAAe,EAAE,WAAW,CAAC,EAAE,gBAAgB;IAuGvE,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;YA+Cd,kBAAkB;YAiDlB,wBAAwB;IA0BtC,OAAO,CAAC,kBAAkB;YA6CZ,iBAAiB;IAa/B,OAAO,CAAC,eAAe,CAAkB;YAE3B,sBAAsB;IAgDpC,OAAO,CAAC,gBAAgB;IAqCxB,OAAO,CAAC,aAAa;IA0XrB,OAAO,CAAC,wBAAwB;IAoFhC,OAAO,CAAC,kBAAkB;IAqE1B,OAAO,CAAC,uBAAuB;IAwB/B,OAAO,CAAC,qBAAqB;IAiF7B,OAAO,CAAC,2BAA2B;YA0UrB,SAAS;YA2DT,WAAW;YAkFX,WAAW;YA0CX,cAAc;YA8Md,gBAAgB;IAqD9B,OAAO,CAAC,mBAAmB;IAwE3B,OAAO,CAAC,eAAe;YAsBT,eAAe;IA2L7B,OAAO,CAAC,kBAAkB;IAQ1B,OAAO,CAAC,uBAAuB;IA0D/B,OAAO,CAAC,iBAAiB;YAqFX,WAAW;YAgCX,oBAAoB;IAuFlC,OAAO,CAAC,aAAa;YAQP,qBAAqB;YAwDrB,iBAAiB;YAiKjB,OAAO;YAgDP,cAAc;YAwFd,iBAAiB;IAqC/B,OAAO,CAAC,iBAAiB;IA0BzB,OAAO,CAAC,iBAAiB;IA0BzB,OAAO,CAAC,eAAe;IAwCvB,OAAO,CAAC,kBAAkB;IAiC1B,OAAO,CAAC,aAAa;IAoCrB,OAAO,CAAC,0BAA0B;IAgClC,OAAO,CAAC,4BAA4B;YAKtB,oBAAoB;IAsDlC,OAAO,CAAC,gBAAgB;YAiBV,SAAS;YA6CT,kBAAkB;YAqElB,uBAAuB;YAsDvB,iBAAiB;IAqE/B,OAAO,CAAC,qBAAqB;IA8C7B,OAAO,CAAC,uBAAuB;IA4D/B,OAAO,CAAC,wBAAwB;IAkChC,OAAO,CAAC,iBAAiB;YAoDX,mBAAmB;YAoEnB,qBAAqB;IAS7B,OAAO,CAAC,SAAS,EAAE,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC;YAS9B,aAAa;YAcb,iBAAiB;YAoBjB,WAAW;YAwBX,eAAe;YAqBf,mBAAmB;YAwBnB,yBAAyB;IA4CvC,OAAO,CAAC,kBAAkB;YAiBZ,gBAAgB;YA6HhB,2BAA2B;YAiE3B,2BAA2B;IAyEnC,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;IA0BpB,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;CAgEhC"}
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/mcp/server.ts"],"names":[],"mappings":"AA0CA,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAE5D,OAAO,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AAmGnE,qBAAa,yBAAyB;IACpC,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,EAAE,CAAgC;IAC1C,OAAO,CAAC,UAAU,CAA+B;IACjD,OAAO,CAAC,eAAe,CAAgC;IACvD,OAAO,CAAC,WAAW,CAAgB;IACnC,OAAO,CAAC,KAAK,CAAqB;IAClC,OAAO,CAAC,UAAU,CAAa;IAC/B,OAAO,CAAC,eAAe,CAAC,CAAkB;IAC1C,OAAO,CAAC,YAAY,CAAuB;IAC3C,OAAO,CAAC,qBAAqB,CAAsB;IACnD,OAAO,CAAC,WAAW,CAAiC;IACpD,OAAO,CAAC,kBAAkB,CAA4B;IACtD,OAAO,CAAC,iBAAiB,CAAkB;IAC3C,OAAO,CAAC,aAAa,CAAoC;IACzD,OAAO,CAAC,UAAU,CAAkB;gBAExB,eAAe,CAAC,EAAE,eAAe,EAAE,WAAW,CAAC,EAAE,gBAAgB;IA8GvE,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;YA+Cd,kBAAkB;YAiDlB,wBAAwB;IA0BtC,OAAO,CAAC,kBAAkB;YA6CZ,iBAAiB;IAa/B,OAAO,CAAC,eAAe,CAAkB;YAE3B,sBAAsB;IAgDpC,OAAO,CAAC,gBAAgB;IAqCxB,OAAO,CAAC,aAAa;IA0XrB,OAAO,CAAC,wBAAwB;IAoFhC,OAAO,CAAC,kBAAkB;IA0E1B,OAAO,CAAC,uBAAuB;IAwB/B,OAAO,CAAC,qBAAqB;IAiF7B,OAAO,CAAC,2BAA2B;YA8VrB,SAAS;YA2DT,WAAW;YAkFX,WAAW;YA0CX,cAAc;YA8Md,gBAAgB;IAqD9B,OAAO,CAAC,mBAAmB;IAwE3B,OAAO,CAAC,eAAe;YAsBT,eAAe;IA2L7B,OAAO,CAAC,kBAAkB;IAQ1B,OAAO,CAAC,uBAAuB;IA0D/B,OAAO,CAAC,iBAAiB;YAqFX,WAAW;YAgCX,oBAAoB;IAuFlC,OAAO,CAAC,aAAa;YAQP,qBAAqB;YAwDrB,iBAAiB;YAiKjB,OAAO;YAgDP,cAAc;YAwFd,iBAAiB;IAqC/B,OAAO,CAAC,iBAAiB;IA0BzB,OAAO,CAAC,iBAAiB;IA0BzB,OAAO,CAAC,eAAe;IAwCvB,OAAO,CAAC,kBAAkB;IAiC1B,OAAO,CAAC,aAAa;IAoCrB,OAAO,CAAC,0BAA0B;IAgClC,OAAO,CAAC,4BAA4B;YAKtB,oBAAoB;IAsDlC,OAAO,CAAC,gBAAgB;YAiBV,SAAS;YA6CT,kBAAkB;YAqElB,uBAAuB;YAsDvB,iBAAiB;IAqE/B,OAAO,CAAC,qBAAqB;IA8C7B,OAAO,CAAC,uBAAuB;IA4D/B,OAAO,CAAC,wBAAwB;IAkChC,OAAO,CAAC,iBAAiB;YAoDX,mBAAmB;YAoEnB,qBAAqB;IAS7B,OAAO,CAAC,SAAS,EAAE,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC;YAS9B,aAAa;YAcb,iBAAiB;YAoBjB,WAAW;YAwBX,eAAe;YAqBf,mBAAmB;YAwBnB,yBAAyB;IA4CvC,OAAO,CAAC,kBAAkB;YAiBZ,gBAAgB;YA6HhB,2BAA2B;YAiE3B,2BAA2B;IAyEnC,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;IA0BpB,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;CAgEhC"}

24
dist/mcp/server.js vendored
View File

@@ -124,6 +124,7 @@ class N8NDocumentationMCPServer {
this.earlyLogger.logCheckpoint(startup_checkpoints_1.STARTUP_CHECKPOINTS.N8N_API_READY);
}
});
this.initialized.catch(() => { });
logger_1.logger.info('Initializing n8n Documentation MCP server');
this.server = new index_js_1.Server({
name: 'n8n-documentation-mcp',
@@ -719,6 +720,11 @@ class N8NDocumentationMCPServer {
? { valid: true, errors: [] }
: { valid: false, errors: [{ field: 'action', message: 'action is required' }] };
break;
case 'n8n_manage_datatable':
validationResult = args.action
? { valid: true, errors: [] }
: { valid: false, errors: [{ field: 'action', message: 'action is required' }] };
break;
case 'n8n_deploy_template':
validationResult = args.templateId !== undefined
? { valid: true, errors: [] }
@@ -1108,6 +1114,24 @@ class N8NDocumentationMCPServer {
if (!this.repository)
throw new Error('Repository not initialized');
return n8nHandlers.handleDeployTemplate(args, this.templateService, this.repository, this.instanceContext);
case 'n8n_manage_datatable': {
this.validateToolParams(name, args, ['action']);
const dtAction = args.action;
switch (dtAction) {
case 'createTable': return n8nHandlers.handleCreateTable(args, this.instanceContext);
case 'listTables': return n8nHandlers.handleListTables(args, this.instanceContext);
case 'getTable': return n8nHandlers.handleGetTable(args, this.instanceContext);
case 'updateTable': return n8nHandlers.handleUpdateTable(args, this.instanceContext);
case 'deleteTable': return n8nHandlers.handleDeleteTable(args, this.instanceContext);
case 'getRows': return n8nHandlers.handleGetRows(args, this.instanceContext);
case 'insertRows': return n8nHandlers.handleInsertRows(args, this.instanceContext);
case 'updateRows': return n8nHandlers.handleUpdateRows(args, this.instanceContext);
case 'upsertRows': return n8nHandlers.handleUpsertRows(args, this.instanceContext);
case 'deleteRows': return n8nHandlers.handleDeleteRows(args, this.instanceContext);
default:
throw new Error(`Unknown action: ${dtAction}. Valid actions: createTable, listTables, getTable, updateTable, deleteTable, getRows, insertRows, updateRows, upsertRows, deleteRows`);
}
}
default:
throw new Error(`Unknown tool: ${name}`);
}

File diff suppressed because one or more lines are too long

View File

@@ -1 +1 @@
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/mcp/tool-docs/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AA4B5C,eAAO,MAAM,kBAAkB,EAAE,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAmChE,CAAC;AAGF,YAAY,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC"}
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/mcp/tool-docs/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AA6B5C,eAAO,MAAM,kBAAkB,EAAE,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAoChE,CAAC;AAGF,YAAY,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC"}

View File

@@ -29,6 +29,7 @@ exports.toolsDocumentation = {
n8n_test_workflow: workflow_management_1.n8nTestWorkflowDoc,
n8n_executions: workflow_management_1.n8nExecutionsDoc,
n8n_workflow_versions: workflow_management_1.n8nWorkflowVersionsDoc,
n8n_deploy_template: workflow_management_1.n8nDeployTemplateDoc
n8n_deploy_template: workflow_management_1.n8nDeployTemplateDoc,
n8n_manage_datatable: workflow_management_1.n8nManageDatatableDoc
};
//# sourceMappingURL=index.js.map

View File

@@ -1 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/mcp/tool-docs/index.ts"],"names":[],"mappings":";;;AAGA,2CAA6C;AAC7C,mDAA6C;AAC7C,6CAAoE;AACpE,2CAAiE;AACjE,qCAGkB;AAClB,qCAAyC;AACzC,+DAa+B;AAGlB,QAAA,kBAAkB,GAAsC;IAEnE,mBAAmB,EAAE,8BAAqB;IAC1C,gBAAgB,EAAE,0BAAiB;IAGnC,eAAe,EAAE,sBAAa;IAG9B,YAAY,EAAE,0BAAc;IAG5B,QAAQ,EAAE,0BAAU;IAGpB,aAAa,EAAE,4BAAe;IAC9B,iBAAiB,EAAE,gCAAmB;IAGtC,YAAY,EAAE,0BAAc;IAC5B,gBAAgB,EAAE,8BAAkB;IAGpC,mBAAmB,EAAE,0CAAoB;IACzC,gBAAgB,EAAE,uCAAiB;IACnC,wBAAwB,EAAE,8CAAwB;IAClD,2BAA2B,EAAE,iDAA2B;IACxD,mBAAmB,EAAE,0CAAoB;IACzC,kBAAkB,EAAE,yCAAmB;IACvC,qBAAqB,EAAE,4CAAsB;IAC7C,oBAAoB,EAAE,2CAAqB;IAC3C,iBAAiB,EAAE,wCAAkB;IACrC,cAAc,EAAE,sCAAgB;IAChC,qBAAqB,EAAE,4CAAsB;IAC7C,mBAAmB,EAAE,0CAAoB;CAC1C,CAAC"}
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/mcp/tool-docs/index.ts"],"names":[],"mappings":";;;AAGA,2CAA6C;AAC7C,mDAA6C;AAC7C,6CAAoE;AACpE,2CAAiE;AACjE,qCAGkB;AAClB,qCAAyC;AACzC,+DAc+B;AAGlB,QAAA,kBAAkB,GAAsC;IAEnE,mBAAmB,EAAE,8BAAqB;IAC1C,gBAAgB,EAAE,0BAAiB;IAGnC,eAAe,EAAE,sBAAa;IAG9B,YAAY,EAAE,0BAAc;IAG5B,QAAQ,EAAE,0BAAU;IAGpB,aAAa,EAAE,4BAAe;IAC9B,iBAAiB,EAAE,gCAAmB;IAGtC,YAAY,EAAE,0BAAc;IAC5B,gBAAgB,EAAE,8BAAkB;IAGpC,mBAAmB,EAAE,0CAAoB;IACzC,gBAAgB,EAAE,uCAAiB;IACnC,wBAAwB,EAAE,8CAAwB;IAClD,2BAA2B,EAAE,iDAA2B;IACxD,mBAAmB,EAAE,0CAAoB;IACzC,kBAAkB,EAAE,yCAAmB;IACvC,qBAAqB,EAAE,4CAAsB;IAC7C,oBAAoB,EAAE,2CAAqB;IAC3C,iBAAiB,EAAE,wCAAkB;IACrC,cAAc,EAAE,sCAAgB;IAChC,qBAAqB,EAAE,4CAAsB;IAC7C,mBAAmB,EAAE,0CAAoB;IACzC,oBAAoB,EAAE,2CAAqB;CAC5C,CAAC"}

View File

@@ -10,4 +10,5 @@ export { n8nTestWorkflowDoc } from './n8n-test-workflow';
export { n8nExecutionsDoc } from './n8n-executions';
export { n8nWorkflowVersionsDoc } from './n8n-workflow-versions';
export { n8nDeployTemplateDoc } from './n8n-deploy-template';
export { n8nManageDatatableDoc } from './n8n-manage-datatable';
//# sourceMappingURL=index.d.ts.map

View File

@@ -1 +1 @@
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/mcp/tool-docs/workflow_management/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,EAAE,wBAAwB,EAAE,MAAM,4BAA4B,CAAC;AACtE,OAAO,EAAE,2BAA2B,EAAE,MAAM,+BAA+B,CAAC;AAC5E,OAAO,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AACjE,OAAO,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AAC/D,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AACjE,OAAO,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC"}
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/mcp/tool-docs/workflow_management/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,EAAE,wBAAwB,EAAE,MAAM,4BAA4B,CAAC;AACtE,OAAO,EAAE,2BAA2B,EAAE,MAAM,+BAA+B,CAAC;AAC5E,OAAO,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AACjE,OAAO,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AAC/D,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AACjE,OAAO,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC"}

View File

@@ -1,6 +1,6 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.n8nDeployTemplateDoc = exports.n8nWorkflowVersionsDoc = exports.n8nExecutionsDoc = exports.n8nTestWorkflowDoc = exports.n8nAutofixWorkflowDoc = exports.n8nValidateWorkflowDoc = exports.n8nListWorkflowsDoc = exports.n8nDeleteWorkflowDoc = exports.n8nUpdatePartialWorkflowDoc = exports.n8nUpdateFullWorkflowDoc = exports.n8nGetWorkflowDoc = exports.n8nCreateWorkflowDoc = void 0;
exports.n8nManageDatatableDoc = exports.n8nDeployTemplateDoc = exports.n8nWorkflowVersionsDoc = exports.n8nExecutionsDoc = exports.n8nTestWorkflowDoc = exports.n8nAutofixWorkflowDoc = exports.n8nValidateWorkflowDoc = exports.n8nListWorkflowsDoc = exports.n8nDeleteWorkflowDoc = exports.n8nUpdatePartialWorkflowDoc = exports.n8nUpdateFullWorkflowDoc = exports.n8nGetWorkflowDoc = exports.n8nCreateWorkflowDoc = void 0;
var n8n_create_workflow_1 = require("./n8n-create-workflow");
Object.defineProperty(exports, "n8nCreateWorkflowDoc", { enumerable: true, get: function () { return n8n_create_workflow_1.n8nCreateWorkflowDoc; } });
var n8n_get_workflow_1 = require("./n8n-get-workflow");
@@ -25,4 +25,6 @@ var n8n_workflow_versions_1 = require("./n8n-workflow-versions");
Object.defineProperty(exports, "n8nWorkflowVersionsDoc", { enumerable: true, get: function () { return n8n_workflow_versions_1.n8nWorkflowVersionsDoc; } });
var n8n_deploy_template_1 = require("./n8n-deploy-template");
Object.defineProperty(exports, "n8nDeployTemplateDoc", { enumerable: true, get: function () { return n8n_deploy_template_1.n8nDeployTemplateDoc; } });
var n8n_manage_datatable_1 = require("./n8n-manage-datatable");
Object.defineProperty(exports, "n8nManageDatatableDoc", { enumerable: true, get: function () { return n8n_manage_datatable_1.n8nManageDatatableDoc; } });
//# sourceMappingURL=index.js.map

View File

@@ -1 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/mcp/tool-docs/workflow_management/index.ts"],"names":[],"mappings":";;;AAAA,6DAA6D;AAApD,2HAAA,oBAAoB,OAAA;AAC7B,uDAAuD;AAA9C,qHAAA,iBAAiB,OAAA;AAC1B,uEAAsE;AAA7D,oIAAA,wBAAwB,OAAA;AACjC,6EAA4E;AAAnE,0IAAA,2BAA2B,OAAA;AACpC,6DAA6D;AAApD,2HAAA,oBAAoB,OAAA;AAC7B,2DAA2D;AAAlD,yHAAA,mBAAmB,OAAA;AAC5B,iEAAiE;AAAxD,+HAAA,sBAAsB,OAAA;AAC/B,+DAA+D;AAAtD,6HAAA,qBAAqB,OAAA;AAC9B,yDAAyD;AAAhD,uHAAA,kBAAkB,OAAA;AAC3B,mDAAoD;AAA3C,kHAAA,gBAAgB,OAAA;AACzB,iEAAiE;AAAxD,+HAAA,sBAAsB,OAAA;AAC/B,6DAA6D;AAApD,2HAAA,oBAAoB,OAAA"}
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/mcp/tool-docs/workflow_management/index.ts"],"names":[],"mappings":";;;AAAA,6DAA6D;AAApD,2HAAA,oBAAoB,OAAA;AAC7B,uDAAuD;AAA9C,qHAAA,iBAAiB,OAAA;AAC1B,uEAAsE;AAA7D,oIAAA,wBAAwB,OAAA;AACjC,6EAA4E;AAAnE,0IAAA,2BAA2B,OAAA;AACpC,6DAA6D;AAApD,2HAAA,oBAAoB,OAAA;AAC7B,2DAA2D;AAAlD,yHAAA,mBAAmB,OAAA;AAC5B,iEAAiE;AAAxD,+HAAA,sBAAsB,OAAA;AAC/B,+DAA+D;AAAtD,6HAAA,qBAAqB,OAAA;AAC9B,yDAAyD;AAAhD,uHAAA,kBAAkB,OAAA;AAC3B,mDAAoD;AAA3C,kHAAA,gBAAgB,OAAA;AACzB,iEAAiE;AAAxD,+HAAA,sBAAsB,OAAA;AAC/B,6DAA6D;AAApD,2HAAA,oBAAoB,OAAA;AAC7B,+DAA+D;AAAtD,6HAAA,qBAAqB,OAAA"}

View File

@@ -1 +1 @@
{"version":3,"file":"n8n-update-partial-workflow.d.ts","sourceRoot":"","sources":["../../../../src/mcp/tool-docs/workflow_management/n8n-update-partial-workflow.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAE7C,eAAO,MAAM,2BAA2B,EAAE,iBA+ZzC,CAAC"}
{"version":3,"file":"n8n-update-partial-workflow.d.ts","sourceRoot":"","sources":["../../../../src/mcp/tool-docs/workflow_management/n8n-update-partial-workflow.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAE7C,eAAO,MAAM,2BAA2B,EAAE,iBAuazC,CAAC"}

View File

@@ -5,7 +5,7 @@ exports.n8nUpdatePartialWorkflowDoc = {
name: 'n8n_update_partial_workflow',
category: 'workflow_management',
essentials: {
description: 'Update workflow incrementally with diff operations. Types: addNode, removeNode, updateNode, moveNode, enable/disableNode, addConnection, removeConnection, rewireConnection, cleanStaleConnections, replaceConnections, updateSettings, updateName, add/removeTag, activateWorkflow, deactivateWorkflow. Supports smart parameters (branch, case) for multi-output nodes. Full support for AI connections (ai_languageModel, ai_tool, ai_memory, ai_embedding, ai_vectorStore, ai_document, ai_textSplitter, ai_outputParser).',
description: 'Update workflow incrementally with diff operations. Types: addNode, removeNode, updateNode, moveNode, enable/disableNode, addConnection, removeConnection, rewireConnection, cleanStaleConnections, replaceConnections, updateSettings, updateName, add/removeTag, activateWorkflow, deactivateWorkflow, transferWorkflow. Supports smart parameters (branch, case) for multi-output nodes. Full support for AI connections (ai_languageModel, ai_tool, ai_memory, ai_embedding, ai_vectorStore, ai_document, ai_textSplitter, ai_outputParser).',
keyParameters: ['id', 'operations', 'continueOnError'],
example: 'n8n_update_partial_workflow({id: "wf_123", operations: [{type: "rewireConnection", source: "IF", from: "Old", to: "New", branch: "true"}]})',
performance: 'Fast (50-200ms)',
@@ -23,7 +23,8 @@ exports.n8nUpdatePartialWorkflowDoc = {
'Batch AI component connections for atomic updates',
'Auto-sanitization: ALL nodes auto-fixed during updates (operator structures, missing metadata)',
'Node renames automatically update all connection references - no manual connection operations needed',
'Activate/deactivate workflows: Use activateWorkflow/deactivateWorkflow operations (requires activatable triggers like webhook/schedule)'
'Activate/deactivate workflows: Use activateWorkflow/deactivateWorkflow operations (requires activatable triggers like webhook/schedule)',
'Transfer workflows between projects: Use transferWorkflow with destinationProjectId (enterprise feature)'
]
},
full: {
@@ -56,6 +57,9 @@ exports.n8nUpdatePartialWorkflowDoc = {
- **activateWorkflow**: Activate the workflow to enable automatic execution via triggers
- **deactivateWorkflow**: Deactivate the workflow to prevent automatic execution
### Project Management Operations (1 type):
- **transferWorkflow**: Transfer the workflow to a different project. Requires \`destinationProjectId\`. Enterprise/cloud feature.
## Smart Parameters for Multi-Output Nodes
For **IF nodes**, use semantic 'branch' parameter instead of technical sourceIndex:
@@ -195,12 +199,12 @@ Please choose a different name.
- Can rename a node and add/remove connections using the new name in the same batch
- Use \`validateOnly: true\` to preview effects before applying
## Removing Properties with undefined
## Removing Properties with null
To remove a property from a node, set its value to \`undefined\` in the updates object. This is essential when migrating from deprecated properties or cleaning up optional configuration fields.
To remove a property from a node, set its value to \`null\` in the updates object. This is essential when migrating from deprecated properties or cleaning up optional configuration fields.
### Why Use undefined?
- **Property removal vs. null**: Setting a property to \`undefined\` removes it completely from the node object, while \`null\` sets the property to a null value
### Why Use null?
- **Property removal**: Setting a property to \`null\` removes it completely from the node object
- **Validation constraints**: Some properties are mutually exclusive (e.g., \`continueOnFail\` and \`onError\`). Simply setting one without removing the other will fail validation
- **Deprecated property migration**: When n8n deprecates properties, you must remove the old property before the new one will work
@@ -212,7 +216,7 @@ n8n_update_partial_workflow({
operations: [{
type: "updateNode",
nodeName: "HTTP Request",
updates: { onError: undefined }
updates: { onError: null }
}]
});
@@ -222,7 +226,7 @@ n8n_update_partial_workflow({
operations: [{
type: "updateNode",
nodeId: "node_abc",
updates: { disabled: undefined }
updates: { disabled: null }
}]
});
\`\`\`
@@ -236,7 +240,7 @@ n8n_update_partial_workflow({
operations: [{
type: "updateNode",
nodeName: "API Request",
updates: { "parameters.authentication": undefined }
updates: { "parameters.authentication": null }
}]
});
@@ -246,7 +250,7 @@ n8n_update_partial_workflow({
operations: [{
type: "updateNode",
nodeName: "HTTP Request",
updates: { "parameters.headers": undefined }
updates: { "parameters.headers": null }
}]
});
\`\`\`
@@ -272,7 +276,7 @@ n8n_update_partial_workflow({
type: "updateNode",
nodeName: "HTTP Request",
updates: {
continueOnFail: undefined,
continueOnFail: null,
onError: "continueErrorOutput"
}
}]
@@ -288,15 +292,15 @@ n8n_update_partial_workflow({
type: "updateNode",
nodeName: "Data Processor",
updates: {
continueOnFail: undefined,
alwaysOutputData: undefined,
"parameters.legacy_option": undefined
continueOnFail: null,
alwaysOutputData: null,
"parameters.legacy_option": null
}
}]
});
\`\`\`
### When to Use undefined
### When to Use null
- Removing deprecated properties during migration
- Cleaning up optional configuration flags
- Resolving mutual exclusivity validation errors
@@ -342,11 +346,14 @@ n8n_update_partial_workflow({
'// Rewire AI Agent to use different language model\nn8n_update_partial_workflow({id: "ai9", operations: [{type: "rewireConnection", source: "AI Agent", from: "OpenAI Chat Model", to: "Anthropic Chat Model", sourceOutput: "ai_languageModel"}]})',
'// Replace all AI tools for an agent\nn8n_update_partial_workflow({id: "ai10", operations: [\n {type: "removeConnection", source: "Old Tool 1", target: "AI Agent", sourceOutput: "ai_tool"},\n {type: "removeConnection", source: "Old Tool 2", target: "AI Agent", sourceOutput: "ai_tool"},\n {type: "addConnection", source: "New HTTP Tool", target: "AI Agent", sourceOutput: "ai_tool"},\n {type: "addConnection", source: "New Code Tool", target: "AI Agent", sourceOutput: "ai_tool"}\n]})',
'\n// ============ REMOVING PROPERTIES EXAMPLES ============',
'// Remove a simple property\nn8n_update_partial_workflow({id: "rm1", operations: [{type: "updateNode", nodeName: "HTTP Request", updates: {onError: undefined}}]})',
'// Migrate from deprecated continueOnFail to onError\nn8n_update_partial_workflow({id: "rm2", operations: [{type: "updateNode", nodeName: "HTTP Request", updates: {continueOnFail: undefined, onError: "continueErrorOutput"}}]})',
'// Remove nested property\nn8n_update_partial_workflow({id: "rm3", operations: [{type: "updateNode", nodeName: "API Request", updates: {"parameters.authentication": undefined}}]})',
'// Remove multiple properties\nn8n_update_partial_workflow({id: "rm4", operations: [{type: "updateNode", nodeName: "Data Processor", updates: {continueOnFail: undefined, alwaysOutputData: undefined, "parameters.legacy_option": undefined}}]})',
'// Remove entire array property\nn8n_update_partial_workflow({id: "rm5", operations: [{type: "updateNode", nodeName: "HTTP Request", updates: {"parameters.headers": undefined}}]})'
'// Remove a simple property\nn8n_update_partial_workflow({id: "rm1", operations: [{type: "updateNode", nodeName: "HTTP Request", updates: {onError: null}}]})',
'// Migrate from deprecated continueOnFail to onError\nn8n_update_partial_workflow({id: "rm2", operations: [{type: "updateNode", nodeName: "HTTP Request", updates: {continueOnFail: null, onError: "continueErrorOutput"}}]})',
'// Remove nested property\nn8n_update_partial_workflow({id: "rm3", operations: [{type: "updateNode", nodeName: "API Request", updates: {"parameters.authentication": null}}]})',
'// Remove multiple properties\nn8n_update_partial_workflow({id: "rm4", operations: [{type: "updateNode", nodeName: "Data Processor", updates: {continueOnFail: null, alwaysOutputData: null, "parameters.legacy_option": null}}]})',
'// Remove entire array property\nn8n_update_partial_workflow({id: "rm5", operations: [{type: "updateNode", nodeName: "HTTP Request", updates: {"parameters.headers": null}}]})',
'\n// ============ PROJECT TRANSFER EXAMPLES ============',
'// Transfer workflow to a different project\nn8n_update_partial_workflow({id: "tf1", operations: [{type: "transferWorkflow", destinationProjectId: "project-abc-123"}]})',
'// Transfer and activate in one call\nn8n_update_partial_workflow({id: "tf2", operations: [{type: "transferWorkflow", destinationProjectId: "project-abc-123"}, {type: "activateWorkflow"}]})'
],
useCases: [
'Rewire connections when replacing nodes',
@@ -364,7 +371,8 @@ n8n_update_partial_workflow({
'Add fallback language models to AI Agents',
'Configure Vector Store retrieval systems',
'Swap language models in existing AI workflows',
'Batch-update AI tool connections'
'Batch-update AI tool connections',
'Transfer workflows between team projects (enterprise)'
],
performance: 'Very fast - typically 50-200ms. Much faster than full updates as only changes are processed.',
bestPractices: [
@@ -384,9 +392,9 @@ n8n_update_partial_workflow({
'Use targetIndex for fallback models (primary=0, fallback=1)',
'Batch AI component connections in a single operation for atomicity',
'Validate AI workflows after connection changes to catch configuration errors',
'To remove properties, set them to undefined (not null) in the updates object',
'To remove properties, set them to null in the updates object',
'When migrating from deprecated properties, remove the old property and add the new one in the same operation',
'Use undefined to resolve mutual exclusivity validation errors between properties',
'Use null to resolve mutual exclusivity validation errors between properties',
'Batch multiple property removals in a single updateNode operation for efficiency'
],
pitfalls: [
@@ -408,8 +416,8 @@ n8n_update_partial_workflow({
'**Auto-sanitization runs on ALL nodes**: When ANY update is made, ALL nodes in the workflow are sanitized (not just modified ones)',
'**Auto-sanitization cannot fix everything**: It fixes operator structures and missing metadata, but cannot fix broken connections or branch mismatches',
'**Corrupted workflows beyond repair**: Workflows in paradoxical states (API returns corrupt, API rejects updates) cannot be fixed via API - must be recreated',
'Setting a property to null does NOT remove it - use undefined instead',
'When properties are mutually exclusive (e.g., continueOnFail and onError), setting only the new property will fail - you must remove the old one with undefined',
'To remove a property, set it to null in the updates object',
'When properties are mutually exclusive (e.g., continueOnFail and onError), setting only the new property will fail - you must remove the old one with null',
'Removing a required property may cause validation errors - check node documentation first',
'Nested property removal with dot notation only removes the specific nested field, not the entire parent object',
'Array index notation (e.g., "parameters.headers[0]") is not supported - remove the entire array property instead'

View File

@@ -1 +1 @@
{"version":3,"file":"n8n-update-partial-workflow.js","sourceRoot":"","sources":["../../../../src/mcp/tool-docs/workflow_management/n8n-update-partial-workflow.ts"],"names":[],"mappings":"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"}
{"version":3,"file":"n8n-update-partial-workflow.js","sourceRoot":"","sources":["../../../../src/mcp/tool-docs/workflow_management/n8n-update-partial-workflow.ts"],"names":[],"mappings":"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"}

View File

@@ -1 +1 @@
{"version":3,"file":"tools-n8n-manager.d.ts","sourceRoot":"","sources":["../../src/mcp/tools-n8n-manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAQ1C,eAAO,MAAM,kBAAkB,EAAE,cAAc,EAqlB9C,CAAC"}
{"version":3,"file":"tools-n8n-manager.d.ts","sourceRoot":"","sources":["../../src/mcp/tools-n8n-manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAQ1C,eAAO,MAAM,kBAAkB,EAAE,cAAc,EAwoB9C,CAAC"}

View File

@@ -57,6 +57,10 @@ exports.n8nManagementTools = [
executionTimeout: { type: 'number' },
errorWorkflow: { type: 'string' }
}
},
projectId: {
type: 'string',
description: 'Optional project ID to create the workflow in (enterprise feature)'
}
},
required: ['name', 'nodes', 'connections']
@@ -137,7 +141,7 @@ exports.n8nManagementTools = [
},
{
name: 'n8n_update_partial_workflow',
description: `Update workflow incrementally with diff operations. Types: addNode, removeNode, updateNode, moveNode, enable/disableNode, addConnection, removeConnection, updateSettings, updateName, add/removeTag. See tools_documentation("n8n_update_partial_workflow", "full") for details.`,
description: `Update workflow incrementally with diff operations. Types: addNode, removeNode, updateNode, moveNode, enable/disableNode, addConnection, removeConnection, updateSettings, updateName, add/removeTag, activate/deactivateWorkflow, transferWorkflow. See tools_documentation("n8n_update_partial_workflow", "full") for details.`,
inputSchema: {
type: 'object',
additionalProperties: true,
@@ -583,6 +587,53 @@ exports.n8nManagementTools = [
destructiveHint: false,
openWorldHint: true,
},
}
},
{
name: 'n8n_manage_datatable',
description: `Manage n8n data tables and rows. Actions: createTable, listTables, getTable, updateTable, deleteTable, getRows, insertRows, updateRows, upsertRows, deleteRows.`,
inputSchema: {
type: 'object',
properties: {
action: {
type: 'string',
enum: ['createTable', 'listTables', 'getTable', 'updateTable', 'deleteTable', 'getRows', 'insertRows', 'updateRows', 'upsertRows', 'deleteRows'],
description: 'Operation to perform',
},
tableId: { type: 'string', description: 'Data table ID (required for all actions except createTable and listTables)' },
name: { type: 'string', description: 'For createTable: table name. For updateTable: new name (rename only — schema is immutable after creation)' },
columns: {
type: 'array',
description: 'For createTable only: column definitions (schema is immutable after creation via public API)',
items: {
type: 'object',
properties: {
name: { type: 'string' },
type: { type: 'string', enum: ['string', 'number', 'boolean', 'date'] },
},
required: ['name'],
},
},
data: { description: 'For insertRows: array of row objects. For updateRows/upsertRows: object with column values.' },
filter: {
type: 'object',
description: 'For getRows/updateRows/upsertRows/deleteRows: {type?: "and"|"or", filters: [{columnName, condition, value}]}',
},
limit: { type: 'number', description: 'For listTables/getRows: max results (1-100)' },
cursor: { type: 'string', description: 'For listTables/getRows: pagination cursor' },
sortBy: { type: 'string', description: 'For getRows: "columnName:asc" or "columnName:desc"' },
search: { type: 'string', description: 'For getRows: text search across string columns' },
returnType: { type: 'string', enum: ['count', 'id', 'all'], description: 'For insertRows: what to return (default: count)' },
returnData: { type: 'boolean', description: 'For updateRows/upsertRows/deleteRows: return affected rows (default: false)' },
dryRun: { type: 'boolean', description: 'For updateRows/upsertRows/deleteRows: preview without applying (default: false)' },
},
required: ['action'],
},
annotations: {
title: 'Manage Data Tables',
readOnlyHint: false,
destructiveHint: true,
openWorldHint: true,
},
},
];
//# sourceMappingURL=tools-n8n-manager.js.map

File diff suppressed because one or more lines are too long

View File

@@ -33,8 +33,8 @@ export declare function validateVectorStoreTool(node: WorkflowNode, reverseConne
export declare function validateWorkflowTool(node: WorkflowNode, reverseConnections?: Map<string, ReverseConnection[]>): ValidationIssue[];
export declare function validateAIAgentTool(node: WorkflowNode, reverseConnections: Map<string, ReverseConnection[]>): ValidationIssue[];
export declare function validateMCPClientTool(node: WorkflowNode): ValidationIssue[];
export declare function validateCalculatorTool(node: WorkflowNode): ValidationIssue[];
export declare function validateThinkTool(node: WorkflowNode): ValidationIssue[];
export declare function validateCalculatorTool(_node: WorkflowNode): ValidationIssue[];
export declare function validateThinkTool(_node: WorkflowNode): ValidationIssue[];
export declare function validateSerpApiTool(node: WorkflowNode): ValidationIssue[];
export declare function validateWikipediaTool(node: WorkflowNode): ValidationIssue[];
export declare function validateSearXngTool(node: WorkflowNode): ValidationIssue[];

View File

@@ -1 +1 @@
{"version":3,"file":"ai-tool-validators.d.ts","sourceRoot":"","sources":["../../src/services/ai-tool-validators.ts"],"names":[],"mappings":"AAmBA,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC3B,UAAU,EAAE,GAAG,CAAC;IAChB,WAAW,CAAC,EAAE,GAAG,CAAC;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,YAAY,EAAE,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IACjC,QAAQ,CAAC,EAAE,GAAG,CAAC;CAChB;AAED,MAAM,WAAW,iBAAiB;IAChC,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,OAAO,GAAG,SAAS,GAAG,MAAM,CAAC;IACvC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAMD,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,YAAY,GAAG,eAAe,EAAE,CAuJ7E;AAMD,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,YAAY,GAAG,eAAe,EAAE,CAoCtE;AAMD,wBAAgB,uBAAuB,CACrC,IAAI,EAAE,YAAY,EAClB,kBAAkB,EAAE,GAAG,CAAC,MAAM,EAAE,iBAAiB,EAAE,CAAC,EACpD,QAAQ,EAAE,YAAY,GACrB,eAAe,EAAE,CAmCnB;AAMD,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,YAAY,EAAE,kBAAkB,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,iBAAiB,EAAE,CAAC,GAAG,eAAe,EAAE,CA0BjI;AAMD,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,YAAY,EAClB,kBAAkB,EAAE,GAAG,CAAC,MAAM,EAAE,iBAAiB,EAAE,CAAC,GACnD,eAAe,EAAE,CAmCnB;AAMD,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,YAAY,GAAG,eAAe,EAAE,CA0B3E;AAMD,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,YAAY,GAAG,eAAe,EAAE,CAM5E;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,YAAY,GAAG,eAAe,EAAE,CAMvE;AAMD,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,YAAY,GAAG,eAAe,EAAE,CAyBzE;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,YAAY,GAAG,eAAe,EAAE,CA4B3E;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,YAAY,GAAG,eAAe,EAAE,CA0BzE;AAED,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,YAAY,GAAG,eAAe,EAAE,CAyB9E;AAKD,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;CAarB,CAAC;AAKX,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAGzD;AAKD,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,YAAY,EAClB,QAAQ,EAAE,MAAM,EAChB,kBAAkB,EAAE,GAAG,CAAC,MAAM,EAAE,iBAAiB,EAAE,CAAC,EACpD,QAAQ,EAAE,YAAY,GACrB,eAAe,EAAE,CAgCnB"}
{"version":3,"file":"ai-tool-validators.d.ts","sourceRoot":"","sources":["../../src/services/ai-tool-validators.ts"],"names":[],"mappings":"AAmBA,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC3B,UAAU,EAAE,GAAG,CAAC;IAChB,WAAW,CAAC,EAAE,GAAG,CAAC;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAiBD,MAAM,WAAW,YAAY;IAC3B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,YAAY,EAAE,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IACjC,QAAQ,CAAC,EAAE,GAAG,CAAC;CAChB;AAED,MAAM,WAAW,iBAAiB;IAChC,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,OAAO,GAAG,SAAS,GAAG,MAAM,CAAC;IACvC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAMD,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,YAAY,GAAG,eAAe,EAAE,CAuJ7E;AAMD,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,YAAY,GAAG,eAAe,EAAE,CAoCtE;AAMD,wBAAgB,uBAAuB,CACrC,IAAI,EAAE,YAAY,EAClB,kBAAkB,EAAE,GAAG,CAAC,MAAM,EAAE,iBAAiB,EAAE,CAAC,EACpD,QAAQ,EAAE,YAAY,GACrB,eAAe,EAAE,CAmCnB;AAMD,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,YAAY,EAAE,kBAAkB,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,iBAAiB,EAAE,CAAC,GAAG,eAAe,EAAE,CA0BjI;AAMD,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,YAAY,EAClB,kBAAkB,EAAE,GAAG,CAAC,MAAM,EAAE,iBAAiB,EAAE,CAAC,GACnD,eAAe,EAAE,CAmCnB;AAMD,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,YAAY,GAAG,eAAe,EAAE,CA0B3E;AAMD,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,YAAY,GAAG,eAAe,EAAE,CAG7E;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,YAAY,GAAG,eAAe,EAAE,CAGxE;AAMD,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,YAAY,GAAG,eAAe,EAAE,CAyBzE;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,YAAY,GAAG,eAAe,EAAE,CA4B3E;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,YAAY,GAAG,eAAe,EAAE,CA0BzE;AAED,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,YAAY,GAAG,eAAe,EAAE,CAyB9E;AAKD,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;CAarB,CAAC;AAKX,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAGzD;AAKD,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,YAAY,EAClB,QAAQ,EAAE,MAAM,EAChB,kBAAkB,EAAE,GAAG,CAAC,MAAM,EAAE,iBAAiB,EAAE,CAAC,EACpD,QAAQ,EAAE,YAAY,GACrB,eAAe,EAAE,CAgCnB"}

View File

@@ -21,9 +21,14 @@ const MIN_DESCRIPTION_LENGTH_MEDIUM = 15;
const MIN_DESCRIPTION_LENGTH_LONG = 20;
const MAX_ITERATIONS_WARNING_THRESHOLD = 50;
const MAX_TOPK_WARNING_THRESHOLD = 20;
function getToolDescription(node) {
return (node.parameters.toolDescription ||
node.parameters.description ||
node.parameters.options?.description);
}
function validateHTTPRequestTool(node) {
const issues = [];
if (!node.parameters.toolDescription) {
if (!getToolDescription(node)) {
issues.push({
severity: 'error',
nodeId: node.id,
@@ -32,7 +37,7 @@ function validateHTTPRequestTool(node) {
code: 'MISSING_TOOL_DESCRIPTION'
});
}
else if (node.parameters.toolDescription.trim().length < MIN_DESCRIPTION_LENGTH_MEDIUM) {
else if (getToolDescription(node).trim().length < MIN_DESCRIPTION_LENGTH_MEDIUM) {
issues.push({
severity: 'warning',
nodeId: node.id,
@@ -154,7 +159,7 @@ function validateHTTPRequestTool(node) {
}
function validateCodeTool(node) {
const issues = [];
if (!node.parameters.toolDescription) {
if (!getToolDescription(node)) {
issues.push({
severity: 'error',
nodeId: node.id,
@@ -184,7 +189,7 @@ function validateCodeTool(node) {
}
function validateVectorStoreTool(node, reverseConnections, workflow) {
const issues = [];
if (!node.parameters.toolDescription) {
if (!getToolDescription(node)) {
issues.push({
severity: 'error',
nodeId: node.id,
@@ -216,7 +221,7 @@ function validateVectorStoreTool(node, reverseConnections, workflow) {
}
function validateWorkflowTool(node, reverseConnections) {
const issues = [];
if (!node.parameters.toolDescription) {
if (!getToolDescription(node)) {
issues.push({
severity: 'error',
nodeId: node.id,
@@ -238,7 +243,7 @@ function validateWorkflowTool(node, reverseConnections) {
}
function validateAIAgentTool(node, reverseConnections) {
const issues = [];
if (!node.parameters.toolDescription) {
if (!getToolDescription(node)) {
issues.push({
severity: 'error',
nodeId: node.id,
@@ -270,7 +275,7 @@ function validateAIAgentTool(node, reverseConnections) {
}
function validateMCPClientTool(node) {
const issues = [];
if (!node.parameters.toolDescription) {
if (!getToolDescription(node)) {
issues.push({
severity: 'error',
nodeId: node.id,
@@ -290,17 +295,15 @@ function validateMCPClientTool(node) {
}
return issues;
}
function validateCalculatorTool(node) {
const issues = [];
return issues;
function validateCalculatorTool(_node) {
return [];
}
function validateThinkTool(node) {
const issues = [];
return issues;
function validateThinkTool(_node) {
return [];
}
function validateSerpApiTool(node) {
const issues = [];
if (!node.parameters.toolDescription) {
if (!getToolDescription(node)) {
issues.push({
severity: 'error',
nodeId: node.id,
@@ -321,7 +324,7 @@ function validateSerpApiTool(node) {
}
function validateWikipediaTool(node) {
const issues = [];
if (!node.parameters.toolDescription) {
if (!getToolDescription(node)) {
issues.push({
severity: 'error',
nodeId: node.id,
@@ -345,7 +348,7 @@ function validateWikipediaTool(node) {
}
function validateSearXngTool(node) {
const issues = [];
if (!node.parameters.toolDescription) {
if (!getToolDescription(node)) {
issues.push({
severity: 'error',
nodeId: node.id,
@@ -376,7 +379,7 @@ function validateWolframAlphaTool(node) {
code: 'MISSING_CREDENTIALS'
});
}
if (!node.parameters.description && !node.parameters.toolDescription) {
if (!getToolDescription(node)) {
issues.push({
severity: 'info',
nodeId: node.id,

File diff suppressed because one or more lines are too long

View File

@@ -1,4 +1,4 @@
import { Workflow, WorkflowListParams, WorkflowListResponse, Execution, ExecutionListParams, ExecutionListResponse, Credential, CredentialListParams, CredentialListResponse, Tag, TagListParams, TagListResponse, HealthCheckResponse, N8nVersionInfo, Variable, WebhookRequest, SourceControlStatus, SourceControlPullResult, SourceControlPushResult } from '../types/n8n-api';
import { Workflow, WorkflowListParams, WorkflowListResponse, Execution, ExecutionListParams, ExecutionListResponse, Credential, CredentialListParams, CredentialListResponse, Tag, TagListParams, TagListResponse, HealthCheckResponse, N8nVersionInfo, Variable, WebhookRequest, SourceControlStatus, SourceControlPullResult, SourceControlPushResult, DataTable, DataTableColumn, DataTableListParams, DataTableRow, DataTableRowListParams, DataTableInsertRowsParams, DataTableUpdateRowsParams, DataTableUpsertRowParams, DataTableDeleteRowsParams } from '../types/n8n-api';
export interface N8nApiClientConfig {
baseUrl: string;
apiKey: string;
@@ -20,6 +20,7 @@ export declare class N8nApiClient {
getWorkflow(id: string): Promise<Workflow>;
updateWorkflow(id: string, workflow: Partial<Workflow>): Promise<Workflow>;
deleteWorkflow(id: string): Promise<Workflow>;
transferWorkflow(id: string, destinationProjectId: string): Promise<void>;
activateWorkflow(id: string): Promise<Workflow>;
deactivateWorkflow(id: string): Promise<Workflow>;
listWorkflows(params?: WorkflowListParams): Promise<WorkflowListResponse>;
@@ -36,6 +37,7 @@ export declare class N8nApiClient {
createTag(tag: Partial<Tag>): Promise<Tag>;
updateTag(id: string, tag: Partial<Tag>): Promise<Tag>;
deleteTag(id: string): Promise<void>;
updateWorkflowTags(workflowId: string, tagIds: string[]): Promise<Tag[]>;
getSourceControlStatus(): Promise<SourceControlStatus>;
pullSourceControl(force?: boolean): Promise<SourceControlPullResult>;
pushSourceControl(message: string, fileNames?: string[]): Promise<SourceControlPushResult>;
@@ -43,6 +45,28 @@ export declare class N8nApiClient {
createVariable(variable: Partial<Variable>): Promise<Variable>;
updateVariable(id: string, variable: Partial<Variable>): Promise<Variable>;
deleteVariable(id: string): Promise<void>;
createDataTable(params: {
name: string;
columns?: DataTableColumn[];
}): Promise<DataTable>;
listDataTables(params?: DataTableListParams): Promise<{
data: DataTable[];
nextCursor?: string | null;
}>;
getDataTable(id: string): Promise<DataTable>;
updateDataTable(id: string, params: {
name: string;
}): Promise<DataTable>;
deleteDataTable(id: string): Promise<void>;
getDataTableRows(id: string, params?: DataTableRowListParams): Promise<{
data: DataTableRow[];
nextCursor?: string | null;
}>;
insertDataTableRows(id: string, params: DataTableInsertRowsParams): Promise<any>;
updateDataTableRows(id: string, params: DataTableUpdateRowsParams): Promise<any>;
upsertDataTableRow(id: string, params: DataTableUpsertRowParams): Promise<any>;
deleteDataTableRows(id: string, params: DataTableDeleteRowsParams): Promise<any>;
private serializeDataTableParams;
private validateListResponse;
}
//# sourceMappingURL=n8n-api-client.d.ts.map

View File

@@ -1 +1 @@
{"version":3,"file":"n8n-api-client.d.ts","sourceRoot":"","sources":["../../src/services/n8n-api-client.ts"],"names":[],"mappings":"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"}
{"version":3,"file":"n8n-api-client.d.ts","sourceRoot":"","sources":["../../src/services/n8n-api-client.ts"],"names":[],"mappings":"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"}

View File

@@ -194,9 +194,17 @@ class N8nApiClient {
throw (0, n8n_errors_1.handleN8nApiError)(error);
}
}
async transferWorkflow(id, destinationProjectId) {
try {
await this.client.put(`/workflows/${id}/transfer`, { destinationProjectId });
}
catch (error) {
throw (0, n8n_errors_1.handleN8nApiError)(error);
}
}
async activateWorkflow(id) {
try {
const response = await this.client.post(`/workflows/${id}/activate`);
const response = await this.client.post(`/workflows/${id}/activate`, {});
return response.data;
}
catch (error) {
@@ -205,7 +213,7 @@ class N8nApiClient {
}
async deactivateWorkflow(id) {
try {
const response = await this.client.post(`/workflows/${id}/deactivate`);
const response = await this.client.post(`/workflows/${id}/deactivate`, {});
return response.data;
}
catch (error) {
@@ -365,6 +373,15 @@ class N8nApiClient {
throw (0, n8n_errors_1.handleN8nApiError)(error);
}
}
async updateWorkflowTags(workflowId, tagIds) {
try {
const response = await this.client.put(`/workflows/${workflowId}/tags`, tagIds.filter(id => id).map(id => ({ id })));
return response.data;
}
catch (error) {
throw (0, n8n_errors_1.handleN8nApiError)(error);
}
}
async getSourceControlStatus() {
try {
const response = await this.client.get('/source-control/status');
@@ -431,6 +448,110 @@ class N8nApiClient {
throw (0, n8n_errors_1.handleN8nApiError)(error);
}
}
async createDataTable(params) {
try {
const response = await this.client.post('/data-tables', params);
return response.data;
}
catch (error) {
throw (0, n8n_errors_1.handleN8nApiError)(error);
}
}
async listDataTables(params = {}) {
try {
const response = await this.client.get('/data-tables', { params });
return this.validateListResponse(response.data, 'data-tables');
}
catch (error) {
throw (0, n8n_errors_1.handleN8nApiError)(error);
}
}
async getDataTable(id) {
try {
const response = await this.client.get(`/data-tables/${id}`);
return response.data;
}
catch (error) {
throw (0, n8n_errors_1.handleN8nApiError)(error);
}
}
async updateDataTable(id, params) {
try {
const response = await this.client.patch(`/data-tables/${id}`, params);
return response.data;
}
catch (error) {
throw (0, n8n_errors_1.handleN8nApiError)(error);
}
}
async deleteDataTable(id) {
try {
await this.client.delete(`/data-tables/${id}`);
}
catch (error) {
throw (0, n8n_errors_1.handleN8nApiError)(error);
}
}
async getDataTableRows(id, params = {}) {
try {
const response = await this.client.get(`/data-tables/${id}/rows`, {
params,
paramsSerializer: (p) => this.serializeDataTableParams(p),
});
return this.validateListResponse(response.data, 'data-table-rows');
}
catch (error) {
throw (0, n8n_errors_1.handleN8nApiError)(error);
}
}
async insertDataTableRows(id, params) {
try {
const response = await this.client.post(`/data-tables/${id}/rows`, params);
return response.data;
}
catch (error) {
throw (0, n8n_errors_1.handleN8nApiError)(error);
}
}
async updateDataTableRows(id, params) {
try {
const response = await this.client.patch(`/data-tables/${id}/rows/update`, params);
return response.data;
}
catch (error) {
throw (0, n8n_errors_1.handleN8nApiError)(error);
}
}
async upsertDataTableRow(id, params) {
try {
const response = await this.client.post(`/data-tables/${id}/rows/upsert`, params);
return response.data;
}
catch (error) {
throw (0, n8n_errors_1.handleN8nApiError)(error);
}
}
async deleteDataTableRows(id, params) {
try {
const response = await this.client.delete(`/data-tables/${id}/rows/delete`, {
params,
paramsSerializer: (p) => this.serializeDataTableParams(p),
});
return response.data;
}
catch (error) {
throw (0, n8n_errors_1.handleN8nApiError)(error);
}
}
serializeDataTableParams(params) {
const parts = [];
for (const [key, value] of Object.entries(params)) {
if (value === undefined || value === null)
continue;
parts.push(`${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`);
}
return parts.join('&');
}
validateListResponse(responseData, resourceType) {
if (!responseData || typeof responseData !== 'object') {
throw new Error(`Invalid response from n8n API for ${resourceType}: response is not an object`);

File diff suppressed because one or more lines are too long

View File

@@ -144,79 +144,227 @@ export declare const workflowConnectionSchema: z.ZodRecord<z.ZodString, z.ZodObj
node: string;
index: number;
}>, "many">, "many">>;
}, "strip", z.ZodArray<z.ZodArray<z.ZodObject<{
node: z.ZodString;
type: z.ZodString;
index: z.ZodNumber;
}, "strip", z.ZodTypeAny, {
error?: {
type: string;
node: string;
index: number;
}[][] | undefined;
main?: {
type: string;
node: string;
index: number;
}[][] | undefined;
ai_tool?: {
type: string;
node: string;
index: number;
}[][] | undefined;
ai_languageModel?: {
type: string;
node: string;
index: number;
}[][] | undefined;
ai_memory?: {
type: string;
node: string;
index: number;
}[][] | undefined;
ai_embedding?: {
type: string;
node: string;
index: number;
}[][] | undefined;
ai_vectorStore?: {
type: string;
node: string;
index: number;
}[][] | undefined;
type: string;
node: string;
index: number;
}, {
error?: {
type: string;
node: string;
index: number;
}>, "many">, "many">, z.objectOutputType<{
main: z.ZodOptional<z.ZodArray<z.ZodArray<z.ZodObject<{
node: z.ZodString;
type: z.ZodString;
index: z.ZodNumber;
}, "strip", z.ZodTypeAny, {
type: string;
node: string;
index: number;
}[][] | undefined;
main?: {
}, {
type: string;
node: string;
index: number;
}[][] | undefined;
ai_tool?: {
}>, "many">, "many">>;
error: z.ZodOptional<z.ZodArray<z.ZodArray<z.ZodObject<{
node: z.ZodString;
type: z.ZodString;
index: z.ZodNumber;
}, "strip", z.ZodTypeAny, {
type: string;
node: string;
index: number;
}[][] | undefined;
ai_languageModel?: {
}, {
type: string;
node: string;
index: number;
}[][] | undefined;
ai_memory?: {
}>, "many">, "many">>;
ai_tool: z.ZodOptional<z.ZodArray<z.ZodArray<z.ZodObject<{
node: z.ZodString;
type: z.ZodString;
index: z.ZodNumber;
}, "strip", z.ZodTypeAny, {
type: string;
node: string;
index: number;
}[][] | undefined;
ai_embedding?: {
}, {
type: string;
node: string;
index: number;
}[][] | undefined;
ai_vectorStore?: {
}>, "many">, "many">>;
ai_languageModel: z.ZodOptional<z.ZodArray<z.ZodArray<z.ZodObject<{
node: z.ZodString;
type: z.ZodString;
index: z.ZodNumber;
}, "strip", z.ZodTypeAny, {
type: string;
node: string;
index: number;
}[][] | undefined;
}>>;
}, {
type: string;
node: string;
index: number;
}>, "many">, "many">>;
ai_memory: z.ZodOptional<z.ZodArray<z.ZodArray<z.ZodObject<{
node: z.ZodString;
type: z.ZodString;
index: z.ZodNumber;
}, "strip", z.ZodTypeAny, {
type: string;
node: string;
index: number;
}, {
type: string;
node: string;
index: number;
}>, "many">, "many">>;
ai_embedding: z.ZodOptional<z.ZodArray<z.ZodArray<z.ZodObject<{
node: z.ZodString;
type: z.ZodString;
index: z.ZodNumber;
}, "strip", z.ZodTypeAny, {
type: string;
node: string;
index: number;
}, {
type: string;
node: string;
index: number;
}>, "many">, "many">>;
ai_vectorStore: z.ZodOptional<z.ZodArray<z.ZodArray<z.ZodObject<{
node: z.ZodString;
type: z.ZodString;
index: z.ZodNumber;
}, "strip", z.ZodTypeAny, {
type: string;
node: string;
index: number;
}, {
type: string;
node: string;
index: number;
}>, "many">, "many">>;
}, z.ZodArray<z.ZodArray<z.ZodObject<{
node: z.ZodString;
type: z.ZodString;
index: z.ZodNumber;
}, "strip", z.ZodTypeAny, {
type: string;
node: string;
index: number;
}, {
type: string;
node: string;
index: number;
}>, "many">, "many">, "strip">, z.objectInputType<{
main: z.ZodOptional<z.ZodArray<z.ZodArray<z.ZodObject<{
node: z.ZodString;
type: z.ZodString;
index: z.ZodNumber;
}, "strip", z.ZodTypeAny, {
type: string;
node: string;
index: number;
}, {
type: string;
node: string;
index: number;
}>, "many">, "many">>;
error: z.ZodOptional<z.ZodArray<z.ZodArray<z.ZodObject<{
node: z.ZodString;
type: z.ZodString;
index: z.ZodNumber;
}, "strip", z.ZodTypeAny, {
type: string;
node: string;
index: number;
}, {
type: string;
node: string;
index: number;
}>, "many">, "many">>;
ai_tool: z.ZodOptional<z.ZodArray<z.ZodArray<z.ZodObject<{
node: z.ZodString;
type: z.ZodString;
index: z.ZodNumber;
}, "strip", z.ZodTypeAny, {
type: string;
node: string;
index: number;
}, {
type: string;
node: string;
index: number;
}>, "many">, "many">>;
ai_languageModel: z.ZodOptional<z.ZodArray<z.ZodArray<z.ZodObject<{
node: z.ZodString;
type: z.ZodString;
index: z.ZodNumber;
}, "strip", z.ZodTypeAny, {
type: string;
node: string;
index: number;
}, {
type: string;
node: string;
index: number;
}>, "many">, "many">>;
ai_memory: z.ZodOptional<z.ZodArray<z.ZodArray<z.ZodObject<{
node: z.ZodString;
type: z.ZodString;
index: z.ZodNumber;
}, "strip", z.ZodTypeAny, {
type: string;
node: string;
index: number;
}, {
type: string;
node: string;
index: number;
}>, "many">, "many">>;
ai_embedding: z.ZodOptional<z.ZodArray<z.ZodArray<z.ZodObject<{
node: z.ZodString;
type: z.ZodString;
index: z.ZodNumber;
}, "strip", z.ZodTypeAny, {
type: string;
node: string;
index: number;
}, {
type: string;
node: string;
index: number;
}>, "many">, "many">>;
ai_vectorStore: z.ZodOptional<z.ZodArray<z.ZodArray<z.ZodObject<{
node: z.ZodString;
type: z.ZodString;
index: z.ZodNumber;
}, "strip", z.ZodTypeAny, {
type: string;
node: string;
index: number;
}, {
type: string;
node: string;
index: number;
}>, "many">, "many">>;
}, z.ZodArray<z.ZodArray<z.ZodObject<{
node: z.ZodString;
type: z.ZodString;
index: z.ZodNumber;
}, "strip", z.ZodTypeAny, {
type: string;
node: string;
index: number;
}, {
type: string;
node: string;
index: number;
}>, "many">, "many">, "strip">>>;
export declare const workflowSettingsSchema: z.ZodObject<{
executionOrder: z.ZodDefault<z.ZodEnum<["v0", "v1"]>>;
timezone: z.ZodOptional<z.ZodString>;

View File

@@ -1 +1 @@
{"version":3,"file":"n8n-validation.d.ts","sourceRoot":"","sources":["../../src/services/n8n-validation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,YAAY,EAAE,kBAAkB,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAM9E,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAiB7B,CAAC;AAkBH,eAAO,MAAM,wBAAwB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAUpC,CAAC;AAEF,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAWjC,CAAC;AAGH,eAAO,MAAM,uBAAuB;;;;;;CAMnC,CAAC;AAGF,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,OAAO,GAAG,YAAY,CAEhE;AAED,wBAAgB,2BAA2B,CAAC,WAAW,EAAE,OAAO,GAAG,kBAAkB,CAEpF;AAED,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,OAAO,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAElG;AAGD,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,OAAO,CAAC,QAAQ,CAAC,GAAG,OAAO,CAAC,QAAQ,CAAC,CAsBrF;AAiBD,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,CAoE5E;AAGD,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,OAAO,CAAC,QAAQ,CAAC,GAAG,MAAM,EAAE,CA6P/E;AAGD,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAK7D;AAMD,wBAAgB,+BAA+B,CAAC,IAAI,EAAE,YAAY,GAAG,MAAM,EAAE,CA+F5E;AAMD,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CA0D/E;AAGD,wBAAgB,aAAa,CAAC,QAAQ,EAAE,QAAQ,GAAG,MAAM,GAAG,IAAI,CAmB/D;AAGD,wBAAgB,2BAA2B,IAAI,MAAM,CA6CpD;AAGD,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAmBpE"}
{"version":3,"file":"n8n-validation.d.ts","sourceRoot":"","sources":["../../src/services/n8n-validation.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,YAAY,EAAE,kBAAkB,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAM9E,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAiB7B,CAAC;AAkBH,eAAO,MAAM,wBAAwB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;gCAUpC,CAAC;AAEF,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAWjC,CAAC;AAGH,eAAO,MAAM,uBAAuB;;;;;;CAMnC,CAAC;AAGF,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,OAAO,GAAG,YAAY,CAEhE;AAED,wBAAgB,2BAA2B,CAAC,WAAW,EAAE,OAAO,GAAG,kBAAkB,CAEpF;AAED,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,OAAO,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAElG;AAmBD,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,OAAO,CAAC,QAAQ,CAAC,GAAG,OAAO,CAAC,QAAQ,CAAC,CAwBrF;AAiBD,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,CAsE5E;AAGD,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,OAAO,CAAC,QAAQ,CAAC,GAAG,MAAM,EAAE,CAkQ/E;AAGD,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAK7D;AAMD,wBAAgB,+BAA+B,CAAC,IAAI,EAAE,YAAY,GAAG,MAAM,EAAE,CA+F5E;AAMD,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CA0D/E;AAGD,wBAAgB,aAAa,CAAC,QAAQ,EAAE,QAAQ,GAAG,MAAM,GAAG,IAAI,CAmB/D;AAGD,wBAAgB,2BAA2B,IAAI,MAAM,CA6CpD;AAGD,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAmBpE"}

View File

@@ -1,4 +1,7 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.defaultWorkflowSettings = exports.workflowSettingsSchema = exports.workflowConnectionSchema = exports.workflowNodeSchema = void 0;
exports.validateWorkflowNode = validateWorkflowNode;
@@ -13,6 +16,7 @@ exports.validateOperatorStructure = validateOperatorStructure;
exports.getWebhookUrl = getWebhookUrl;
exports.getWorkflowStructureExample = getWorkflowStructureExample;
exports.getWorkflowFixSuggestions = getWorkflowFixSuggestions;
const crypto_1 = __importDefault(require("crypto"));
const zod_1 = require("zod");
const node_type_utils_1 = require("../utils/node-type-utils");
const node_classification_1 = require("../utils/node-classification");
@@ -47,7 +51,7 @@ exports.workflowConnectionSchema = zod_1.z.record(zod_1.z.object({
ai_memory: connectionArraySchema.optional(),
ai_embedding: connectionArraySchema.optional(),
ai_vectorStore: connectionArraySchema.optional(),
}));
}).catchall(connectionArraySchema));
exports.workflowSettingsSchema = zod_1.z.object({
executionOrder: zod_1.z.enum(['v0', 'v1']).default('v1'),
timezone: zod_1.z.string().optional(),
@@ -76,11 +80,27 @@ function validateWorkflowConnections(connections) {
function validateWorkflowSettings(settings) {
return exports.workflowSettingsSchema.parse(settings);
}
const WEBHOOK_NODE_TYPES = new Set([
'n8n-nodes-base.webhook',
'n8n-nodes-base.webhookTrigger',
'n8n-nodes-base.formTrigger',
'@n8n/n8n-nodes-langchain.chatTrigger',
]);
function ensureWebhookIds(nodes) {
if (!nodes)
return;
for (const node of nodes) {
if (WEBHOOK_NODE_TYPES.has(node.type) && !node.webhookId) {
node.webhookId = crypto_1.default.randomUUID();
}
}
}
function cleanWorkflowForCreate(workflow) {
const { id, createdAt, updatedAt, versionId, meta, active, tags, ...cleanedWorkflow } = workflow;
if (!cleanedWorkflow.settings || Object.keys(cleanedWorkflow.settings).length === 0) {
cleanedWorkflow.settings = exports.defaultWorkflowSettings;
}
ensureWebhookIds(cleanedWorkflow.nodes);
return cleanedWorkflow;
}
function cleanWorkflowForUpdate(workflow) {
@@ -116,6 +136,7 @@ function cleanWorkflowForUpdate(workflow) {
else {
cleanedWorkflow.settings = { executionOrder: 'v1' };
}
ensureWebhookIds(cleanedWorkflow.nodes);
return cleanedWorkflow;
}
function validateWorkflowStructure(workflow) {
@@ -152,11 +173,10 @@ function validateWorkflowStructure(workflow) {
}
else if (connectionCount > 0 || executableNodes.length > 1) {
const connectedNodes = new Set();
const ALL_CONNECTION_TYPES = ['main', 'error', 'ai_tool', 'ai_languageModel', 'ai_memory', 'ai_embedding', 'ai_vectorStore'];
Object.entries(workflow.connections).forEach(([sourceName, connection]) => {
connectedNodes.add(sourceName);
ALL_CONNECTION_TYPES.forEach(connType => {
const connData = connection[connType];
const connectionRecord = connection;
Object.values(connectionRecord).forEach((connData) => {
if (connData && Array.isArray(connData)) {
connData.forEach((outputs) => {
if (Array.isArray(outputs)) {
@@ -282,23 +302,28 @@ function validateWorkflowStructure(workflow) {
errors.push(`Connection references non-existent node: ${sourceName}`);
}
}
if (connection.main && Array.isArray(connection.main)) {
connection.main.forEach((outputs, outputIndex) => {
if (Array.isArray(outputs)) {
outputs.forEach((target, targetIndex) => {
if (!nodeNames.has(target.node)) {
if (nodeIds.has(target.node)) {
const correctName = nodeIdToName.get(target.node);
errors.push(`Connection target uses node ID '${target.node}' but must use node name '${correctName}' (from ${sourceName}[${outputIndex}][${targetIndex}])`);
const connectionRecord = connection;
Object.values(connectionRecord).forEach((connData) => {
if (connData && Array.isArray(connData)) {
connData.forEach((outputs, outputIndex) => {
if (Array.isArray(outputs)) {
outputs.forEach((target, targetIndex) => {
if (!target?.node)
return;
if (!nodeNames.has(target.node)) {
if (nodeIds.has(target.node)) {
const correctName = nodeIdToName.get(target.node);
errors.push(`Connection target uses node ID '${target.node}' but must use node name '${correctName}' (from ${sourceName}[${outputIndex}][${targetIndex}])`);
}
else {
errors.push(`Connection references non-existent target node: ${target.node} (from ${sourceName}[${outputIndex}][${targetIndex}])`);
}
}
else {
errors.push(`Connection references non-existent target node: ${target.node} (from ${sourceName}[${outputIndex}][${targetIndex}])`);
}
}
});
}
});
}
});
}
});
}
});
});
}
return errors;

File diff suppressed because one or more lines are too long

View File

@@ -1 +1 @@
{"version":3,"file":"node-sanitizer.d.ts","sourceRoot":"","sources":["../../src/services/node-sanitizer.ts"],"names":[],"mappings":"AAaA,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAKhD,wBAAgB,YAAY,CAAC,IAAI,EAAE,YAAY,GAAG,YAAY,CAa7D;AAKD,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,GAAG,GAAG,GAAG,CASxD;AAoND,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,YAAY,GAAG,MAAM,EAAE,CAgEjE"}
{"version":3,"file":"node-sanitizer.d.ts","sourceRoot":"","sources":["../../src/services/node-sanitizer.ts"],"names":[],"mappings":"AAaA,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAKhD,wBAAgB,YAAY,CAAC,IAAI,EAAE,YAAY,GAAG,YAAY,CAa7D;AAKD,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,GAAG,GAAG,GAAG,CASxD;AA6ND,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,YAAY,GAAG,MAAM,EAAE,CAgEjE"}

View File

@@ -17,7 +17,7 @@ function sanitizeWorkflowNodes(workflow) {
}
return {
...workflow,
nodes: workflow.nodes.map((node) => sanitizeNode(node))
nodes: workflow.nodes.map(sanitizeNode)
};
}
function isFilterBasedNode(nodeType, typeVersion) {
@@ -66,7 +66,7 @@ function sanitizeFilterConditions(conditions) {
...sanitized.options
};
if (sanitized.conditions && Array.isArray(sanitized.conditions)) {
sanitized.conditions = sanitized.conditions.map((condition) => sanitizeCondition(condition));
sanitized.conditions = sanitized.conditions.map(sanitizeCondition);
}
return sanitized;
}
@@ -124,6 +124,10 @@ function inferDataType(operation) {
if (dateOps.some(op => operation.includes(op))) {
return 'dateTime';
}
const objectOps = ['empty', 'notEmpty', 'exists', 'notExists'];
if (objectOps.includes(operation)) {
return 'object';
}
return 'string';
}
function isUnaryOperator(operation) {
@@ -132,7 +136,11 @@ function isUnaryOperator(operation) {
'isNotEmpty',
'true',
'false',
'isNumeric'
'isNumeric',
'empty',
'notEmpty',
'exists',
'notExists'
];
return unaryOps.includes(operation);
}

File diff suppressed because one or more lines are too long

View File

@@ -1 +1 @@
{"version":3,"file":"node-specific-validators.d.ts","sourceRoot":"","sources":["../../src/services/node-specific-validators.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAExE,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC5B,MAAM,EAAE,eAAe,EAAE,CAAC;IAC1B,QAAQ,EAAE,iBAAiB,EAAE,CAAC;IAC9B,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;CAC9B;AAED,qBAAa,sBAAsB;IAIjC,MAAM,CAAC,aAAa,CAAC,OAAO,EAAE,qBAAqB,GAAG,IAAI;IAqE1D,OAAO,CAAC,MAAM,CAAC,wBAAwB;IAkDvC,OAAO,CAAC,MAAM,CAAC,0BAA0B;IAsBzC,OAAO,CAAC,MAAM,CAAC,0BAA0B;IA4BzC,OAAO,CAAC,MAAM,CAAC,0BAA0B;IA2CzC,MAAM,CAAC,oBAAoB,CAAC,OAAO,EAAE,qBAAqB,GAAG,IAAI;IAiDjE,OAAO,CAAC,MAAM,CAAC,0BAA0B;IA0BzC,OAAO,CAAC,MAAM,CAAC,wBAAwB;IAkBvC,OAAO,CAAC,MAAM,CAAC,0BAA0B;IAsBzC,OAAO,CAAC,MAAM,CAAC,0BAA0B;IA4BzC,OAAO,CAAC,MAAM,CAAC,yBAAyB;IAwCxC,MAAM,CAAC,cAAc,CAAC,OAAO,EAAE,qBAAqB,GAAG,IAAI;IAwF3D,MAAM,CAAC,eAAe,CAAC,OAAO,EAAE,qBAAqB,GAAG,IAAI;IAyG5D,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,qBAAqB,GAAG,IAAI;IAkI7D,MAAM,CAAC,eAAe,CAAC,OAAO,EAAE,qBAAqB,GAAG,IAAI;IAmG5D,MAAM,CAAC,aAAa,CAAC,OAAO,EAAE,qBAAqB,GAAG,IAAI;IA6F1D,OAAO,CAAC,MAAM,CAAC,gBAAgB;IAkF/B,MAAM,CAAC,mBAAmB,CAAC,OAAO,EAAE,qBAAqB,GAAG,IAAI;IAiGhE,MAAM,CAAC,eAAe,CAAC,OAAO,EAAE,qBAAqB,GAAG,IAAI;IA6D5D,MAAM,CAAC,YAAY,CAAC,OAAO,EAAE,qBAAqB,GAAG,IAAI;IA8DzD,OAAO,CAAC,MAAM,CAAC,sBAAsB;IAuDrC,OAAO,CAAC,MAAM,CAAC,kBAAkB;IAuDjC,OAAO,CAAC,MAAM,CAAC,uBAAuB;IAsFtC,OAAO,CAAC,MAAM,CAAC,oBAAoB;IAuKnC,OAAO,CAAC,MAAM,CAAC,oBAAoB;IA2EnC,MAAM,CAAC,WAAW,CAAC,OAAO,EAAE,qBAAqB,GAAG,IAAI;CAoDzD"}
{"version":3,"file":"node-specific-validators.d.ts","sourceRoot":"","sources":["../../src/services/node-specific-validators.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAExE,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC5B,MAAM,EAAE,eAAe,EAAE,CAAC;IAC1B,QAAQ,EAAE,iBAAiB,EAAE,CAAC;IAC9B,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;CAC9B;AAED,qBAAa,sBAAsB;IAIjC,MAAM,CAAC,aAAa,CAAC,OAAO,EAAE,qBAAqB,GAAG,IAAI;IAqE1D,OAAO,CAAC,MAAM,CAAC,wBAAwB;IAkDvC,OAAO,CAAC,MAAM,CAAC,0BAA0B;IAsBzC,OAAO,CAAC,MAAM,CAAC,0BAA0B;IA4BzC,OAAO,CAAC,MAAM,CAAC,0BAA0B;IA2CzC,MAAM,CAAC,oBAAoB,CAAC,OAAO,EAAE,qBAAqB,GAAG,IAAI;IAiDjE,OAAO,CAAC,MAAM,CAAC,0BAA0B;IA0BzC,OAAO,CAAC,MAAM,CAAC,wBAAwB;IAkBvC,OAAO,CAAC,MAAM,CAAC,0BAA0B;IAsBzC,OAAO,CAAC,MAAM,CAAC,0BAA0B;IA4BzC,OAAO,CAAC,MAAM,CAAC,yBAAyB;IAwCxC,MAAM,CAAC,cAAc,CAAC,OAAO,EAAE,qBAAqB,GAAG,IAAI;IAwF3D,MAAM,CAAC,eAAe,CAAC,OAAO,EAAE,qBAAqB,GAAG,IAAI;IAyG5D,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,qBAAqB,GAAG,IAAI;IAkI7D,MAAM,CAAC,eAAe,CAAC,OAAO,EAAE,qBAAqB,GAAG,IAAI;IAmG5D,MAAM,CAAC,aAAa,CAAC,OAAO,EAAE,qBAAqB,GAAG,IAAI;IA6F1D,OAAO,CAAC,MAAM,CAAC,gBAAgB;IAkF/B,MAAM,CAAC,mBAAmB,CAAC,OAAO,EAAE,qBAAqB,GAAG,IAAI;IAiGhE,MAAM,CAAC,eAAe,CAAC,OAAO,EAAE,qBAAqB,GAAG,IAAI;IA6D5D,MAAM,CAAC,YAAY,CAAC,OAAO,EAAE,qBAAqB,GAAG,IAAI;IA8DzD,OAAO,CAAC,MAAM,CAAC,sBAAsB;IAuDrC,OAAO,CAAC,MAAM,CAAC,kBAAkB;IAuDjC,OAAO,CAAC,MAAM,CAAC,uBAAuB;IAyFtC,OAAO,CAAC,MAAM,CAAC,oBAAoB;IAuKnC,OAAO,CAAC,MAAM,CAAC,oBAAoB;IA2EnC,MAAM,CAAC,WAAW,CAAC,OAAO,EAAE,qBAAqB,GAAG,IAAI;CAoDzD"}

View File

@@ -1067,7 +1067,8 @@ class NodeSpecificValidators {
fix: 'Wrap in array: return [{json: yourObject}]'
});
}
if (/return\s+(true|false|null|undefined|\d+|['"`])/m.test(code)) {
const hasHelperFunctions = /(?:function\s+\w+\s*\(|(?:const|let|var)\s+\w+\s*=\s*(?:async\s+)?(?:function|\([^)]*\)\s*=>|\w+\s*=>))/.test(code);
if (!hasHelperFunctions && /return\s+(true|false|null|undefined|\d+|['"`])/m.test(code)) {
errors.push({
type: 'invalid_value',
property: 'jsCode',
@@ -1149,7 +1150,7 @@ class NodeSpecificValidators {
}
});
if (language === 'javaScript') {
if (/\$(?![a-zA-Z])/.test(code) && !code.includes('${')) {
if (/\$(?![a-zA-Z_(])/.test(code) && !code.includes('${')) {
warnings.push({
type: 'best_practice',
message: 'Invalid $ usage detected',

File diff suppressed because one or more lines are too long

View File

@@ -1 +1 @@
{"version":3,"file":"workflow-auto-fixer.d.ts","sourceRoot":"","sources":["../../src/services/workflow-auto-fixer.ts"],"names":[],"mappings":"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"}
{"version":3,"file":"workflow-auto-fixer.d.ts","sourceRoot":"","sources":["../../src/services/workflow-auto-fixer.ts"],"names":[],"mappings":"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"}

View File

@@ -405,7 +405,7 @@ class WorkflowAutoFixer {
const hasConnectionFixes = filteredFixes.some(f => exports.CONNECTION_FIX_TYPES.includes(f.type));
return operations.filter(op => {
if (op.type === 'updateNode') {
return fixedNodes.has(op.nodeId || '');
return fixedNodes.has(op.nodeName || '') || fixedNodes.has(op.nodeId || '');
}
if (op.type === 'replaceConnections') {
return hasConnectionFixes;
@@ -794,6 +794,7 @@ class WorkflowAutoFixer {
const operation = {
type: 'updateNode',
nodeId: node.id,
nodeName: node.name,
updates: {
typeVersion: parseFloat(latestVersion),
parameters: migrationResult.updatedNode.parameters,

File diff suppressed because one or more lines are too long

View File

@@ -3,6 +3,11 @@ import { Workflow } from '../types/n8n-api';
export declare class WorkflowDiffEngine {
private renameMap;
private warnings;
private modifiedNodeIds;
private removedNodeNames;
private tagsToAdd;
private tagsToRemove;
private transferToProjectId;
applyDiff(workflow: Workflow, request: WorkflowDiffRequest): Promise<WorkflowDiffResult>;
private validateOperation;
private applyOperation;
@@ -32,6 +37,8 @@ export declare class WorkflowDiffEngine {
private validateDeactivateWorkflow;
private applyActivateWorkflow;
private applyDeactivateWorkflow;
private validateTransferWorkflow;
private applyTransferWorkflow;
private validateCleanStaleConnections;
private validateReplaceConnections;
private applyCleanStaleConnections;

View File

@@ -1 +1 @@
{"version":3,"file":"workflow-diff-engine.d.ts","sourceRoot":"","sources":["../../src/services/workflow-diff-engine.ts"],"names":[],"mappings":"AAMA,OAAO,EAEL,mBAAmB,EACnB,kBAAkB,EAsBnB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,QAAQ,EAAoC,MAAM,kBAAkB,CAAC;AAQ9E,qBAAa,kBAAkB;IAE7B,OAAO,CAAC,SAAS,CAAkC;IAEnD,OAAO,CAAC,QAAQ,CAAqC;IAK/C,SAAS,CACb,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,mBAAmB,GAC3B,OAAO,CAAC,kBAAkB,CAAC;IA0M9B,OAAO,CAAC,iBAAiB;IAwCzB,OAAO,CAAC,cAAc;IAyDtB,OAAO,CAAC,eAAe;IAwBvB,OAAO,CAAC,kBAAkB;IAuB1B,OAAO,CAAC,kBAAkB;IAoC1B,OAAO,CAAC,gBAAgB;IAQxB,OAAO,CAAC,kBAAkB;IAU1B,OAAO,CAAC,qBAAqB;IAkD7B,OAAO,CAAC,wBAAwB;IAuChC,OAAO,CAAC,wBAAwB;IAmDhC,OAAO,CAAC,YAAY;IA2BpB,OAAO,CAAC,eAAe;IAkCvB,OAAO,CAAC,eAAe;IAwBvB,OAAO,CAAC,aAAa;IAOrB,OAAO,CAAC,eAAe;IAOvB,OAAO,CAAC,gBAAgB;IAWxB,OAAO,CAAC,sBAAsB;IAgD9B,OAAO,CAAC,kBAAkB;IA4C1B,OAAO,CAAC,qBAAqB;IA2C7B,OAAO,CAAC,qBAAqB;IA0B7B,OAAO,CAAC,mBAAmB;IAW3B,OAAO,CAAC,eAAe;IAIvB,OAAO,CAAC,WAAW;IASnB,OAAO,CAAC,cAAc;IAUtB,OAAO,CAAC,wBAAwB;IAchC,OAAO,CAAC,0BAA0B;IAMlC,OAAO,CAAC,qBAAqB;IAM7B,OAAO,CAAC,uBAAuB;IAO/B,OAAO,CAAC,6BAA6B;IAKrC,OAAO,CAAC,0BAA0B;IA0BlC,OAAO,CAAC,0BAA0B;IA0ElC,OAAO,CAAC,uBAAuB;IAe/B,OAAO,CAAC,0BAA0B;IAkElC,OAAO,CAAC,iBAAiB;IAkBzB,OAAO,CAAC,QAAQ;IAsChB,OAAO,CAAC,uBAAuB;IAW/B,OAAO,CAAC,iBAAiB;CAc1B"}
{"version":3,"file":"workflow-diff-engine.d.ts","sourceRoot":"","sources":["../../src/services/workflow-diff-engine.ts"],"names":[],"mappings":"AAMA,OAAO,EAEL,mBAAmB,EACnB,kBAAkB,EAuBnB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,QAAQ,EAAoC,MAAM,kBAAkB,CAAC;AAY9E,qBAAa,kBAAkB;IAE7B,OAAO,CAAC,SAAS,CAAkC;IAEnD,OAAO,CAAC,QAAQ,CAAqC;IAErD,OAAO,CAAC,eAAe,CAAqB;IAE5C,OAAO,CAAC,gBAAgB,CAAqB;IAE7C,OAAO,CAAC,SAAS,CAAgB;IACjC,OAAO,CAAC,YAAY,CAAgB;IAEpC,OAAO,CAAC,mBAAmB,CAAqB;IAK1C,SAAS,CACb,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,mBAAmB,GAC3B,OAAO,CAAC,kBAAkB,CAAC;IAgO9B,OAAO,CAAC,iBAAiB;IA0CzB,OAAO,CAAC,cAAc;IA4DtB,OAAO,CAAC,eAAe;IAwBvB,OAAO,CAAC,kBAAkB;IAuB1B,OAAO,CAAC,kBAAkB;IAoC1B,OAAO,CAAC,gBAAgB;IAQxB,OAAO,CAAC,kBAAkB;IAU1B,OAAO,CAAC,qBAAqB;IAkD7B,OAAO,CAAC,wBAAwB;IA6ChC,OAAO,CAAC,wBAAwB;IAmDhC,OAAO,CAAC,YAAY;IA4BpB,OAAO,CAAC,eAAe;IAwCvB,OAAO,CAAC,eAAe;IA0BvB,OAAO,CAAC,aAAa;IAOrB,OAAO,CAAC,eAAe;IAOvB,OAAO,CAAC,gBAAgB;IAWxB,OAAO,CAAC,sBAAsB;IAwD9B,OAAO,CAAC,kBAAkB;IA6C1B,OAAO,CAAC,qBAAqB;IAuC7B,OAAO,CAAC,qBAAqB;IA0B7B,OAAO,CAAC,mBAAmB;IAW3B,OAAO,CAAC,eAAe;IAIvB,OAAO,CAAC,WAAW;IAYnB,OAAO,CAAC,cAAc;IAatB,OAAO,CAAC,wBAAwB;IAchC,OAAO,CAAC,0BAA0B;IAMlC,OAAO,CAAC,qBAAqB;IAM7B,OAAO,CAAC,uBAAuB;IAO/B,OAAO,CAAC,wBAAwB;IAOhC,OAAO,CAAC,qBAAqB;IAK7B,OAAO,CAAC,6BAA6B;IAKrC,OAAO,CAAC,0BAA0B;IA0BlC,OAAO,CAAC,0BAA0B;IA+ElC,OAAO,CAAC,uBAAuB;IAe/B,OAAO,CAAC,0BAA0B;IAmElC,OAAO,CAAC,iBAAiB;IAkBzB,OAAO,CAAC,QAAQ;IAsChB,OAAO,CAAC,uBAAuB;IAW/B,OAAO,CAAC,iBAAiB;CAoB1B"}

View File

@@ -10,11 +10,20 @@ class WorkflowDiffEngine {
constructor() {
this.renameMap = new Map();
this.warnings = [];
this.modifiedNodeIds = new Set();
this.removedNodeNames = new Set();
this.tagsToAdd = [];
this.tagsToRemove = [];
}
async applyDiff(workflow, request) {
try {
this.renameMap.clear();
this.warnings = [];
this.modifiedNodeIds.clear();
this.removedNodeNames.clear();
this.tagsToAdd = [];
this.tagsToRemove = [];
this.transferToProjectId = undefined;
const workflowCopy = JSON.parse(JSON.stringify(workflow));
const nodeOperationTypes = ['addNode', 'removeNode', 'updateNode', 'moveNode', 'enableNode', 'disableNode'];
const nodeOperations = [];
@@ -73,6 +82,10 @@ class WorkflowDiffEngine {
failed: failedIndices
};
}
const shouldActivate = workflowCopy._shouldActivate === true;
const shouldDeactivate = workflowCopy._shouldDeactivate === true;
delete workflowCopy._shouldActivate;
delete workflowCopy._shouldDeactivate;
const success = appliedIndices.length > 0;
return {
success,
@@ -82,7 +95,12 @@ class WorkflowDiffEngine {
errors: errors.length > 0 ? errors : undefined,
warnings: this.warnings.length > 0 ? this.warnings : undefined,
applied: appliedIndices,
failed: failedIndices
failed: failedIndices,
shouldActivate: shouldActivate || undefined,
shouldDeactivate: shouldDeactivate || undefined,
tagsToAdd: this.tagsToAdd.length > 0 ? this.tagsToAdd : undefined,
tagsToRemove: this.tagsToRemove.length > 0 ? this.tagsToRemove : undefined,
transferToProjectId: this.transferToProjectId || undefined
};
}
else {
@@ -142,8 +160,15 @@ class WorkflowDiffEngine {
};
}
}
workflowCopy.nodes = workflowCopy.nodes.map((node) => (0, node_sanitizer_1.sanitizeNode)(node));
logger.debug('Applied full-workflow sanitization to all nodes');
if (this.modifiedNodeIds.size > 0) {
workflowCopy.nodes = workflowCopy.nodes.map((node) => {
if (this.modifiedNodeIds.has(node.id)) {
return (0, node_sanitizer_1.sanitizeNode)(node);
}
return node;
});
logger.debug(`Sanitized ${this.modifiedNodeIds.size} modified nodes`);
}
if (request.validateOnly) {
return {
success: true,
@@ -162,7 +187,10 @@ class WorkflowDiffEngine {
message: `Successfully applied ${operationsApplied} operations (${nodeOperations.length} node ops, ${otherOperations.length} other ops)`,
warnings: this.warnings.length > 0 ? this.warnings : undefined,
shouldActivate: shouldActivate || undefined,
shouldDeactivate: shouldDeactivate || undefined
shouldDeactivate: shouldDeactivate || undefined,
tagsToAdd: this.tagsToAdd.length > 0 ? this.tagsToAdd : undefined,
tagsToRemove: this.tagsToRemove.length > 0 ? this.tagsToRemove : undefined,
transferToProjectId: this.transferToProjectId || undefined
};
}
}
@@ -201,6 +229,8 @@ class WorkflowDiffEngine {
case 'addTag':
case 'removeTag':
return null;
case 'transferWorkflow':
return this.validateTransferWorkflow(workflow, operation);
case 'activateWorkflow':
return this.validateActivateWorkflow(workflow, operation);
case 'deactivateWorkflow':
@@ -266,6 +296,9 @@ class WorkflowDiffEngine {
case 'replaceConnections':
this.applyReplaceConnections(workflow, operation);
break;
case 'transferWorkflow':
this.applyTransferWorkflow(workflow, operation);
break;
}
}
validateAddNode(workflow, operation) {
@@ -302,7 +335,7 @@ class WorkflowDiffEngine {
return `Invalid parameter 'changes'. The updateNode operation requires 'updates' (not 'changes'). Example: {type: "updateNode", nodeId: "abc", updates: {name: "New Name", "parameters.url": "https://example.com"}}`;
}
if (!operation.updates) {
return `Missing required parameter 'updates'. The updateNode operation requires an 'updates' object containing properties to modify. Example: {type: "updateNode", nodeId: "abc", updates: {name: "New Name"}}`;
return `Missing required parameter 'updates'. The updateNode operation requires an 'updates' object. Correct structure: {type: "updateNode", nodeId: "abc-123" OR nodeName: "My Node", updates: {name: "New Name", "parameters.url": "https://example.com"}}`;
}
const node = this.findNode(workflow, operation.nodeId, operation.nodeName);
if (!node) {
@@ -382,12 +415,18 @@ class WorkflowDiffEngine {
const sourceNode = this.findNode(workflow, operation.source, operation.source);
const targetNode = this.findNode(workflow, operation.target, operation.target);
if (!sourceNode) {
if (this.removedNodeNames.has(operation.source)) {
return `Source node "${operation.source}" was already removed by a prior removeNode operation. Its connections were automatically cleaned up — no separate removeConnection needed.`;
}
const availableNodes = workflow.nodes
.map(n => `"${n.name}" (id: ${n.id.substring(0, 8)}...)`)
.join(', ');
return `Source node not found: "${operation.source}". Available nodes: ${availableNodes}. Tip: Use node ID for names with special characters.`;
}
if (!targetNode) {
if (this.removedNodeNames.has(operation.target)) {
return `Target node "${operation.target}" was already removed by a prior removeNode operation. Its connections were automatically cleaned up — no separate removeConnection needed.`;
}
const availableNodes = workflow.nodes
.map(n => `"${n.name}" (id: ${n.id.substring(0, 8)}...)`)
.join(', ');
@@ -461,34 +500,40 @@ class WorkflowDiffEngine {
executeOnce: operation.node.executeOnce
};
const sanitizedNode = (0, node_sanitizer_1.sanitizeNode)(newNode);
this.modifiedNodeIds.add(sanitizedNode.id);
workflow.nodes.push(sanitizedNode);
}
applyRemoveNode(workflow, operation) {
const node = this.findNode(workflow, operation.nodeId, operation.nodeName);
if (!node)
return;
this.removedNodeNames.add(node.name);
const index = workflow.nodes.findIndex(n => n.id === node.id);
if (index !== -1) {
workflow.nodes.splice(index, 1);
}
delete workflow.connections[node.name];
Object.keys(workflow.connections).forEach(sourceName => {
const sourceConnections = workflow.connections[sourceName];
Object.keys(sourceConnections).forEach(outputName => {
sourceConnections[outputName] = sourceConnections[outputName].map(connections => connections.filter(conn => conn.node !== node.name)).filter(connections => connections.length > 0);
if (sourceConnections[outputName].length === 0) {
for (const [sourceName, sourceConnections] of Object.entries(workflow.connections)) {
for (const [outputName, outputConns] of Object.entries(sourceConnections)) {
sourceConnections[outputName] = outputConns.map(connections => connections.filter(conn => conn.node !== node.name));
const trimmed = sourceConnections[outputName];
while (trimmed.length > 0 && trimmed[trimmed.length - 1].length === 0) {
trimmed.pop();
}
if (trimmed.length === 0) {
delete sourceConnections[outputName];
}
});
}
if (Object.keys(sourceConnections).length === 0) {
delete workflow.connections[sourceName];
}
});
}
}
applyUpdateNode(workflow, operation) {
const node = this.findNode(workflow, operation.nodeId, operation.nodeName);
if (!node)
return;
this.modifiedNodeIds.add(node.id);
if (operation.updates.name && operation.updates.name !== node.name) {
const oldName = node.name;
const newName = operation.updates.name;
@@ -521,8 +566,13 @@ class WorkflowDiffEngine {
}
resolveSmartParameters(workflow, operation) {
const sourceNode = this.findNode(workflow, operation.source, operation.source);
let sourceOutput = operation.sourceOutput ?? 'main';
let sourceOutput = String(operation.sourceOutput ?? 'main');
let sourceIndex = operation.sourceIndex ?? 0;
if (/^\d+$/.test(sourceOutput) && operation.sourceIndex === undefined
&& operation.branch === undefined && operation.case === undefined) {
sourceIndex = parseInt(sourceOutput, 10);
sourceOutput = 'main';
}
if (operation.branch !== undefined && operation.sourceIndex === undefined) {
if (sourceNode?.type === 'n8n-nodes-base.if') {
sourceIndex = operation.branch === 'true' ? 0 : 1;
@@ -556,7 +606,7 @@ class WorkflowDiffEngine {
if (!sourceNode || !targetNode)
return;
const { sourceOutput, sourceIndex } = this.resolveSmartParameters(workflow, operation);
const targetInput = operation.targetInput ?? sourceOutput;
const targetInput = String(operation.targetInput ?? sourceOutput);
const targetIndex = operation.targetIndex ?? 0;
if (!workflow.connections[sourceNode.name]) {
workflow.connections[sourceNode.name] = {};
@@ -581,12 +631,9 @@ class WorkflowDiffEngine {
const sourceNode = this.findNode(workflow, operation.source, operation.source);
const targetNode = this.findNode(workflow, operation.target, operation.target);
if (!sourceNode || !targetNode) {
if (operation.ignoreErrors) {
return;
}
return;
}
const sourceOutput = operation.sourceOutput || 'main';
const sourceOutput = String(operation.sourceOutput ?? 'main');
const connections = workflow.connections[sourceNode.name]?.[sourceOutput];
if (!connections)
return;
@@ -633,19 +680,21 @@ class WorkflowDiffEngine {
workflow.name = operation.name;
}
applyAddTag(workflow, operation) {
if (!workflow.tags) {
workflow.tags = [];
const removeIdx = this.tagsToRemove.indexOf(operation.tag);
if (removeIdx !== -1) {
this.tagsToRemove.splice(removeIdx, 1);
}
if (!workflow.tags.includes(operation.tag)) {
workflow.tags.push(operation.tag);
if (!this.tagsToAdd.includes(operation.tag)) {
this.tagsToAdd.push(operation.tag);
}
}
applyRemoveTag(workflow, operation) {
if (!workflow.tags)
return;
const index = workflow.tags.indexOf(operation.tag);
if (index !== -1) {
workflow.tags.splice(index, 1);
const addIdx = this.tagsToAdd.indexOf(operation.tag);
if (addIdx !== -1) {
this.tagsToAdd.splice(addIdx, 1);
}
if (!this.tagsToRemove.includes(operation.tag)) {
this.tagsToRemove.push(operation.tag);
}
}
validateActivateWorkflow(workflow, operation) {
@@ -664,6 +713,15 @@ class WorkflowDiffEngine {
applyDeactivateWorkflow(workflow, operation) {
workflow._shouldDeactivate = true;
}
validateTransferWorkflow(_workflow, operation) {
if (!operation.destinationProjectId) {
return 'transferWorkflow requires a non-empty destinationProjectId string';
}
return null;
}
applyTransferWorkflow(_workflow, operation) {
this.transferToProjectId = operation.destinationProjectId;
}
validateCleanStaleConnections(workflow, operation) {
return null;
}
@@ -734,7 +792,10 @@ class WorkflowDiffEngine {
return false;
}
return true;
})).filter(conns => conns.length > 0);
}));
while (filteredConnections.length > 0 && filteredConnections[filteredConnections.length - 1].length === 0) {
filteredConnections.pop();
}
if (filteredConnections.length === 0) {
delete outputs[outputName];
}
@@ -768,9 +829,10 @@ class WorkflowDiffEngine {
for (let connIndex = 0; connIndex < connectionsAtIndex.length; connIndex++) {
const connection = connectionsAtIndex[connIndex];
if (renames.has(connection.node)) {
const oldTargetName = connection.node;
const newTargetName = renames.get(connection.node);
connection.node = newTargetName;
logger.debug(`Updated connection: ${sourceName}[${outputType}][${outputIndex}][${connIndex}].node: "${connection.node}" → "${newTargetName}"`);
logger.debug(`Updated connection: ${sourceName}[${outputType}][${outputIndex}][${connIndex}].node: "${oldTargetName}" → "${newTargetName}"`);
}
}
}
@@ -818,12 +880,20 @@ class WorkflowDiffEngine {
let current = obj;
for (let i = 0; i < keys.length - 1; i++) {
const key = keys[i];
if (!(key in current) || typeof current[key] !== 'object') {
if (!(key in current) || typeof current[key] !== 'object' || current[key] === null) {
if (value === null)
return;
current[key] = {};
}
current = current[key];
}
current[keys[keys.length - 1]] = value;
const finalKey = keys[keys.length - 1];
if (value === null) {
delete current[finalKey];
}
else {
current[finalKey] = value;
}
}
}
exports.WorkflowDiffEngine = WorkflowDiffEngine;

File diff suppressed because one or more lines are too long

View File

@@ -259,6 +259,7 @@ export interface WebhookRequest {
}
export interface McpToolResponse {
success: boolean;
saved?: boolean;
data?: unknown;
error?: string;
message?: string;
@@ -266,6 +267,7 @@ export interface McpToolResponse {
details?: Record<string, unknown>;
executionId?: string;
workflowId?: string;
operationsApplied?: number;
}
export type ExecutionMode = 'preview' | 'summary' | 'filtered' | 'full' | 'error';
export interface ExecutionPreview {
@@ -372,4 +374,69 @@ export interface ErrorSuggestion {
description: string;
confidence: 'high' | 'medium' | 'low';
}
export interface DataTableColumn {
name: string;
type?: 'string' | 'number' | 'boolean' | 'date';
}
export interface DataTableColumnResponse {
id: string;
name: string;
type: 'string' | 'number' | 'boolean' | 'date';
index: number;
}
export interface DataTable {
id: string;
name: string;
columns?: DataTableColumnResponse[];
projectId?: string;
createdAt?: string;
updatedAt?: string;
}
export interface DataTableRow {
id?: number;
createdAt?: string;
updatedAt?: string;
[columnName: string]: unknown;
}
export interface DataTableFilterCondition {
columnName: string;
condition: 'eq' | 'neq' | 'like' | 'ilike' | 'gt' | 'gte' | 'lt' | 'lte';
value?: any;
}
export interface DataTableFilter {
type?: 'and' | 'or';
filters: DataTableFilterCondition[];
}
export interface DataTableListParams {
limit?: number;
cursor?: string;
}
export interface DataTableRowListParams {
limit?: number;
cursor?: string;
filter?: string;
sortBy?: string;
search?: string;
}
export interface DataTableInsertRowsParams {
data: Record<string, unknown>[];
returnType?: 'count' | 'id' | 'all';
}
export interface DataTableUpdateRowsParams {
filter: DataTableFilter;
data: Record<string, unknown>;
returnData?: boolean;
dryRun?: boolean;
}
export interface DataTableUpsertRowParams {
filter: DataTableFilter;
data: Record<string, unknown>;
returnData?: boolean;
dryRun?: boolean;
}
export interface DataTableDeleteRowsParams {
filter: string;
returnData?: boolean;
dryRun?: boolean;
}
//# sourceMappingURL=n8n-api.d.ts.map

File diff suppressed because one or more lines are too long

View File

@@ -94,6 +94,10 @@ export interface ActivateWorkflowOperation extends DiffOperation {
export interface DeactivateWorkflowOperation extends DiffOperation {
type: 'deactivateWorkflow';
}
export interface TransferWorkflowOperation extends DiffOperation {
type: 'transferWorkflow';
destinationProjectId: string;
}
export interface CleanStaleConnectionsOperation extends DiffOperation {
type: 'cleanStaleConnections';
dryRun?: boolean;
@@ -110,7 +114,7 @@ export interface ReplaceConnectionsOperation extends DiffOperation {
};
};
}
export type WorkflowDiffOperation = AddNodeOperation | RemoveNodeOperation | UpdateNodeOperation | MoveNodeOperation | EnableNodeOperation | DisableNodeOperation | AddConnectionOperation | RemoveConnectionOperation | RewireConnectionOperation | UpdateSettingsOperation | UpdateNameOperation | AddTagOperation | RemoveTagOperation | ActivateWorkflowOperation | DeactivateWorkflowOperation | CleanStaleConnectionsOperation | ReplaceConnectionsOperation;
export type WorkflowDiffOperation = AddNodeOperation | RemoveNodeOperation | UpdateNodeOperation | MoveNodeOperation | EnableNodeOperation | DisableNodeOperation | AddConnectionOperation | RemoveConnectionOperation | RewireConnectionOperation | UpdateSettingsOperation | UpdateNameOperation | AddTagOperation | RemoveTagOperation | ActivateWorkflowOperation | DeactivateWorkflowOperation | CleanStaleConnectionsOperation | ReplaceConnectionsOperation | TransferWorkflowOperation;
export interface WorkflowDiffRequest {
id: string;
operations: WorkflowDiffOperation[];
@@ -137,6 +141,9 @@ export interface WorkflowDiffResult {
}>;
shouldActivate?: boolean;
shouldDeactivate?: boolean;
tagsToAdd?: string[];
tagsToRemove?: string[];
transferToProjectId?: string;
}
export interface NodeReference {
id?: string;

View File

@@ -1 +1 @@
{"version":3,"file":"workflow-diff.d.ts","sourceRoot":"","sources":["../../src/types/workflow-diff.ts"],"names":[],"mappings":"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"}
{"version":3,"file":"workflow-diff.d.ts","sourceRoot":"","sources":["../../src/types/workflow-diff.ts"],"names":[],"mappings":"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"}

View File

@@ -1 +1 @@
{"version":3,"file":"workflow-diff.js","sourceRoot":"","sources":["../../src/types/workflow-diff.ts"],"names":[],"mappings":";;AAyMA,0CAIC;AAED,sDAGC;AAED,kDAGC;AAdD,SAAgB,eAAe,CAAC,EAAyB;IAGvD,OAAO,CAAC,SAAS,EAAE,YAAY,EAAE,YAAY,EAAE,UAAU,EAAE,YAAY,EAAE,aAAa,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC;AAC5G,CAAC;AAED,SAAgB,qBAAqB,CAAC,EAAyB;IAE7D,OAAO,CAAC,eAAe,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,uBAAuB,EAAE,oBAAoB,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC;AACpI,CAAC;AAED,SAAgB,mBAAmB,CAAC,EAAyB;IAE3D,OAAO,CAAC,gBAAgB,EAAE,YAAY,EAAE,QAAQ,EAAE,WAAW,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC;AACnF,CAAC"}
{"version":3,"file":"workflow-diff.js","sourceRoot":"","sources":["../../src/types/workflow-diff.ts"],"names":[],"mappings":";;AAkNA,0CAIC;AAED,sDAGC;AAED,kDAGC;AAdD,SAAgB,eAAe,CAAC,EAAyB;IAGvD,OAAO,CAAC,SAAS,EAAE,YAAY,EAAE,YAAY,EAAE,UAAU,EAAE,YAAY,EAAE,aAAa,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC;AAC5G,CAAC;AAED,SAAgB,qBAAqB,CAAC,EAAyB;IAE7D,OAAO,CAAC,eAAe,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,uBAAuB,EAAE,oBAAoB,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC;AACpI,CAAC;AAED,SAAgB,mBAAmB,CAAC,EAAyB;IAE3D,OAAO,CAAC,gBAAgB,EAAE,YAAY,EAAE,QAAQ,EAAE,WAAW,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC;AACnF,CAAC"}

View File

@@ -8,7 +8,7 @@ export declare class N8nAuthenticationError extends N8nApiError {
constructor(message?: string);
}
export declare class N8nNotFoundError extends N8nApiError {
constructor(resource: string, id?: string);
constructor(messageOrResource: string, id?: string);
}
export declare class N8nValidationError extends N8nApiError {
constructor(message: string, details?: unknown);

View File

@@ -1 +1 @@
{"version":3,"file":"n8n-errors.d.ts","sourceRoot":"","sources":["../../src/utils/n8n-errors.ts"],"names":[],"mappings":"AAIA,qBAAa,WAAY,SAAQ,KAAK;IAG3B,UAAU,CAAC,EAAE,MAAM;IACnB,IAAI,CAAC,EAAE,MAAM;IACb,OAAO,CAAC,EAAE,OAAO;gBAHxB,OAAO,EAAE,MAAM,EACR,UAAU,CAAC,EAAE,MAAM,YAAA,EACnB,IAAI,CAAC,EAAE,MAAM,YAAA,EACb,OAAO,CAAC,EAAE,OAAO,YAAA;CAK3B;AAED,qBAAa,sBAAuB,SAAQ,WAAW;gBACzC,OAAO,SAA0B;CAI9C;AAED,qBAAa,gBAAiB,SAAQ,WAAW;gBACnC,QAAQ,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,MAAM;CAK1C;AAED,qBAAa,kBAAmB,SAAQ,WAAW;gBACrC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO;CAI/C;AAED,qBAAa,iBAAkB,SAAQ,WAAW;gBACpC,UAAU,CAAC,EAAE,MAAM;CAOhC;AAED,qBAAa,cAAe,SAAQ,WAAW;gBACjC,OAAO,SAA0B,EAAE,UAAU,SAAM;CAIhE;AAGD,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,GAAG,WAAW,CAuC7D;AAQD,wBAAgB,oBAAoB,CAAC,WAAW,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM,CAGrF;AAMD,wBAAgB,sBAAsB,IAAI,MAAM,CAE/C;AAGD,wBAAgB,2BAA2B,CAAC,KAAK,EAAE,WAAW,GAAG,MAAM,CAmBtE;AAGD,wBAAgB,WAAW,CAAC,KAAK,EAAE,WAAW,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAiBtE"}
{"version":3,"file":"n8n-errors.d.ts","sourceRoot":"","sources":["../../src/utils/n8n-errors.ts"],"names":[],"mappings":"AAIA,qBAAa,WAAY,SAAQ,KAAK;IAG3B,UAAU,CAAC,EAAE,MAAM;IACnB,IAAI,CAAC,EAAE,MAAM;IACb,OAAO,CAAC,EAAE,OAAO;gBAHxB,OAAO,EAAE,MAAM,EACR,UAAU,CAAC,EAAE,MAAM,YAAA,EACnB,IAAI,CAAC,EAAE,MAAM,YAAA,EACb,OAAO,CAAC,EAAE,OAAO,YAAA;CAK3B;AAED,qBAAa,sBAAuB,SAAQ,WAAW;gBACzC,OAAO,SAA0B;CAI9C;AAED,qBAAa,gBAAiB,SAAQ,WAAW;gBACnC,iBAAiB,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,MAAM;CAOnD;AAED,qBAAa,kBAAmB,SAAQ,WAAW;gBACrC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO;CAI/C;AAED,qBAAa,iBAAkB,SAAQ,WAAW;gBACpC,UAAU,CAAC,EAAE,MAAM;CAOhC;AAED,qBAAa,cAAe,SAAQ,WAAW;gBACjC,OAAO,SAA0B,EAAE,UAAU,SAAM;CAIhE;AAGD,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,GAAG,WAAW,CAuC7D;AAQD,wBAAgB,oBAAoB,CAAC,WAAW,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM,CAGrF;AAMD,wBAAgB,sBAAsB,IAAI,MAAM,CAE/C;AAGD,wBAAgB,2BAA2B,CAAC,KAAK,EAAE,WAAW,GAAG,MAAM,CAmBtE;AAGD,wBAAgB,WAAW,CAAC,KAAK,EAAE,WAAW,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAiBtE"}

View File

@@ -25,8 +25,8 @@ class N8nAuthenticationError extends N8nApiError {
}
exports.N8nAuthenticationError = N8nAuthenticationError;
class N8nNotFoundError extends N8nApiError {
constructor(resource, id) {
const message = id ? `${resource} with ID ${id} not found` : `${resource} not found`;
constructor(messageOrResource, id) {
const message = id ? `${messageOrResource} with ID ${id} not found` : messageOrResource;
super(message, 404, 'NOT_FOUND');
this.name = 'N8nNotFoundError';
}
@@ -69,7 +69,7 @@ function handleN8nApiError(error) {
case 401:
return new N8nAuthenticationError(message);
case 404:
return new N8nNotFoundError('Resource', message);
return new N8nNotFoundError(message || 'Resource');
case 400:
return new N8nValidationError(message, data);
case 429:

View File

@@ -1 +1 @@
{"version":3,"file":"n8n-errors.js","sourceRoot":"","sources":["../../src/utils/n8n-errors.ts"],"names":[],"mappings":"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"}
{"version":3,"file":"n8n-errors.js","sourceRoot":"","sources":["../../src/utils/n8n-errors.ts"],"names":[],"mappings":";;;AA0DA,8CAuCC;AAQD,oDAGC;AAMD,wDAEC;AAGD,kEAmBC;AAGD,kCAiBC;AA9JD,qCAAkC;AAIlC,MAAa,WAAY,SAAQ,KAAK;IACpC,YACE,OAAe,EACR,UAAmB,EACnB,IAAa,EACb,OAAiB;QAExB,KAAK,CAAC,OAAO,CAAC,CAAC;QAJR,eAAU,GAAV,UAAU,CAAS;QACnB,SAAI,GAAJ,IAAI,CAAS;QACb,YAAO,GAAP,OAAO,CAAU;QAGxB,IAAI,CAAC,IAAI,GAAG,aAAa,CAAC;IAC5B,CAAC;CACF;AAVD,kCAUC;AAED,MAAa,sBAAuB,SAAQ,WAAW;IACrD,YAAY,OAAO,GAAG,uBAAuB;QAC3C,KAAK,CAAC,OAAO,EAAE,GAAG,EAAE,sBAAsB,CAAC,CAAC;QAC5C,IAAI,CAAC,IAAI,GAAG,wBAAwB,CAAC;IACvC,CAAC;CACF;AALD,wDAKC;AAED,MAAa,gBAAiB,SAAQ,WAAW;IAC/C,YAAY,iBAAyB,EAAE,EAAW;QAGhD,MAAM,OAAO,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG,iBAAiB,YAAY,EAAE,YAAY,CAAC,CAAC,CAAC,iBAAiB,CAAC;QACxF,KAAK,CAAC,OAAO,EAAE,GAAG,EAAE,WAAW,CAAC,CAAC;QACjC,IAAI,CAAC,IAAI,GAAG,kBAAkB,CAAC;IACjC,CAAC;CACF;AARD,4CAQC;AAED,MAAa,kBAAmB,SAAQ,WAAW;IACjD,YAAY,OAAe,EAAE,OAAiB;QAC5C,KAAK,CAAC,OAAO,EAAE,GAAG,EAAE,kBAAkB,EAAE,OAAO,CAAC,CAAC;QACjD,IAAI,CAAC,IAAI,GAAG,oBAAoB,CAAC;IACnC,CAAC;CACF;AALD,gDAKC;AAED,MAAa,iBAAkB,SAAQ,WAAW;IAChD,YAAY,UAAmB;QAC7B,MAAM,OAAO,GAAG,UAAU;YACxB,CAAC,CAAC,oCAAoC,UAAU,UAAU;YAC1D,CAAC,CAAC,qBAAqB,CAAC;QAC1B,KAAK,CAAC,OAAO,EAAE,GAAG,EAAE,kBAAkB,EAAE,EAAE,UAAU,EAAE,CAAC,CAAC;QACxD,IAAI,CAAC,IAAI,GAAG,mBAAmB,CAAC;IAClC,CAAC;CACF;AARD,8CAQC;AAED,MAAa,cAAe,SAAQ,WAAW;IAC7C,YAAY,OAAO,GAAG,uBAAuB,EAAE,UAAU,GAAG,GAAG;QAC7D,KAAK,CAAC,OAAO,EAAE,UAAU,EAAE,cAAc,CAAC,CAAC;QAC3C,IAAI,CAAC,IAAI,GAAG,gBAAgB,CAAC;IAC/B,CAAC;CACF;AALD,wCAKC;AAGD,SAAgB,iBAAiB,CAAC,KAAc;IAC9C,IAAI,KAAK,YAAY,WAAW,EAAE,CAAC;QACjC,OAAO,KAAK,CAAC;IACf,CAAC;IAED,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;QAE3B,MAAM,UAAU,GAAG,KAAY,CAAC;QAChC,IAAI,UAAU,CAAC,QAAQ,EAAE,CAAC;YACxB,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,UAAU,CAAC,QAAQ,CAAC;YAC7C,MAAM,OAAO,GAAG,IAAI,EAAE,OAAO,IAAI,UAAU,CAAC,OAAO,CAAC;YAEpD,QAAQ,MAAM,EAAE,CAAC;gBACf,KAAK,GAAG;oBACN,OAAO,IAAI,sBAAsB,CAAC,OAAO,CAAC,CAAC;gBAC7C,KAAK,GAAG;oBACN,OAAO,IAAI,gBAAgB,CAAC,OAAO,IAAI,UAAU,CAAC,CAAC;gBACrD,KAAK,GAAG;oBACN,OAAO,IAAI,kBAAkB,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;gBAC/C,KAAK,GAAG;oBACN,MAAM,UAAU,GAAG,UAAU,CAAC,QAAQ,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;oBAC9D,OAAO,IAAI,iBAAiB,CAAC,UAAU,CAAC,CAAC,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;gBAC9E;oBACE,IAAI,MAAM,IAAI,GAAG,EAAE,CAAC;wBAClB,OAAO,IAAI,cAAc,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;oBAC7C,CAAC;oBACD,OAAO,IAAI,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,IAAI,CAAC,CAAC;YAC/D,CAAC;QACH,CAAC;aAAM,IAAI,UAAU,CAAC,OAAO,EAAE,CAAC;YAE9B,OAAO,IAAI,WAAW,CAAC,6BAA6B,EAAE,SAAS,EAAE,aAAa,CAAC,CAAC;QAClF,CAAC;aAAM,CAAC;YAEN,OAAO,IAAI,WAAW,CAAC,UAAU,CAAC,OAAO,EAAE,SAAS,EAAE,eAAe,CAAC,CAAC;QACzE,CAAC;IACH,CAAC;IAGD,OAAO,IAAI,WAAW,CAAC,wBAAwB,EAAE,SAAS,EAAE,eAAe,EAAE,KAAK,CAAC,CAAC;AACtF,CAAC;AAQD,SAAgB,oBAAoB,CAAC,WAAmB,EAAE,UAAmB;IAC3E,MAAM,cAAc,GAAG,UAAU,CAAC,CAAC,CAAC,YAAY,UAAU,aAAa,CAAC,CAAC,CAAC,YAAY,CAAC;IACvF,OAAO,GAAG,cAAc,GAAG,WAAW,wCAAwC,WAAW,gDAAgD,CAAC;AAC5I,CAAC;AAMD,SAAgB,sBAAsB;IACpC,OAAO,2IAA2I,CAAC;AACrJ,CAAC;AAGD,SAAgB,2BAA2B,CAAC,KAAkB;IAC5D,QAAQ,KAAK,CAAC,IAAI,EAAE,CAAC;QACnB,KAAK,sBAAsB;YACzB,OAAO,6DAA6D,CAAC;QACvE,KAAK,WAAW;YACd,OAAO,KAAK,CAAC,OAAO,CAAC;QACvB,KAAK,kBAAkB;YACrB,OAAO,oBAAoB,KAAK,CAAC,OAAO,EAAE,CAAC;QAC7C,KAAK,kBAAkB;YACrB,OAAO,wDAAwD,CAAC;QAClE,KAAK,aAAa;YAChB,OAAO,kFAAkF,CAAC;QAC5F,KAAK,cAAc;YAGjB,OAAO,KAAK,CAAC,OAAO,IAAI,2BAA2B,CAAC;QACtD;YACE,OAAO,KAAK,CAAC,OAAO,IAAI,8BAA8B,CAAC;IAC3D,CAAC;AACH,CAAC;AAGD,SAAgB,WAAW,CAAC,KAAkB,EAAE,OAAgB;IAC9D,MAAM,SAAS,GAAG;QAChB,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,OAAO,EAAE,KAAK,CAAC,OAAO;QACtB,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,UAAU,EAAE,KAAK,CAAC,UAAU;QAC5B,OAAO,EAAE,KAAK,CAAC,OAAO;QACtB,OAAO;KACR,CAAC;IAEF,IAAI,KAAK,CAAC,UAAU,IAAI,KAAK,CAAC,UAAU,IAAI,GAAG,EAAE,CAAC;QAChD,eAAM,CAAC,KAAK,CAAC,sBAAsB,EAAE,SAAS,CAAC,CAAC;IAClD,CAAC;SAAM,IAAI,KAAK,CAAC,UAAU,IAAI,KAAK,CAAC,UAAU,IAAI,GAAG,EAAE,CAAC;QACvD,eAAM,CAAC,IAAI,CAAC,sBAAsB,EAAE,SAAS,CAAC,CAAC;IACjD,CAAC;SAAM,CAAC;QACN,eAAM,CAAC,KAAK,CAAC,eAAe,EAAE,SAAS,CAAC,CAAC;IAC3C,CAAC;AACH,CAAC"}

View File

@@ -87,12 +87,10 @@ function isTriggerNode(nodeType) {
if (lowerType.includes('webhook') && !lowerType.includes('respond')) {
return true;
}
const specificTriggers = [
'nodes-base.start',
'nodes-base.manualTrigger',
'nodes-base.formTrigger'
];
return specificTriggers.includes(normalized);
if (lowerType.includes('emailread') || lowerType.includes('emailreadimap')) {
return true;
}
return normalized === 'nodes-base.start';
}
function isActivatableTrigger(nodeType) {
return isTriggerNode(nodeType);

View File

@@ -1 +1 @@
{"version":3,"file":"node-type-utils.js","sourceRoot":"","sources":["../../src/utils/node-type-utils.ts"],"names":[],"mappings":"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"}
{"version":3,"file":"node-type-utils.js","sourceRoot":"","sources":["../../src/utils/node-type-utils.ts"],"names":[],"mappings":"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"}

5722
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
{
"name": "n8n-mcp",
"version": "2.37.1",
"version": "2.41.0",
"description": "Integration between n8n workflow automation and Model Context Protocol (MCP)",
"main": "dist/index.js",
"types": "dist/index.d.ts",
@@ -152,17 +152,17 @@
"vitest": "^3.2.4"
},
"dependencies": {
"@modelcontextprotocol/sdk": "^1.27.1",
"@n8n/n8n-nodes-langchain": "^2.11.2",
"@modelcontextprotocol/sdk": "1.28.0",
"@n8n/n8n-nodes-langchain": "^2.13.1",
"@supabase/supabase-js": "^2.57.4",
"dotenv": "^16.5.0",
"express": "^5.1.0",
"express-rate-limit": "^7.1.5",
"form-data": "^4.0.5",
"lru-cache": "^11.2.1",
"n8n": "^2.11.4",
"n8n-core": "^2.11.1",
"n8n-workflow": "^2.11.1",
"n8n": "^2.13.3",
"n8n-core": "^2.13.1",
"n8n-workflow": "^2.13.1",
"openai": "^4.77.0",
"sql.js": "^1.13.0",
"tslib": "^2.6.2",

View File

@@ -77,6 +77,8 @@ const DEFAULT_CONFIG: Required<Omit<DocumentationGeneratorConfig, 'baseUrl' | 't
*/
export class DocumentationGenerator {
private client: OpenAI;
private baseUrl: string;
private apiKey: string;
private model: string;
private maxTokens: number;
private timeout: number;
@@ -85,6 +87,8 @@ export class DocumentationGenerator {
constructor(config: DocumentationGeneratorConfig) {
const fullConfig = { ...DEFAULT_CONFIG, ...config };
this.baseUrl = config.baseUrl;
this.apiKey = fullConfig.apiKey;
this.client = new OpenAI({
baseURL: config.baseUrl,
apiKey: fullConfig.apiKey,
@@ -103,21 +107,10 @@ export class DocumentationGenerator {
try {
const prompt = this.buildPrompt(input);
const completion = await this.client.chat.completions.create({
model: this.model,
max_completion_tokens: this.maxTokens,
...(this.temperature !== undefined ? { temperature: this.temperature } : {}),
messages: [
{
role: 'system',
content: this.getSystemPrompt(),
},
{
role: 'user',
content: prompt,
},
],
});
const completion = await this.chatCompletion([
{ role: 'system', content: this.getSystemPrompt() },
{ role: 'user', content: prompt },
], this.maxTokens);
const content = completion.choices[0]?.message?.content;
if (!content) {
@@ -246,20 +239,23 @@ Guidelines:
* Extract JSON from LLM response (handles markdown code blocks)
*/
private extractJson(content: string): string {
// Strip <think>...</think> blocks from thinking models (e.g., Qwen3-Thinking)
const stripped = content.replace(/<think>[\s\S]*?<\/think>/g, '').trim();
// Try to extract from markdown code block
const jsonBlockMatch = content.match(/```(?:json)?\s*([\s\S]*?)```/);
const jsonBlockMatch = stripped.match(/```(?:json)?\s*([\s\S]*?)```/);
if (jsonBlockMatch) {
return jsonBlockMatch[1].trim();
}
// Try to find JSON object directly
const jsonMatch = content.match(/\{[\s\S]*\}/);
const jsonMatch = stripped.match(/\{[\s\S]*\}/);
if (jsonMatch) {
return jsonMatch[0];
}
// Return as-is if no extraction needed
return content.trim();
return stripped;
}
/**
@@ -323,16 +319,9 @@ Guidelines:
*/
async testConnection(): Promise<{ success: boolean; message: string }> {
try {
const completion = await this.client.chat.completions.create({
model: this.model,
max_completion_tokens: 200,
messages: [
{
role: 'user',
content: 'Hello',
},
],
});
const completion = await this.chatCompletion([
{ role: 'user', content: 'Hello' },
], 200);
if (completion.choices[0]?.message?.content) {
return { success: true, message: `Connected to ${this.model}` };
@@ -345,6 +334,44 @@ Guidelines:
}
}
/**
* Make a chat completion request with chat_template_kwargs support for vLLM thinking models
*/
private async chatCompletion(
messages: Array<{ role: string; content: string }>,
maxTokens: number
): Promise<{ choices: Array<{ message: { content: string | null } }> }> {
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
try {
const response = await fetch(`${this.baseUrl}/chat/completions`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
...(this.apiKey !== 'not-needed' ? { Authorization: `Bearer ${this.apiKey}` } : {}),
},
body: JSON.stringify({
model: this.model,
messages,
max_completion_tokens: maxTokens,
...(this.temperature !== undefined ? { temperature: this.temperature } : {}),
chat_template_kwargs: { enable_thinking: false },
}),
signal: controller.signal,
});
if (!response.ok) {
const text = await response.text();
throw new Error(`${response.status} ${text}`);
}
return (await response.json()) as { choices: Array<{ message: { content: string | null } }> };
} finally {
clearTimeout(timeoutId);
}
}
private sleep(ms: number): Promise<void> {
return new Promise((resolve) => setTimeout(resolve, ms));
}

View File

@@ -35,7 +35,7 @@ export class NodeRepository {
*/
saveNode(node: ParsedNode & Partial<CommunityNodeFields>): void {
const stmt = this.db.prepare(`
INSERT OR REPLACE INTO nodes (
INSERT INTO nodes (
node_type, package_name, display_name, description,
category, development_style, is_ai_tool, is_trigger,
is_webhook, is_versioned, is_tool_variant, tool_variant_of,
@@ -45,6 +45,35 @@ export class NodeRepository {
is_community, is_verified, author_name, author_github_url,
npm_package_name, npm_version, npm_downloads, community_fetched_at
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
ON CONFLICT(node_type) DO UPDATE SET
package_name = excluded.package_name,
display_name = excluded.display_name,
description = excluded.description,
category = excluded.category,
development_style = excluded.development_style,
is_ai_tool = excluded.is_ai_tool,
is_trigger = excluded.is_trigger,
is_webhook = excluded.is_webhook,
is_versioned = excluded.is_versioned,
is_tool_variant = excluded.is_tool_variant,
tool_variant_of = excluded.tool_variant_of,
has_tool_variant = excluded.has_tool_variant,
version = excluded.version,
documentation = excluded.documentation,
properties_schema = excluded.properties_schema,
operations = excluded.operations,
credentials_required = excluded.credentials_required,
outputs = excluded.outputs,
output_names = excluded.output_names,
is_community = excluded.is_community,
is_verified = excluded.is_verified,
author_name = excluded.author_name,
author_github_url = excluded.author_github_url,
npm_package_name = excluded.npm_package_name,
npm_version = excluded.npm_version,
npm_downloads = excluded.npm_downloads,
community_fetched_at = excluded.community_fetched_at,
updated_at = CURRENT_TIMESTAMP
`);
stmt.run(

View File

@@ -253,6 +253,22 @@ export class SingleSessionHTTPServer {
// This ensures compatibility with all MCP clients and proxies
return Boolean(sessionId && sessionId.length > 0);
}
/**
* Checks if a request body is a JSON-RPC notification (or batch of only notifications).
* Per JSON-RPC 2.0 §4.1, a notification is a request without an "id" member.
* Note: `!('id' in msg)` is strict — messages with `id: null` are treated as
* requests, not notifications. This is spec-compliant.
*/
private isJsonRpcNotification(body: unknown): boolean {
if (!body || typeof body !== 'object') return false;
const isSingleNotification = (msg: any): boolean =>
msg && typeof msg.method === 'string' && !('id' in msg);
if (Array.isArray(body)) {
return body.length > 0 && body.every(isSingleNotification);
}
return isSingleNotification(body);
}
/**
* Sanitize error information for client responses
@@ -614,6 +630,22 @@ export class SingleSessionHTTPServer {
logger.info('handleRequest: Reusing existing transport for session', { sessionId });
transport = this.transports[sessionId];
// TOCTOU guard: session may have been removed between the check above and here
if (!transport) {
if (this.isJsonRpcNotification(req.body)) {
logger.info('handleRequest: Session removed during lookup, accepting notification', { sessionId });
res.status(202).end();
return;
}
logger.warn('handleRequest: Session removed between check and use (TOCTOU)', { sessionId });
res.status(400).json({
jsonrpc: '2.0',
error: { code: -32000, message: 'Bad Request: Session not found or expired' },
id: req.body?.id || null,
});
return;
}
// In multi-tenant shared mode, update instance context if provided
const isMultiTenantEnabled = process.env.ENABLE_MULTI_TENANT === 'true';
const sessionStrategy = process.env.MULTI_TENANT_SESSION_STRATEGY || 'instance';
@@ -627,23 +659,33 @@ export class SingleSessionHTTPServer {
this.updateSessionAccess(sessionId);
} else {
// Invalid request - no session ID and not an initialize request
// Notifications are fire-and-forget; returning 400 triggers reconnection storms (#654)
if (this.isJsonRpcNotification(req.body)) {
logger.info('handleRequest: Accepting notification for stale/missing session', {
method: req.body?.method,
sessionId: sessionId || 'none',
});
res.status(202).end();
return;
}
// Only return 400 for actual requests that need a valid session
const errorDetails = {
hasSessionId: !!sessionId,
isInitialize: isInitialize,
sessionIdValid: sessionId ? this.isValidSessionId(sessionId) : false,
sessionExists: sessionId ? !!this.transports[sessionId] : false
};
logger.warn('handleRequest: Invalid request - no session ID and not initialize', errorDetails);
let errorMessage = 'Bad Request: No valid session ID provided and not an initialize request';
if (sessionId && !this.isValidSessionId(sessionId)) {
errorMessage = 'Bad Request: Invalid session ID format';
} else if (sessionId && !this.transports[sessionId]) {
errorMessage = 'Bad Request: Session not found or expired';
}
res.status(400).json({
jsonrpc: '2.0',
error: {

View File

@@ -8,7 +8,7 @@ import {
WebhookRequest,
McpToolResponse,
ExecutionFilterOptions,
ExecutionMode
ExecutionMode,
} from '../types/n8n-api';
import type { TriggerType, TestWorkflowInput } from '../triggers/types';
import {
@@ -383,6 +383,7 @@ const createWorkflowSchema = z.object({
executionTimeout: z.number().optional(),
errorWorkflow: z.string().optional(),
}).optional(),
projectId: z.string().optional(),
});
const updateWorkflowSchema = z.object({
@@ -1974,7 +1975,7 @@ export async function handleDiagnostic(request: any, context?: InstanceContext):
// Check which tools are available
const documentationTools = 7; // Base documentation tools (after v2.26.0 consolidation)
const managementTools = apiConfigured ? 13 : 0; // Management tools requiring API (includes n8n_deploy_template)
const managementTools = apiConfigured ? 14 : 0; // Management tools requiring API (includes n8n_manage_datatable)
const totalTools = documentationTools + managementTools;
// Check npm version
@@ -2688,3 +2689,260 @@ export async function handleTriggerWebhookWorkflow(args: unknown, context?: Inst
};
}
}
// ========================================================================
// Data Table Handlers
// ========================================================================
// Shared Zod schemas for data table operations
const dataTableFilterConditionSchema = z.object({
columnName: z.string().min(1),
condition: z.enum(['eq', 'neq', 'like', 'ilike', 'gt', 'gte', 'lt', 'lte']),
value: z.any(),
});
const dataTableFilterSchema = z.object({
type: z.enum(['and', 'or']).optional().default('and'),
filters: z.array(dataTableFilterConditionSchema).min(1, 'At least one filter condition is required'),
});
// Shared base schema for actions requiring a tableId
const tableIdSchema = z.object({
tableId: z.string().min(1, 'tableId is required'),
});
// Per-action Zod schemas
const createTableSchema = z.object({
name: z.string().min(1, 'Table name cannot be empty'),
columns: z.array(z.object({
name: z.string().min(1, 'Column name cannot be empty'),
type: z.enum(['string', 'number', 'boolean', 'date']).optional(),
})).optional(),
});
const listTablesSchema = z.object({
limit: z.number().min(1).max(100).optional(),
cursor: z.string().optional(),
});
const updateTableSchema = tableIdSchema.extend({
name: z.string().min(1, 'New table name cannot be empty'),
});
// MCP transports may serialize JSON objects/arrays as strings.
// Parse them back, but return the original value on failure so Zod reports a proper type error.
function tryParseJson(val: unknown): unknown {
if (typeof val !== 'string') return val;
try { return JSON.parse(val); } catch { return val; }
}
const coerceJsonArray = z.preprocess(tryParseJson, z.array(z.record(z.unknown())));
const coerceJsonObject = z.preprocess(tryParseJson, z.record(z.unknown()));
const coerceJsonFilter = z.preprocess(tryParseJson, dataTableFilterSchema);
const getRowsSchema = tableIdSchema.extend({
limit: z.number().min(1).max(100).optional(),
cursor: z.string().optional(),
filter: z.union([coerceJsonFilter, z.string()]).optional(),
sortBy: z.string().optional(),
search: z.string().optional(),
});
const insertRowsSchema = tableIdSchema.extend({
data: coerceJsonArray.pipe(z.array(z.record(z.unknown())).min(1, 'At least one row is required')),
returnType: z.enum(['count', 'id', 'all']).optional(),
});
// Shared schema for update/upsert (identical structure)
const mutateRowsSchema = tableIdSchema.extend({
filter: coerceJsonFilter,
data: coerceJsonObject,
returnData: z.boolean().optional(),
dryRun: z.boolean().optional(),
});
const deleteRowsSchema = tableIdSchema.extend({
filter: coerceJsonFilter,
returnData: z.boolean().optional(),
dryRun: z.boolean().optional(),
});
function handleDataTableError(error: unknown): McpToolResponse {
if (error instanceof z.ZodError) {
return { success: false, error: 'Invalid input', details: { errors: error.errors } };
}
if (error instanceof N8nApiError) {
return {
success: false,
error: getUserFriendlyErrorMessage(error),
code: error.code,
details: error.details as Record<string, unknown> | undefined,
};
}
return { success: false, error: error instanceof Error ? error.message : 'Unknown error occurred' };
}
export async function handleCreateTable(args: unknown, context?: InstanceContext): Promise<McpToolResponse> {
try {
const client = ensureApiConfigured(context);
const input = createTableSchema.parse(args);
const dataTable = await client.createDataTable(input);
if (!dataTable || !dataTable.id) {
return { success: false, error: 'Data table creation failed: n8n API returned an empty or invalid response' };
}
return {
success: true,
data: { id: dataTable.id, name: dataTable.name },
message: `Data table "${dataTable.name}" created with ID: ${dataTable.id}`,
};
} catch (error) {
return handleDataTableError(error);
}
}
export async function handleListTables(args: unknown, context?: InstanceContext): Promise<McpToolResponse> {
try {
const client = ensureApiConfigured(context);
const input = listTablesSchema.parse(args || {});
const result = await client.listDataTables(input);
return {
success: true,
data: {
tables: result.data,
count: result.data.length,
nextCursor: result.nextCursor || undefined,
},
};
} catch (error) {
return handleDataTableError(error);
}
}
export async function handleGetTable(args: unknown, context?: InstanceContext): Promise<McpToolResponse> {
try {
const client = ensureApiConfigured(context);
const { tableId } = tableIdSchema.parse(args);
const dataTable = await client.getDataTable(tableId);
return { success: true, data: dataTable };
} catch (error) {
return handleDataTableError(error);
}
}
export async function handleUpdateTable(args: unknown, context?: InstanceContext): Promise<McpToolResponse> {
try {
const client = ensureApiConfigured(context);
const { tableId, name } = updateTableSchema.parse(args);
const dataTable = await client.updateDataTable(tableId, { name });
const rawArgs = args as Record<string, unknown>;
const hasColumns = rawArgs && typeof rawArgs === 'object' && 'columns' in rawArgs;
return {
success: true,
data: dataTable,
message: `Data table renamed to "${dataTable.name}"` +
(hasColumns ? '. Note: columns parameter was ignored — table schema is immutable after creation via the public API' : ''),
};
} catch (error) {
return handleDataTableError(error);
}
}
export async function handleDeleteTable(args: unknown, context?: InstanceContext): Promise<McpToolResponse> {
try {
const client = ensureApiConfigured(context);
const { tableId } = tableIdSchema.parse(args);
await client.deleteDataTable(tableId);
return { success: true, message: `Data table ${tableId} deleted successfully` };
} catch (error) {
return handleDataTableError(error);
}
}
export async function handleGetRows(args: unknown, context?: InstanceContext): Promise<McpToolResponse> {
try {
const client = ensureApiConfigured(context);
const { tableId, filter, sortBy, ...params } = getRowsSchema.parse(args);
const queryParams: Record<string, unknown> = { ...params };
if (filter) {
queryParams.filter = typeof filter === 'string' ? filter : JSON.stringify(filter);
}
if (sortBy) {
queryParams.sortBy = sortBy;
}
const result = await client.getDataTableRows(tableId, queryParams as any);
return {
success: true,
data: {
rows: result.data,
count: result.data.length,
nextCursor: result.nextCursor || undefined,
},
};
} catch (error) {
return handleDataTableError(error);
}
}
export async function handleInsertRows(args: unknown, context?: InstanceContext): Promise<McpToolResponse> {
try {
const client = ensureApiConfigured(context);
const { tableId, ...params } = insertRowsSchema.parse(args);
const result = await client.insertDataTableRows(tableId, params);
return {
success: true,
data: result,
message: `Rows inserted into data table ${tableId}`,
};
} catch (error) {
return handleDataTableError(error);
}
}
export async function handleUpdateRows(args: unknown, context?: InstanceContext): Promise<McpToolResponse> {
try {
const client = ensureApiConfigured(context);
const { tableId, ...params } = mutateRowsSchema.parse(args);
const result = await client.updateDataTableRows(tableId, params);
return {
success: true,
data: result,
message: params.dryRun ? 'Dry run: rows matched (no changes applied)' : 'Rows updated successfully',
};
} catch (error) {
return handleDataTableError(error);
}
}
export async function handleUpsertRows(args: unknown, context?: InstanceContext): Promise<McpToolResponse> {
try {
const client = ensureApiConfigured(context);
const { tableId, ...params } = mutateRowsSchema.parse(args);
const result = await client.upsertDataTableRow(tableId, params);
return {
success: true,
data: result,
message: params.dryRun ? 'Dry run: upsert previewed (no changes applied)' : 'Row upserted successfully',
};
} catch (error) {
return handleDataTableError(error);
}
}
export async function handleDeleteRows(args: unknown, context?: InstanceContext): Promise<McpToolResponse> {
try {
const client = ensureApiConfigured(context);
const { tableId, filter, ...params } = deleteRowsSchema.parse(args);
const queryParams = {
filter: JSON.stringify(filter),
...params,
};
const result = await client.deleteDataTableRows(tableId, queryParams as any);
return {
success: true,
data: result,
message: params.dryRun ? 'Dry run: rows matched for deletion (no changes applied)' : 'Rows deleted successfully',
};
} catch (error) {
return handleDataTableError(error);
}
}

View File

@@ -31,6 +31,11 @@ function getValidator(repository: NodeRepository): WorkflowValidator {
return cachedValidator;
}
// Operation types that identify nodes by nodeId/nodeName
const NODE_TARGETING_OPERATIONS = new Set([
'updateNode', 'removeNode', 'moveNode', 'enableNode', 'disableNode'
]);
// Zod schema for the diff request
const workflowDiffSchema = z.object({
id: z.string(),
@@ -63,6 +68,25 @@ const workflowDiffSchema = z.object({
settings: z.any().optional(),
name: z.string().optional(),
tag: z.string().optional(),
// Transfer operation
destinationProjectId: z.string().min(1).optional(),
// Aliases: LLMs often use "id" instead of "nodeId" — accept both
id: z.string().optional(),
}).transform((op) => {
// Normalize common field aliases for node-targeting operations:
// - "name" → "nodeName" (LLMs confuse the updateName "name" field with node identification)
// - "id" → "nodeId" (natural alias)
if (NODE_TARGETING_OPERATIONS.has(op.type)) {
if (!op.nodeName && !op.nodeId && op.name) {
op.nodeName = op.name;
op.name = undefined;
}
if (!op.nodeId && op.id) {
op.nodeId = op.id;
op.id = undefined;
}
}
return op;
})),
validateOnly: z.boolean().optional(),
continueOnError: z.boolean().optional(),
@@ -348,6 +372,26 @@ export async function handleUpdatePartialWorkflow(
}
}
// Handle project transfer if requested (before activation so workflow is in target project first)
let transferMessage = '';
if (diffResult.transferToProjectId) {
try {
await client.transferWorkflow(input.id, diffResult.transferToProjectId);
transferMessage = ` Workflow transferred to project ${diffResult.transferToProjectId}.`;
} catch (transferError) {
logger.error('Failed to transfer workflow to project', transferError);
return {
success: false,
saved: true,
error: 'Workflow updated successfully but project transfer failed',
details: {
workflowUpdated: true,
transferError: transferError instanceof Error ? transferError.message : 'Unknown error'
}
};
}
}
// Handle activation/deactivation if requested
let finalWorkflow = updatedWorkflow;
let activationMessage = '';
@@ -432,7 +476,7 @@ export async function handleUpdatePartialWorkflow(
nodeCount: finalWorkflow.nodes?.length || 0,
operationsApplied: diffResult.operationsApplied
},
message: `Workflow "${finalWorkflow.name}" updated successfully. Applied ${diffResult.operationsApplied} operations.${activationMessage} Use n8n_get_workflow with mode 'structure' to verify current state.`,
message: `Workflow "${finalWorkflow.name}" updated successfully. Applied ${diffResult.operationsApplied} operations.${transferMessage}${activationMessage} Use n8n_get_workflow with mode 'structure' to verify current state.`,
details: {
applied: diffResult.applied,
failed: diffResult.failed,
@@ -537,6 +581,8 @@ function inferIntentFromOperations(operations: any[]): string {
return 'Activate workflow';
case 'deactivateWorkflow':
return 'Deactivate workflow';
case 'transferWorkflow':
return `Transfer workflow to project ${op.destinationProjectId || ''}`.trim();
default:
return `Workflow ${op.type}`;
}

View File

@@ -1029,6 +1029,11 @@ export class N8NDocumentationMCPServer {
? { valid: true, errors: [] }
: { valid: false, errors: [{ field: 'action', message: 'action is required' }] };
break;
case 'n8n_manage_datatable':
validationResult = args.action
? { valid: true, errors: [] }
: { valid: false, errors: [{ field: 'action', message: 'action is required' }] };
break;
case 'n8n_deploy_template':
// Requires templateId parameter
validationResult = args.templateId !== undefined
@@ -1496,6 +1501,26 @@ export class N8NDocumentationMCPServer {
if (!this.repository) throw new Error('Repository not initialized');
return n8nHandlers.handleDeployTemplate(args, this.templateService, this.repository, this.instanceContext);
case 'n8n_manage_datatable': {
this.validateToolParams(name, args, ['action']);
const dtAction = args.action;
// Each handler validates its own inputs via Zod schemas
switch (dtAction) {
case 'createTable': return n8nHandlers.handleCreateTable(args, this.instanceContext);
case 'listTables': return n8nHandlers.handleListTables(args, this.instanceContext);
case 'getTable': return n8nHandlers.handleGetTable(args, this.instanceContext);
case 'updateTable': return n8nHandlers.handleUpdateTable(args, this.instanceContext);
case 'deleteTable': return n8nHandlers.handleDeleteTable(args, this.instanceContext);
case 'getRows': return n8nHandlers.handleGetRows(args, this.instanceContext);
case 'insertRows': return n8nHandlers.handleInsertRows(args, this.instanceContext);
case 'updateRows': return n8nHandlers.handleUpdateRows(args, this.instanceContext);
case 'upsertRows': return n8nHandlers.handleUpsertRows(args, this.instanceContext);
case 'deleteRows': return n8nHandlers.handleDeleteRows(args, this.instanceContext);
default:
throw new Error(`Unknown action: ${dtAction}. Valid actions: createTable, listTables, getTable, updateTable, deleteTable, getRows, insertRows, updateRows, upsertRows, deleteRows`);
}
}
default:
throw new Error(`Unknown tool: ${name}`);
}

View File

@@ -22,7 +22,8 @@ import {
n8nTestWorkflowDoc,
n8nExecutionsDoc,
n8nWorkflowVersionsDoc,
n8nDeployTemplateDoc
n8nDeployTemplateDoc,
n8nManageDatatableDoc
} from './workflow_management';
// Combine all tool documentations into a single object
@@ -60,7 +61,8 @@ export const toolsDocumentation: Record<string, ToolDocumentation> = {
n8n_test_workflow: n8nTestWorkflowDoc,
n8n_executions: n8nExecutionsDoc,
n8n_workflow_versions: n8nWorkflowVersionsDoc,
n8n_deploy_template: n8nDeployTemplateDoc
n8n_deploy_template: n8nDeployTemplateDoc,
n8n_manage_datatable: n8nManageDatatableDoc
};
// Re-export types

View File

@@ -10,3 +10,4 @@ export { n8nTestWorkflowDoc } from './n8n-test-workflow';
export { n8nExecutionsDoc } from './n8n-executions';
export { n8nWorkflowVersionsDoc } from './n8n-workflow-versions';
export { n8nDeployTemplateDoc } from './n8n-deploy-template';
export { n8nManageDatatableDoc } from './n8n-manage-datatable';

View File

@@ -0,0 +1,107 @@
import { ToolDocumentation } from '../types';
export const n8nManageDatatableDoc: ToolDocumentation = {
name: 'n8n_manage_datatable',
category: 'workflow_management',
essentials: {
description: 'Manage n8n data tables and rows. Unified tool for table CRUD and row operations with filtering, pagination, and dry-run support.',
keyParameters: ['action', 'tableId', 'name', 'data', 'filter'],
example: 'n8n_manage_datatable({action: "createTable", name: "Contacts", columns: [{name: "email", type: "string"}]})',
performance: 'Fast (100-500ms)',
tips: [
'Table actions: createTable, listTables, getTable, updateTable (rename only), deleteTable',
'Row actions: getRows, insertRows, updateRows, upsertRows, deleteRows',
'Use dryRun: true to preview update/upsert/delete before applying',
'Filter supports: eq, neq, like, ilike, gt, gte, lt, lte conditions',
'Use returnData: true to get affected rows back from update/upsert/delete',
'Requires N8N_API_URL and N8N_API_KEY configured'
]
},
full: {
description: `**Table Actions:**
- **createTable**: Create a new data table with optional typed columns
- **listTables**: List all data tables (paginated)
- **getTable**: Get table details and column definitions by ID
- **updateTable**: Rename an existing table (name only — column modifications not supported via API)
- **deleteTable**: Permanently delete a table and all its rows
**Row Actions:**
- **getRows**: List rows with filtering, sorting, search, and pagination
- **insertRows**: Insert one or more rows (bulk)
- **updateRows**: Update rows matching a filter condition
- **upsertRows**: Update matching row or insert if none match
- **deleteRows**: Delete rows matching a filter condition (filter required)
**Filter System:** Used in getRows, updateRows, upsertRows, deleteRows
- Combine conditions with "and" (default) or "or"
- Conditions: eq, neq, like, ilike, gt, gte, lt, lte
- Example: {type: "and", filters: [{columnName: "status", condition: "eq", value: "active"}]}
**Dry Run:** updateRows, upsertRows, and deleteRows support dryRun: true to preview changes without applying them.`,
parameters: {
action: { type: 'string', required: true, description: 'Operation to perform' },
tableId: { type: 'string', required: false, description: 'Data table ID (required for all except createTable and listTables)' },
name: { type: 'string', required: false, description: 'For createTable/updateTable: table name' },
columns: { type: 'array', required: false, description: 'For createTable: column definitions [{name, type?}]. Types: string, number, boolean, date' },
data: { type: 'array|object', required: false, description: 'For insertRows: array of row objects. For updateRows/upsertRows: object with column values' },
filter: { type: 'object', required: false, description: 'Filter: {type?: "and"|"or", filters: [{columnName, condition, value}]}' },
limit: { type: 'number', required: false, description: 'For listTables/getRows: max results (1-100)' },
cursor: { type: 'string', required: false, description: 'For listTables/getRows: pagination cursor' },
sortBy: { type: 'string', required: false, description: 'For getRows: "columnName:asc" or "columnName:desc"' },
search: { type: 'string', required: false, description: 'For getRows: full-text search across string columns' },
returnType: { type: 'string', required: false, description: 'For insertRows: "count" (default), "id", or "all"' },
returnData: { type: 'boolean', required: false, description: 'For updateRows/upsertRows/deleteRows: return affected rows (default: false)' },
dryRun: { type: 'boolean', required: false, description: 'For updateRows/upsertRows/deleteRows: preview without applying (default: false)' },
},
returns: `Depends on action:
- createTable: {id, name}
- listTables: {tables, count, nextCursor?}
- getTable: Full table object with columns
- updateTable: Updated table object
- deleteTable: Success message
- getRows: {rows, count, nextCursor?}
- insertRows: Depends on returnType (count/ids/rows)
- updateRows: Update result with optional rows
- upsertRows: Upsert result with action type
- deleteRows: Delete result with optional rows`,
examples: [
'// Create a table\nn8n_manage_datatable({action: "createTable", name: "Contacts", columns: [{name: "email", type: "string"}, {name: "score", type: "number"}]})',
'// List all tables\nn8n_manage_datatable({action: "listTables"})',
'// Get table details\nn8n_manage_datatable({action: "getTable", tableId: "dt-123"})',
'// Rename a table\nn8n_manage_datatable({action: "updateTable", tableId: "dt-123", name: "New Name"})',
'// Delete a table\nn8n_manage_datatable({action: "deleteTable", tableId: "dt-123"})',
'// Get rows with filter\nn8n_manage_datatable({action: "getRows", tableId: "dt-123", filter: {filters: [{columnName: "status", condition: "eq", value: "active"}]}, limit: 50})',
'// Search rows\nn8n_manage_datatable({action: "getRows", tableId: "dt-123", search: "john", sortBy: "name:asc"})',
'// Insert rows\nn8n_manage_datatable({action: "insertRows", tableId: "dt-123", data: [{email: "a@b.com", score: 10}], returnType: "all"})',
'// Update rows (dry run)\nn8n_manage_datatable({action: "updateRows", tableId: "dt-123", filter: {filters: [{columnName: "score", condition: "lt", value: 5}]}, data: {status: "inactive"}, dryRun: true})',
'// Upsert a row\nn8n_manage_datatable({action: "upsertRows", tableId: "dt-123", filter: {filters: [{columnName: "email", condition: "eq", value: "a@b.com"}]}, data: {score: 15}, returnData: true})',
'// Delete rows\nn8n_manage_datatable({action: "deleteRows", tableId: "dt-123", filter: {filters: [{columnName: "status", condition: "eq", value: "deleted"}]}})',
],
useCases: [
'Persist structured workflow data across executions',
'Store and query lookup tables for workflow logic',
'Bulk insert records from external data sources',
'Conditionally update records matching criteria',
'Upsert to maintain unique records by key column',
'Clean up old or invalid rows with filtered delete',
'Preview changes with dryRun before modifying data',
],
performance: 'Table operations: 50-300ms. Row operations: 100-500ms depending on data size and filters.',
bestPractices: [
'Define column types upfront for schema consistency',
'Use dryRun: true before bulk updates/deletes to verify filter correctness',
'Use returnType: "count" (default) for insertRows to minimize response size',
'Use filter with specific conditions to avoid unintended bulk operations',
'Use cursor-based pagination for large result sets',
'Use sortBy for deterministic row ordering',
],
pitfalls: [
'deleteTable permanently deletes all rows — cannot be undone',
'deleteRows requires a filter — cannot delete all rows without one',
'Column types cannot be changed after table creation via API',
'updateTable can only rename the table (no column modifications via public API)',
'projectId cannot be set via the public API — use the n8n UI',
],
relatedTools: ['n8n_create_workflow', 'n8n_list_workflows', 'n8n_health_check'],
},
};

View File

@@ -4,7 +4,7 @@ export const n8nUpdatePartialWorkflowDoc: ToolDocumentation = {
name: 'n8n_update_partial_workflow',
category: 'workflow_management',
essentials: {
description: 'Update workflow incrementally with diff operations. Types: addNode, removeNode, updateNode, moveNode, enable/disableNode, addConnection, removeConnection, rewireConnection, cleanStaleConnections, replaceConnections, updateSettings, updateName, add/removeTag, activateWorkflow, deactivateWorkflow. Supports smart parameters (branch, case) for multi-output nodes. Full support for AI connections (ai_languageModel, ai_tool, ai_memory, ai_embedding, ai_vectorStore, ai_document, ai_textSplitter, ai_outputParser).',
description: 'Update workflow incrementally with diff operations. Types: addNode, removeNode, updateNode, moveNode, enable/disableNode, addConnection, removeConnection, rewireConnection, cleanStaleConnections, replaceConnections, updateSettings, updateName, add/removeTag, activateWorkflow, deactivateWorkflow, transferWorkflow. Supports smart parameters (branch, case) for multi-output nodes. Full support for AI connections (ai_languageModel, ai_tool, ai_memory, ai_embedding, ai_vectorStore, ai_document, ai_textSplitter, ai_outputParser).',
keyParameters: ['id', 'operations', 'continueOnError'],
example: 'n8n_update_partial_workflow({id: "wf_123", operations: [{type: "rewireConnection", source: "IF", from: "Old", to: "New", branch: "true"}]})',
performance: 'Fast (50-200ms)',
@@ -22,7 +22,8 @@ export const n8nUpdatePartialWorkflowDoc: ToolDocumentation = {
'Batch AI component connections for atomic updates',
'Auto-sanitization: ALL nodes auto-fixed during updates (operator structures, missing metadata)',
'Node renames automatically update all connection references - no manual connection operations needed',
'Activate/deactivate workflows: Use activateWorkflow/deactivateWorkflow operations (requires activatable triggers like webhook/schedule)'
'Activate/deactivate workflows: Use activateWorkflow/deactivateWorkflow operations (requires activatable triggers like webhook/schedule)',
'Transfer workflows between projects: Use transferWorkflow with destinationProjectId (enterprise feature)'
]
},
full: {
@@ -55,6 +56,9 @@ export const n8nUpdatePartialWorkflowDoc: ToolDocumentation = {
- **activateWorkflow**: Activate the workflow to enable automatic execution via triggers
- **deactivateWorkflow**: Deactivate the workflow to prevent automatic execution
### Project Management Operations (1 type):
- **transferWorkflow**: Transfer the workflow to a different project. Requires \`destinationProjectId\`. Enterprise/cloud feature.
## Smart Parameters for Multi-Output Nodes
For **IF nodes**, use semantic 'branch' parameter instead of technical sourceIndex:
@@ -194,12 +198,12 @@ Please choose a different name.
- Can rename a node and add/remove connections using the new name in the same batch
- Use \`validateOnly: true\` to preview effects before applying
## Removing Properties with undefined
## Removing Properties with null
To remove a property from a node, set its value to \`undefined\` in the updates object. This is essential when migrating from deprecated properties or cleaning up optional configuration fields.
To remove a property from a node, set its value to \`null\` in the updates object. This is essential when migrating from deprecated properties or cleaning up optional configuration fields.
### Why Use undefined?
- **Property removal vs. null**: Setting a property to \`undefined\` removes it completely from the node object, while \`null\` sets the property to a null value
### Why Use null?
- **Property removal**: Setting a property to \`null\` removes it completely from the node object
- **Validation constraints**: Some properties are mutually exclusive (e.g., \`continueOnFail\` and \`onError\`). Simply setting one without removing the other will fail validation
- **Deprecated property migration**: When n8n deprecates properties, you must remove the old property before the new one will work
@@ -211,7 +215,7 @@ n8n_update_partial_workflow({
operations: [{
type: "updateNode",
nodeName: "HTTP Request",
updates: { onError: undefined }
updates: { onError: null }
}]
});
@@ -221,7 +225,7 @@ n8n_update_partial_workflow({
operations: [{
type: "updateNode",
nodeId: "node_abc",
updates: { disabled: undefined }
updates: { disabled: null }
}]
});
\`\`\`
@@ -235,7 +239,7 @@ n8n_update_partial_workflow({
operations: [{
type: "updateNode",
nodeName: "API Request",
updates: { "parameters.authentication": undefined }
updates: { "parameters.authentication": null }
}]
});
@@ -245,7 +249,7 @@ n8n_update_partial_workflow({
operations: [{
type: "updateNode",
nodeName: "HTTP Request",
updates: { "parameters.headers": undefined }
updates: { "parameters.headers": null }
}]
});
\`\`\`
@@ -271,7 +275,7 @@ n8n_update_partial_workflow({
type: "updateNode",
nodeName: "HTTP Request",
updates: {
continueOnFail: undefined,
continueOnFail: null,
onError: "continueErrorOutput"
}
}]
@@ -287,15 +291,15 @@ n8n_update_partial_workflow({
type: "updateNode",
nodeName: "Data Processor",
updates: {
continueOnFail: undefined,
alwaysOutputData: undefined,
"parameters.legacy_option": undefined
continueOnFail: null,
alwaysOutputData: null,
"parameters.legacy_option": null
}
}]
});
\`\`\`
### When to Use undefined
### When to Use null
- Removing deprecated properties during migration
- Cleaning up optional configuration flags
- Resolving mutual exclusivity validation errors
@@ -341,11 +345,14 @@ n8n_update_partial_workflow({
'// Rewire AI Agent to use different language model\nn8n_update_partial_workflow({id: "ai9", operations: [{type: "rewireConnection", source: "AI Agent", from: "OpenAI Chat Model", to: "Anthropic Chat Model", sourceOutput: "ai_languageModel"}]})',
'// Replace all AI tools for an agent\nn8n_update_partial_workflow({id: "ai10", operations: [\n {type: "removeConnection", source: "Old Tool 1", target: "AI Agent", sourceOutput: "ai_tool"},\n {type: "removeConnection", source: "Old Tool 2", target: "AI Agent", sourceOutput: "ai_tool"},\n {type: "addConnection", source: "New HTTP Tool", target: "AI Agent", sourceOutput: "ai_tool"},\n {type: "addConnection", source: "New Code Tool", target: "AI Agent", sourceOutput: "ai_tool"}\n]})',
'\n// ============ REMOVING PROPERTIES EXAMPLES ============',
'// Remove a simple property\nn8n_update_partial_workflow({id: "rm1", operations: [{type: "updateNode", nodeName: "HTTP Request", updates: {onError: undefined}}]})',
'// Migrate from deprecated continueOnFail to onError\nn8n_update_partial_workflow({id: "rm2", operations: [{type: "updateNode", nodeName: "HTTP Request", updates: {continueOnFail: undefined, onError: "continueErrorOutput"}}]})',
'// Remove nested property\nn8n_update_partial_workflow({id: "rm3", operations: [{type: "updateNode", nodeName: "API Request", updates: {"parameters.authentication": undefined}}]})',
'// Remove multiple properties\nn8n_update_partial_workflow({id: "rm4", operations: [{type: "updateNode", nodeName: "Data Processor", updates: {continueOnFail: undefined, alwaysOutputData: undefined, "parameters.legacy_option": undefined}}]})',
'// Remove entire array property\nn8n_update_partial_workflow({id: "rm5", operations: [{type: "updateNode", nodeName: "HTTP Request", updates: {"parameters.headers": undefined}}]})'
'// Remove a simple property\nn8n_update_partial_workflow({id: "rm1", operations: [{type: "updateNode", nodeName: "HTTP Request", updates: {onError: null}}]})',
'// Migrate from deprecated continueOnFail to onError\nn8n_update_partial_workflow({id: "rm2", operations: [{type: "updateNode", nodeName: "HTTP Request", updates: {continueOnFail: null, onError: "continueErrorOutput"}}]})',
'// Remove nested property\nn8n_update_partial_workflow({id: "rm3", operations: [{type: "updateNode", nodeName: "API Request", updates: {"parameters.authentication": null}}]})',
'// Remove multiple properties\nn8n_update_partial_workflow({id: "rm4", operations: [{type: "updateNode", nodeName: "Data Processor", updates: {continueOnFail: null, alwaysOutputData: null, "parameters.legacy_option": null}}]})',
'// Remove entire array property\nn8n_update_partial_workflow({id: "rm5", operations: [{type: "updateNode", nodeName: "HTTP Request", updates: {"parameters.headers": null}}]})',
'\n// ============ PROJECT TRANSFER EXAMPLES ============',
'// Transfer workflow to a different project\nn8n_update_partial_workflow({id: "tf1", operations: [{type: "transferWorkflow", destinationProjectId: "project-abc-123"}]})',
'// Transfer and activate in one call\nn8n_update_partial_workflow({id: "tf2", operations: [{type: "transferWorkflow", destinationProjectId: "project-abc-123"}, {type: "activateWorkflow"}]})'
],
useCases: [
'Rewire connections when replacing nodes',
@@ -363,7 +370,8 @@ n8n_update_partial_workflow({
'Add fallback language models to AI Agents',
'Configure Vector Store retrieval systems',
'Swap language models in existing AI workflows',
'Batch-update AI tool connections'
'Batch-update AI tool connections',
'Transfer workflows between team projects (enterprise)'
],
performance: 'Very fast - typically 50-200ms. Much faster than full updates as only changes are processed.',
bestPractices: [
@@ -383,9 +391,9 @@ n8n_update_partial_workflow({
'Use targetIndex for fallback models (primary=0, fallback=1)',
'Batch AI component connections in a single operation for atomicity',
'Validate AI workflows after connection changes to catch configuration errors',
'To remove properties, set them to undefined (not null) in the updates object',
'To remove properties, set them to null in the updates object',
'When migrating from deprecated properties, remove the old property and add the new one in the same operation',
'Use undefined to resolve mutual exclusivity validation errors between properties',
'Use null to resolve mutual exclusivity validation errors between properties',
'Batch multiple property removals in a single updateNode operation for efficiency'
],
pitfalls: [
@@ -407,8 +415,8 @@ n8n_update_partial_workflow({
'**Auto-sanitization runs on ALL nodes**: When ANY update is made, ALL nodes in the workflow are sanitized (not just modified ones)',
'**Auto-sanitization cannot fix everything**: It fixes operator structures and missing metadata, but cannot fix broken connections or branch mismatches',
'**Corrupted workflows beyond repair**: Workflows in paradoxical states (API returns corrupt, API rejects updates) cannot be fixed via API - must be recreated',
'Setting a property to null does NOT remove it - use undefined instead',
'When properties are mutually exclusive (e.g., continueOnFail and onError), setting only the new property will fail - you must remove the old one with undefined',
'To remove a property, set it to null in the updates object',
'When properties are mutually exclusive (e.g., continueOnFail and onError), setting only the new property will fail - you must remove the old one with null',
'Removing a required property may cause validation errors - check node documentation first',
'Nested property removal with dot notation only removes the specific nested field, not the entire parent object',
'Array index notation (e.g., "parameters.headers[0]") is not supported - remove the entire array property instead'

View File

@@ -63,6 +63,10 @@ export const n8nManagementTools: ToolDefinition[] = [
executionTimeout: { type: 'number' },
errorWorkflow: { type: 'string' }
}
},
projectId: {
type: 'string',
description: 'Optional project ID to create the workflow in (enterprise feature)'
}
},
required: ['name', 'nodes', 'connections']
@@ -143,7 +147,7 @@ export const n8nManagementTools: ToolDefinition[] = [
},
{
name: 'n8n_update_partial_workflow',
description: `Update workflow incrementally with diff operations. Types: addNode, removeNode, updateNode, moveNode, enable/disableNode, addConnection, removeConnection, updateSettings, updateName, add/removeTag. See tools_documentation("n8n_update_partial_workflow", "full") for details.`,
description: `Update workflow incrementally with diff operations. Types: addNode, removeNode, updateNode, moveNode, enable/disableNode, addConnection, removeConnection, updateSettings, updateName, add/removeTag, activate/deactivateWorkflow, transferWorkflow. See tools_documentation("n8n_update_partial_workflow", "full") for details.`,
inputSchema: {
type: 'object',
additionalProperties: true, // Allow any extra properties Claude Desktop might add
@@ -602,5 +606,52 @@ export const n8nManagementTools: ToolDefinition[] = [
destructiveHint: false,
openWorldHint: true,
},
}
},
{
name: 'n8n_manage_datatable',
description: `Manage n8n data tables and rows. Actions: createTable, listTables, getTable, updateTable, deleteTable, getRows, insertRows, updateRows, upsertRows, deleteRows.`,
inputSchema: {
type: 'object',
properties: {
action: {
type: 'string',
enum: ['createTable', 'listTables', 'getTable', 'updateTable', 'deleteTable', 'getRows', 'insertRows', 'updateRows', 'upsertRows', 'deleteRows'],
description: 'Operation to perform',
},
tableId: { type: 'string', description: 'Data table ID (required for all actions except createTable and listTables)' },
name: { type: 'string', description: 'For createTable: table name. For updateTable: new name (rename only — schema is immutable after creation)' },
columns: {
type: 'array',
description: 'For createTable only: column definitions (schema is immutable after creation via public API)',
items: {
type: 'object',
properties: {
name: { type: 'string' },
type: { type: 'string', enum: ['string', 'number', 'boolean', 'date'] },
},
required: ['name'],
},
},
data: { description: 'For insertRows: array of row objects. For updateRows/upsertRows: object with column values.' },
filter: {
type: 'object',
description: 'For getRows/updateRows/upsertRows/deleteRows: {type?: "and"|"or", filters: [{columnName, condition, value}]}',
},
limit: { type: 'number', description: 'For listTables/getRows: max results (1-100)' },
cursor: { type: 'string', description: 'For listTables/getRows: pagination cursor' },
sortBy: { type: 'string', description: 'For getRows: "columnName:asc" or "columnName:desc"' },
search: { type: 'string', description: 'For getRows: text search across string columns' },
returnType: { type: 'string', enum: ['count', 'id', 'all'], description: 'For insertRows: what to return (default: count)' },
returnData: { type: 'boolean', description: 'For updateRows/upsertRows/deleteRows: return affected rows (default: false)' },
dryRun: { type: 'boolean', description: 'For updateRows/upsertRows/deleteRows: preview without applying (default: false)' },
},
required: ['action'],
},
annotations: {
title: 'Manage Data Tables',
readOnlyHint: false,
destructiveHint: true,
openWorldHint: true,
},
},
];

View File

@@ -3,13 +3,14 @@
* Fetch community nodes from n8n Strapi API and npm registry.
*
* Usage:
* npm run fetch:community # Full rebuild (verified + top 100 npm)
* npm run fetch:community # Upsert all (preserves READMEs and AI summaries)
* npm run fetch:community:verified # Verified nodes only (fast)
* npm run fetch:community:update # Incremental update (skip existing)
*
* Options:
* --verified-only Only fetch verified nodes from Strapi API
* --update Skip nodes that already exist in database
* --rebuild Delete all community nodes first (wipes READMEs/AI summaries!)
* --npm-limit=N Maximum number of npm packages to fetch (default: 100)
* --staging Use staging Strapi API instead of production
*/
@@ -22,6 +23,7 @@ import { createDatabaseAdapter } from '../database/database-adapter';
interface CliOptions {
verifiedOnly: boolean;
update: boolean;
rebuild: boolean;
npmLimit: number;
staging: boolean;
}
@@ -32,6 +34,7 @@ function parseArgs(): CliOptions {
const options: CliOptions = {
verifiedOnly: false,
update: false,
rebuild: false,
npmLimit: 100,
staging: false,
};
@@ -41,6 +44,8 @@ function parseArgs(): CliOptions {
options.verifiedOnly = true;
} else if (arg === '--update') {
options.update = true;
} else if (arg === '--rebuild') {
options.rebuild = true;
} else if (arg === '--staging') {
options.staging = true;
} else if (arg.startsWith('--npm-limit=')) {
@@ -73,7 +78,7 @@ async function main(): Promise<void> {
// Print options
console.log('Options:');
console.log(` - Mode: ${cliOptions.update ? 'Update (incremental)' : 'Rebuild'}`);
console.log(` - Mode: ${cliOptions.rebuild ? 'Rebuild (clean slate)' : cliOptions.update ? 'Update (skip existing)' : 'Upsert (preserves docs)'}`);
console.log(` - Verified only: ${cliOptions.verifiedOnly ? 'Yes' : 'No'}`);
if (!cliOptions.verifiedOnly) {
console.log(` - npm package limit: ${cliOptions.npmLimit}`);
@@ -92,9 +97,10 @@ async function main(): Promise<void> {
const environment = cliOptions.staging ? 'staging' : 'production';
const service = new CommunityNodeService(repository, environment);
// If not updating, delete existing community nodes
if (!cliOptions.update) {
console.log('\nClearing existing community nodes...');
// Only delete existing community nodes when --rebuild is explicitly requested
if (cliOptions.rebuild) {
console.log('\nClearing existing community nodes (--rebuild)...');
console.log(' WARNING: This wipes READMEs and AI summaries!');
const deleted = service.deleteCommunityNodes();
console.log(` Deleted ${deleted} existing community nodes`);
}

View File

@@ -22,6 +22,15 @@ import {
SourceControlStatus,
SourceControlPullResult,
SourceControlPushResult,
DataTable,
DataTableColumn,
DataTableListParams,
DataTableRow,
DataTableRowListParams,
DataTableInsertRowsParams,
DataTableUpdateRowsParams,
DataTableUpsertRowParams,
DataTableDeleteRowsParams,
} from '../types/n8n-api';
import { handleN8nApiError, logN8nError } from '../utils/n8n-errors';
import { cleanWorkflowForCreate, cleanWorkflowForUpdate } from './n8n-validation';
@@ -252,6 +261,14 @@ export class N8nApiClient {
}
}
async transferWorkflow(id: string, destinationProjectId: string): Promise<void> {
try {
await this.client.put(`/workflows/${id}/transfer`, { destinationProjectId });
} catch (error) {
throw handleN8nApiError(error);
}
}
async activateWorkflow(id: string): Promise<Workflow> {
try {
const response = await this.client.post(`/workflows/${id}/activate`, {});
@@ -574,6 +591,114 @@ export class N8nApiClient {
}
}
async createDataTable(params: { name: string; columns?: DataTableColumn[] }): Promise<DataTable> {
try {
const response = await this.client.post('/data-tables', params);
return response.data;
} catch (error) {
throw handleN8nApiError(error);
}
}
async listDataTables(params: DataTableListParams = {}): Promise<{ data: DataTable[]; nextCursor?: string | null }> {
try {
const response = await this.client.get('/data-tables', { params });
return this.validateListResponse<DataTable>(response.data, 'data-tables');
} catch (error) {
throw handleN8nApiError(error);
}
}
async getDataTable(id: string): Promise<DataTable> {
try {
const response = await this.client.get(`/data-tables/${id}`);
return response.data;
} catch (error) {
throw handleN8nApiError(error);
}
}
async updateDataTable(id: string, params: { name: string }): Promise<DataTable> {
try {
const response = await this.client.patch(`/data-tables/${id}`, params);
return response.data;
} catch (error) {
throw handleN8nApiError(error);
}
}
async deleteDataTable(id: string): Promise<void> {
try {
await this.client.delete(`/data-tables/${id}`);
} catch (error) {
throw handleN8nApiError(error);
}
}
async getDataTableRows(id: string, params: DataTableRowListParams = {}): Promise<{ data: DataTableRow[]; nextCursor?: string | null }> {
try {
const response = await this.client.get(`/data-tables/${id}/rows`, {
params,
paramsSerializer: (p) => this.serializeDataTableParams(p),
});
return this.validateListResponse<DataTableRow>(response.data, 'data-table-rows');
} catch (error) {
throw handleN8nApiError(error);
}
}
async insertDataTableRows(id: string, params: DataTableInsertRowsParams): Promise<any> {
try {
const response = await this.client.post(`/data-tables/${id}/rows`, params);
return response.data;
} catch (error) {
throw handleN8nApiError(error);
}
}
async updateDataTableRows(id: string, params: DataTableUpdateRowsParams): Promise<any> {
try {
const response = await this.client.patch(`/data-tables/${id}/rows/update`, params);
return response.data;
} catch (error) {
throw handleN8nApiError(error);
}
}
async upsertDataTableRow(id: string, params: DataTableUpsertRowParams): Promise<any> {
try {
const response = await this.client.post(`/data-tables/${id}/rows/upsert`, params);
return response.data;
} catch (error) {
throw handleN8nApiError(error);
}
}
async deleteDataTableRows(id: string, params: DataTableDeleteRowsParams): Promise<any> {
try {
const response = await this.client.delete(`/data-tables/${id}/rows/delete`, {
params,
paramsSerializer: (p) => this.serializeDataTableParams(p),
});
return response.data;
} catch (error) {
throw handleN8nApiError(error);
}
}
/**
* Serializes data table query params with explicit encodeURIComponent.
* Axios's default serializer doesn't encode some reserved chars that n8n rejects.
*/
private serializeDataTableParams(params: Record<string, any>): string {
const parts: string[] = [];
for (const [key, value] of Object.entries(params)) {
if (value === undefined || value === null) continue;
parts.push(`${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`);
}
return parts.join('&');
}
/**
* Validates and normalizes n8n API list responses.
* Handles both modern format {data: [], nextCursor?: string} and legacy array format.

View File

@@ -1,3 +1,4 @@
import crypto from 'crypto';
import { z } from 'zod';
import { WorkflowNode, WorkflowConnection, Workflow } from '../types/n8n-api';
import { isTriggerNode, isActivatableTrigger } from '../utils/node-type-utils';
@@ -49,7 +50,7 @@ export const workflowConnectionSchema = z.record(
ai_memory: connectionArraySchema.optional(),
ai_embedding: connectionArraySchema.optional(),
ai_vectorStore: connectionArraySchema.optional(),
})
}).catchall(connectionArraySchema) // Allow additional AI connection types (ai_outputParser, ai_document, ai_textSplitter, etc.)
);
export const workflowSettingsSchema = z.object({
@@ -87,6 +88,22 @@ export function validateWorkflowSettings(settings: unknown): z.infer<typeof work
return workflowSettingsSchema.parse(settings);
}
const WEBHOOK_NODE_TYPES = new Set([
'n8n-nodes-base.webhook',
'n8n-nodes-base.webhookTrigger',
'n8n-nodes-base.formTrigger',
'@n8n/n8n-nodes-langchain.chatTrigger',
]);
function ensureWebhookIds(nodes?: WorkflowNode[]): void {
if (!nodes) return;
for (const node of nodes) {
if (WEBHOOK_NODE_TYPES.has(node.type) && !node.webhookId) {
node.webhookId = crypto.randomUUID();
}
}
}
// Clean workflow data for API operations
export function cleanWorkflowForCreate(workflow: Partial<Workflow>): Partial<Workflow> {
const {
@@ -109,6 +126,8 @@ export function cleanWorkflowForCreate(workflow: Partial<Workflow>): Partial<Wor
cleanedWorkflow.settings = defaultWorkflowSettings;
}
ensureWebhookIds(cleanedWorkflow.nodes);
return cleanedWorkflow;
}
@@ -194,6 +213,8 @@ export function cleanWorkflowForUpdate(workflow: Workflow): Partial<Workflow> {
cleanedWorkflow.settings = { executionOrder: 'v1' as const };
}
ensureWebhookIds(cleanedWorkflow.nodes);
return cleanedWorkflow;
}
@@ -248,15 +269,15 @@ export function validateWorkflowStructure(workflow: Partial<Workflow>): string[]
const connectedNodes = new Set<string>();
// Collect all nodes that appear in connections (as source or target)
// Check ALL connection types, not just 'main' - AI workflows use ai_tool, ai_languageModel, etc.
const ALL_CONNECTION_TYPES = ['main', 'error', 'ai_tool', 'ai_languageModel', 'ai_memory', 'ai_embedding', 'ai_vectorStore'] as const;
// Iterate over ALL connection types present in the data — not a hardcoded list —
// so that every AI connection type (ai_outputParser, ai_document, ai_textSplitter,
// ai_agent, ai_chain, ai_retriever, etc.) is covered automatically.
Object.entries(workflow.connections).forEach(([sourceName, connection]) => {
connectedNodes.add(sourceName); // Node has outgoing connection
// Check all connection types for target nodes
ALL_CONNECTION_TYPES.forEach(connType => {
const connData = (connection as Record<string, unknown>)[connType];
// Check every connection type key present on this source node
const connectionRecord = connection as Record<string, unknown>;
Object.values(connectionRecord).forEach((connData) => {
if (connData && Array.isArray(connData)) {
connData.forEach((outputs) => {
if (Array.isArray(outputs)) {
@@ -429,24 +450,29 @@ export function validateWorkflowStructure(workflow: Partial<Workflow>): string[]
}
}
if (connection.main && Array.isArray(connection.main)) {
connection.main.forEach((outputs, outputIndex) => {
if (Array.isArray(outputs)) {
outputs.forEach((target, targetIndex) => {
// Check if target exists by name (correct)
if (!nodeNames.has(target.node)) {
// Check if they're using an ID instead of name
if (nodeIds.has(target.node)) {
const correctName = nodeIdToName.get(target.node);
errors.push(`Connection target uses node ID '${target.node}' but must use node name '${correctName}' (from ${sourceName}[${outputIndex}][${targetIndex}])`);
} else {
errors.push(`Connection references non-existent target node: ${target.node} (from ${sourceName}[${outputIndex}][${targetIndex}])`);
// Check all connection types (main, error, ai_tool, ai_languageModel, etc.)
const connectionRecord = connection as Record<string, unknown>;
Object.values(connectionRecord).forEach((connData) => {
if (connData && Array.isArray(connData)) {
connData.forEach((outputs: any, outputIndex: number) => {
if (Array.isArray(outputs)) {
outputs.forEach((target: any, targetIndex: number) => {
if (!target?.node) return;
// Check if target exists by name (correct)
if (!nodeNames.has(target.node)) {
// Check if they're using an ID instead of name
if (nodeIds.has(target.node)) {
const correctName = nodeIdToName.get(target.node);
errors.push(`Connection target uses node ID '${target.node}' but must use node name '${correctName}' (from ${sourceName}[${outputIndex}][${targetIndex}])`);
} else {
errors.push(`Connection references non-existent target node: ${target.node} (from ${sourceName}[${outputIndex}][${targetIndex}])`);
}
}
}
});
}
});
}
});
}
});
}
});
});
}

View File

@@ -1374,8 +1374,11 @@ export class NodeSpecificValidators {
});
}
// Check for primitive return
if (/return\s+(true|false|null|undefined|\d+|['"`])/m.test(code)) {
// Skip primitive return check when helper functions are present,
// since we can't distinguish top-level vs nested returns without AST.
// Matches: function name(), const/let/var name = [async] function/arrow
const hasHelperFunctions = /(?:function\s+\w+\s*\(|(?:const|let|var)\s+\w+\s*=\s*(?:async\s+)?(?:function|\([^)]*\)\s*=>|\w+\s*=>))/.test(code);
if (!hasHelperFunctions && /return\s+(true|false|null|undefined|\d+|['"`])/m.test(code)) {
errors.push({
type: 'invalid_value',
property: 'jsCode',
@@ -1487,7 +1490,7 @@ export class NodeSpecificValidators {
// Check for common variable mistakes
if (language === 'javaScript') {
// Using $ without proper variable
if (/\$(?![a-zA-Z])/.test(code) && !code.includes('${')) {
if (/\$(?![a-zA-Z_(])/.test(code) && !code.includes('${')) {
warnings.push({
type: 'best_practice',
message: 'Invalid $ usage detected',

View File

@@ -671,11 +671,13 @@ export class WorkflowAutoFixer {
filteredFixes: FixOperation[],
allFixes: FixOperation[]
): WorkflowDiffOperation[] {
// fixedNodes contains node names (FixOperation.node = node.name)
const fixedNodes = new Set(filteredFixes.map(f => f.node));
const hasConnectionFixes = filteredFixes.some(f => CONNECTION_FIX_TYPES.includes(f.type));
return operations.filter(op => {
if (op.type === 'updateNode') {
return fixedNodes.has(op.nodeId || '');
// Check both nodeName and nodeId — operations may use either
return fixedNodes.has(op.nodeName || '') || fixedNodes.has(op.nodeId || '');
}
if (op.type === 'replaceConnections') {
return hasConnectionFixes;
@@ -1186,10 +1188,11 @@ export class WorkflowAutoFixer {
description: `Upgrade ${node.name} from v${currentVersion} to v${latestVersion}. ${analysis.reason}`
});
// Create update operation
// Create update operation — both nodeId and nodeName needed for fix filtering
const operation: UpdateNodeOperation = {
type: 'updateNode',
nodeId: node.id,
nodeName: node.name,
updates: {
typeVersion: parseFloat(latestVersion),
parameters: migrationResult.updatedNode.parameters,

View File

@@ -28,7 +28,8 @@ import {
ActivateWorkflowOperation,
DeactivateWorkflowOperation,
CleanStaleConnectionsOperation,
ReplaceConnectionsOperation
ReplaceConnectionsOperation,
TransferWorkflowOperation
} from '../types/workflow-diff';
import { Workflow, WorkflowNode, WorkflowConnection } from '../types/n8n-api';
import { Logger } from '../utils/logger';
@@ -54,6 +55,8 @@ export class WorkflowDiffEngine {
// Track tag operations for dedicated API calls
private tagsToAdd: string[] = [];
private tagsToRemove: string[] = [];
// Track transfer operation for dedicated API call
private transferToProjectId: string | undefined;
/**
* Apply diff operations to a workflow
@@ -70,6 +73,7 @@ export class WorkflowDiffEngine {
this.removedNodeNames.clear();
this.tagsToAdd = [];
this.tagsToRemove = [];
this.transferToProjectId = undefined;
// Clone workflow to avoid modifying original
const workflowCopy = JSON.parse(JSON.stringify(workflow));
@@ -141,6 +145,12 @@ export class WorkflowDiffEngine {
};
}
// Extract and clean up activation flags (same as atomic mode)
const shouldActivate = (workflowCopy as any)._shouldActivate === true;
const shouldDeactivate = (workflowCopy as any)._shouldDeactivate === true;
delete (workflowCopy as any)._shouldActivate;
delete (workflowCopy as any)._shouldDeactivate;
const success = appliedIndices.length > 0;
return {
success,
@@ -151,8 +161,11 @@ export class WorkflowDiffEngine {
warnings: this.warnings.length > 0 ? this.warnings : undefined,
applied: appliedIndices,
failed: failedIndices,
shouldActivate: shouldActivate || undefined,
shouldDeactivate: shouldDeactivate || undefined,
tagsToAdd: this.tagsToAdd.length > 0 ? this.tagsToAdd : undefined,
tagsToRemove: this.tagsToRemove.length > 0 ? this.tagsToRemove : undefined
tagsToRemove: this.tagsToRemove.length > 0 ? this.tagsToRemove : undefined,
transferToProjectId: this.transferToProjectId || undefined
};
} else {
// Atomic mode: all operations must succeed
@@ -256,7 +269,8 @@ export class WorkflowDiffEngine {
shouldActivate: shouldActivate || undefined,
shouldDeactivate: shouldDeactivate || undefined,
tagsToAdd: this.tagsToAdd.length > 0 ? this.tagsToAdd : undefined,
tagsToRemove: this.tagsToRemove.length > 0 ? this.tagsToRemove : undefined
tagsToRemove: this.tagsToRemove.length > 0 ? this.tagsToRemove : undefined,
transferToProjectId: this.transferToProjectId || undefined
};
}
} catch (error) {
@@ -298,6 +312,8 @@ export class WorkflowDiffEngine {
case 'addTag':
case 'removeTag':
return null; // These are always valid
case 'transferWorkflow':
return this.validateTransferWorkflow(workflow, operation as TransferWorkflowOperation);
case 'activateWorkflow':
return this.validateActivateWorkflow(workflow, operation);
case 'deactivateWorkflow':
@@ -367,6 +383,9 @@ export class WorkflowDiffEngine {
case 'replaceConnections':
this.applyReplaceConnections(workflow, operation);
break;
case 'transferWorkflow':
this.applyTransferWorkflow(workflow, operation as TransferWorkflowOperation);
break;
}
}
@@ -975,6 +994,18 @@ export class WorkflowDiffEngine {
(workflow as any)._shouldDeactivate = true;
}
// Transfer operation — uses dedicated API call (PUT /workflows/{id}/transfer)
private validateTransferWorkflow(_workflow: Workflow, operation: TransferWorkflowOperation): string | null {
if (!operation.destinationProjectId) {
return 'transferWorkflow requires a non-empty destinationProjectId string';
}
return null;
}
private applyTransferWorkflow(_workflow: Workflow, operation: TransferWorkflowOperation): void {
this.transferToProjectId = operation.destinationProjectId;
}
// Connection cleanup operation validators
private validateCleanStaleConnections(workflow: Workflow, operation: CleanStaleConnectionsOperation): string | null {
// This operation is always valid - it just cleans up what it finds
@@ -1128,9 +1159,10 @@ export class WorkflowDiffEngine {
const connection = connectionsAtIndex[connIndex];
// Check if target node was renamed
if (renames.has(connection.node)) {
const oldTargetName = connection.node;
const newTargetName = renames.get(connection.node)!;
connection.node = newTargetName;
logger.debug(`Updated connection: ${sourceName}[${outputType}][${outputIndex}][${connIndex}].node: "${connection.node}" → "${newTargetName}"`);
logger.debug(`Updated connection: ${sourceName}[${outputType}][${outputIndex}][${connIndex}].node: "${oldTargetName}" → "${newTargetName}"`);
}
}
}
@@ -1237,15 +1269,21 @@ export class WorkflowDiffEngine {
private setNestedProperty(obj: any, path: string, value: any): void {
const keys = path.split('.');
let current = obj;
for (let i = 0; i < keys.length - 1; i++) {
const key = keys[i];
if (!(key in current) || typeof current[key] !== 'object') {
if (!(key in current) || typeof current[key] !== 'object' || current[key] === null) {
if (value === null) return; // parent path doesn't exist, nothing to delete
current[key] = {};
}
current = current[key];
}
current[keys[keys.length - 1]] = value;
const finalKey = keys[keys.length - 1];
if (value === null) {
delete current[finalKey];
} else {
current[finalKey] = value;
}
}
}

View File

@@ -454,4 +454,82 @@ export interface ErrorSuggestion {
title: string;
description: string;
confidence: 'high' | 'medium' | 'low';
}
// Data Table types
export interface DataTableColumn {
name: string;
type?: 'string' | 'number' | 'boolean' | 'date';
}
export interface DataTableColumnResponse {
id: string;
name: string;
type: 'string' | 'number' | 'boolean' | 'date';
index: number;
}
export interface DataTable {
id: string;
name: string;
columns?: DataTableColumnResponse[];
projectId?: string;
createdAt?: string;
updatedAt?: string;
}
export interface DataTableRow {
id?: number;
createdAt?: string;
updatedAt?: string;
[columnName: string]: unknown;
}
export interface DataTableFilterCondition {
columnName: string;
condition: 'eq' | 'neq' | 'like' | 'ilike' | 'gt' | 'gte' | 'lt' | 'lte';
value?: any;
}
export interface DataTableFilter {
type?: 'and' | 'or';
filters: DataTableFilterCondition[];
}
export interface DataTableListParams {
limit?: number;
cursor?: string;
}
export interface DataTableRowListParams {
limit?: number;
cursor?: string;
filter?: string;
sortBy?: string;
search?: string;
}
export interface DataTableInsertRowsParams {
data: Record<string, unknown>[];
returnType?: 'count' | 'id' | 'all';
}
export interface DataTableUpdateRowsParams {
filter: DataTableFilter;
data: Record<string, unknown>;
returnData?: boolean;
dryRun?: boolean;
}
export interface DataTableUpsertRowParams {
filter: DataTableFilter;
data: Record<string, unknown>;
returnData?: boolean;
dryRun?: boolean;
}
export interface DataTableDeleteRowsParams {
filter: string;
returnData?: boolean;
dryRun?: boolean;
}

View File

@@ -124,6 +124,11 @@ export interface DeactivateWorkflowOperation extends DiffOperation {
// No additional properties needed - just deactivates the workflow
}
export interface TransferWorkflowOperation extends DiffOperation {
type: 'transferWorkflow';
destinationProjectId: string;
}
// Connection Cleanup Operations
export interface CleanStaleConnectionsOperation extends DiffOperation {
type: 'cleanStaleConnections';
@@ -161,7 +166,8 @@ export type WorkflowDiffOperation =
| ActivateWorkflowOperation
| DeactivateWorkflowOperation
| CleanStaleConnectionsOperation
| ReplaceConnectionsOperation;
| ReplaceConnectionsOperation
| TransferWorkflowOperation;
// Main diff request structure
export interface WorkflowDiffRequest {
@@ -192,6 +198,7 @@ export interface WorkflowDiffResult {
shouldDeactivate?: boolean; // Flag to deactivate workflow after update (for deactivateWorkflow operation)
tagsToAdd?: string[];
tagsToRemove?: string[];
transferToProjectId?: string; // For transferWorkflow operation - uses dedicated API call
}
// Helper type for node reference (supports both ID and name)

View File

@@ -22,8 +22,10 @@ export class N8nAuthenticationError extends N8nApiError {
}
export class N8nNotFoundError extends N8nApiError {
constructor(resource: string, id?: string) {
const message = id ? `${resource} with ID ${id} not found` : `${resource} not found`;
constructor(messageOrResource: string, id?: string) {
// If id is provided, format as "resource with ID id not found"
// Otherwise, use messageOrResource as-is (it's already a complete message from the API)
const message = id ? `${messageOrResource} with ID ${id} not found` : messageOrResource;
super(message, 404, 'NOT_FOUND');
this.name = 'N8nNotFoundError';
}
@@ -70,7 +72,7 @@ export function handleN8nApiError(error: unknown): N8nApiError {
case 401:
return new N8nAuthenticationError(message);
case 404:
return new N8nNotFoundError('Resource', message);
return new N8nNotFoundError(message || 'Resource');
case 400:
return new N8nValidationError(message, data);
case 429:

View File

@@ -87,7 +87,7 @@ class InMemoryDatabaseAdapter implements DatabaseAdapter {
class InMemoryPreparedStatement implements PreparedStatement {
run = vi.fn((...params: any[]): RunResult => {
if (this.sql.includes('INSERT OR REPLACE INTO nodes')) {
if (this.sql.includes('INSERT INTO nodes')) {
const node = this.paramsToNode(params);
this.adapter.saveNode(node);
return { changes: 1, lastInsertRowid: 1 };

View File

@@ -0,0 +1,115 @@
#!/usr/bin/env tsx
/**
* Cleanup Non-Test Workflows
*
* Deletes all workflows from the n8n test instance EXCEPT those
* with "[TEST]" in the name. This helps keep the test instance
* clean and prevents list endpoint pagination issues.
*
* Usage:
* npx tsx tests/integration/n8n-api/scripts/cleanup-non-test-workflows.ts
* npx tsx tests/integration/n8n-api/scripts/cleanup-non-test-workflows.ts --dry-run
*/
import { getN8nCredentials, validateCredentials } from '../utils/credentials';
const DRY_RUN = process.argv.includes('--dry-run');
interface Workflow {
id: string;
name: string;
active: boolean;
}
async function fetchAllWorkflows(baseUrl: string, apiKey: string): Promise<Workflow[]> {
const all: Workflow[] = [];
let cursor: string | undefined;
while (true) {
const url = new URL('/api/v1/workflows', baseUrl);
url.searchParams.set('limit', '100');
if (cursor) url.searchParams.set('cursor', cursor);
const res = await fetch(url.toString(), {
headers: { 'X-N8N-API-KEY': apiKey }
});
if (!res.ok) {
throw new Error(`Failed to list workflows: ${res.status} ${res.statusText}`);
}
const body = await res.json() as { data: Workflow[]; nextCursor?: string };
all.push(...body.data);
if (!body.nextCursor) break;
cursor = body.nextCursor;
}
return all;
}
async function deleteWorkflow(baseUrl: string, apiKey: string, id: string): Promise<void> {
const res = await fetch(`${baseUrl}/api/v1/workflows/${id}`, {
method: 'DELETE',
headers: { 'X-N8N-API-KEY': apiKey }
});
if (!res.ok) {
throw new Error(`Failed to delete workflow ${id}: ${res.status} ${res.statusText}`);
}
}
async function main() {
const creds = getN8nCredentials();
validateCredentials(creds);
console.log(`n8n Instance: ${creds.url}`);
console.log(`Mode: ${DRY_RUN ? 'DRY RUN' : 'LIVE DELETE'}\n`);
const workflows = await fetchAllWorkflows(creds.url, creds.apiKey);
console.log(`Total workflows found: ${workflows.length}\n`);
const toKeep = workflows.filter(w => w.name.includes('[TEST]'));
const toDelete = workflows.filter(w => !w.name.includes('[TEST]'));
console.log(`Keeping (${toKeep.length}):`);
for (const w of toKeep) {
console.log(`${w.id} - ${w.name}`);
}
console.log(`\nDeleting (${toDelete.length}):`);
for (const w of toDelete) {
console.log(` 🗑️ ${w.id} - ${w.name}${w.active ? ' (ACTIVE)' : ''}`);
}
if (DRY_RUN) {
console.log('\nDry run complete. No workflows were deleted.');
return;
}
if (toDelete.length === 0) {
console.log('\nNothing to delete.');
return;
}
console.log(`\nDeleting ${toDelete.length} workflows...`);
let deleted = 0;
let failed = 0;
for (const w of toDelete) {
try {
await deleteWorkflow(creds.url, creds.apiKey, w.id);
deleted++;
} catch (err) {
console.error(` Failed to delete ${w.id} (${w.name}): ${err}`);
failed++;
}
}
console.log(`\nDone! Deleted: ${deleted}, Failed: ${failed}, Kept: ${toKeep.length}`);
}
main().catch(err => {
console.error('Fatal error:', err);
process.exit(1);
});

File diff suppressed because it is too large Load Diff

View File

@@ -120,7 +120,7 @@ class MockPreparedStatement implements PreparedStatement {
}
// saveNode - INSERT OR REPLACE
if (this.sql.includes('INSERT OR REPLACE INTO nodes')) {
if (this.sql.includes('INSERT INTO nodes')) {
this.run = vi.fn((...params: any[]): RunResult => {
const nodes = this.mockData.get('community_nodes') || [];
const nodeType = params[0];

View File

@@ -91,7 +91,7 @@ describe('NodeRepository - Core Functionality', () => {
repository.saveNode(parsedNode);
// Verify prepare was called with correct SQL
expect(mockAdapter.prepare).toHaveBeenCalledWith(expect.stringContaining('INSERT OR REPLACE INTO nodes'));
expect(mockAdapter.prepare).toHaveBeenCalledWith(expect.stringContaining('INSERT INTO nodes'));
// Get the prepared statement and verify run was called
const stmt = mockAdapter._getStatement(mockAdapter.prepare.mock.lastCall?.[0] || '');

View File

@@ -55,18 +55,9 @@ describe('NodeRepository - Outputs Handling', () => {
repository.saveNode(node);
expect(mockDb.prepare).toHaveBeenCalledWith(`
INSERT OR REPLACE INTO nodes (
node_type, package_name, display_name, description,
category, development_style, is_ai_tool, is_trigger,
is_webhook, is_versioned, is_tool_variant, tool_variant_of,
has_tool_variant, version, documentation,
properties_schema, operations, credentials_required,
outputs, output_names,
is_community, is_verified, author_name, author_github_url,
npm_package_name, npm_version, npm_downloads, community_fetched_at
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
`);
expect(mockDb.prepare).toHaveBeenCalledWith(
expect.stringContaining('INSERT INTO nodes')
);
expect(mockStatement.run).toHaveBeenCalledWith(
'nodes-base.splitInBatches',

View File

@@ -219,6 +219,7 @@ describe('HTTP Server Session Management', () => {
status: vi.fn().mockReturnThis(),
json: vi.fn().mockReturnThis(),
send: vi.fn().mockReturnThis(),
end: vi.fn().mockReturnThis(),
setHeader: vi.fn((key: string, value: string) => {
headers[key.toLowerCase()] = value;
}),
@@ -1170,7 +1171,7 @@ describe('HTTP Server Session Management', () => {
it('should show legacy SSE session when present', async () => {
server = new SingleSessionHTTPServer();
// Mock legacy session
const mockSession = {
sessionId: 'sse-session-123',
@@ -1180,10 +1181,127 @@ describe('HTTP Server Session Management', () => {
(server as any).session = mockSession;
const sessionInfo = server.getSessionInfo();
expect(sessionInfo.active).toBe(true);
expect(sessionInfo.sessionId).toBe('sse-session-123');
expect(sessionInfo.age).toBeGreaterThanOrEqual(0);
});
});
describe('Notification handling for stale sessions (#654)', () => {
beforeEach(() => {
// Re-apply mockImplementation after vi.clearAllMocks() resets it
mockConsoleManager.wrapOperation.mockImplementation(async (fn: () => Promise<any>) => {
return await fn();
});
});
it('should return 202 for notification with stale session ID', async () => {
server = new SingleSessionHTTPServer();
const { req, res } = createMockReqRes();
req.headers = { 'mcp-session-id': 'stale-session-that-does-not-exist' };
req.method = 'POST';
req.body = {
jsonrpc: '2.0',
method: 'notifications/initialized',
};
await server.handleRequest(req as any, res as any);
expect(res.status).toHaveBeenCalledWith(202);
expect(res.end).toHaveBeenCalled();
});
it('should return 202 for notification batch with stale session ID', async () => {
server = new SingleSessionHTTPServer();
const { req, res } = createMockReqRes();
req.headers = { 'mcp-session-id': 'stale-session-that-does-not-exist' };
req.method = 'POST';
req.body = [
{ jsonrpc: '2.0', method: 'notifications/initialized' },
{ jsonrpc: '2.0', method: 'notifications/cancelled' },
];
await server.handleRequest(req as any, res as any);
expect(res.status).toHaveBeenCalledWith(202);
expect(res.end).toHaveBeenCalled();
});
it('should return 400 for request (with id) with stale session ID', async () => {
server = new SingleSessionHTTPServer();
const { req, res } = createMockReqRes();
req.headers = { 'mcp-session-id': 'stale-session-that-does-not-exist' };
req.method = 'POST';
req.body = {
jsonrpc: '2.0',
method: 'tools/call',
params: { name: 'search_nodes', arguments: { query: 'http' } },
id: 42,
};
await server.handleRequest(req as any, res as any);
expect(res.status).toHaveBeenCalledWith(400);
expect(res.json).toHaveBeenCalledWith(expect.objectContaining({
error: expect.objectContaining({
message: 'Bad Request: Session not found or expired',
}),
}));
});
it('should return 202 for notification with no session ID', async () => {
server = new SingleSessionHTTPServer();
const { req, res } = createMockReqRes();
req.method = 'POST';
req.body = {
jsonrpc: '2.0',
method: 'notifications/cancelled',
};
await server.handleRequest(req as any, res as any);
expect(res.status).toHaveBeenCalledWith(202);
expect(res.end).toHaveBeenCalled();
});
it('should return 400 for request with no session ID and not initialize', async () => {
server = new SingleSessionHTTPServer();
const { req, res } = createMockReqRes();
req.method = 'POST';
req.body = {
jsonrpc: '2.0',
method: 'tools/list',
id: 1,
};
await server.handleRequest(req as any, res as any);
expect(res.status).toHaveBeenCalledWith(400);
});
it('should return 400 for mixed batch (notification + request) with stale session', async () => {
server = new SingleSessionHTTPServer();
const { req, res } = createMockReqRes();
req.headers = { 'mcp-session-id': 'stale-session-that-does-not-exist' };
req.method = 'POST';
req.body = [
{ jsonrpc: '2.0', method: 'notifications/initialized' },
{ jsonrpc: '2.0', method: 'tools/list', id: 1 },
];
await server.handleRequest(req as any, res as any);
expect(res.status).toHaveBeenCalledWith(400);
});
});
});

Some files were not shown because too many files have changed in this diff Show More