Compare commits

..

1 Commits

Author SHA1 Message Date
czlonkowski
f5088918aa fix: memory leak in SSE session reset (#542)
When SSE sessions are recreated every 5 minutes, the old session's MCP
server was not being closed, causing:
- SimpleCache cleanup timer continuing to run indefinitely
- Database connections remaining open
- Cached data (~50-100MB per session) persisting in memory

Added server.close() call before transport.close() in resetSessionSSE(),
mirroring the existing cleanup pattern in removeSession().

Fixes #542

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-21 13:04:04 +01:00
264 changed files with 28566 additions and 30899 deletions

176
.github/workflows/benchmark-pr.yml vendored Normal file
View File

@@ -0,0 +1,176 @@
name: Benchmark PR Comparison
on:
pull_request:
branches: [main]
paths-ignore:
- '**.md'
- '**.txt'
- 'docs/**'
- 'examples/**'
- '.github/FUNDING.yml'
- '.github/ISSUE_TEMPLATE/**'
- '.github/pull_request_template.md'
- '.gitignore'
- 'LICENSE*'
- 'ATTRIBUTION.md'
- 'SECURITY.md'
- 'CODE_OF_CONDUCT.md'
permissions:
pull-requests: write
contents: read
statuses: write
jobs:
benchmark-comparison:
runs-on: ubuntu-latest
steps:
- name: Checkout PR branch
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20
cache: 'npm'
- name: Install dependencies
run: npm ci
# Run benchmarks on current branch
- name: Run current benchmarks
run: npm run benchmark:ci
- name: Save current results
run: cp benchmark-results.json benchmark-current.json
# Checkout and run benchmarks on base branch
- name: Checkout base branch
run: |
git checkout ${{ github.event.pull_request.base.sha }}
git status
- name: Install base dependencies
run: npm ci
- name: Run baseline benchmarks
run: npm run benchmark:ci
continue-on-error: true
- name: Save baseline results
run: |
if [ -f benchmark-results.json ]; then
cp benchmark-results.json benchmark-baseline.json
else
echo '{"files":[]}' > benchmark-baseline.json
fi
# Compare results
- name: Checkout PR branch again
run: git checkout ${{ github.event.pull_request.head.sha }}
- name: Compare benchmarks
id: compare
run: |
node scripts/compare-benchmarks.js benchmark-current.json benchmark-baseline.json || echo "REGRESSION=true" >> $GITHUB_OUTPUT
# Upload comparison artifacts
- name: Upload benchmark comparison
if: always()
uses: actions/upload-artifact@v4
with:
name: benchmark-comparison-${{ github.run_number }}
path: |
benchmark-current.json
benchmark-baseline.json
benchmark-comparison.json
benchmark-comparison.md
retention-days: 30
# Post comparison to PR
- name: Post benchmark comparison to PR
if: always()
uses: actions/github-script@v7
continue-on-error: true
with:
script: |
try {
const fs = require('fs');
let comment = '## ⚡ Benchmark Comparison\n\n';
try {
if (fs.existsSync('benchmark-comparison.md')) {
const comparison = fs.readFileSync('benchmark-comparison.md', 'utf8');
comment += comparison;
} else {
comment += 'Benchmark comparison could not be generated.';
}
} catch (error) {
comment += `Error reading benchmark comparison: ${error.message}`;
}
comment += '\n\n---\n';
comment += `*[View full benchmark results](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }})*`;
// Find existing comment
const { data: comments } = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
});
const botComment = comments.find(comment =>
comment.user.type === 'Bot' &&
comment.body.includes('## ⚡ Benchmark Comparison')
);
if (botComment) {
await github.rest.issues.updateComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: botComment.id,
body: comment
});
} else {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body: comment
});
}
} catch (error) {
console.error('Failed to create/update PR comment:', error.message);
console.log('This is likely due to insufficient permissions for external PRs.');
console.log('Benchmark comparison has been saved to artifacts instead.');
}
# Add status check
- name: Set benchmark status
if: always()
uses: actions/github-script@v7
continue-on-error: true
with:
script: |
try {
const hasRegression = '${{ steps.compare.outputs.REGRESSION }}' === 'true';
const state = hasRegression ? 'failure' : 'success';
const description = hasRegression
? 'Performance regressions detected'
: 'No performance regressions';
await github.rest.repos.createCommitStatus({
owner: context.repo.owner,
repo: context.repo.repo,
sha: context.sha,
state: state,
target_url: `https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}`,
description: description,
context: 'benchmarks/regression-check'
});
} catch (error) {
console.error('Failed to create commit status:', error.message);
console.log('This is likely due to insufficient permissions for external PRs.');
}

214
.github/workflows/benchmark.yml vendored Normal file
View File

@@ -0,0 +1,214 @@
name: Performance Benchmarks
on:
push:
branches: [main, feat/comprehensive-testing-suite]
paths-ignore:
- '**.md'
- '**.txt'
- 'docs/**'
- 'examples/**'
- '.github/FUNDING.yml'
- '.github/ISSUE_TEMPLATE/**'
- '.github/pull_request_template.md'
- '.gitignore'
- 'LICENSE*'
- 'ATTRIBUTION.md'
- 'SECURITY.md'
- 'CODE_OF_CONDUCT.md'
pull_request:
branches: [main]
paths-ignore:
- '**.md'
- '**.txt'
- 'docs/**'
- 'examples/**'
- '.github/FUNDING.yml'
- '.github/ISSUE_TEMPLATE/**'
- '.github/pull_request_template.md'
- '.gitignore'
- 'LICENSE*'
- 'ATTRIBUTION.md'
- 'SECURITY.md'
- 'CODE_OF_CONDUCT.md'
workflow_dispatch:
permissions:
# For PR comments
pull-requests: write
# For pushing to gh-pages branch
contents: write
# For deployment to GitHub Pages
pages: write
id-token: write
jobs:
benchmark:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
# Fetch all history for proper benchmark comparison
fetch-depth: 0
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Build project
run: npm run build
- name: Run benchmarks
run: npm run benchmark:ci
- name: Format benchmark results
run: node scripts/format-benchmark-results.js
- name: Upload benchmark artifacts
uses: actions/upload-artifact@v4
with:
name: benchmark-results
path: |
benchmark-results.json
benchmark-results-formatted.json
benchmark-summary.json
# Ensure gh-pages branch exists
- name: Check and create gh-pages branch
run: |
git fetch origin gh-pages:gh-pages 2>/dev/null || {
echo "gh-pages branch doesn't exist. Creating it..."
git checkout --orphan gh-pages
git rm -rf .
echo "# Benchmark Results" > README.md
git add README.md
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git commit -m "Initial gh-pages commit"
git push origin gh-pages
git checkout ${{ github.ref_name }}
}
# Clean up workspace before benchmark action
- name: Clean workspace
run: |
git add -A
git stash || true
# Store benchmark results and compare
- name: Store benchmark result
uses: benchmark-action/github-action-benchmark@v1
continue-on-error: true
id: benchmark
with:
name: n8n-mcp Benchmarks
tool: 'customSmallerIsBetter'
output-file-path: benchmark-results-formatted.json
github-token: ${{ secrets.GITHUB_TOKEN }}
auto-push: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }}
# Where to store benchmark data
benchmark-data-dir-path: 'benchmarks'
# Alert when performance regresses by 10%
alert-threshold: '110%'
# Comment on PR when regression is detected
comment-on-alert: true
alert-comment-cc-users: '@czlonkowski'
# Summary always
summary-always: true
# Max number of data points to retain
max-items-in-chart: 50
fail-on-alert: false
# Comment on PR with benchmark results
- name: Comment PR with results
uses: actions/github-script@v7
if: github.event_name == 'pull_request'
continue-on-error: true
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
try {
const fs = require('fs');
const summary = JSON.parse(fs.readFileSync('benchmark-summary.json', 'utf8'));
// Format results for PR comment
let comment = '## 📊 Performance Benchmark Results\n\n';
comment += `🕐 Run at: ${new Date(summary.timestamp).toLocaleString()}\n\n`;
comment += '| Benchmark | Time | Ops/sec | Range |\n';
comment += '|-----------|------|---------|-------|\n';
// Group benchmarks by category
const categories = {};
for (const benchmark of summary.benchmarks) {
const [category, ...nameParts] = benchmark.name.split(' - ');
if (!categories[category]) categories[category] = [];
categories[category].push({
...benchmark,
shortName: nameParts.join(' - ')
});
}
// Display by category
for (const [category, benchmarks] of Object.entries(categories)) {
comment += `\n### ${category}\n`;
for (const benchmark of benchmarks) {
comment += `| ${benchmark.shortName} | ${benchmark.time} | ${benchmark.opsPerSec} | ${benchmark.range} |\n`;
}
}
// Add comparison link
comment += '\n\n📈 [View historical benchmark trends](https://czlonkowski.github.io/n8n-mcp/benchmarks/)\n';
comment += '\n⚡ Performance regressions >10% will be flagged automatically.\n';
await github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: comment
});
} catch (error) {
console.error('Failed to create PR comment:', error.message);
console.log('This is likely due to insufficient permissions for external PRs.');
console.log('Benchmark results have been saved to artifacts instead.');
}
# Deploy benchmark results to GitHub Pages
deploy:
needs: benchmark
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
steps:
- name: Checkout
uses: actions/checkout@v4
with:
ref: gh-pages
continue-on-error: true
# If gh-pages checkout failed, create a minimal structure
- name: Ensure gh-pages content exists
run: |
if [ ! -f "index.html" ]; then
echo "Creating minimal gh-pages structure..."
mkdir -p benchmarks
echo '<!DOCTYPE html><html><head><title>n8n-mcp Benchmarks</title></head><body><h1>n8n-mcp Benchmarks</h1><p>Benchmark data will appear here after the first run.</p></body></html>' > index.html
fi
- name: Setup Pages
uses: actions/configure-pages@v4
- name: Upload Pages artifact
uses: actions/upload-pages-artifact@v3
with:
path: '.'
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4

View File

@@ -59,9 +59,7 @@ jobs:
run: |
npm init -y
# Install from tarball WITHOUT lockfile (simulates npm install n8n-mcp)
# Use --ignore-scripts to skip native compilation of transitive deps like isolated-vm
# (n8n-mcp only reads node metadata, it doesn't execute n8n nodes at runtime)
npm install --ignore-scripts ./n8n-mcp-*.tgz
npm install ./n8n-mcp-*.tgz
- name: Verify critical dependency versions
working-directory: /tmp/fresh-install-test
@@ -77,15 +75,15 @@ jobs:
echo "Zod version: $ZOD_VERSION"
echo ""
# Check MCP SDK version - must be exactly 1.28.0
# Check MCP SDK version - must be exactly 1.20.1
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.28.0" ]]; then
if [[ "$SDK_VERSION" != "1.20.1" ]]; then
echo "❌ FAILED: MCP SDK version mismatch!"
echo " Expected: 1.28.0"
echo " Expected: 1.20.1"
echo " Got: $SDK_VERSION"
echo ""
echo "This can cause runtime errors. See issues #440, #444, #446, #447, #450"
@@ -100,7 +98,7 @@ jobs:
exit 1
fi
if [[ "$ZOD_VERSION" =~ ^4\. ]]; then
echo "❌ FAILED: Zod v4 detected - incompatible with MCP SDK 1.27.1!"
echo "❌ FAILED: Zod v4 detected - incompatible with MCP SDK 1.20.1!"
echo " Expected: 3.x"
echo " Got: $ZOD_VERSION"
echo ""

View File

@@ -29,15 +29,9 @@ jobs:
with:
lfs: true
- name: Log in to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to GitHub Container Registry
if: github.event_name != 'pull_request'
uses: docker/login-action@v3

View File

@@ -55,12 +55,6 @@ jobs:
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Log in to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

View File

@@ -71,19 +71,13 @@ jobs:
"
echo "✅ Synced package.runtime.json to version $VERSION"
- name: Log in to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
id: buildx
uses: docker/setup-buildx-action@v3
- name: Log in to GitHub Container Registry
if: github.event_name != 'pull_request'
uses: docker/login-action@v3
@@ -91,7 +85,7 @@ jobs:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
@@ -179,19 +173,13 @@ jobs:
"
echo "✅ Synced package.runtime.json to version $VERSION"
- name: Log in to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
id: buildx
uses: docker/setup-buildx-action@v3
- name: Log in to GitHub Container Registry
if: github.event_name != 'pull_request'
uses: docker/login-action@v3

View File

@@ -283,8 +283,8 @@ jobs:
- name: Install dependencies
run: npm ci
- name: Build project (server + UI apps)
run: npm run build:all
- name: Build project
run: npm run build
# Database is already built and committed during development
# Rebuilding here causes segfault due to memory pressure (exit code 139)
@@ -322,8 +322,8 @@ jobs:
- name: Install dependencies
run: npm ci
- name: Build project (server + UI apps)
run: npm run build:all
- name: Build project
run: npm run build
# Database is already built and committed during development
- name: Verify database exists
@@ -347,8 +347,6 @@ jobs:
# Copy necessary files
cp -r dist $PUBLISH_DIR/
cp -r data $PUBLISH_DIR/
mkdir -p $PUBLISH_DIR/ui-apps
cp -r ui-apps/dist $PUBLISH_DIR/ui-apps/
cp README.md $PUBLISH_DIR/
cp LICENSE $PUBLISH_DIR/
cp .env.example $PUBLISH_DIR/
@@ -379,7 +377,7 @@ jobs:
pkg.license = 'MIT';
pkg.bugs = { url: 'https://github.com/czlonkowski/n8n-mcp/issues' };
pkg.homepage = 'https://github.com/czlonkowski/n8n-mcp#readme';
pkg.files = ['dist/**/*', 'ui-apps/dist/**/*', 'data/nodes.db', '.env.example', 'README.md', 'LICENSE'];
pkg.files = ['dist/**/*', 'data/nodes.db', '.env.example', 'README.md', 'LICENSE'];
delete pkg.private;
require('fs').writeFileSync('./package.json', JSON.stringify(pkg, null, 2));
"
@@ -441,18 +439,12 @@ jobs:
"
echo "✅ Synced package.runtime.json to version $VERSION"
- name: Log in to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
with:

View File

@@ -133,6 +133,23 @@ jobs:
- name: Run type checking
run: npm run typecheck
# Run benchmarks
- name: Run benchmarks
id: benchmarks
run: npm run benchmark:ci
continue-on-error: true
# Upload benchmark results
- name: Upload benchmark results
if: always() && steps.benchmarks.outcome != 'skipped'
uses: actions/upload-artifact@v4
with:
name: benchmark-results-${{ github.run_number }}-${{ github.run_attempt }}
path: |
benchmark-results.json
retention-days: 30
if-no-files-found: warn
# Create test report comment for PRs
- name: Create test report comment
if: github.event_name == 'pull_request' && always()
@@ -205,6 +222,7 @@ jobs:
echo "" >> $GITHUB_STEP_SUMMARY
echo "- [Test Results](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }})" >> $GITHUB_STEP_SUMMARY
echo "- [Coverage Report](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }})" >> $GITHUB_STEP_SUMMARY
echo "- [Benchmark Results](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }})" >> $GITHUB_STEP_SUMMARY
# Store test metadata
- name: Store test metadata
@@ -234,21 +252,24 @@ jobs:
path: test-metadata.json
retention-days: 30
# Publish test results as checks
# Separate job to process and publish test results
publish-results:
needs: test
runs-on: ubuntu-latest
if: always()
permissions:
checks: write
pull-requests: write
steps:
- uses: actions/checkout@v4
- name: Download test results
# Download all artifacts
- name: Download all artifacts
uses: actions/download-artifact@v4
with:
path: artifacts
# Publish test results as checks
- name: Publish test results
uses: dorny/test-reporter@v1
if: always()
@@ -258,4 +279,75 @@ jobs:
path: 'artifacts/test-results-*/test-results/junit.xml'
reporter: java-junit
fail-on-error: false
fail-on-empty: false
fail-on-empty: false
# Create a combined artifact with all results
- name: Create combined results artifact
if: always()
run: |
mkdir -p combined-results
cp -r artifacts/* combined-results/ 2>/dev/null || true
# Create index file
cat > combined-results/index.html << 'EOF'
<!DOCTYPE html>
<html>
<head>
<title>n8n-mcp Test Results</title>
<style>
body { font-family: Arial, sans-serif; margin: 40px; }
h1 { color: #333; }
.section { margin: 20px 0; padding: 20px; border: 1px solid #ddd; border-radius: 5px; }
a { color: #0066cc; text-decoration: none; }
a:hover { text-decoration: underline; }
</style>
</head>
<body>
<h1>n8n-mcp Test Results</h1>
<div class="section">
<h2>Test Reports</h2>
<ul>
<li><a href="test-results-${{ github.run_number }}-${{ github.run_attempt }}/test-reports/report.html">📊 Detailed HTML Report</a></li>
<li><a href="test-results-${{ github.run_number }}-${{ github.run_attempt }}/test-results/html/index.html">📈 Vitest HTML Report</a></li>
<li><a href="test-results-${{ github.run_number }}-${{ github.run_attempt }}/test-reports/report.md">📄 Markdown Report</a></li>
<li><a href="test-results-${{ github.run_number }}-${{ github.run_attempt }}/test-summary.md">📝 PR Summary</a></li>
<li><a href="test-results-${{ github.run_number }}-${{ github.run_attempt }}/test-results/junit.xml">🔧 JUnit XML</a></li>
<li><a href="test-results-${{ github.run_number }}-${{ github.run_attempt }}/test-results/results.json">🔢 JSON Results</a></li>
<li><a href="test-results-${{ github.run_number }}-${{ github.run_attempt }}/test-reports/report.json">📊 Full JSON Report</a></li>
</ul>
</div>
<div class="section">
<h2>Coverage Reports</h2>
<ul>
<li><a href="coverage-${{ github.run_number }}-${{ github.run_attempt }}/html/index.html">HTML Coverage Report</a></li>
<li><a href="coverage-${{ github.run_number }}-${{ github.run_attempt }}/lcov.info">LCOV Report</a></li>
<li><a href="coverage-${{ github.run_number }}-${{ github.run_attempt }}/coverage-summary.json">Coverage Summary JSON</a></li>
</ul>
</div>
<div class="section">
<h2>Benchmark Results</h2>
<ul>
<li><a href="benchmark-results-${{ github.run_number }}-${{ github.run_attempt }}/benchmark-results.json">Benchmark Results JSON</a></li>
</ul>
</div>
<div class="section">
<h2>Metadata</h2>
<ul>
<li><a href="test-metadata-${{ github.run_number }}-${{ github.run_attempt }}/test-metadata.json">Test Run Metadata</a></li>
</ul>
</div>
<div class="section">
<p><em>Generated at $(date -u +%Y-%m-%dT%H:%M:%SZ)</em></p>
<p><em>Run: #${{ github.run_number }} | SHA: ${{ github.sha }}</em></p>
</div>
</body>
</html>
EOF
- name: Upload combined results
if: always()
uses: actions/upload-artifact@v4
with:
name: all-test-results-${{ github.run_number }}
path: combined-results/
retention-days: 90

4
.gitignore vendored
View File

@@ -138,9 +138,5 @@ n8n-mcp-wrapper.sh
# MCP configuration files
.mcp.json
# UI Apps build output
ui-apps/dist/
ui-apps/node_modules/
# Telemetry configuration (user-specific)
~/.n8n-mcp/

View File

@@ -7,458 +7,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
## [2.41.3] - 2026-03-27
### Fixed
- **Session timeout default too low** (Issue #626): Raised `SESSION_TIMEOUT_MINUTES` default from 5 to 30 minutes. The 5-minute default caused sessions to expire mid-operation during complex multi-step workflows (validate → get structure → patch → validate), forcing users to retry. Configurable via environment variable.
- **Operations array received as string from VS Code** (Issue #600): Added `z.preprocess` JSON string parsing to the `operations` parameter in `n8n_update_partial_workflow`. The VS Code MCP extension serializes arrays as JSON strings — the Zod schema now transparently parses them before validation.
- **`undefined` values rejected in MCP tool calls from VS Code** (Issue #611): Strip explicit `undefined` values from tool arguments before Zod validation. VS Code sends `undefined` as a value which Zod's `.optional()` rejects (it expects the field to be missing, not present-but-undefined).
Conceived by Romuald Członkowski - https://www.aiadvisors.pl/en
## [2.41.2] - 2026-03-27
### Fixed
- **MCP initialization floods Claude Desktop with JSON parse errors** (Issues #628, #627, #567): Intercept `process.stdout.write` in stdio mode to redirect non-JSON-RPC output to stderr. Console method suppression alone was insufficient — native modules (better-sqlite3), n8n packages, and third-party code can call `process.stdout.write()` directly, corrupting the JSON-RPC stream. Only writes containing valid JSON-RPC messages (`{"jsonrpc":...}`) are now allowed through stdout; everything else is redirected to stderr. This fixes the flood of "Unexpected token is not valid JSON" warnings on every new chat in Claude Desktop, including leaked `refCount`, `dbPath`, `clientVersion`, `protocolVersion`, and other debug strings.
Conceived by Romuald Członkowski - https://www.aiadvisors.pl/en
## [2.41.1] - 2026-03-27
### Fixed
- **If node operators silently fail at runtime** (Issue #665): Replaced incorrect operator names `isNotEmpty`/`isEmpty` with `notEmpty`/`empty` across all validators, sanitizer, documentation, and error messages. n8n's execution engine does not recognize `isNotEmpty`/`isEmpty` — unknown operators silently return `false`, causing If/Switch conditions to always take the wrong branch. Added auto-correction in the sanitizer so existing workflows using legacy names are fixed on update.
- **`addConnection` creates broken connections with `type: "0"`** (Issue #659): Fixed two edge cases where numeric `targetInput` or `sourceOutput` values leaked into connection objects as `"type": "0"` instead of `"type": "main"`. Numeric `targetInput` values are now remapped to `"main"`, and the `sourceOutput` remapping guard was relaxed to handle redundant `sourceOutput: 0` + `sourceIndex: 0` combinations. Also resolves Issue #653 (dangling connections after `removeNode`) which was caused by malformed connections from this bug.
- **`__patch_find_replace` corrupts Code node jsCode** (Issue #642): Implemented the `__patch_find_replace` feature for surgical string edits in `updateNode` operations. Previously, passing `{"parameters.jsCode": {"__patch_find_replace": [...]}}` stored the patch object literally as jsCode, producing `[object Object]` at runtime. The feature now reads the current string value, applies each `{find, replace}` entry sequentially, and writes back the modified string. Includes validation for patch format, target property existence, and string type.
### Improved
- Extracted `OPERATOR_CORRECTIONS` and `UNARY_OPERATORS` to module-level constants for better performance and single source of truth
- Added `exists`/`notExists` to unary operator lists for consistency across sanitizer and validator
- Fixed recovery guidance referencing non-existent `validate_node_operation` tool (now `validate_node`)
Conceived by Romuald Członkowski - https://www.aiadvisors.pl/en
## [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
- **Numeric sourceOutput remapping** (Issue #537): `addConnection` with numeric `sourceOutput` values like `"0"` or `"1"` now correctly maps to `"main"` with the corresponding `sourceIndex`, preventing malformed connection keys
- **IMAP Email Trigger activation** (Issue #538): `n8n-nodes-base.emailReadImap` and other IMAP-based polling triggers are now recognized as activatable triggers, allowing workflow activation
- **AI tool description false positives** (Issue #477): Validators now check `description` and `options.description` in addition to `toolDescription`, fixing false `MISSING_TOOL_DESCRIPTION` errors for toolWorkflow, toolCode, and toolSerpApi nodes
- **n8n_create_workflow undefined ID** (Issue #602): Added defensive check for missing workflow ID in API response with actionable error message
- **Flaky CI performance test**: Relaxed bulk insert ratio threshold from 15 to 20 to accommodate CI runner variability
Conceived by Romuald Czlonkowski - https://www.aiadvisors.pl/en
## [2.37.0] - 2026-03-14
### Fixed
- **Unary operator sanitization** (Issue #592): Added missing `empty`, `notEmpty`, `exists`, `notExists` operators to the sanitizer's unary operator list, preventing IF/Switch node corruption during partial updates
- **Positional connection array preservation** (Issue #610): `removeNode` and `cleanStaleConnections` now trim only trailing empty arrays, preserving intermediate positional indices for IF/Switch multi-output nodes
- **Scoped sanitization**: Auto-sanitization now only runs on nodes that were actually added or updated, preventing unrelated nodes (e.g., HTTP Request parameters) from being silently modified
- **Activate/deactivate 415 errors** (Issue #633): Added empty body `{}` to POST calls for workflow activation/deactivation endpoints
- **Zod error readability** (Issue #630): Validation errors now return human-readable `"path: message"` strings instead of raw Zod error objects
- **updateNode error hints** (Issue #623): Improved error message when `updates` parameter is missing, showing correct structure with `nodeId`/`nodeName` and `updates` fields
- **removeConnection after removeNode** (Issue #624): When a node was already removed by a prior `removeNode` operation, the error message now explains that connections were automatically cleaned up
- **Connection type coercion** (Issue #629): `sourceOutput` and `targetInput` are now coerced to strings, handling numeric values (0, 1) passed by MCP clients
### Added
- **`saved` field in responses** (Issue #625): All `n8n_update_partial_workflow` responses now include `saved: true/false` to distinguish whether the workflow was persisted to n8n
- **Tag operations via dedicated API** (Issue #599): `addTag`/`removeTag` now use the n8n tag API (`PUT /workflows/{id}/tags`) instead of embedding tags in the workflow body, fixing silent tag failures. Includes automatic tag creation, case-insensitive name resolution, and last-operation-wins reconciliation for conflicting add/remove
- **`updateWorkflowTags` API client method**: New method on `N8nApiClient` for managing workflow tag associations via the dedicated endpoint
- **`operationsApplied` in top-level response**: Promoted from nested `details` to top-level for easier consumption by MCP clients
Conceived by Romuald Czlonkowski - https://www.aiadvisors.pl/en
## [2.36.2] - 2026-03-14
### Changed
- **Updated n8n dependencies**: n8n 2.10.3 → 2.11.4, n8n-core 2.10.1 → 2.11.1, n8n-workflow 2.10.1 → 2.11.1, @n8n/n8n-nodes-langchain 2.10.1 → 2.11.2
- **Updated @modelcontextprotocol/sdk**: 1.20.1 → 1.27.1 (fixes critical cross-client data leak vulnerability CVE GHSA-345p-7cg4-v4c7)
- Rebuilt node database with 1,239 nodes (809 core + 430 community preserved)
- Updated README badge with new n8n version and node counts
Conceived by Romuald Czlonkowski - https://www.aiadvisors.pl/en
## [2.36.1] - 2026-03-08
### Added
- **Conditional branch fan-out detection** (`CONDITIONAL_BRANCH_FANOUT`): Warns when IF, Filter, or Switch nodes have all connections crammed into `main[0]` with higher-index outputs empty, which usually means all target nodes execute together on one branch while other branches have no effect
- Detects IF nodes with both true/false targets on `main[0]`
- Detects Filter nodes with both matched/unmatched targets on `main[0]`
- Detects Switch nodes with all targets on output 0 and other outputs unused
- Skips warning when fan-out is legitimate (higher outputs also have connections)
- Skips warning for single connections (intentional true-only/matched-only usage)
### Changed
- **Refactored output index validation**: Extracted `getShortNodeType()` and `getConditionalOutputInfo()` helpers to eliminate duplicated conditional node detection logic between `validateOutputIndexBounds` and the new `validateConditionalBranchUsage`
Conceived by Romuald Czlonkowski - https://www.aiadvisors.pl/en
## [2.36.0] - 2026-03-07
### Added
- **Connection validation: detect broken/malformed workflow connections** (Issue #620):
- Unknown output keys (`UNKNOWN_CONNECTION_KEY`): Flags invalid connection keys like `"0"`, `"1"`, `"output"` with fix suggestions (e.g., "use main[1] instead" for numeric keys)
- Invalid type field (`INVALID_CONNECTION_TYPE`): Detects invalid `type` values in connection targets (e.g., `"0"` instead of `"main"`)
- Output index bounds checking (`OUTPUT_INDEX_OUT_OF_BOUNDS`): Catches connections using output indices beyond what a node supports, with awareness of `onError: 'continueErrorOutput'`, Switch rules, and IF/Filter nodes
- Input index bounds checking (`INPUT_INDEX_OUT_OF_BOUNDS`): Validates target input indices against known node input counts (Merge=2, triggers=0, others=1)
- BFS-based trigger reachability analysis: Replaces simple orphan detection with proper graph traversal from trigger nodes, flagging unreachable subgraphs
- Flexible `WorkflowConnection` interface: Changed from explicit `main?/error?/ai_tool?` to `[outputType: string]` for accurate validation of all connection types
Conceived by Romuald Czlonkowski - https://www.aiadvisors.pl/en
## [2.35.6] - 2026-03-04
### Changed
- **Updated n8n dependencies**: n8n 2.8.3 → 2.10.3, n8n-core 2.8.1 → 2.10.1, n8n-workflow 2.8.0 → 2.10.1, @n8n/n8n-nodes-langchain 2.8.1 → 2.10.1
- Rebuilt node database with 806 core nodes (community nodes preserved from previous build)
Conceived by Romuald Czlonkowski - https://www.aiadvisors.pl/en
## [2.35.5] - 2026-02-22
### Fixed
- **Comprehensive parameter type coercion for Claude Desktop / Claude.ai** (Issue #605): Expanded the v2.35.4 fix to handle ALL type mismatches, not just stringified objects/arrays. Testing revealed 6/9 tools still failing in Claude Desktop after the initial fix.
- Extended `coerceStringifiedJsonParams()` to coerce every schema type: `string→number`, `string→boolean`, `number→string`, `boolean→string` (in addition to existing `string→object` and `string→array`)
- Added top-level safeguard to parse the entire `args` object if it arrives as a JSON string
- Added `[Diagnostic]` section to error responses showing received argument types, enabling users to report exactly what their MCP client sends
- Added 9 new unit tests (24 total) covering number, boolean, and number-to-string coercion
Conceived by Romuald Czlonkowski - https://www.aiadvisors.pl/en
## [2.35.4] - 2026-02-20
### Fixed
- **Defensive JSON.parse for stringified object/array parameters** (Issue #605): Claude Desktop 1.1.3189 serializes JSON object/array MCP parameters as strings, causing ZodError failures for ~60% of tools that accept nested parameters
- Added schema-driven `coerceStringifiedJsonParams()` in the central `CallToolRequestSchema` handler
- Automatically detects string values where the tool's `inputSchema` expects `object` or `array`, and parses them back
- Safe: prefix check before parsing, type verification after, try/catch preserves original on failure
- No-op for correct clients: native objects pass through unchanged
- Affects 9 tools with object/array params: `validate_node`, `validate_workflow`, `n8n_create_workflow`, `n8n_update_full_workflow`, `n8n_update_partial_workflow`, `n8n_validate_workflow`, `n8n_autofix_workflow`, `n8n_test_workflow`, `n8n_executions`
- Added 15 unit tests covering coercion, no-op, safety, and end-to-end scenarios
Conceived by Romuald Czlonkowski - https://www.aiadvisors.pl/en
## [2.35.3] - 2026-02-19
### Changed
- **Updated n8n dependencies**: n8n 2.6.3 → 2.8.3, n8n-core 2.6.1 → 2.8.1, n8n-workflow 2.6.0 → 2.8.0, @n8n/n8n-nodes-langchain 2.6.2 → 2.8.1
- **Fixed node loader for langchain package**: Adapted node loader to bypass restricted package.json `exports` field in @n8n/n8n-nodes-langchain >=2.9.0, resolving node files via absolute paths instead of `require.resolve()`
- **Fixed community doc generation for cloud LLMs**: Added `N8N_MCP_LLM_API_KEY`/`OPENAI_API_KEY` env var support, switched to `max_completion_tokens`, and auto-omit `temperature` for cloud API endpoints
- Rebuilt node database with 1,236 nodes (673 from n8n-nodes-base, 133 from @n8n/n8n-nodes-langchain, 430 community)
- Refreshed community nodes (361 verified + 69 npm) with 424/430 AI documentation summaries
Conceived by Romuald Czlonkowski - https://www.aiadvisors.pl/en
## [2.35.2] - 2026-02-09
### Changed
- **MCP Apps: Disable non-rendering apps in Claude.ai**: Disabled 3 MCP Apps (workflow-list, execution-history, health-dashboard) that render as collapsed accordions in Claude.ai, and removed `n8n_deploy_template` tool mapping which renders blank content. The server sets `_meta` correctly on the wire but the Claude.ai host ignores it for these tools. The 2 working apps (operation-result for 6 tools, validation-summary for 3 tools) remain active. Disabled apps can be re-enabled once the host-side issue is resolved.
Conceived by Romuald Czlonkowski - https://www.aiadvisors.pl/en
## [2.35.1] - 2026-02-09
### Fixed
- **MCP Apps: Fix UI not rendering for some tools in Claude**: Added legacy flat `_meta["ui/resourceUri"]` key alongside the nested `_meta.ui.resourceUri` in tool definitions. Claude.ai reads the flat key format; without it, tools like `n8n_health_check` and `n8n_list_workflows` showed as collapsed accordions instead of rendering their rich UI apps. Both key formats are now set by `injectToolMeta()`, matching the behavior of the official `registerAppTool` helper from `@modelcontextprotocol/ext-apps/server`.
Conceived by Romuald Czlonkowski - https://www.aiadvisors.pl/en
## [2.35.0] - 2026-02-09
### Added
- **3 new MCP Apps**: workflow-list (compact table with status/tags), execution-history (status summary bar + execution table), health-dashboard (connection status, versions, performance metrics)
- **Enhanced operation-result**: operation-aware headers (create/update/delete/test/deploy), detail panels with workflow metadata, copy-to-clipboard for IDs/URLs, autofix diff viewer
- **CopyButton shared component**: reusable clipboard button with visual feedback
- **Local preview harness** (`ui-apps/preview.html`): test all 5 apps with mock data, dark/light theme toggle, JSON-RPC protocol simulation
- **Expanded shared types**: TypeScript types for workflow-list, execution-history, and health-dashboard data
### Fixed
- **React hooks violation**: Fixed `useMemo` called after early returns in `execution-history/App.tsx` and `validation-summary/App.tsx`, causing React error #310 ("Rendered more hooks than during the previous render") and blank iframes
- **JSON-RPC catch-all handler**: Preview harness responds to unknown SDK requests to prevent hangs
Conceived by Romuald Czlonkowski - https://www.aiadvisors.pl/en
## [2.34.5] - 2026-02-08
### Fixed
- **MCP Apps: Fix blank UI and wrong status badge in Claude**: Rewrote `useToolData` hook to use the official `useApp` hook from `@modelcontextprotocol/ext-apps/react` for proper lifecycle management. Updated UI types and components to match actual server response format (`success: boolean` instead of `status: string`, nested `data` object for workflow details). Validation summary now handles both direct and wrapped (`n8n_validate_workflow`) response shapes.
Conceived by Romuald Czlonkowski - https://www.aiadvisors.pl/en
## [2.34.3] - 2026-02-07
### Fixed
- **MCP Apps: Use correct MIME type for ext-apps spec**: Changed resource MIME type from `text/html` to `text/html;profile=mcp-app` (the `RESOURCE_MIME_TYPE` constant from `@modelcontextprotocol/ext-apps`). Without this profile parameter, Claude Desktop/web fails to recognize resources as MCP Apps and shows "Failed to load MCP App: the resource may exceed the 5 MB size limit."
Conceived by Romuald Czlonkowski - https://www.aiadvisors.pl/en
## [2.34.2] - 2026-02-07
### Fixed
- **CI: UI apps missing from npm package**: Release pipeline only ran `npm run build` (TypeScript), so `ui-apps/dist/` was never built and excluded from published packages
- Changed build step to `npm run build:all` in `build-and-verify` and `publish-npm` jobs
- Added `ui-apps/dist/` to npm publish staging directory
- Added `ui-apps/dist/**/*` to published package files list
Conceived by Romuald Czlonkowski - https://www.aiadvisors.pl/en
## [2.34.1] - 2026-02-07
### Changed
- **MCP Apps: Align with official ext-apps spec** for Claude Desktop/web compatibility
- URI scheme changed from `n8n-mcp://ui/{id}` to `ui://n8n-mcp/{id}` per MCP ext-apps spec
- `_meta.ui.resourceUri` now set on tool definitions (`tools/list`) instead of tool call responses
- `UIMetadata.ui.app` renamed to `UIMetadata.ui.resourceUri`
- Added `_meta` field to `ToolDefinition` type
- Added `UIAppRegistry.injectToolMeta()` method for enriching tool definitions
- UI apps now use `@modelcontextprotocol/ext-apps` `App` class instead of `window.__MCP_DATA__`
- Updated `ReadResource` URI parser to match new `ui://` scheme
Conceived by Romuald Czlonkowski - https://www.aiadvisors.pl/en
## [2.34.0] - 2026-02-07
### Added
- **MCP Apps**: Rich HTML UIs rendered by MCP hosts alongside tool results via `_meta.ui` and the MCP resources protocol
- Server-side UI module (`src/mcp/ui/`) with tool-to-UI mapping and `_meta.ui` injection
- `UIAppRegistry` static class for loading and serving self-contained HTML apps
- `UI_APP_CONFIGS` mapping tools to their corresponding UI apps
- **Operation Result UI**: Visual summary for workflow operation tools
- Status badge, operation type, workflow details card
- Expandable sections for nodes added, modified, and removed
- Mapped to: `n8n_create_workflow`, `n8n_update_full_workflow`, `n8n_update_partial_workflow`, `n8n_delete_workflow`, `n8n_test_workflow`, `n8n_autofix_workflow`, `n8n_deploy_template`
- **Validation Summary UI**: Visual summary for validation tools
- Valid/invalid badge with error and warning counts
- Expandable error list with type, property, message, and fix
- Expandable warning list and suggestions
- Mapped to: `validate_node`, `validate_workflow`, `n8n_validate_workflow`
- **React + Vite Build Pipeline** (`ui-apps/`):
- React 19, Vite 6, vite-plugin-singlefile for self-contained HTML output
- Shared component library: Card, Badge, Expandable
- `useToolData` hook for reading data from `window.__MCP_DATA__` or embedded JSON
- n8n-branded dark theme with CSS custom properties
- Per-app builds via `APP_NAME` environment variable
- **MCP Resources Protocol**: Server now exposes `resources` capability
- `ListResources` handler returns available UI apps
- `ReadResource` handler serves self-contained HTML via `n8n-mcp://ui/{id}` URIs
- **New Scripts**:
- `build:ui`: Build UI apps (`cd ui-apps && npm install && npm run build`)
- `build:all`: Build UI apps then server (`npm run build:ui && npm run build`)
### Changed
- **MCP Server**: Added `resources: {}` to server capabilities alongside existing `tools: {}`
- **Tool Responses**: Tools with matching UI apps now include `_meta.ui.app` URI pointing to their visual representation
- **Graceful Degradation**: Server starts and operates normally without `ui-apps/dist/`; UI metadata is only injected when HTML is available
Conceived by Romuald Czlonkowski - https://www.aiadvisors.pl/en
## [2.33.6] - 2026-02-06
### Changed
- Updated n8n from 2.4.4 to 2.6.3
- Updated n8n-core from 2.4.2 to 2.6.1
- Updated n8n-workflow from 2.4.2 to 2.6.0
- Updated @n8n/n8n-nodes-langchain from 2.4.3 to 2.6.2
- Rebuilt node database with 806 nodes (544 from n8n-nodes-base, 262 from @n8n/n8n-nodes-langchain)
- Updated README badge with new n8n version
## [2.33.5] - 2026-01-23
### Fixed
- **Critical memory leak: per-session database connections** (Issue #542): Fixed severe memory leak where each MCP session created its own database connection (~900MB per session)
- Root cause: `N8NDocumentationMCPServer` called `createDatabaseAdapter()` for every new session, duplicating the entire 68MB database in memory
- With 3-4 sessions, memory would exceed 4GB causing OOM kills every ~20 minutes
- Fix: Implemented singleton `SharedDatabase` pattern - all sessions now share ONE database connection
- Memory impact: Reduced from ~900MB per session to ~68MB total (shared) + ~5MB per session overhead
- Added `getSharedDatabase()` and `releaseSharedDatabase()` for thread-safe connection management
- Added reference counting to track active sessions using the shared connection
- **Session timeout optimization**: Reduced default session timeout from 30 minutes to 5 minutes
- Faster cleanup of stale sessions reduces memory buildup
- Configurable via `SESSION_TIMEOUT_MINUTES` environment variable
- **Eager instance cleanup**: When a client reconnects, previous sessions for the same instanceId are now immediately cleaned up
- Prevents memory accumulation from reconnecting clients in multi-tenant deployments
- **Telemetry event listener leak**: Fixed event listeners in `TelemetryBatchProcessor` that were never removed
- Added proper cleanup in `stop()` method
- Added guard against multiple `start()` calls
### Added
- **New module: `src/database/shared-database.ts`** - Singleton database manager
- `getSharedDatabase(dbPath)`: Thread-safe initialization with promise lock pattern
- `releaseSharedDatabase(state)`: Reference counting for cleanup
- `closeSharedDatabase()`: Graceful shutdown for process termination
- `isSharedDatabaseInitialized()` and `getSharedDatabaseRefCount()`: Monitoring helpers
### Changed
- **`N8NDocumentationMCPServer.close()`**: Now releases shared database reference instead of closing the connection
- **`SingleSessionHTTPServer.shutdown()`**: Calls `closeSharedDatabase()` during graceful shutdown
## [2.33.4] - 2026-01-21
### Fixed

View File

@@ -1,16 +1,9 @@
# n8n Update Process - Quick Reference
## ⚡ Recommended Fast Workflow (2026-03-25)
## ⚡ Recommended Fast Workflow (2025-11-04)
**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
@@ -22,45 +15,24 @@ git checkout main && git pull
# 3. Check for updates (dry run)
npm run update:n8n:check
# 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)
# 4. Run update and skip tests (we'll test in CI)
yes y | npm run update:n8n
# 6. Restore community nodes after rebuild
sqlite3 data/nodes.db < /tmp/n8n_community_backup.sql
# 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
# 5. Create feature branch
git checkout -b update/n8n-X.X.X
# 7. Update version in package.json (must be HIGHER than latest release!)
# 6. Update version in package.json (must be HIGHER than latest release!)
# Edit: "version": "2.XX.X" (not the version from the release list!)
# 8. Update CHANGELOG.md
# 7. Update CHANGELOG.md
# - Change version number to match package.json
# - Update date to today
# - Update dependency versions
# - Include community node refresh counts
# 9. Update README badge and node counts
# 8. Update README badge
# Edit line 8: Change n8n version badge to new n8n version
# Update total node count in description (core + community)
# 10. Commit and push
# 9. Commit and push
git add -A
git commit -m "chore: update n8n to X.X.X and bump version to 2.XX.X
@@ -69,8 +41,7 @@ git commit -m "chore: update n8n to X.X.X and bump version to 2.XX.X
- Updated n8n-workflow from X.X.X to X.X.X
- Updated @n8n/n8n-nodes-langchain from X.X.X to X.X.X
- Rebuilt node database with XXX nodes (XXX from n8n-nodes-base, XXX from @n8n/n8n-nodes-langchain)
- Refreshed community nodes (XXX verified + XXX npm)
- Updated README badge with new n8n version and node counts
- Updated README badge with new n8n version
- Updated CHANGELOG with dependency changes
Conceived by Romuald Członkowski - https://www.aiadvisors.pl/en
@@ -81,10 +52,10 @@ Co-Authored-By: Claude <noreply@anthropic.com>"
git push -u origin update/n8n-X.X.X
# 11. Create PR
# 10. Create PR
gh pr create --title "chore: update n8n to X.X.X" --body "Updates n8n and all related dependencies to the latest versions..."
# 12. After PR is merged, verify release triggered
# 11. After PR is merged, verify release triggered
gh release list | head -1
# If the new version appears, you're done!
# If not, the version might have already been released - bump version again and create new PR

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.13.3-orange.svg)](https://github.com/n8n-io/n8n)
[![n8n version](https://img.shields.io/badge/n8n-2.4.4-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,396 workflow automation nodes (812 core + 584 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,084 workflow automation nodes (537 core + 547 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,396 n8n nodes** - 812 core nodes + 584 community nodes (516 verified)
- 📚 **1,084 n8n nodes** - 537 core nodes + 547 community nodes (301 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

@@ -311,17 +311,6 @@ class SQLJSStatement {
this.stmt = stmt;
this.onModify = onModify;
this.boundParams = null;
this.freed = false;
}
freeStatement() {
if (!this.freed && this.stmt) {
try {
this.stmt.free();
this.freed = true;
}
catch (e) {
}
}
}
run(...params) {
try {
@@ -342,9 +331,6 @@ class SQLJSStatement {
this.stmt.reset();
throw error;
}
finally {
this.freeStatement();
}
}
get(...params) {
try {
@@ -366,9 +352,6 @@ class SQLJSStatement {
this.stmt.reset();
throw error;
}
finally {
this.freeStatement();
}
}
all(...params) {
try {
@@ -389,9 +372,6 @@ class SQLJSStatement {
this.stmt.reset();
throw error;
}
finally {
this.freeStatement();
}
}
iterate(...params) {
return this.all(...params)[Symbol.iterator]();

File diff suppressed because one or more lines are too long

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

@@ -12,7 +12,6 @@ class NodeRepository {
this.db = dbOrService;
}
saveNode(node) {
const existing = this.db.prepare('SELECT npm_readme, ai_documentation_summary, ai_summary_generated_at FROM nodes WHERE node_type = ?').get(node.nodeType);
const stmt = this.db.prepare(`
INSERT OR REPLACE INTO nodes (
node_type, package_name, display_name, description,
@@ -22,11 +21,10 @@ class NodeRepository {
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,
npm_readme, ai_documentation_summary, ai_summary_generated_at
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
npm_package_name, npm_version, npm_downloads, community_fetched_at
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
`);
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, existing?.npm_readme || null, existing?.ai_documentation_summary || null, existing?.ai_summary_generated_at || null);
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);
}
getNode(nodeType) {
const normalizedType = node_type_normalizer_1.NodeTypeNormalizer.normalizeToFullForm(nodeType);

File diff suppressed because one or more lines are too long

View File

@@ -21,7 +21,6 @@ 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;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"}
{"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;AAuErD,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;IAC3B,OAAO,CAAC,cAAc,CAAkB;IACxC,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;YAmOF,eAAe;IA8C7B,OAAO,CAAC,SAAS;IAYjB,OAAO,CAAC,gBAAgB;IASlB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAgnBtB,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAkD/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

@@ -22,7 +22,6 @@ const crypto_1 = require("crypto");
const types_js_1 = require("@modelcontextprotocol/sdk/types.js");
const protocol_version_1 = require("./utils/protocol-version");
const instance_context_1 = require("./types/instance-context");
const shared_database_1 = require("./database/shared-database");
dotenv_1.default.config();
const DEFAULT_PROTOCOL_VERSION = protocol_version_1.STANDARD_PROTOCOL_VERSION;
const MAX_SESSIONS = Math.max(1, parseInt(process.env.N8N_MCP_MAX_SESSIONS || '100', 10));
@@ -53,7 +52,7 @@ class SingleSessionHTTPServer {
this.contextSwitchLocks = new Map();
this.session = null;
this.consoleManager = new console_manager_1.ConsoleManager();
this.sessionTimeout = parseInt(process.env.SESSION_TIMEOUT_MINUTES || '5', 10) * 60 * 1000;
this.sessionTimeout = 30 * 60 * 1000;
this.authToken = null;
this.cleanupTimer = null;
this.validateEnvironment();
@@ -133,15 +132,6 @@ 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) {
@@ -300,25 +290,6 @@ class SingleSessionHTTPServer {
return;
}
logger_1.logger.info('handleRequest: Creating new transport for initialize request');
if (instanceContext?.instanceId) {
const sessionsToRemove = [];
for (const [existingSessionId, context] of Object.entries(this.sessionContexts)) {
if (context?.instanceId === instanceContext.instanceId) {
sessionsToRemove.push(existingSessionId);
}
}
for (const oldSessionId of sessionsToRemove) {
if (!this.transports[oldSessionId]) {
continue;
}
logger_1.logger.info('Cleaning up previous session for instance', {
instanceId: instanceContext.instanceId,
oldSession: oldSessionId,
reason: 'instance_reconnect'
});
await this.removeSession(oldSessionId, 'instance_reconnect');
}
}
let sessionIdToUse;
const isMultiTenantEnabled = process.env.ENABLE_MULTI_TENANT === 'true';
const sessionStrategy = process.env.MULTI_TENANT_SESSION_STRATEGY || 'instance';
@@ -390,20 +361,6 @@ 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) {
@@ -412,14 +369,6 @@ 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,
@@ -485,21 +434,12 @@ class SingleSessionHTTPServer {
}
async resetSessionSSE(res) {
if (this.session) {
const sessionId = this.session.sessionId;
logger_1.logger.info('Closing previous session for SSE', { sessionId });
if (this.session.server && typeof this.session.server.close === 'function') {
try {
await this.session.server.close();
}
catch (serverError) {
logger_1.logger.warn('Error closing server for SSE session', { sessionId, error: serverError });
}
}
try {
logger_1.logger.info('Closing previous session for SSE', { sessionId: this.session.sessionId });
await this.session.transport.close();
}
catch (transportError) {
logger_1.logger.warn('Error closing transport for SSE session', { sessionId, error: transportError });
catch (error) {
logger_1.logger.warn('Error closing previous session:', error);
}
}
try {
@@ -1074,13 +1014,6 @@ class SingleSessionHTTPServer {
});
});
}
try {
await (0, shared_database_1.closeSharedDatabase)();
logger_1.logger.info('Shared database closed');
}
catch (error) {
logger_1.logger.warn('Error closing shared database:', error);
}
logger_1.logger.info('Single-Session HTTP server shutdown completed');
}
getSessionInfo() {

File diff suppressed because one or more lines are too long

2
dist/index.d.ts vendored
View File

@@ -5,8 +5,6 @@ export { N8NDocumentationMCPServer } from './mcp/server';
export type { InstanceContext } from './types/instance-context';
export { validateInstanceContext, isInstanceContext } from './types/instance-context';
export type { SessionState } from './types/session-state';
export type { UIAppConfig, UIMetadata } from './mcp/ui/types';
export { UI_APP_CONFIGS } from './mcp/ui/app-configs';
export type { Tool, CallToolResult, ListToolsResult } from '@modelcontextprotocol/sdk/types.js';
import N8NMCPEngine from './mcp-engine';
export default N8NMCPEngine;

2
dist/index.d.ts.map vendored
View File

@@ -1 +1 @@
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AACzE,OAAO,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAC;AACvE,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACzD,OAAO,EAAE,yBAAyB,EAAE,MAAM,cAAc,CAAC;AAGzD,YAAY,EACV,eAAe,EAChB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EACL,uBAAuB,EACvB,iBAAiB,EAClB,MAAM,0BAA0B,CAAC;AAClC,YAAY,EACV,YAAY,EACb,MAAM,uBAAuB,CAAC;AAG/B,YAAY,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAC9D,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAGtD,YAAY,EACV,IAAI,EACJ,cAAc,EACd,eAAe,EAChB,MAAM,oCAAoC,CAAC;AAG5C,OAAO,YAAY,MAAM,cAAc,CAAC;AACxC,eAAe,YAAY,CAAC"}
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AACzE,OAAO,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAC;AACvE,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACzD,OAAO,EAAE,yBAAyB,EAAE,MAAM,cAAc,CAAC;AAGzD,YAAY,EACV,eAAe,EAChB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EACL,uBAAuB,EACvB,iBAAiB,EAClB,MAAM,0BAA0B,CAAC;AAClC,YAAY,EACV,YAAY,EACb,MAAM,uBAAuB,CAAC;AAG/B,YAAY,EACV,IAAI,EACJ,cAAc,EACd,eAAe,EAChB,MAAM,oCAAoC,CAAC;AAG5C,OAAO,YAAY,MAAM,cAAc,CAAC;AACxC,eAAe,YAAY,CAAC"}

4
dist/index.js vendored
View File

@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.UI_APP_CONFIGS = exports.isInstanceContext = exports.validateInstanceContext = exports.N8NDocumentationMCPServer = exports.ConsoleManager = exports.SingleSessionHTTPServer = exports.N8NMCPEngine = void 0;
exports.isInstanceContext = exports.validateInstanceContext = exports.N8NDocumentationMCPServer = exports.ConsoleManager = exports.SingleSessionHTTPServer = exports.N8NMCPEngine = void 0;
var mcp_engine_1 = require("./mcp-engine");
Object.defineProperty(exports, "N8NMCPEngine", { enumerable: true, get: function () { return mcp_engine_1.N8NMCPEngine; } });
var http_server_single_session_1 = require("./http-server-single-session");
@@ -15,8 +15,6 @@ Object.defineProperty(exports, "N8NDocumentationMCPServer", { enumerable: true,
var instance_context_1 = require("./types/instance-context");
Object.defineProperty(exports, "validateInstanceContext", { enumerable: true, get: function () { return instance_context_1.validateInstanceContext; } });
Object.defineProperty(exports, "isInstanceContext", { enumerable: true, get: function () { return instance_context_1.isInstanceContext; } });
var app_configs_1 = require("./mcp/ui/app-configs");
Object.defineProperty(exports, "UI_APP_CONFIGS", { enumerable: true, get: function () { return app_configs_1.UI_APP_CONFIGS; } });
const mcp_engine_2 = __importDefault(require("./mcp-engine"));
exports.default = mcp_engine_2.default;
//# sourceMappingURL=index.js.map

2
dist/index.js.map vendored
View File

@@ -1 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;AAOA,2CAAyE;AAAhE,0GAAA,YAAY,OAAA;AACrB,2EAAuE;AAA9D,qIAAA,uBAAuB,OAAA;AAChC,2DAAyD;AAAhD,iHAAA,cAAc,OAAA;AACvB,uCAAyD;AAAhD,mHAAA,yBAAyB,OAAA;AAMlC,6DAGkC;AAFhC,2HAAA,uBAAuB,OAAA;AACvB,qHAAA,iBAAiB,OAAA;AAQnB,oDAAsD;AAA7C,6GAAA,cAAc,OAAA;AAUvB,8DAAwC;AACxC,kBAAe,oBAAY,CAAC"}
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;AAOA,2CAAyE;AAAhE,0GAAA,YAAY,OAAA;AACrB,2EAAuE;AAA9D,qIAAA,uBAAuB,OAAA;AAChC,2DAAyD;AAAhD,iHAAA,cAAc,OAAA;AACvB,uCAAyD;AAAhD,mHAAA,yBAAyB,OAAA;AAMlC,6DAGkC;AAFhC,2HAAA,uBAAuB,OAAA;AACvB,qHAAA,iBAAiB,OAAA;AAcnB,8DAAwC;AACxC,kBAAe,oBAAY,CAAC"}

View File

@@ -6,8 +6,6 @@ export interface LoadedNode {
export declare class N8nNodeLoader {
private readonly CORE_PACKAGES;
loadAllNodes(): Promise<LoadedNode[]>;
private resolvePackageDir;
private loadNodeModule;
private loadPackageNodes;
}
//# sourceMappingURL=node-loader.d.ts.map

View File

@@ -1 +1 @@
{"version":3,"file":"node-loader.d.ts","sourceRoot":"","sources":["../../src/loaders/node-loader.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,UAAU;IACzB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,GAAG,CAAC;CAChB;AAED,qBAAa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAC,aAAa,CAG5B;IAEI,YAAY,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC;IAuB3C,OAAO,CAAC,iBAAiB;IAUzB,OAAO,CAAC,cAAc;YAIR,gBAAgB;CAuD/B"}
{"version":3,"file":"node-loader.d.ts","sourceRoot":"","sources":["../../src/loaders/node-loader.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,UAAU;IACzB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,GAAG,CAAC;CAChB;AAED,qBAAa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAC,aAAa,CAG5B;IAEI,YAAY,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC;YAmB7B,gBAAgB;CAqD/B"}

View File

@@ -28,23 +28,15 @@ class N8nNodeLoader {
}
return results;
}
resolvePackageDir(packagePath) {
const pkgJsonPath = require.resolve(`${packagePath}/package.json`);
return path_1.default.dirname(pkgJsonPath);
}
loadNodeModule(absolutePath) {
return require(absolutePath);
}
async loadPackageNodes(packageName, packagePath, packageJson) {
const n8nConfig = packageJson.n8n || {};
const nodes = [];
const packageDir = this.resolvePackageDir(packagePath);
const nodesList = n8nConfig.nodes || [];
if (Array.isArray(nodesList)) {
for (const nodePath of nodesList) {
try {
const fullPath = path_1.default.join(packageDir, nodePath);
const nodeModule = this.loadNodeModule(fullPath);
const fullPath = require.resolve(`${packagePath}/${nodePath}`);
const nodeModule = require(fullPath);
const nodeNameMatch = nodePath.match(/\/([^\/]+)\.node\.(js|ts)$/);
const nodeName = nodeNameMatch ? nodeNameMatch[1] : path_1.default.basename(nodePath, '.node.js');
const NodeClass = nodeModule.default || nodeModule[nodeName] || Object.values(nodeModule)[0];
@@ -64,8 +56,8 @@ class N8nNodeLoader {
else {
for (const [nodeName, nodePath] of Object.entries(nodesList)) {
try {
const fullPath = path_1.default.join(packageDir, nodePath);
const nodeModule = this.loadNodeModule(fullPath);
const fullPath = require.resolve(`${packagePath}/${nodePath}`);
const nodeModule = require(fullPath);
const NodeClass = nodeModule.default || nodeModule[nodeName] || Object.values(nodeModule)[0];
if (NodeClass) {
nodes.push({ packageName, nodeName, NodeClass });

View File

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

View File

@@ -26,14 +26,4 @@ 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,16 +56,6 @@ 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");
@@ -185,7 +175,6 @@ 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(),
@@ -223,13 +212,7 @@ const autofixWorkflowSchema = zod_1.z.object({
'node-type-correction',
'webhook-missing-path',
'typeversion-upgrade',
'version-migration',
'tool-variant-correction',
'connection-numeric-keys',
'connection-invalid-type',
'connection-id-to-name',
'connection-duplicate-removal',
'connection-input-index'
'version-migration'
])).optional(),
confidenceThreshold: zod_1.z.enum(['high', 'medium', 'low']).optional().default('medium'),
maxFixes: zod_1.z.number().optional().default(50)
@@ -299,15 +282,6 @@ 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,
@@ -1481,7 +1455,7 @@ async function handleDiagnostic(request, context) {
}
}
const documentationTools = 7;
const managementTools = apiConfigured ? 14 : 0;
const managementTools = apiConfigured ? 13 : 0;
const totalTools = documentationTools + managementTools;
const versionCheck = await (0, npm_version_checker_1.checkNpmVersion)();
const cacheMetricsData = getInstanceCacheMetrics();
@@ -2049,244 +2023,4 @@ 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;AAkF7D,wBAAsB,2BAA2B,CAC/C,IAAI,EAAE,OAAO,EACb,UAAU,EAAE,cAAc,EAC1B,OAAO,CAAC,EAAE,eAAe,GACxB,OAAO,CAAC,eAAe,CAAC,CAib1B"}
{"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"}

View File

@@ -50,9 +50,6 @@ 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({
@@ -67,8 +64,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.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(),
sourceOutput: zod_1.z.string().optional(),
targetInput: zod_1.z.string().optional(),
sourceIndex: zod_1.z.number().optional(),
targetIndex: zod_1.z.number().optional(),
branch: zod_1.z.enum(['true', 'false']).optional(),
@@ -79,20 +76,6 @@ 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(),
@@ -184,12 +167,11 @@ 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
}
@@ -231,9 +213,9 @@ async function handleUpdatePartialWorkflow(args, repository, context) {
});
const recoverySteps = [];
if (errorTypes.has('operator_issues')) {
recoverySteps.push('Operator structure issue detected. Use validate_node to check specific nodes.');
recoverySteps.push('Operator structure issue detected. Use validate_node_operation to check specific nodes.');
recoverySteps.push('Binary operators (equals, contains, greaterThan, etc.) must NOT have singleValue:true');
recoverySteps.push('Unary operators (empty, notEmpty, true, false) REQUIRE singleValue:true');
recoverySteps.push('Unary operators (isEmpty, isNotEmpty, true, false) REQUIRE singleValue:true');
}
if (errorTypes.has('connection_issues')) {
recoverySteps.push('Connection validation failed. Check all node connections reference existing nodes.');
@@ -257,7 +239,6 @@ async function handleUpdatePartialWorkflow(args, repository, context) {
if (!skipValidation) {
return {
success: false,
saved: false,
error: errorMessage,
details: {
errors: structureErrors,
@@ -266,7 +247,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 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.'
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.'
}
};
}
@@ -278,77 +259,6 @@ 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 {
@@ -376,7 +286,6 @@ 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,
@@ -394,7 +303,6 @@ 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,
@@ -421,7 +329,6 @@ async function handleUpdatePartialWorkflow(args, repository, context) {
}
return {
success: true,
saved: true,
data: {
id: finalWorkflow.id,
name: finalWorkflow.name,
@@ -429,12 +336,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.${transferMessage}${activationMessage} Use n8n_get_workflow with mode 'structure' to verify current state.`,
message: `Workflow "${finalWorkflow.name}" updated successfully. Applied ${diffResult.operationsApplied} operations.${activationMessage} Use n8n_get_workflow with mode 'structure' to verify current state.`,
details: {
applied: diffResult.applied,
failed: diffResult.failed,
errors: diffResult.errors,
warnings: mergeWarnings(diffResult.warnings, tagWarnings)
warnings: diffResult.warnings
}
};
}
@@ -472,9 +379,7 @@ async function handleUpdatePartialWorkflow(args, repository, context) {
return {
success: false,
error: 'Invalid input',
details: {
errors: error.errors.map(e => `${e.path.join('.')}: ${e.message}`)
}
details: { errors: error.errors }
};
}
logger_1.logger.error('Failed to update partial workflow', error);
@@ -484,13 +389,6 @@ 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';
@@ -518,8 +416,6 @@ 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

@@ -13,9 +13,6 @@ export declare class N8NDocumentationMCPServer {
private previousToolTimestamp;
private earlyLogger;
private disabledToolsCache;
private useSharedDatabase;
private sharedDbState;
private isShutdown;
constructor(instanceContext?: InstanceContext, earlyLogger?: EarlyErrorLogger);
close(): Promise<void>;
private initializeDatabase;
@@ -30,7 +27,6 @@ export declare class N8NDocumentationMCPServer {
private validateToolParams;
private validateToolParamsBasic;
private validateExtractedArgs;
private coerceStringifiedJsonParams;
private listNodes;
private getNodeInfo;
private searchNodes;

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;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"}
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/mcp/server.ts"],"names":[],"mappings":"AAsCA,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;gBAE1C,eAAe,CAAC,EAAE,eAAe,EAAE,WAAW,CAAC,EAAE,gBAAgB;IAiGvE,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;YA6Bd,kBAAkB;YAwClB,wBAAwB;IA0BtC,OAAO,CAAC,kBAAkB;YA6CZ,iBAAiB;IAa/B,OAAO,CAAC,eAAe,CAAkB;YAE3B,sBAAsB;IAgDpC,OAAO,CAAC,gBAAgB;IAqCxB,OAAO,CAAC,aAAa;IAoTrB,OAAO,CAAC,wBAAwB;IAoFhC,OAAO,CAAC,kBAAkB;IAqE1B,OAAO,CAAC,uBAAuB;IAwB/B,OAAO,CAAC,qBAAqB;YAoTf,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;CAuBhC"}

245
dist/mcp/server.js vendored
View File

@@ -43,14 +43,12 @@ const types_js_1 = require("@modelcontextprotocol/sdk/types.js");
const fs_1 = require("fs");
const path_1 = __importDefault(require("path"));
const tools_1 = require("./tools");
const ui_1 = require("./ui");
const tools_n8n_manager_1 = require("./tools-n8n-manager");
const tools_n8n_friendly_1 = require("./tools-n8n-friendly");
const workflow_examples_1 = require("./workflow-examples");
const logger_1 = require("../utils/logger");
const node_repository_1 = require("../database/node-repository");
const database_adapter_1 = require("../database/database-adapter");
const shared_database_1 = require("../database/shared-database");
const property_filter_1 = require("../services/property-filter");
const task_templates_1 = require("../services/task-templates");
const config_validator_1 = require("../services/config-validator");
@@ -82,9 +80,6 @@ class N8NDocumentationMCPServer {
this.previousToolTimestamp = Date.now();
this.earlyLogger = null;
this.disabledToolsCache = null;
this.useSharedDatabase = false;
this.sharedDbState = null;
this.isShutdown = false;
this.dbHealthChecked = false;
this.instanceContext = instanceContext;
this.earlyLogger = earlyLogger || null;
@@ -124,7 +119,6 @@ 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',
@@ -150,29 +144,15 @@ class N8NDocumentationMCPServer {
}, {
capabilities: {
tools: {},
resources: {},
},
});
ui_1.UIAppRegistry.load();
this.setupHandlers();
}
async close() {
try {
await this.initialized;
}
catch (error) {
logger_1.logger.debug('Initialization had failed, proceeding with cleanup', {
error: error instanceof Error ? error.message : String(error)
});
}
try {
await this.server.close();
this.cache.destroy();
if (this.useSharedDatabase && this.sharedDbState) {
(0, shared_database_1.releaseSharedDatabase)(this.sharedDbState);
logger_1.logger.debug('Released shared database reference');
}
else if (this.db) {
if (this.db) {
try {
this.db.close();
}
@@ -186,7 +166,6 @@ class N8NDocumentationMCPServer {
this.repository = null;
this.templateService = null;
this.earlyLogger = null;
this.sharedDbState = null;
}
catch (error) {
logger_1.logger.warn('Error closing MCP server', { error: error instanceof Error ? error.message : String(error) });
@@ -198,27 +177,17 @@ class N8NDocumentationMCPServer {
this.earlyLogger.logCheckpoint(startup_checkpoints_1.STARTUP_CHECKPOINTS.DATABASE_CONNECTING);
}
logger_1.logger.debug('Database initialization starting...', { dbPath });
this.db = await (0, database_adapter_1.createDatabaseAdapter)(dbPath);
logger_1.logger.debug('Database adapter created');
if (dbPath === ':memory:') {
this.db = await (0, database_adapter_1.createDatabaseAdapter)(dbPath);
logger_1.logger.debug('Database adapter created (in-memory mode)');
await this.initializeInMemorySchema();
logger_1.logger.debug('In-memory schema initialized');
this.repository = new node_repository_1.NodeRepository(this.db);
this.templateService = new template_service_1.TemplateService(this.db);
enhanced_config_validator_1.EnhancedConfigValidator.initializeSimilarityServices(this.repository);
this.useSharedDatabase = false;
}
else {
const sharedState = await (0, shared_database_1.getSharedDatabase)(dbPath);
this.db = sharedState.db;
this.repository = sharedState.repository;
this.templateService = sharedState.templateService;
this.sharedDbState = sharedState;
this.useSharedDatabase = true;
logger_1.logger.debug('Using shared database connection');
}
this.repository = new node_repository_1.NodeRepository(this.db);
logger_1.logger.debug('Node repository initialized');
this.templateService = new template_service_1.TemplateService(this.db);
logger_1.logger.debug('Template service initialized');
enhanced_config_validator_1.EnhancedConfigValidator.initializeSimilarityServices(this.repository);
logger_1.logger.debug('Similarity services initialized');
if (this.earlyLogger) {
this.earlyLogger.logCheckpoint(startup_checkpoints_1.STARTUP_CHECKPOINTS.DATABASE_CONNECTED);
@@ -372,7 +341,6 @@ class N8NDocumentationMCPServer {
protocolVersion: negotiationResult.version,
capabilities: {
tools: {},
resources: {},
},
serverInfo: {
name: 'n8n-documentation-mcp',
@@ -428,7 +396,6 @@ class N8NDocumentationMCPServer {
description: tool.description
});
});
ui_1.UIAppRegistry.injectToolMeta(tools);
return { tools };
});
this.server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
@@ -458,18 +425,6 @@ class N8NDocumentationMCPServer {
};
}
let processedArgs = args;
if (typeof args === 'string') {
try {
const parsed = JSON.parse(args);
if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {
processedArgs = parsed;
logger_1.logger.warn(`Coerced stringified args object for tool "${name}"`);
}
}
catch {
logger_1.logger.warn(`Tool "${name}" received string args that are not valid JSON`);
}
}
if (args && typeof args === 'object' && 'output' in args) {
try {
const possibleNestedData = args.output;
@@ -498,7 +453,6 @@ class N8NDocumentationMCPServer {
});
}
}
processedArgs = this.coerceStringifiedJsonParams(name, processedArgs);
try {
logger_1.logger.debug(`Executing tool: ${name}`, { args: processedArgs });
const startTime = Date.now();
@@ -570,13 +524,6 @@ class N8NDocumentationMCPServer {
if (name.startsWith('validate_') && (errorMessage.includes('config') || errorMessage.includes('nodeType'))) {
helpfulMessage += '\n\nFor validation tools:\n- nodeType should be a string (e.g., "nodes-base.webhook")\n- config should be an object (e.g., {})';
}
try {
const argDiag = processedArgs && typeof processedArgs === 'object'
? Object.entries(processedArgs).map(([k, v]) => `${k}: ${typeof v}`).join(', ')
: `args type: ${typeof processedArgs}`;
helpfulMessage += `\n\n[Diagnostic] Received arg types: {${argDiag}}`;
}
catch { }
return {
content: [
{
@@ -588,39 +535,6 @@ class N8NDocumentationMCPServer {
};
}
});
this.server.setRequestHandler(types_js_1.ListResourcesRequestSchema, async () => {
const apps = ui_1.UIAppRegistry.getAllApps();
return {
resources: apps
.filter(app => app.html !== null)
.map(app => ({
uri: app.config.uri,
name: app.config.displayName,
description: app.config.description,
mimeType: app.config.mimeType,
})),
};
});
this.server.setRequestHandler(types_js_1.ReadResourceRequestSchema, async (request) => {
const uri = request.params.uri;
const match = uri.match(/^ui:\/\/n8n-mcp\/(.+)$/);
if (!match) {
throw new Error(`Unknown resource URI: ${uri}`);
}
const app = ui_1.UIAppRegistry.getAppById(match[1]);
if (!app || !app.html) {
throw new Error(`UI app not found or not built: ${match[1]}`);
}
return {
contents: [
{
uri: app.config.uri,
mimeType: app.config.mimeType,
text: app.html,
},
],
};
});
}
sanitizeValidationResult(result, toolName) {
if (!result || typeof result !== 'object') {
@@ -720,11 +634,6 @@ 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: [] }
@@ -821,93 +730,6 @@ class N8NDocumentationMCPServer {
}
return true;
}
coerceStringifiedJsonParams(toolName, args) {
if (!args || typeof args !== 'object')
return args;
const allTools = [...tools_1.n8nDocumentationToolsFinal, ...tools_n8n_manager_1.n8nManagementTools];
const tool = allTools.find(t => t.name === toolName);
if (!tool?.inputSchema?.properties)
return args;
const properties = tool.inputSchema.properties;
const coerced = { ...args };
let coercedAny = false;
for (const [key, value] of Object.entries(coerced)) {
if (value === undefined || value === null)
continue;
const propSchema = properties[key];
if (!propSchema)
continue;
const expectedType = propSchema.type;
if (!expectedType)
continue;
const actualType = typeof value;
if (expectedType === 'string' && actualType === 'string')
continue;
if ((expectedType === 'number' || expectedType === 'integer') && actualType === 'number')
continue;
if (expectedType === 'boolean' && actualType === 'boolean')
continue;
if (expectedType === 'object' && actualType === 'object' && !Array.isArray(value))
continue;
if (expectedType === 'array' && Array.isArray(value))
continue;
if (actualType === 'string') {
const trimmed = value.trim();
if (expectedType === 'object' && trimmed.startsWith('{')) {
try {
const parsed = JSON.parse(trimmed);
if (typeof parsed === 'object' && parsed !== null && !Array.isArray(parsed)) {
coerced[key] = parsed;
coercedAny = true;
}
}
catch { }
continue;
}
if (expectedType === 'array' && trimmed.startsWith('[')) {
try {
const parsed = JSON.parse(trimmed);
if (Array.isArray(parsed)) {
coerced[key] = parsed;
coercedAny = true;
}
}
catch { }
continue;
}
if (expectedType === 'number' || expectedType === 'integer') {
const num = Number(trimmed);
if (!isNaN(num) && trimmed !== '') {
coerced[key] = expectedType === 'integer' ? Math.trunc(num) : num;
coercedAny = true;
}
continue;
}
if (expectedType === 'boolean') {
if (trimmed === 'true') {
coerced[key] = true;
coercedAny = true;
}
else if (trimmed === 'false') {
coerced[key] = false;
coercedAny = true;
}
continue;
}
}
if (expectedType === 'string' && (actualType === 'number' || actualType === 'boolean')) {
coerced[key] = String(value);
coercedAny = true;
continue;
}
}
if (coercedAny) {
logger_1.logger.warn(`Coerced mistyped params for tool "${toolName}"`, {
original: Object.fromEntries(Object.entries(args).map(([k, v]) => [k, `${typeof v}: ${typeof v === 'string' ? v.substring(0, 80) : v}`])),
});
}
return coerced;
}
async executeTool(name, args) {
args = args || {};
const disabledTools = this.getDisabledTools();
@@ -1114,24 +936,6 @@ 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}`);
}
@@ -3085,26 +2889,7 @@ Full documentation is being prepared. For now, use get_node_essentials for confi
process.stdin.resume();
}
async shutdown() {
if (this.isShutdown) {
logger_1.logger.debug('Shutdown already called, skipping');
return;
}
this.isShutdown = true;
logger_1.logger.info('Shutting down MCP server...');
try {
await this.initialized;
}
catch (error) {
logger_1.logger.debug('Initialization had failed, proceeding with cleanup', {
error: error instanceof Error ? error.message : String(error)
});
}
try {
await this.server.close();
}
catch (error) {
logger_1.logger.error('Error closing MCP server:', error);
}
if (this.cache) {
try {
this.cache.destroy();
@@ -3114,29 +2899,15 @@ Full documentation is being prepared. For now, use get_node_essentials for confi
logger_1.logger.error('Error cleaning up cache:', error);
}
}
if (this.useSharedDatabase && this.sharedDbState) {
if (this.db) {
try {
(0, shared_database_1.releaseSharedDatabase)(this.sharedDbState);
logger_1.logger.info('Released shared database reference');
}
catch (error) {
logger_1.logger.error('Error releasing shared database:', error);
}
}
else if (this.db) {
try {
this.db.close();
await this.db.close();
logger_1.logger.info('Database connection closed');
}
catch (error) {
logger_1.logger.error('Error closing database:', error);
}
}
this.db = null;
this.repository = null;
this.templateService = null;
this.earlyLogger = null;
this.sharedDbState = null;
}
}
exports.N8NDocumentationMCPServer = N8NDocumentationMCPServer;

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;AA6B5C,eAAO,MAAM,kBAAkB,EAAE,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAoChE,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;AA4B5C,eAAO,MAAM,kBAAkB,EAAE,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAmChE,CAAC;AAGF,YAAY,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC"}

View File

@@ -29,7 +29,6 @@ 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_manage_datatable: workflow_management_1.n8nManageDatatableDoc
n8n_deploy_template: workflow_management_1.n8nDeployTemplateDoc
};
//# 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,+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"}
{"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"}

View File

@@ -10,5 +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';
//# 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;AAC7D,OAAO,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,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"}

View File

@@ -1,6 +1,6 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
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;
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,6 +25,4 @@ 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;AAC7B,+DAA+D;AAAtD,6HAAA,qBAAqB,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"}

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,iBA2azC,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,iBA+ZzC,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, 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).',
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).',
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,8 +23,7 @@ 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)',
'Transfer workflows between projects: Use transferWorkflow with destinationProjectId (enterprise feature)'
'Activate/deactivate workflows: Use activateWorkflow/deactivateWorkflow operations (requires activatable triggers like webhook/schedule)'
]
},
full: {
@@ -57,9 +56,6 @@ 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:
@@ -120,8 +116,8 @@ When ANY workflow update is made, ALL nodes in the workflow are automatically sa
1. **Operator Structure Fixes**:
- Binary operators (equals, contains, greaterThan, etc.) automatically have \`singleValue\` removed
- Unary operators (empty, notEmpty, true, false) automatically get \`singleValue: true\` added
- Invalid operator structures (e.g., \`{type: "notEmpty"}\`) are corrected to \`{type: "object", operation: "notEmpty"}\`
- Unary operators (isEmpty, isNotEmpty, true, false) automatically get \`singleValue: true\` added
- Invalid operator structures (e.g., \`{type: "isNotEmpty"}\`) are corrected to \`{type: "boolean", operation: "isNotEmpty"}\`
2. **Missing Metadata Added**:
- IF nodes with conditions get complete \`conditions.options\` structure if missing
@@ -199,12 +195,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 null
## Removing Properties with undefined
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.
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.
### Why Use null?
- **Property removal**: Setting a property to \`null\` removes it completely from the node object
### 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
- **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
@@ -216,7 +212,7 @@ n8n_update_partial_workflow({
operations: [{
type: "updateNode",
nodeName: "HTTP Request",
updates: { onError: null }
updates: { onError: undefined }
}]
});
@@ -226,7 +222,7 @@ n8n_update_partial_workflow({
operations: [{
type: "updateNode",
nodeId: "node_abc",
updates: { disabled: null }
updates: { disabled: undefined }
}]
});
\`\`\`
@@ -240,7 +236,7 @@ n8n_update_partial_workflow({
operations: [{
type: "updateNode",
nodeName: "API Request",
updates: { "parameters.authentication": null }
updates: { "parameters.authentication": undefined }
}]
});
@@ -250,7 +246,7 @@ n8n_update_partial_workflow({
operations: [{
type: "updateNode",
nodeName: "HTTP Request",
updates: { "parameters.headers": null }
updates: { "parameters.headers": undefined }
}]
});
\`\`\`
@@ -276,7 +272,7 @@ n8n_update_partial_workflow({
type: "updateNode",
nodeName: "HTTP Request",
updates: {
continueOnFail: null,
continueOnFail: undefined,
onError: "continueErrorOutput"
}
}]
@@ -292,15 +288,15 @@ n8n_update_partial_workflow({
type: "updateNode",
nodeName: "Data Processor",
updates: {
continueOnFail: null,
alwaysOutputData: null,
"parameters.legacy_option": null
continueOnFail: undefined,
alwaysOutputData: undefined,
"parameters.legacy_option": undefined
}
}]
});
\`\`\`
### When to Use null
### When to Use undefined
- Removing deprecated properties during migration
- Cleaning up optional configuration flags
- Resolving mutual exclusivity validation errors
@@ -334,8 +330,6 @@ n8n_update_partial_workflow({
'// Best-effort mode: apply what works, report what fails\nn8n_update_partial_workflow({id: "vwx", operations: [\n {type: "updateName", name: "Fixed Workflow"},\n {type: "removeConnection", source: "Broken", target: "Node"},\n {type: "cleanStaleConnections"}\n], continueOnError: true})',
'// Update node parameter\nn8n_update_partial_workflow({id: "yza", operations: [{type: "updateNode", nodeName: "HTTP Request", updates: {"parameters.url": "https://api.example.com"}}]})',
'// Validate before applying\nn8n_update_partial_workflow({id: "bcd", operations: [{type: "removeNode", nodeName: "Old Process"}], validateOnly: true})',
'// Surgically edit code using __patch_find_replace (avoids replacing entire code block)\nn8n_update_partial_workflow({id: "pfr1", operations: [{type: "updateNode", nodeName: "Code", updates: {"parameters.jsCode": {"__patch_find_replace": [{"find": "const limit = 10;", "replace": "const limit = 50;"}]}}}]})',
'// Multiple sequential patches on the same property\nn8n_update_partial_workflow({id: "pfr2", operations: [{type: "updateNode", nodeName: "Code", updates: {"parameters.jsCode": {"__patch_find_replace": [{"find": "api.old-domain.com", "replace": "api.new-domain.com"}, {"find": "Authorization: Bearer old_token", "replace": "Authorization: Bearer new_token"}]}}}]})',
'\n// ============ AI CONNECTION EXAMPLES ============',
'// Connect language model to AI Agent\nn8n_update_partial_workflow({id: "ai1", operations: [{type: "addConnection", source: "OpenAI Chat Model", target: "AI Agent", sourceOutput: "ai_languageModel"}]})',
'// Connect tool to AI Agent\nn8n_update_partial_workflow({id: "ai2", operations: [{type: "addConnection", source: "HTTP Request Tool", target: "AI Agent", sourceOutput: "ai_tool"}]})',
@@ -348,14 +342,11 @@ 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: 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"}]})'
'// 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}}]})'
],
useCases: [
'Rewire connections when replacing nodes',
@@ -373,8 +364,7 @@ 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',
'Transfer workflows between team projects (enterprise)'
'Batch-update AI tool connections'
],
performance: 'Very fast - typically 50-200ms. Much faster than full updates as only changes are processed.',
bestPractices: [
@@ -394,9 +384,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 null in the updates object',
'To remove properties, set them to undefined (not null) in the updates object',
'When migrating from deprecated properties, remove the old property and add the new one in the same operation',
'Use null to resolve mutual exclusivity validation errors between properties',
'Use undefined to resolve mutual exclusivity validation errors between properties',
'Batch multiple property removals in a single updateNode operation for efficiency'
],
pitfalls: [
@@ -414,14 +404,12 @@ n8n_update_partial_workflow({
'**CRITICAL**: For Switch nodes, ALWAYS use case=N instead of sourceIndex. Using same sourceIndex for multiple connections will put them on the same case output.',
'cleanStaleConnections removes ALL broken connections - cannot be selective',
'replaceConnections overwrites entire connections object - all previous connections lost',
'**Auto-sanitization behavior**: Binary operators (equals, contains) automatically have singleValue removed; unary operators (empty, notEmpty) automatically get singleValue:true added',
'**Auto-sanitization behavior**: Binary operators (equals, contains) automatically have singleValue removed; unary operators (isEmpty, isNotEmpty) automatically get singleValue:true added',
'**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',
'**__patch_find_replace for code edits**: Instead of replacing entire code blocks, use `{"parameters.jsCode": {"__patch_find_replace": [{"find": "old text", "replace": "new text"}]}}` to surgically edit string properties',
'__patch_find_replace replaces the FIRST occurrence of each find string. Patches are applied sequentially — order matters',
'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',
'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',
'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,EAwoB9C,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,EAqlB9C,CAAC"}

View File

@@ -57,10 +57,6 @@ 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']
@@ -141,7 +137,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, activate/deactivateWorkflow, transferWorkflow. 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. See tools_documentation("n8n_update_partial_workflow", "full") for details.`,
inputSchema: {
type: 'object',
additionalProperties: true,
@@ -282,7 +278,7 @@ exports.n8nManagementTools = [
},
{
name: 'n8n_autofix_workflow',
description: `Automatically fix common workflow validation errors. Preview fixes or apply them. Fixes expression format, typeVersion, error output config, webhook paths, connection structure issues (numeric keys, invalid types, ID-to-name, duplicates, out-of-bounds indices).`,
description: `Automatically fix common workflow validation errors. Preview fixes or apply them. Fixes expression format, typeVersion, error output config, webhook paths.`,
inputSchema: {
type: 'object',
properties: {
@@ -299,7 +295,7 @@ exports.n8nManagementTools = [
description: 'Types of fixes to apply (default: all)',
items: {
type: 'string',
enum: ['expression-format', 'typeversion-correction', 'error-output-config', 'node-type-correction', 'webhook-missing-path', 'typeversion-upgrade', 'version-migration', 'tool-variant-correction', 'connection-numeric-keys', 'connection-invalid-type', 'connection-id-to-name', 'connection-duplicate-removal', 'connection-input-index']
enum: ['expression-format', 'typeversion-correction', 'error-output-config', 'node-type-correction', 'webhook-missing-path', 'typeversion-upgrade', 'version-migration']
}
},
confidenceThreshold: {
@@ -587,53 +583,6 @@ 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

@@ -130,9 +130,6 @@ async function rebuild() {
}
}
console.log(`💾 Save completed: ${saved} nodes saved successfully`);
console.log('\n🔍 Rebuilding FTS5 search index...');
db.prepare("INSERT INTO nodes_fts(nodes_fts) VALUES('rebuild')").run();
console.log('✅ FTS5 index rebuilt successfully');
console.log('\n🔍 Running validation checks...');
try {
const validationResults = validateDatabase(repository);

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;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"}
{"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"}

View File

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

File diff suppressed because one or more lines are too long

View File

@@ -730,30 +730,30 @@ class EnhancedConfigValidator extends config_validator_1.ConfigValidator {
'empty', 'notEmpty', 'equals', 'notEquals',
'contains', 'notContains', 'startsWith', 'notStartsWith',
'endsWith', 'notEndsWith', 'regex', 'notRegex',
'exists', 'notExists'
'exists', 'notExists', 'isNotEmpty'
],
number: [
'empty', 'notEmpty', 'equals', 'notEquals', 'gt', 'lt', 'gte', 'lte',
'exists', 'notExists'
'exists', 'notExists', 'isNotEmpty'
],
dateTime: [
'empty', 'notEmpty', 'equals', 'notEquals', 'after', 'before', 'afterOrEquals', 'beforeOrEquals',
'exists', 'notExists'
'exists', 'notExists', 'isNotEmpty'
],
boolean: [
'empty', 'notEmpty', 'true', 'false', 'equals', 'notEquals',
'exists', 'notExists'
'exists', 'notExists', 'isNotEmpty'
],
array: [
'contains', 'notContains', 'lengthEquals', 'lengthNotEquals',
'lengthGt', 'lengthLt', 'lengthGte', 'lengthLte', 'empty', 'notEmpty',
'exists', 'notExists'
'exists', 'notExists', 'isNotEmpty'
],
object: [
'empty', 'notEmpty',
'exists', 'notExists'
'exists', 'notExists', 'isNotEmpty'
],
any: ['exists', 'notExists']
any: ['exists', 'notExists', 'isNotEmpty']
};
for (let i = 0; i < conditions.length; i++) {
const condition = conditions[i];

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, DataTable, DataTableColumn, DataTableListParams, DataTableRow, DataTableRowListParams, DataTableInsertRowsParams, DataTableUpdateRowsParams, DataTableUpsertRowParams, DataTableDeleteRowsParams } from '../types/n8n-api';
import { Workflow, WorkflowListParams, WorkflowListResponse, Execution, ExecutionListParams, ExecutionListResponse, Credential, CredentialListParams, CredentialListResponse, Tag, TagListParams, TagListResponse, HealthCheckResponse, N8nVersionInfo, Variable, WebhookRequest, SourceControlStatus, SourceControlPullResult, SourceControlPushResult } from '../types/n8n-api';
export interface N8nApiClientConfig {
baseUrl: string;
apiKey: string;
@@ -20,7 +20,6 @@ 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>;
@@ -37,7 +36,6 @@ 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>;
@@ -45,28 +43,6 @@ 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,17 +194,9 @@ 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) {
@@ -213,7 +205,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) {
@@ -373,15 +365,6 @@ 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');
@@ -448,110 +431,6 @@ 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

@@ -26,10 +26,10 @@ export declare const workflowNodeSchema: z.ZodObject<{
parameters: Record<string, unknown>;
credentials?: Record<string, unknown> | undefined;
retryOnFail?: boolean | undefined;
continueOnFail?: boolean | undefined;
maxTries?: number | undefined;
waitBetweenTries?: number | undefined;
alwaysOutputData?: boolean | undefined;
continueOnFail?: boolean | undefined;
executeOnce?: boolean | undefined;
disabled?: boolean | undefined;
notes?: string | undefined;
@@ -43,10 +43,10 @@ export declare const workflowNodeSchema: z.ZodObject<{
parameters: Record<string, unknown>;
credentials?: Record<string, unknown> | undefined;
retryOnFail?: boolean | undefined;
continueOnFail?: boolean | undefined;
maxTries?: number | undefined;
waitBetweenTries?: number | undefined;
alwaysOutputData?: boolean | undefined;
continueOnFail?: boolean | undefined;
executeOnce?: boolean | undefined;
disabled?: boolean | undefined;
notes?: string | undefined;
@@ -144,227 +144,79 @@ 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, {
type: string;
node: string;
index: number;
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;
}>, "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, {
error?: {
type: string;
node: string;
index: number;
}, {
}[][] | undefined;
main?: {
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, {
}[][] | undefined;
ai_tool?: {
type: string;
node: string;
index: number;
}, {
}[][] | undefined;
ai_languageModel?: {
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, {
}[][] | undefined;
ai_memory?: {
type: string;
node: string;
index: number;
}, {
}[][] | undefined;
ai_embedding?: {
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, {
}[][] | undefined;
ai_vectorStore?: {
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">, 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">>>;
}[][] | undefined;
}>>;
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":"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"}
{"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"}

View File

@@ -1,7 +1,4 @@
"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;
@@ -16,7 +13,6 @@ 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");
@@ -51,7 +47,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(),
@@ -80,27 +76,11 @@ 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) {
@@ -136,7 +116,6 @@ function cleanWorkflowForUpdate(workflow) {
else {
cleanedWorkflow.settings = { executionOrder: 'v1' };
}
ensureWebhookIds(cleanedWorkflow.nodes);
return cleanedWorkflow;
}
function validateWorkflowStructure(workflow) {
@@ -173,10 +152,11 @@ 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);
const connectionRecord = connection;
Object.values(connectionRecord).forEach((connData) => {
ALL_CONNECTION_TYPES.forEach(connType => {
const connData = connection[connType];
if (connData && Array.isArray(connData)) {
connData.forEach((outputs) => {
if (Array.isArray(outputs)) {
@@ -302,28 +282,23 @@ function validateWorkflowStructure(workflow) {
errors.push(`Connection references non-existent node: ${sourceName}`);
}
}
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}])`);
}
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}])`);
}
});
}
});
}
});
else {
errors.push(`Connection references non-existent target node: ${target.node} (from ${sourceName}[${outputIndex}][${targetIndex}])`);
}
}
});
}
});
}
});
}
return errors;
@@ -419,10 +394,10 @@ function validateOperatorStructure(operator, path) {
}
if (!operator.operation) {
errors.push(`${path}: missing required field "operation". ` +
'Operation specifies the comparison type (e.g., "equals", "contains", "notEmpty")');
'Operation specifies the comparison type (e.g., "equals", "contains", "isNotEmpty")');
}
if (operator.operation) {
const unaryOperators = ['empty', 'notEmpty', 'true', 'false', 'isNumeric', 'exists', 'notExists'];
const unaryOperators = ['isEmpty', 'isNotEmpty', 'true', 'false', 'isNumeric'];
const isUnary = unaryOperators.includes(operator.operation);
if (isUnary) {
if (operator.singleValue !== true) {
@@ -433,7 +408,7 @@ function validateOperatorStructure(operator, path) {
else {
if (operator.singleValue === true) {
errors.push(`${path}: binary operator "${operator.operation}" should not have "singleValue: true". ` +
'Only unary operators (empty, notEmpty, true, false, isNumeric, exists, notExists) need this property.');
'Only unary operators (isEmpty, isNotEmpty, true, false, isNumeric) need this property.');
}
}
}

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;AAsBhD,wBAAgB,YAAY,CAAC,IAAI,EAAE,YAAY,GAAG,YAAY,CAa7D;AAKD,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,GAAG,GAAG,GAAG,CASxD;AAgND,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;AAoND,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,YAAY,GAAG,MAAM,EAAE,CAgEjE"}

View File

@@ -4,19 +4,6 @@ exports.sanitizeNode = sanitizeNode;
exports.sanitizeWorkflowNodes = sanitizeWorkflowNodes;
exports.validateNodeMetadata = validateNodeMetadata;
const logger_1 = require("../utils/logger");
const OPERATOR_CORRECTIONS = {
'isEmpty': 'empty',
'isNotEmpty': 'notEmpty',
};
const UNARY_OPERATORS = new Set([
'true',
'false',
'isNumeric',
'empty',
'notEmpty',
'exists',
'notExists',
]);
function sanitizeNode(node) {
const sanitized = { ...node };
if (isFilterBasedNode(node.type, node.typeVersion)) {
@@ -30,7 +17,7 @@ function sanitizeWorkflowNodes(workflow) {
}
return {
...workflow,
nodes: workflow.nodes.map(sanitizeNode)
nodes: workflow.nodes.map((node) => sanitizeNode(node))
};
}
function isFilterBasedNode(nodeType, typeVersion) {
@@ -79,7 +66,7 @@ function sanitizeFilterConditions(conditions) {
...sanitized.options
};
if (sanitized.conditions && Array.isArray(sanitized.conditions)) {
sanitized.conditions = sanitized.conditions.map(sanitizeCondition);
sanitized.conditions = sanitized.conditions.map((condition) => sanitizeCondition(condition));
}
return sanitized;
}
@@ -105,13 +92,11 @@ function sanitizeOperator(operator) {
const typeValue = sanitized.type;
if (isOperationName(typeValue)) {
logger_1.logger.debug(`Fixing operator structure: converting type="${typeValue}" to operation`);
sanitized.type = inferDataType(typeValue);
const dataType = inferDataType(typeValue);
sanitized.type = dataType;
sanitized.operation = typeValue;
}
}
if (sanitized.operation && OPERATOR_CORRECTIONS[sanitized.operation]) {
sanitized.operation = OPERATOR_CORRECTIONS[sanitized.operation];
}
if (sanitized.operation) {
if (isUnaryOperator(sanitized.operation)) {
sanitized.singleValue = true;
@@ -127,7 +112,7 @@ function isOperationName(value) {
return !dataTypes.includes(value) && /^[a-z][a-zA-Z]*$/.test(value);
}
function inferDataType(operation) {
const booleanOps = ['true', 'false'];
const booleanOps = ['true', 'false', 'isEmpty', 'isNotEmpty'];
if (booleanOps.includes(operation)) {
return 'boolean';
}
@@ -139,14 +124,17 @@ 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) {
return UNARY_OPERATORS.has(operation);
const unaryOps = [
'isEmpty',
'isNotEmpty',
'true',
'false',
'isNumeric'
];
return unaryOps.includes(operation);
}
function generateConditionId() {
return `condition-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;

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;IAyFtC,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;IAsFtC,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,8 +1067,7 @@ class NodeSpecificValidators {
fix: 'Wrap in array: return [{json: yourObject}]'
});
}
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)) {
if (/return\s+(true|false|null|undefined|\d+|['"`])/m.test(code)) {
errors.push({
type: 'invalid_value',
property: 'jsCode',
@@ -1150,7 +1149,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

@@ -5,8 +5,7 @@ import { WorkflowDiffOperation } from '../types/workflow-diff';
import { Workflow } from '../types/n8n-api';
import { PostUpdateGuidance } from './post-update-validator';
export type FixConfidenceLevel = 'high' | 'medium' | 'low';
export type FixType = 'expression-format' | 'typeversion-correction' | 'error-output-config' | 'node-type-correction' | 'webhook-missing-path' | 'typeversion-upgrade' | 'version-migration' | 'tool-variant-correction' | 'connection-numeric-keys' | 'connection-invalid-type' | 'connection-id-to-name' | 'connection-duplicate-removal' | 'connection-input-index';
export declare const CONNECTION_FIX_TYPES: FixType[];
export type FixType = 'expression-format' | 'typeversion-correction' | 'error-output-config' | 'node-type-correction' | 'webhook-missing-path' | 'typeversion-upgrade' | 'version-migration' | 'tool-variant-correction';
export interface AutoFixConfig {
applyFixes: boolean;
fixTypes?: FixType[];
@@ -69,12 +68,6 @@ export declare class WorkflowAutoFixer {
private filterOperationsByFixes;
private calculateStats;
private generateSummary;
private processConnectionFixes;
private fixNumericKeys;
private fixIdToName;
private fixInvalidTypes;
private fixInputIndices;
private fixDuplicateConnections;
private processVersionUpgradeFixes;
private processVersionMigrationFixes;
}

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

@@ -3,10 +3,9 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.WorkflowAutoFixer = exports.CONNECTION_FIX_TYPES = void 0;
exports.WorkflowAutoFixer = void 0;
exports.isNodeFormatIssue = isNodeFormatIssue;
const crypto_1 = __importDefault(require("crypto"));
const workflow_validator_1 = require("./workflow-validator");
const node_similarity_service_1 = require("./node-similarity-service");
const logger_1 = require("../utils/logger");
const node_version_service_1 = require("./node-version-service");
@@ -14,13 +13,6 @@ const breaking_change_detector_1 = require("./breaking-change-detector");
const node_migration_service_1 = require("./node-migration-service");
const post_update_validator_1 = require("./post-update-validator");
const logger = new logger_1.Logger({ prefix: '[WorkflowAutoFixer]' });
exports.CONNECTION_FIX_TYPES = [
'connection-numeric-keys',
'connection-invalid-type',
'connection-id-to-name',
'connection-duplicate-removal',
'connection-input-index'
];
function isNodeFormatIssue(issue) {
return 'nodeName' in issue && 'nodeId' in issue &&
typeof issue.nodeName === 'string' &&
@@ -80,7 +72,6 @@ class WorkflowAutoFixer {
if (!fullConfig.fixTypes || fullConfig.fixTypes.includes('version-migration')) {
await this.processVersionMigrationFixes(workflow, nodeMap, operations, fixes, postUpdateGuidance);
}
this.processConnectionFixes(workflow, validationResult, fullConfig, operations, fixes);
const filteredFixes = this.filterByConfidence(fixes, fullConfig.confidenceThreshold);
const filteredOperations = this.filterOperationsByFixes(operations, filteredFixes, fixes);
const limitedFixes = filteredFixes.slice(0, fullConfig.maxFixes);
@@ -402,13 +393,9 @@ class WorkflowAutoFixer {
}
filterOperationsByFixes(operations, filteredFixes, allFixes) {
const fixedNodes = new Set(filteredFixes.map(f => f.node));
const hasConnectionFixes = filteredFixes.some(f => exports.CONNECTION_FIX_TYPES.includes(f.type));
return operations.filter(op => {
if (op.type === 'updateNode') {
return fixedNodes.has(op.nodeName || '') || fixedNodes.has(op.nodeId || '');
}
if (op.type === 'replaceConnections') {
return hasConnectionFixes;
return fixedNodes.has(op.nodeId || '');
}
return true;
});
@@ -424,12 +411,7 @@ class WorkflowAutoFixer {
'webhook-missing-path': 0,
'typeversion-upgrade': 0,
'version-migration': 0,
'tool-variant-correction': 0,
'connection-numeric-keys': 0,
'connection-invalid-type': 0,
'connection-id-to-name': 0,
'connection-duplicate-removal': 0,
'connection-input-index': 0
'tool-variant-correction': 0
},
byConfidence: {
'high': 0,
@@ -472,299 +454,11 @@ class WorkflowAutoFixer {
if (stats.byType['tool-variant-correction'] > 0) {
parts.push(`${stats.byType['tool-variant-correction']} tool variant ${stats.byType['tool-variant-correction'] === 1 ? 'correction' : 'corrections'}`);
}
const connectionIssueCount = (stats.byType['connection-numeric-keys'] || 0) +
(stats.byType['connection-invalid-type'] || 0) +
(stats.byType['connection-id-to-name'] || 0) +
(stats.byType['connection-duplicate-removal'] || 0) +
(stats.byType['connection-input-index'] || 0);
if (connectionIssueCount > 0) {
parts.push(`${connectionIssueCount} connection ${connectionIssueCount === 1 ? 'issue' : 'issues'}`);
}
if (parts.length === 0) {
return `Fixed ${stats.total} ${stats.total === 1 ? 'issue' : 'issues'}`;
}
return `Fixed ${parts.join(', ')}`;
}
processConnectionFixes(workflow, validationResult, config, operations, fixes) {
if (!workflow.connections || Object.keys(workflow.connections).length === 0) {
return;
}
const idToNameMap = new Map();
const nameSet = new Set();
for (const node of workflow.nodes) {
idToNameMap.set(node.id, node.name);
nameSet.add(node.name);
}
const conn = JSON.parse(JSON.stringify(workflow.connections));
let anyFixed = false;
if (!config.fixTypes || config.fixTypes.includes('connection-numeric-keys')) {
const numericKeyResult = this.fixNumericKeys(conn);
if (numericKeyResult.length > 0) {
fixes.push(...numericKeyResult);
anyFixed = true;
}
}
if (!config.fixTypes || config.fixTypes.includes('connection-id-to-name')) {
const idToNameResult = this.fixIdToName(conn, idToNameMap, nameSet);
if (idToNameResult.length > 0) {
fixes.push(...idToNameResult);
anyFixed = true;
}
}
if (!config.fixTypes || config.fixTypes.includes('connection-invalid-type')) {
const invalidTypeResult = this.fixInvalidTypes(conn);
if (invalidTypeResult.length > 0) {
fixes.push(...invalidTypeResult);
anyFixed = true;
}
}
if (!config.fixTypes || config.fixTypes.includes('connection-input-index')) {
const inputIndexResult = this.fixInputIndices(conn, validationResult, workflow);
if (inputIndexResult.length > 0) {
fixes.push(...inputIndexResult);
anyFixed = true;
}
}
if (!config.fixTypes || config.fixTypes.includes('connection-duplicate-removal')) {
const dedupResult = this.fixDuplicateConnections(conn);
if (dedupResult.length > 0) {
fixes.push(...dedupResult);
anyFixed = true;
}
}
if (anyFixed) {
const op = {
type: 'replaceConnections',
connections: conn
};
operations.push(op);
}
}
fixNumericKeys(conn) {
const fixes = [];
const sourceNodes = Object.keys(conn);
for (const sourceName of sourceNodes) {
const nodeConn = conn[sourceName];
const numericKeys = Object.keys(nodeConn).filter(k => /^\d+$/.test(k));
if (numericKeys.length === 0)
continue;
if (!nodeConn['main']) {
nodeConn['main'] = [];
}
for (const numKey of numericKeys) {
const index = parseInt(numKey, 10);
const entries = nodeConn[numKey];
while (nodeConn['main'].length <= index) {
nodeConn['main'].push([]);
}
const hadExisting = nodeConn['main'][index] && nodeConn['main'][index].length > 0;
if (Array.isArray(entries)) {
for (const outputGroup of entries) {
if (Array.isArray(outputGroup)) {
nodeConn['main'][index] = [
...nodeConn['main'][index],
...outputGroup
];
}
}
}
if (hadExisting) {
logger.warn(`Merged numeric key "${numKey}" into existing main[${index}] on node "${sourceName}" - dedup pass will clean exact duplicates`);
}
fixes.push({
node: sourceName,
field: `connections.${sourceName}.${numKey}`,
type: 'connection-numeric-keys',
before: numKey,
after: `main[${index}]`,
confidence: hadExisting ? 'medium' : 'high',
description: hadExisting
? `Merged numeric connection key "${numKey}" into existing main[${index}] on node "${sourceName}"`
: `Converted numeric connection key "${numKey}" to main[${index}] on node "${sourceName}"`
});
delete nodeConn[numKey];
}
}
return fixes;
}
fixIdToName(conn, idToNameMap, nameSet) {
const fixes = [];
const renames = [];
const sourceKeys = Object.keys(conn);
for (const sourceKey of sourceKeys) {
if (idToNameMap.has(sourceKey) && !nameSet.has(sourceKey)) {
renames.push({ oldKey: sourceKey, newKey: idToNameMap.get(sourceKey) });
}
}
const newKeyCount = new Map();
for (const r of renames) {
newKeyCount.set(r.newKey, (newKeyCount.get(r.newKey) || 0) + 1);
}
const safeRenames = renames.filter(r => {
if ((newKeyCount.get(r.newKey) || 0) > 1) {
logger.warn(`Skipping ambiguous ID-to-name rename: "${r.oldKey}" → "${r.newKey}" (multiple IDs map to same name)`);
return false;
}
return true;
});
for (const { oldKey, newKey } of safeRenames) {
conn[newKey] = conn[oldKey];
delete conn[oldKey];
fixes.push({
node: newKey,
field: `connections.sourceKey`,
type: 'connection-id-to-name',
before: oldKey,
after: newKey,
confidence: 'high',
description: `Replaced node ID "${oldKey}" with name "${newKey}" as connection source key`
});
}
for (const sourceName of Object.keys(conn)) {
const nodeConn = conn[sourceName];
for (const outputKey of Object.keys(nodeConn)) {
const outputs = nodeConn[outputKey];
if (!Array.isArray(outputs))
continue;
for (const outputGroup of outputs) {
if (!Array.isArray(outputGroup))
continue;
for (const entry of outputGroup) {
if (entry && entry.node && idToNameMap.has(entry.node) && !nameSet.has(entry.node)) {
const oldNode = entry.node;
const newNode = idToNameMap.get(entry.node);
entry.node = newNode;
fixes.push({
node: sourceName,
field: `connections.${sourceName}.${outputKey}[].node`,
type: 'connection-id-to-name',
before: oldNode,
after: newNode,
confidence: 'high',
description: `Replaced target node ID "${oldNode}" with name "${newNode}" in connection from "${sourceName}"`
});
}
}
}
}
}
return fixes;
}
fixInvalidTypes(conn) {
const fixes = [];
for (const sourceName of Object.keys(conn)) {
const nodeConn = conn[sourceName];
for (const outputKey of Object.keys(nodeConn)) {
const outputs = nodeConn[outputKey];
if (!Array.isArray(outputs))
continue;
for (const outputGroup of outputs) {
if (!Array.isArray(outputGroup))
continue;
for (const entry of outputGroup) {
if (entry && entry.type && !workflow_validator_1.VALID_CONNECTION_TYPES.has(entry.type)) {
const oldType = entry.type;
const newType = workflow_validator_1.VALID_CONNECTION_TYPES.has(outputKey) ? outputKey : 'main';
entry.type = newType;
fixes.push({
node: sourceName,
field: `connections.${sourceName}.${outputKey}[].type`,
type: 'connection-invalid-type',
before: oldType,
after: newType,
confidence: 'high',
description: `Fixed invalid connection type "${oldType}" → "${newType}" in connection from "${sourceName}" to "${entry.node}"`
});
}
}
}
}
}
return fixes;
}
fixInputIndices(conn, validationResult, workflow) {
const fixes = [];
for (const error of validationResult.errors) {
if (error.code !== 'INPUT_INDEX_OUT_OF_BOUNDS')
continue;
const targetNodeName = error.nodeName;
if (!targetNodeName)
continue;
const match = error.message.match(/Input index (\d+).*?has (\d+) main input/);
if (!match) {
logger.warn(`Could not parse INPUT_INDEX_OUT_OF_BOUNDS error for node "${targetNodeName}": ${error.message}`);
continue;
}
const badIndex = parseInt(match[1], 10);
const inputCount = parseInt(match[2], 10);
const clampedIndex = inputCount > 1 ? Math.min(badIndex, inputCount - 1) : 0;
for (const sourceName of Object.keys(conn)) {
const nodeConn = conn[sourceName];
for (const outputKey of Object.keys(nodeConn)) {
const outputs = nodeConn[outputKey];
if (!Array.isArray(outputs))
continue;
for (const outputGroup of outputs) {
if (!Array.isArray(outputGroup))
continue;
for (const entry of outputGroup) {
if (entry && entry.node === targetNodeName && entry.index === badIndex) {
entry.index = clampedIndex;
fixes.push({
node: sourceName,
field: `connections.${sourceName}.${outputKey}[].index`,
type: 'connection-input-index',
before: badIndex,
after: clampedIndex,
confidence: 'medium',
description: `Clamped input index ${badIndex}${clampedIndex} for target node "${targetNodeName}" (has ${inputCount} input${inputCount === 1 ? '' : 's'})`
});
}
}
}
}
}
}
return fixes;
}
fixDuplicateConnections(conn) {
const fixes = [];
for (const sourceName of Object.keys(conn)) {
const nodeConn = conn[sourceName];
for (const outputKey of Object.keys(nodeConn)) {
const outputs = nodeConn[outputKey];
if (!Array.isArray(outputs))
continue;
for (let i = 0; i < outputs.length; i++) {
const outputGroup = outputs[i];
if (!Array.isArray(outputGroup))
continue;
const seen = new Set();
const deduped = [];
for (const entry of outputGroup) {
const key = JSON.stringify({ node: entry.node, type: entry.type, index: entry.index });
if (seen.has(key)) {
fixes.push({
node: sourceName,
field: `connections.${sourceName}.${outputKey}[${i}]`,
type: 'connection-duplicate-removal',
before: entry,
after: null,
confidence: 'high',
description: `Removed duplicate connection from "${sourceName}" to "${entry.node}" (type: ${entry.type}, index: ${entry.index})`
});
}
else {
seen.add(key);
deduped.push(entry);
}
}
outputs[i] = deduped;
}
}
}
return fixes;
}
async processVersionUpgradeFixes(workflow, nodeMap, operations, fixes, postUpdateGuidance) {
if (!this.versionService || !this.migrationService || !this.postUpdateValidator) {
logger.warn('Version services not initialized. Skipping version upgrade fixes.');
@@ -794,7 +488,6 @@ 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,11 +3,6 @@ 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;
@@ -37,8 +32,6 @@ export declare class WorkflowDiffEngine {
private validateDeactivateWorkflow;
private applyActivateWorkflow;
private applyDeactivateWorkflow;
private validateTransferWorkflow;
private applyTransferWorkflow;
private validateCleanStaleConnections;
private validateReplaceConnections;
private applyCleanStaleConnections;
@@ -47,7 +40,6 @@ export declare class WorkflowDiffEngine {
private normalizeNodeName;
private findNode;
private formatNodeNotFoundError;
private getNestedProperty;
private setNestedProperty;
}
//# sourceMappingURL=workflow-diff-engine.d.ts.map

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,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;IA6D1B,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;IA6CvB,OAAO,CAAC,aAAa;IAOrB,OAAO,CAAC,eAAe;IAOvB,OAAO,CAAC,gBAAgB;IAWxB,OAAO,CAAC,sBAAsB;IA0D9B,OAAO,CAAC,kBAAkB;IAiD1B,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;IAUzB,OAAO,CAAC,iBAAiB;CAoB1B"}
{"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"}

View File

@@ -10,20 +10,11 @@ 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 = [];
@@ -82,10 +73,6 @@ 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,
@@ -95,12 +82,7 @@ class WorkflowDiffEngine {
errors: errors.length > 0 ? errors : undefined,
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,
transferToProjectId: this.transferToProjectId || undefined
failed: failedIndices
};
}
else {
@@ -160,15 +142,8 @@ class WorkflowDiffEngine {
};
}
}
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`);
}
workflowCopy.nodes = workflowCopy.nodes.map((node) => (0, node_sanitizer_1.sanitizeNode)(node));
logger.debug('Applied full-workflow sanitization to all nodes');
if (request.validateOnly) {
return {
success: true,
@@ -187,10 +162,7 @@ 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,
tagsToAdd: this.tagsToAdd.length > 0 ? this.tagsToAdd : undefined,
tagsToRemove: this.tagsToRemove.length > 0 ? this.tagsToRemove : undefined,
transferToProjectId: this.transferToProjectId || undefined
shouldDeactivate: shouldDeactivate || undefined
};
}
}
@@ -229,8 +201,6 @@ class WorkflowDiffEngine {
case 'addTag':
case 'removeTag':
return null;
case 'transferWorkflow':
return this.validateTransferWorkflow(workflow, operation);
case 'activateWorkflow':
return this.validateActivateWorkflow(workflow, operation);
case 'deactivateWorkflow':
@@ -296,9 +266,6 @@ class WorkflowDiffEngine {
case 'replaceConnections':
this.applyReplaceConnections(workflow, operation);
break;
case 'transferWorkflow':
this.applyTransferWorkflow(workflow, operation);
break;
}
}
validateAddNode(workflow, operation) {
@@ -335,7 +302,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. Correct structure: {type: "updateNode", nodeId: "abc-123" OR nodeName: "My Node", updates: {name: "New Name", "parameters.url": "https://example.com"}}`;
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"}}`;
}
const node = this.findNode(workflow, operation.nodeId, operation.nodeName);
if (!node) {
@@ -351,28 +318,6 @@ class WorkflowDiffEngine {
}
}
}
for (const [path, value] of Object.entries(operation.updates)) {
if (value !== null && typeof value === 'object' && !Array.isArray(value)
&& '__patch_find_replace' in value) {
const patches = value.__patch_find_replace;
if (!Array.isArray(patches)) {
return `Invalid __patch_find_replace at "${path}": must be an array of {find, replace} objects`;
}
for (let i = 0; i < patches.length; i++) {
const patch = patches[i];
if (!patch || typeof patch.find !== 'string' || typeof patch.replace !== 'string') {
return `Invalid __patch_find_replace entry at "${path}[${i}]": each entry must have "find" (string) and "replace" (string)`;
}
}
const currentValue = this.getNestedProperty(node, path);
if (currentValue === undefined) {
return `Cannot apply __patch_find_replace to "${path}": property does not exist on node`;
}
if (typeof currentValue !== 'string') {
return `Cannot apply __patch_find_replace to "${path}": current value is ${typeof currentValue}, expected string`;
}
}
}
return null;
}
validateMoveNode(workflow, operation) {
@@ -437,18 +382,12 @@ 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(', ');
@@ -522,40 +461,34 @@ 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];
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) {
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) {
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;
@@ -563,25 +496,7 @@ class WorkflowDiffEngine {
logger.debug(`Tracking rename: "${oldName}" → "${newName}"`);
}
Object.entries(operation.updates).forEach(([path, value]) => {
if (value !== null && typeof value === 'object' && !Array.isArray(value)
&& '__patch_find_replace' in value) {
const patches = value.__patch_find_replace;
let current = this.getNestedProperty(node, path);
for (const patch of patches) {
if (!current.includes(patch.find)) {
this.warnings.push({
operation: -1,
message: `__patch_find_replace: "${patch.find.substring(0, 50)}" not found in "${path}". Skipped.`
});
continue;
}
current = current.replace(patch.find, patch.replace);
}
this.setNestedProperty(node, path, current);
}
else {
this.setNestedProperty(node, path, value);
}
this.setNestedProperty(node, path, value);
});
const sanitized = (0, node_sanitizer_1.sanitizeNode)(node);
Object.assign(node, sanitized);
@@ -606,15 +521,8 @@ class WorkflowDiffEngine {
}
resolveSmartParameters(workflow, operation) {
const sourceNode = this.findNode(workflow, operation.source, operation.source);
let sourceOutput = String(operation.sourceOutput ?? 'main');
let sourceOutput = operation.sourceOutput ?? 'main';
let sourceIndex = operation.sourceIndex ?? 0;
const numericOutput = /^\d+$/.test(sourceOutput) ? parseInt(sourceOutput, 10) : null;
if (numericOutput !== null
&& (operation.sourceIndex === undefined || operation.sourceIndex === numericOutput)
&& operation.branch === undefined && operation.case === undefined) {
sourceIndex = numericOutput;
sourceOutput = 'main';
}
if (operation.branch !== undefined && operation.sourceIndex === undefined) {
if (sourceNode?.type === 'n8n-nodes-base.if') {
sourceIndex = operation.branch === 'true' ? 0 : 1;
@@ -648,10 +556,7 @@ class WorkflowDiffEngine {
if (!sourceNode || !targetNode)
return;
const { sourceOutput, sourceIndex } = this.resolveSmartParameters(workflow, operation);
let targetInput = String(operation.targetInput ?? sourceOutput);
if (/^\d+$/.test(targetInput)) {
targetInput = 'main';
}
const targetInput = operation.targetInput ?? sourceOutput;
const targetIndex = operation.targetIndex ?? 0;
if (!workflow.connections[sourceNode.name]) {
workflow.connections[sourceNode.name] = {};
@@ -676,9 +581,12 @@ 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 = String(operation.sourceOutput ?? 'main');
const sourceOutput = operation.sourceOutput || 'main';
const connections = workflow.connections[sourceNode.name]?.[sourceOutput];
if (!connections)
return;
@@ -725,21 +633,19 @@ class WorkflowDiffEngine {
workflow.name = operation.name;
}
applyAddTag(workflow, operation) {
const removeIdx = this.tagsToRemove.indexOf(operation.tag);
if (removeIdx !== -1) {
this.tagsToRemove.splice(removeIdx, 1);
if (!workflow.tags) {
workflow.tags = [];
}
if (!this.tagsToAdd.includes(operation.tag)) {
this.tagsToAdd.push(operation.tag);
if (!workflow.tags.includes(operation.tag)) {
workflow.tags.push(operation.tag);
}
}
applyRemoveTag(workflow, operation) {
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);
if (!workflow.tags)
return;
const index = workflow.tags.indexOf(operation.tag);
if (index !== -1) {
workflow.tags.splice(index, 1);
}
}
validateActivateWorkflow(workflow, operation) {
@@ -758,15 +664,6 @@ 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;
}
@@ -837,10 +734,7 @@ class WorkflowDiffEngine {
return false;
}
return true;
}));
while (filteredConnections.length > 0 && filteredConnections[filteredConnections.length - 1].length === 0) {
filteredConnections.pop();
}
})).filter(conns => conns.length > 0);
if (filteredConnections.length === 0) {
delete outputs[outputName];
}
@@ -874,10 +768,9 @@ 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: "${oldTargetName}" → "${newTargetName}"`);
logger.debug(`Updated connection: ${sourceName}[${outputType}][${outputIndex}][${connIndex}].node: "${connection.node}" → "${newTargetName}"`);
}
}
}
@@ -920,35 +813,17 @@ class WorkflowDiffEngine {
.join(', ');
return `Node not found for ${operationType}: "${nodeIdentifier}". Available nodes: ${availableNodes}. Tip: Use node ID for names with special characters (apostrophes, quotes).`;
}
getNestedProperty(obj, path) {
const keys = path.split('.');
let current = obj;
for (const key of keys) {
if (current == null || typeof current !== 'object')
return undefined;
current = current[key];
}
return current;
}
setNestedProperty(obj, path, value) {
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' || current[key] === null) {
if (value === null)
return;
if (!(key in current) || typeof current[key] !== 'object') {
current[key] = {};
}
current = current[key];
}
const finalKey = keys[keys.length - 1];
if (value === null) {
delete current[finalKey];
}
else {
current[finalKey] = value;
}
current[keys[keys.length - 1]] = value;
}
}
exports.WorkflowDiffEngine = WorkflowDiffEngine;

File diff suppressed because one or more lines are too long

View File

@@ -1,6 +1,5 @@
import { NodeRepository } from '../database/node-repository';
import { EnhancedConfigValidator } from './enhanced-config-validator';
export declare const VALID_CONNECTION_TYPES: Set<string>;
interface WorkflowNode {
id: string;
name: string;
@@ -22,7 +21,17 @@ interface WorkflowNode {
}
interface WorkflowConnection {
[sourceNode: string]: {
[outputType: string]: Array<Array<{
main?: Array<Array<{
node: string;
type: string;
index: number;
}>>;
error?: Array<Array<{
node: string;
type: string;
index: number;
}>>;
ai_tool?: Array<Array<{
node: string;
type: string;
index: number;
@@ -85,15 +94,6 @@ export declare class WorkflowValidator {
private validateErrorOutputConfiguration;
private validateAIToolConnection;
private validateAIToolSource;
private getNodeOutputTypes;
private validateNotAISubNode;
private getShortNodeType;
private getConditionalOutputInfo;
private validateOutputIndexBounds;
private validateConditionalBranchUsage;
private validateInputIndexBounds;
private flagOrphanedNodes;
private validateTriggerReachability;
private hasCycle;
private validateExpressions;
private countExpressionsInObject;

View File

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

View File

@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.WorkflowValidator = exports.VALID_CONNECTION_TYPES = void 0;
exports.WorkflowValidator = void 0;
const crypto_1 = __importDefault(require("crypto"));
const expression_validator_1 = require("./expression-validator");
const expression_format_validator_1 = require("./expression-format-validator");
@@ -16,15 +16,6 @@ const node_type_utils_1 = require("../utils/node-type-utils");
const node_classification_1 = require("../utils/node-classification");
const tool_variant_generator_1 = require("./tool-variant-generator");
const logger = new logger_1.Logger({ prefix: '[WorkflowValidator]' });
exports.VALID_CONNECTION_TYPES = new Set([
'main',
'error',
...ai_node_validator_1.AI_CONNECTION_TYPES,
'ai_agent',
'ai_chain',
'ai_retriever',
'ai_reranker',
]);
class WorkflowValidator {
constructor(nodeRepository, nodeValidator) {
this.nodeRepository = nodeRepository;
@@ -402,37 +393,51 @@ class WorkflowValidator {
result.statistics.invalidConnections++;
continue;
}
for (const [outputKey, outputConnections] of Object.entries(outputs)) {
if (!exports.VALID_CONNECTION_TYPES.has(outputKey)) {
let suggestion = '';
if (/^\d+$/.test(outputKey)) {
suggestion = ` If you meant to use output index ${outputKey}, use main[${outputKey}] instead.`;
}
result.errors.push({
type: 'error',
nodeName: sourceName,
message: `Unknown connection output key "${outputKey}" on node "${sourceName}". Valid keys are: ${[...exports.VALID_CONNECTION_TYPES].join(', ')}.${suggestion}`,
code: 'UNKNOWN_CONNECTION_KEY'
});
result.statistics.invalidConnections++;
continue;
}
if (!outputConnections || !Array.isArray(outputConnections))
continue;
if (outputKey === 'ai_tool') {
this.validateAIToolSource(sourceNode, result);
}
if (outputKey === 'main') {
this.validateNotAISubNode(sourceNode, result);
}
this.validateConnectionOutputs(sourceName, outputConnections, nodeMap, nodeIdMap, result, outputKey);
if (outputs.main) {
this.validateConnectionOutputs(sourceName, outputs.main, nodeMap, nodeIdMap, result, 'main');
}
if (outputs.error) {
this.validateConnectionOutputs(sourceName, outputs.error, nodeMap, nodeIdMap, result, 'error');
}
if (outputs.ai_tool) {
this.validateAIToolSource(sourceNode, result);
this.validateConnectionOutputs(sourceName, outputs.ai_tool, nodeMap, nodeIdMap, result, 'ai_tool');
}
}
if (profile !== 'minimal') {
this.validateTriggerReachability(workflow, result);
}
else {
this.flagOrphanedNodes(workflow, result);
const connectedNodes = new Set();
Object.keys(workflow.connections).forEach(name => connectedNodes.add(name));
Object.values(workflow.connections).forEach(outputs => {
if (outputs.main) {
outputs.main.flat().forEach(conn => {
if (conn)
connectedNodes.add(conn.node);
});
}
if (outputs.error) {
outputs.error.flat().forEach(conn => {
if (conn)
connectedNodes.add(conn.node);
});
}
if (outputs.ai_tool) {
outputs.ai_tool.flat().forEach(conn => {
if (conn)
connectedNodes.add(conn.node);
});
}
});
for (const node of workflow.nodes) {
if (node.disabled || (0, node_classification_1.isNonExecutableNode)(node.type))
continue;
const isNodeTrigger = (0, node_type_utils_1.isTriggerNode)(node.type);
if (!connectedNodes.has(node.name) && !isNodeTrigger) {
result.warnings.push({
type: 'warning',
nodeId: node.id,
nodeName: node.name,
message: 'Node is not connected to any other nodes'
});
}
}
if (profile !== 'minimal' && this.hasCycle(workflow)) {
result.errors.push({
@@ -445,8 +450,6 @@ class WorkflowValidator {
const sourceNode = nodeMap.get(sourceName);
if (outputType === 'main' && sourceNode) {
this.validateErrorOutputConfiguration(sourceName, sourceNode, outputs, nodeMap, result);
this.validateOutputIndexBounds(sourceNode, outputs, result);
this.validateConditionalBranchUsage(sourceNode, outputs, result);
}
outputs.forEach((outputConnections, outputIndex) => {
if (!outputConnections)
@@ -460,20 +463,6 @@ class WorkflowValidator {
result.statistics.invalidConnections++;
return;
}
if (connection.type && !exports.VALID_CONNECTION_TYPES.has(connection.type)) {
let suggestion = '';
if (/^\d+$/.test(connection.type)) {
suggestion = ` Numeric types are not valid - use "main", "error", or an AI connection type.`;
}
result.errors.push({
type: 'error',
nodeName: sourceName,
message: `Invalid connection type "${connection.type}" in connection from "${sourceName}" to "${connection.node}". Expected "main", "error", or an AI connection type (ai_tool, ai_languageModel, etc.).${suggestion}`,
code: 'INVALID_CONNECTION_TYPE'
});
result.statistics.invalidConnections++;
return;
}
const isSplitInBatches = sourceNode && (sourceNode.type === 'n8n-nodes-base.splitInBatches' ||
sourceNode.type === 'nodes-base.splitInBatches');
if (isSplitInBatches) {
@@ -517,9 +506,6 @@ class WorkflowValidator {
if (outputType === 'ai_tool') {
this.validateAIToolConnection(sourceName, targetNode, result);
}
if (outputType === 'main') {
this.validateInputIndexBounds(sourceName, targetNode, connection, result);
}
}
});
});
@@ -648,254 +634,6 @@ class WorkflowValidator {
code: 'INVALID_AI_TOOL_SOURCE'
});
}
getNodeOutputTypes(nodeType) {
const normalizedType = node_type_normalizer_1.NodeTypeNormalizer.normalizeToFullForm(nodeType);
const nodeInfo = this.nodeRepository.getNode(normalizedType);
if (!nodeInfo || !nodeInfo.outputs)
return null;
const outputs = nodeInfo.outputs;
if (!Array.isArray(outputs))
return null;
for (const output of outputs) {
if (typeof output === 'string' && output.startsWith('={{')) {
return null;
}
}
return outputs;
}
validateNotAISubNode(sourceNode, result) {
const outputTypes = this.getNodeOutputTypes(sourceNode.type);
if (!outputTypes)
return;
const hasMainOutput = outputTypes.some(t => t === 'main');
if (hasMainOutput)
return;
const aiTypes = outputTypes.filter(t => t !== 'main');
const expectedType = aiTypes[0] || 'ai_languageModel';
result.errors.push({
type: 'error',
nodeId: sourceNode.id,
nodeName: sourceNode.name,
message: `Node "${sourceNode.name}" (${sourceNode.type}) is an AI sub-node that outputs "${expectedType}" connections. ` +
`It cannot be used with "main" connections. Connect it to an AI Agent or Chain via "${expectedType}" instead.`,
code: 'AI_SUBNODE_MAIN_CONNECTION'
});
}
getShortNodeType(sourceNode) {
const normalizedType = node_type_normalizer_1.NodeTypeNormalizer.normalizeToFullForm(sourceNode.type);
return normalizedType.replace(/^(n8n-)?nodes-base\./, '');
}
getConditionalOutputInfo(sourceNode) {
const shortType = this.getShortNodeType(sourceNode);
if (shortType === 'if' || shortType === 'filter') {
return { shortType, expectedOutputs: 2 };
}
if (shortType === 'switch') {
const rules = sourceNode.parameters?.rules?.values || sourceNode.parameters?.rules;
if (Array.isArray(rules)) {
return { shortType, expectedOutputs: rules.length + 1 };
}
return null;
}
return null;
}
validateOutputIndexBounds(sourceNode, outputs, result) {
const normalizedType = node_type_normalizer_1.NodeTypeNormalizer.normalizeToFullForm(sourceNode.type);
const nodeInfo = this.nodeRepository.getNode(normalizedType);
if (!nodeInfo || !nodeInfo.outputs)
return;
let mainOutputCount;
if (Array.isArray(nodeInfo.outputs)) {
mainOutputCount = nodeInfo.outputs.filter((o) => typeof o === 'string' ? o === 'main' : (o.type === 'main' || !o.type)).length;
}
else {
return;
}
if (mainOutputCount === 0)
return;
const conditionalInfo = this.getConditionalOutputInfo(sourceNode);
if (conditionalInfo) {
mainOutputCount = conditionalInfo.expectedOutputs;
}
else if (this.getShortNodeType(sourceNode) === 'switch') {
return;
}
if (sourceNode.onError === 'continueErrorOutput') {
mainOutputCount += 1;
}
const maxOutputIndex = outputs.length - 1;
if (maxOutputIndex >= mainOutputCount) {
for (let i = mainOutputCount; i < outputs.length; i++) {
if (outputs[i] && outputs[i].length > 0) {
result.errors.push({
type: 'error',
nodeId: sourceNode.id,
nodeName: sourceNode.name,
message: `Output index ${i} on node "${sourceNode.name}" exceeds its output count (${mainOutputCount}). ` +
`This node has ${mainOutputCount} main output(s) (indices 0-${mainOutputCount - 1}).`,
code: 'OUTPUT_INDEX_OUT_OF_BOUNDS'
});
result.statistics.invalidConnections++;
}
}
}
}
validateConditionalBranchUsage(sourceNode, outputs, result) {
const conditionalInfo = this.getConditionalOutputInfo(sourceNode);
if (!conditionalInfo || conditionalInfo.expectedOutputs < 2)
return;
const { shortType, expectedOutputs } = conditionalInfo;
const main0Count = outputs[0]?.length || 0;
if (main0Count < 2)
return;
const hasHigherIndexConnections = outputs.slice(1).some(conns => conns && conns.length > 0);
if (hasHigherIndexConnections)
return;
let message;
if (shortType === 'if' || shortType === 'filter') {
const isFilter = shortType === 'filter';
const displayName = isFilter ? 'Filter' : 'IF';
const trueLabel = isFilter ? 'matched' : 'true';
const falseLabel = isFilter ? 'unmatched' : 'false';
message = `${displayName} node "${sourceNode.name}" has ${main0Count} connections on the "${trueLabel}" branch (main[0]) ` +
`but no connections on the "${falseLabel}" branch (main[1]). ` +
`All ${main0Count} target nodes execute together on the "${trueLabel}" branch, ` +
`while the "${falseLabel}" branch has no effect. ` +
`Split connections: main[0] for ${trueLabel}, main[1] for ${falseLabel}.`;
}
else {
message = `Switch node "${sourceNode.name}" has ${main0Count} connections on output 0 ` +
`but no connections on any other outputs (1-${expectedOutputs - 1}). ` +
`All ${main0Count} target nodes execute together on output 0, ` +
`while other switch branches have no effect. ` +
`Distribute connections across outputs to match switch rules.`;
}
result.warnings.push({
type: 'warning',
nodeId: sourceNode.id,
nodeName: sourceNode.name,
message,
code: 'CONDITIONAL_BRANCH_FANOUT'
});
}
validateInputIndexBounds(sourceName, targetNode, connection, result) {
const normalizedType = node_type_normalizer_1.NodeTypeNormalizer.normalizeToFullForm(targetNode.type);
const nodeInfo = this.nodeRepository.getNode(normalizedType);
if (!nodeInfo)
return;
const shortType = normalizedType.replace(/^(n8n-)?nodes-base\./, '');
let mainInputCount = 1;
if (shortType === 'merge' || shortType === 'compareDatasets') {
mainInputCount = 2;
}
if (nodeInfo.isTrigger || (0, node_type_utils_1.isTriggerNode)(targetNode.type)) {
mainInputCount = 0;
}
if (mainInputCount > 0 && connection.index >= mainInputCount) {
result.errors.push({
type: 'error',
nodeName: targetNode.name,
message: `Input index ${connection.index} on node "${targetNode.name}" exceeds its input count (${mainInputCount}). ` +
`Connection from "${sourceName}" targets input ${connection.index}, but this node has ${mainInputCount} main input(s) (indices 0-${mainInputCount - 1}).`,
code: 'INPUT_INDEX_OUT_OF_BOUNDS'
});
result.statistics.invalidConnections++;
}
}
flagOrphanedNodes(workflow, result) {
const connectedNodes = new Set();
for (const [sourceName, outputs] of Object.entries(workflow.connections)) {
connectedNodes.add(sourceName);
for (const outputConns of Object.values(outputs)) {
if (!Array.isArray(outputConns))
continue;
for (const conns of outputConns) {
if (!conns)
continue;
for (const conn of conns) {
if (conn)
connectedNodes.add(conn.node);
}
}
}
}
for (const node of workflow.nodes) {
if (node.disabled || (0, node_classification_1.isNonExecutableNode)(node.type))
continue;
if ((0, node_type_utils_1.isTriggerNode)(node.type))
continue;
if (!connectedNodes.has(node.name)) {
result.warnings.push({
type: 'warning',
nodeId: node.id,
nodeName: node.name,
message: 'Node is not connected to any other nodes'
});
}
}
}
validateTriggerReachability(workflow, result) {
const adjacency = new Map();
for (const [sourceName, outputs] of Object.entries(workflow.connections)) {
if (!adjacency.has(sourceName))
adjacency.set(sourceName, new Set());
for (const outputConns of Object.values(outputs)) {
if (Array.isArray(outputConns)) {
for (const conns of outputConns) {
if (!conns)
continue;
for (const conn of conns) {
if (conn) {
adjacency.get(sourceName).add(conn.node);
if (!adjacency.has(conn.node))
adjacency.set(conn.node, new Set());
}
}
}
}
}
}
const triggerNodes = [];
for (const node of workflow.nodes) {
if ((0, node_type_utils_1.isTriggerNode)(node.type) && !node.disabled) {
triggerNodes.push(node.name);
}
}
if (triggerNodes.length === 0) {
this.flagOrphanedNodes(workflow, result);
return;
}
const reachable = new Set();
const queue = [...triggerNodes];
for (const t of triggerNodes)
reachable.add(t);
while (queue.length > 0) {
const current = queue.shift();
const neighbors = adjacency.get(current);
if (neighbors) {
for (const neighbor of neighbors) {
if (!reachable.has(neighbor)) {
reachable.add(neighbor);
queue.push(neighbor);
}
}
}
}
for (const node of workflow.nodes) {
if (node.disabled || (0, node_classification_1.isNonExecutableNode)(node.type))
continue;
if ((0, node_type_utils_1.isTriggerNode)(node.type))
continue;
if (!reachable.has(node.name)) {
result.warnings.push({
type: 'warning',
nodeId: node.id,
nodeName: node.name,
message: 'Node is not reachable from any trigger node'
});
}
}
}
hasCycle(workflow) {
const visited = new Set();
const recursionStack = new Set();
@@ -919,13 +657,23 @@ class WorkflowValidator {
const connections = workflow.connections[nodeName];
if (connections) {
const allTargets = [];
for (const outputConns of Object.values(connections)) {
if (Array.isArray(outputConns)) {
outputConns.flat().forEach(conn => {
if (conn)
allTargets.push(conn.node);
});
}
if (connections.main) {
connections.main.flat().forEach(conn => {
if (conn)
allTargets.push(conn.node);
});
}
if (connections.error) {
connections.error.flat().forEach(conn => {
if (conn)
allTargets.push(conn.node);
});
}
if (connections.ai_tool) {
connections.ai_tool.flat().forEach(conn => {
if (conn)
allTargets.push(conn.node);
});
}
const currentNodeType = nodeTypeMap.get(nodeName);
const isLoopNode = loopNodeTypes.includes(currentNodeType || '');

File diff suppressed because one or more lines are too long

View File

@@ -12,8 +12,6 @@ export declare class TelemetryBatchProcessor {
private flushTimes;
private deadLetterQueue;
private readonly maxDeadLetterSize;
private eventListeners;
private started;
constructor(supabase: SupabaseClient | null, isEnabled: () => boolean);
start(): void;
stop(): void;

View File

@@ -1 +1 @@
{"version":3,"file":"batch-processor.d.ts","sourceRoot":"","sources":["../../src/telemetry/batch-processor.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,sBAAsB,EAAoB,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAoClI,qBAAa,uBAAuB;IA2BhC,OAAO,CAAC,QAAQ;IAChB,OAAO,CAAC,SAAS;IA3BnB,OAAO,CAAC,UAAU,CAAC,CAAiB;IACpC,OAAO,CAAC,gBAAgB,CAAkB;IAC1C,OAAO,CAAC,mBAAmB,CAAkB;IAC7C,OAAO,CAAC,mBAAmB,CAAkB;IAC7C,OAAO,CAAC,cAAc,CAA0B;IAChD,OAAO,CAAC,OAAO,CAQb;IACF,OAAO,CAAC,UAAU,CAAgB;IAClC,OAAO,CAAC,eAAe,CAAuE;IAC9F,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAO;IAEzC,OAAO,CAAC,cAAc,CAIf;IACP,OAAO,CAAC,OAAO,CAAkB;gBAGvB,QAAQ,EAAE,cAAc,GAAG,IAAI,EAC/B,SAAS,EAAE,MAAM,OAAO;IAQlC,KAAK,IAAI,IAAI;IA0Cb,IAAI,IAAI,IAAI;IAyBN,KAAK,CAAC,MAAM,CAAC,EAAE,cAAc,EAAE,EAAE,SAAS,CAAC,EAAE,iBAAiB,EAAE,EAAE,SAAS,CAAC,EAAE,sBAAsB,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;YAgD9G,WAAW;YAmDX,cAAc;YAuDd,cAAc;YAiEd,gBAAgB;IAgD9B,OAAO,CAAC,aAAa;IAarB,OAAO,CAAC,oBAAoB;IAiB5B,OAAO,CAAC,oBAAoB;YAmBd,sBAAsB;IAgCpC,OAAO,CAAC,eAAe;IAiBvB,UAAU,IAAI,gBAAgB,GAAG;QAAE,mBAAmB,EAAE,GAAG,CAAC;QAAC,mBAAmB,EAAE,MAAM,CAAA;KAAE;IAW1F,YAAY,IAAI,IAAI;CAarB"}
{"version":3,"file":"batch-processor.d.ts","sourceRoot":"","sources":["../../src/telemetry/batch-processor.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,sBAAsB,EAAoB,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAoClI,qBAAa,uBAAuB;IAoBhC,OAAO,CAAC,QAAQ;IAChB,OAAO,CAAC,SAAS;IApBnB,OAAO,CAAC,UAAU,CAAC,CAAiB;IACpC,OAAO,CAAC,gBAAgB,CAAkB;IAC1C,OAAO,CAAC,mBAAmB,CAAkB;IAC7C,OAAO,CAAC,mBAAmB,CAAkB;IAC7C,OAAO,CAAC,cAAc,CAA0B;IAChD,OAAO,CAAC,OAAO,CAQb;IACF,OAAO,CAAC,UAAU,CAAgB;IAClC,OAAO,CAAC,eAAe,CAAuE;IAC9F,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAO;gBAG/B,QAAQ,EAAE,cAAc,GAAG,IAAI,EAC/B,SAAS,EAAE,MAAM,OAAO;IAQlC,KAAK,IAAI,IAAI;IA+Bb,IAAI,IAAI,IAAI;IAWN,KAAK,CAAC,MAAM,CAAC,EAAE,cAAc,EAAE,EAAE,SAAS,CAAC,EAAE,iBAAiB,EAAE,EAAE,SAAS,CAAC,EAAE,sBAAsB,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;YAgD9G,WAAW;YAmDX,cAAc;YAuDd,cAAc;YAiEd,gBAAgB;IAgD9B,OAAO,CAAC,aAAa;IAarB,OAAO,CAAC,oBAAoB;IAiB5B,OAAO,CAAC,oBAAoB;YAmBd,sBAAsB;IAgCpC,OAAO,CAAC,eAAe;IAiBvB,UAAU,IAAI,gBAAgB,GAAG;QAAE,mBAAmB,EAAE,GAAG,CAAC;QAAC,mBAAmB,EAAE,MAAM,CAAA;KAAE;IAW1F,YAAY,IAAI,IAAI;CAarB"}

View File

@@ -33,36 +33,26 @@ class TelemetryBatchProcessor {
this.flushTimes = [];
this.deadLetterQueue = [];
this.maxDeadLetterSize = 100;
this.eventListeners = {};
this.started = false;
this.circuitBreaker = new telemetry_error_1.TelemetryCircuitBreaker();
}
start() {
if (!this.isEnabled() || !this.supabase)
return;
if (this.started) {
logger_1.logger.debug('Telemetry batch processor already started, skipping');
return;
}
this.flushTimer = setInterval(() => {
this.flush();
}, telemetry_types_1.TELEMETRY_CONFIG.BATCH_FLUSH_INTERVAL);
if (typeof this.flushTimer === 'object' && 'unref' in this.flushTimer) {
this.flushTimer.unref();
}
this.eventListeners.beforeExit = () => this.flush();
this.eventListeners.sigint = () => {
process.on('beforeExit', () => this.flush());
process.on('SIGINT', () => {
this.flush();
process.exit(0);
};
this.eventListeners.sigterm = () => {
});
process.on('SIGTERM', () => {
this.flush();
process.exit(0);
};
process.on('beforeExit', this.eventListeners.beforeExit);
process.on('SIGINT', this.eventListeners.sigint);
process.on('SIGTERM', this.eventListeners.sigterm);
this.started = true;
});
logger_1.logger.debug('Telemetry batch processor started');
}
stop() {
@@ -70,17 +60,6 @@ class TelemetryBatchProcessor {
clearInterval(this.flushTimer);
this.flushTimer = undefined;
}
if (this.eventListeners.beforeExit) {
process.removeListener('beforeExit', this.eventListeners.beforeExit);
}
if (this.eventListeners.sigint) {
process.removeListener('SIGINT', this.eventListeners.sigint);
}
if (this.eventListeners.sigterm) {
process.removeListener('SIGTERM', this.eventListeners.sigterm);
}
this.eventListeners = {};
this.started = false;
logger_1.logger.debug('Telemetry batch processor stopped');
}
async flush(events, workflows, mutations) {

File diff suppressed because one or more lines are too long

View File

@@ -30,11 +30,6 @@ export interface ToolDefinition {
additionalProperties?: boolean | Record<string, any>;
};
annotations?: ToolAnnotations;
_meta?: {
ui?: {
resourceUri?: string;
};
};
}
export interface ResourceDefinition {
uri: string;

View File

@@ -1 +1 @@
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AACA,cAAc,cAAc,CAAC;AAC7B,cAAc,mBAAmB,CAAC;AAClC,cAAc,oBAAoB,CAAC;AACnC,cAAc,iBAAiB,CAAC;AAEhC,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAMD,MAAM,WAAW,eAAe;IAE9B,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf,YAAY,CAAC,EAAE,OAAO,CAAC;IAEvB,eAAe,CAAC,EAAE,OAAO,CAAC;IAE1B,cAAc,CAAC,EAAE,OAAO,CAAC;IAEzB,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE;QACX,IAAI,EAAE,MAAM,CAAC;QACb,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QAChC,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;QACpB,oBAAoB,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;KACtD,CAAC;IACF,YAAY,CAAC,EAAE;QACb,IAAI,EAAE,MAAM,CAAC;QACb,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QAChC,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;QACpB,oBAAoB,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;KACtD,CAAC;IAEF,WAAW,CAAC,EAAE,eAAe,CAAC;IAC9B,KAAK,CAAC,EAAE;QACN,EAAE,CAAC,EAAE;YACH,WAAW,CAAC,EAAE,MAAM,CAAC;SACtB,CAAC;KACH,CAAC;CACH;AAED,MAAM,WAAW,kBAAkB;IACjC,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,KAAK,CAAC;QAChB,IAAI,EAAE,MAAM,CAAC;QACb,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;KACpB,CAAC,CAAC;CACJ"}
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AACA,cAAc,cAAc,CAAC;AAC7B,cAAc,mBAAmB,CAAC;AAClC,cAAc,oBAAoB,CAAC;AACnC,cAAc,iBAAiB,CAAC;AAEhC,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAMD,MAAM,WAAW,eAAe;IAE9B,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf,YAAY,CAAC,EAAE,OAAO,CAAC;IAEvB,eAAe,CAAC,EAAE,OAAO,CAAC;IAE1B,cAAc,CAAC,EAAE,OAAO,CAAC;IAEzB,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE;QACX,IAAI,EAAE,MAAM,CAAC;QACb,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QAChC,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;QACpB,oBAAoB,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;KACtD,CAAC;IACF,YAAY,CAAC,EAAE;QACb,IAAI,EAAE,MAAM,CAAC;QACb,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QAChC,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;QACpB,oBAAoB,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;KACtD,CAAC;IAEF,WAAW,CAAC,EAAE,eAAe,CAAC;CAC/B;AAED,MAAM,WAAW,kBAAkB;IACjC,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,KAAK,CAAC;QAChB,IAAI,EAAE,MAAM,CAAC;QACb,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;KACpB,CAAC,CAAC;CACJ"}

View File

@@ -259,7 +259,6 @@ export interface WebhookRequest {
}
export interface McpToolResponse {
success: boolean;
saved?: boolean;
data?: unknown;
error?: string;
message?: string;
@@ -267,7 +266,6 @@ export interface McpToolResponse {
details?: Record<string, unknown>;
executionId?: string;
workflowId?: string;
operationsApplied?: number;
}
export type ExecutionMode = 'preview' | 'summary' | 'filtered' | 'full' | 'error';
export interface ExecutionPreview {
@@ -374,69 +372,4 @@ 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,10 +94,6 @@ 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;
@@ -114,7 +110,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 | TransferWorkflowOperation;
export type WorkflowDiffOperation = AddNodeOperation | RemoveNodeOperation | UpdateNodeOperation | MoveNodeOperation | EnableNodeOperation | DisableNodeOperation | AddConnectionOperation | RemoveConnectionOperation | RewireConnectionOperation | UpdateSettingsOperation | UpdateNameOperation | AddTagOperation | RemoveTagOperation | ActivateWorkflowOperation | DeactivateWorkflowOperation | CleanStaleConnectionsOperation | ReplaceConnectionsOperation;
export interface WorkflowDiffRequest {
id: string;
operations: WorkflowDiffOperation[];
@@ -141,9 +137,6 @@ 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":"AAKA,OAAO,EAAE,YAAY,EAAsB,MAAM,WAAW,CAAC;AAG7D,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAGD,MAAM,WAAW,gBAAiB,SAAQ,aAAa;IACrD,IAAI,EAAE,SAAS,CAAC;IAChB,IAAI,EAAE,OAAO,CAAC,YAAY,CAAC,GAAG;QAC5B,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,MAAM,CAAC;QACb,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;KAC5B,CAAC;CACH;AAED,MAAM,WAAW,mBAAoB,SAAQ,aAAa;IACxD,IAAI,EAAE,YAAY,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,mBAAoB,SAAQ,aAAa;IACxD,IAAI,EAAE,YAAY,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE;QACP,CAAC,IAAI,EAAE,MAAM,GAAG,GAAG,CAAC;KACrB,CAAC;CACH;AAED,MAAM,WAAW,iBAAkB,SAAQ,aAAa;IACtD,IAAI,EAAE,UAAU,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC5B;AAED,MAAM,WAAW,mBAAoB,SAAQ,aAAa;IACxD,IAAI,EAAE,YAAY,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,oBAAqB,SAAQ,aAAa;IACzD,IAAI,EAAE,aAAa,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAGD,MAAM,WAAW,sBAAuB,SAAQ,aAAa;IAC3D,IAAI,EAAE,eAAe,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAC1B,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,yBAA0B,SAAQ,aAAa;IAC9D,IAAI,EAAE,kBAAkB,CAAC;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,yBAA0B,SAAQ,aAAa;IAC9D,IAAI,EAAE,kBAAkB,CAAC;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAC1B,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAGD,MAAM,WAAW,uBAAwB,SAAQ,aAAa;IAC5D,IAAI,EAAE,gBAAgB,CAAC;IACvB,QAAQ,EAAE;QACR,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;KACpB,CAAC;CACH;AAED,MAAM,WAAW,mBAAoB,SAAQ,aAAa;IACxD,IAAI,EAAE,YAAY,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,eAAgB,SAAQ,aAAa;IACpD,IAAI,EAAE,QAAQ,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,kBAAmB,SAAQ,aAAa;IACvD,IAAI,EAAE,WAAW,CAAC;IAClB,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,yBAA0B,SAAQ,aAAa;IAC9D,IAAI,EAAE,kBAAkB,CAAC;CAE1B;AAED,MAAM,WAAW,2BAA4B,SAAQ,aAAa;IAChE,IAAI,EAAE,oBAAoB,CAAC;CAE5B;AAGD,MAAM,WAAW,8BAA+B,SAAQ,aAAa;IACnE,IAAI,EAAE,uBAAuB,CAAC;IAC9B,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,2BAA4B,SAAQ,aAAa;IAChE,IAAI,EAAE,oBAAoB,CAAC;IAC3B,WAAW,EAAE;QACX,CAAC,QAAQ,EAAE,MAAM,GAAG;YAClB,CAAC,UAAU,EAAE,MAAM,GAAG,KAAK,CAAC,KAAK,CAAC;gBAChC,IAAI,EAAE,MAAM,CAAC;gBACb,IAAI,EAAE,MAAM,CAAC;gBACb,KAAK,EAAE,MAAM,CAAC;aACf,CAAC,CAAC,CAAC;SACL,CAAC;KACH,CAAC;CACH;AAGD,MAAM,MAAM,qBAAqB,GAC7B,gBAAgB,GAChB,mBAAmB,GACnB,mBAAmB,GACnB,iBAAiB,GACjB,mBAAmB,GACnB,oBAAoB,GACpB,sBAAsB,GACtB,yBAAyB,GACzB,yBAAyB,GACzB,uBAAuB,GACvB,mBAAmB,GACnB,eAAe,GACf,kBAAkB,GAClB,yBAAyB,GACzB,2BAA2B,GAC3B,8BAA8B,GAC9B,2BAA2B,CAAC;AAGhC,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,qBAAqB,EAAE,CAAC;IACpC,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAGD,MAAM,WAAW,2BAA2B;IAC1C,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,GAAG,CAAC;CACf;AAED,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,GAAG,CAAC;IACf,MAAM,CAAC,EAAE,2BAA2B,EAAE,CAAC;IACvC,QAAQ,CAAC,EAAE,2BAA2B,EAAE,CAAC;IACzC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,uBAAuB,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC9D,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B;AAGD,MAAM,WAAW,aAAa;IAC5B,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAGD,wBAAgB,eAAe,CAAC,EAAE,EAAE,qBAAqB,GAAG,EAAE,IAC5D,gBAAgB,GAAG,mBAAmB,GAAG,mBAAmB,GAC5D,iBAAiB,GAAG,mBAAmB,GAAG,oBAAoB,CAE/D;AAED,wBAAgB,qBAAqB,CAAC,EAAE,EAAE,qBAAqB,GAAG,EAAE,IAClE,sBAAsB,GAAG,yBAAyB,GAAG,yBAAyB,GAAG,8BAA8B,GAAG,2BAA2B,CAE9I;AAED,wBAAgB,mBAAmB,CAAC,EAAE,EAAE,qBAAqB,GAAG,EAAE,IAChE,uBAAuB,GAAG,mBAAmB,GAAG,eAAe,GAAG,kBAAkB,CAErF"}

View File

@@ -1 +1 @@
{"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"}
{"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"}

View File

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

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