fix conflicts

This commit is contained in:
Mutasem 2022-10-13 14:28:22 +02:00
commit 54fe874637
3014 changed files with 214091 additions and 212704 deletions

View File

@ -1,3 +1,7 @@
**/.env
node_modules
packages/node-dev
packages/*/node_modules
packages/*/dist
packages/*/.turbo
.git

View File

@ -1,3 +0,0 @@
packages/editor-ui
packages/design-system
packages/cli/scripts/build.mjs

View File

@ -1,473 +0,0 @@
module.exports = {
root: true,
env: {
browser: true,
es6: true,
node: true,
},
parser: '@typescript-eslint/parser',
parserOptions: {
project: ['./packages/*/tsconfig.json'],
sourceType: 'module',
},
ignorePatterns: [
'.eslintrc.js',
'**/*.js',
'**/node_modules/**',
'**/dist/**',
'**/test/**',
'**/templates/**',
'**/ormconfig.ts',
'**/migrations/**',
],
overrides: [
{
files: './packages/*(cli|core|workflow|node-dev)/**/*.ts',
plugins: [
/**
* Plugin with lint rules for import/export syntax
* https://github.com/import-js/eslint-plugin-import
*/
'eslint-plugin-import',
/**
* @typescript-eslint/eslint-plugin is required by eslint-config-airbnb-typescript
* See step 2: https://github.com/iamturns/eslint-config-airbnb-typescript#2-install-eslint-plugins
*/
'@typescript-eslint',
/**
* Plugin to report formatting violations as lint violations
* https://github.com/prettier/eslint-plugin-prettier
*/
'eslint-plugin-prettier',
],
extends: [
/**
* Config for typescript-eslint recommended ruleset (without type checking)
*
* https://github.com/typescript-eslint/typescript-eslint/blob/1c1b572c3000d72cfe665b7afbada0ec415e7855/packages/eslint-plugin/src/configs/recommended.ts
*/
'plugin:@typescript-eslint/recommended',
/**
* Config for typescript-eslint recommended ruleset (with type checking)
*
* https://github.com/typescript-eslint/typescript-eslint/blob/1c1b572c3000d72cfe665b7afbada0ec415e7855/packages/eslint-plugin/src/configs/recommended-requiring-type-checking.ts
*/
'plugin:@typescript-eslint/recommended-requiring-type-checking',
/**
* Config for Airbnb style guide for TS, /base to remove React rules
*
* https://github.com/iamturns/eslint-config-airbnb-typescript
* https://github.com/airbnb/javascript/tree/master/packages/eslint-config-airbnb-base/rules
*/
'eslint-config-airbnb-typescript/base',
/**
* Config to disable ESLint rules covered by Prettier
*
* https://github.com/prettier/eslint-config-prettier
*/
'eslint-config-prettier',
],
rules: {
// ******************************************************************
// required by prettier plugin
// ******************************************************************
// The following rule enables eslint-plugin-prettier
// See: https://github.com/prettier/eslint-plugin-prettier#recommended-configuration
'prettier/prettier': 'error',
// The following two rules must be disabled when using eslint-plugin-prettier:
// See: https://github.com/prettier/eslint-plugin-prettier#arrow-body-style-and-prefer-arrow-callback-issue
/**
* https://eslint.org/docs/rules/arrow-body-style
*/
'arrow-body-style': 'off',
/**
* https://eslint.org/docs/rules/prefer-arrow-callback
*/
'prefer-arrow-callback': 'off',
// ******************************************************************
// additions to base ruleset
// ******************************************************************
// ----------------------------------
// ESLint
// ----------------------------------
/**
* https://eslint.org/docs/rules/id-denylist
*/
'id-denylist': [
'error',
'err',
'cb',
'callback',
'any',
'Number',
'number',
'String',
'string',
'Boolean',
'boolean',
'Undefined',
'undefined',
],
'no-void': ['error', { allowAsStatement: true }],
// ----------------------------------
// @typescript-eslint
// ----------------------------------
/**
* https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/array-type.md
*/
'@typescript-eslint/array-type': ['error', { default: 'array-simple' }],
/**
* https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/ban-ts-comment.md
*/
'@typescript-eslint/ban-ts-comment': 'off',
/**
* https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/ban-types.md
*/
'@typescript-eslint/ban-types': [
'error',
{
types: {
Object: {
message: 'Use object instead',
fixWith: 'object',
},
String: {
message: 'Use string instead',
fixWith: 'string',
},
Boolean: {
message: 'Use boolean instead',
fixWith: 'boolean',
},
Number: {
message: 'Use number instead',
fixWith: 'number',
},
Symbol: {
message: 'Use symbol instead',
fixWith: 'symbol',
},
Function: {
message: [
'The `Function` type accepts any function-like value.',
'It provides no type safety when calling the function, which can be a common source of bugs.',
'It also accepts things like class declarations, which will throw at runtime as they will not be called with `new`.',
'If you are expecting the function to accept certain arguments, you should explicitly define the function shape.',
].join('\n'),
},
},
extendDefaults: false,
},
],
/**
* https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/consistent-type-assertions.md
*/
'@typescript-eslint/consistent-type-assertions': 'error',
/**
* https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/explicit-member-accessibility.md
*/
'@typescript-eslint/explicit-member-accessibility': [
'error',
{ accessibility: 'no-public' },
],
/**
* https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/member-delimiter-style.md
*/
'@typescript-eslint/member-delimiter-style': [
'error',
{
multiline: {
delimiter: 'semi',
requireLast: true,
},
singleline: {
delimiter: 'semi',
requireLast: false,
},
},
],
/**
* https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/naming-convention.md
*/
'@typescript-eslint/naming-convention': [
'error',
{
selector: 'default',
format: ['camelCase'],
},
{
selector: 'variable',
format: ['camelCase', 'snake_case', 'UPPER_CASE'],
leadingUnderscore: 'allowSingleOrDouble',
trailingUnderscore: 'allowSingleOrDouble',
},
{
selector: 'property',
format: ['camelCase', 'snake_case'],
leadingUnderscore: 'allowSingleOrDouble',
trailingUnderscore: 'allowSingleOrDouble',
},
{
selector: 'typeLike',
format: ['PascalCase'],
},
{
selector: ['method', 'function'],
format: ['camelCase'],
leadingUnderscore: 'allowSingleOrDouble',
},
],
/**
* https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-duplicate-imports.md
*/
'@typescript-eslint/no-duplicate-imports': 'error',
/**
* https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-invalid-void-type.md
*/
'@typescript-eslint/no-invalid-void-type': 'error',
/**
* https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-misused-promises.md
*/
'@typescript-eslint/no-misused-promises': ['error', { checksVoidReturn: false }],
/**
* https://github.com/typescript-eslint/typescript-eslint/blob/v4.30.0/packages/eslint-plugin/docs/rules/no-floating-promises.md
*/
'@typescript-eslint/no-floating-promises': ['error', { ignoreVoid: true }],
/**
* https://github.com/typescript-eslint/typescript-eslint/blob/v4.33.0/packages/eslint-plugin/docs/rules/no-namespace.md
*/
'@typescript-eslint/no-namespace': 'off',
/**
* https://eslint.org/docs/1.0.0/rules/no-throw-literal
*/
'@typescript-eslint/no-throw-literal': 'error',
/**
* https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-unnecessary-boolean-literal-compare.md
*/
'@typescript-eslint/no-unnecessary-boolean-literal-compare': 'error',
/**
* https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-unnecessary-qualifier.md
*/
'@typescript-eslint/no-unnecessary-qualifier': 'error',
/**
* https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-unused-expressions.md
*/
'@typescript-eslint/no-unused-expressions': 'error',
/**
* https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-unused-vars.md
*/
'@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '_' }],
/**
* https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/prefer-nullish-coalescing.md
*/
'@typescript-eslint/prefer-nullish-coalescing': 'error',
/**
* https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/prefer-optional-chain.md
*/
'@typescript-eslint/prefer-optional-chain': 'error',
/**
* https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/promise-function-async.md
*/
'@typescript-eslint/promise-function-async': 'error',
// ----------------------------------
// eslint-plugin-import
// ----------------------------------
/**
* https://github.com/import-js/eslint-plugin-import/blob/master/docs/rules/no-default-export.md
*/
'import/no-default-export': 'error',
/**
* https://github.com/import-js/eslint-plugin-import/blob/master/docs/rules/order.md
*/
'import/order': 'error',
// ******************************************************************
// overrides to base ruleset
// ******************************************************************
// ----------------------------------
// ESLint
// ----------------------------------
/**
* https://eslint.org/docs/rules/class-methods-use-this
*/
'class-methods-use-this': 'off',
/**
* https://eslint.org/docs/rules/eqeqeq
*/
eqeqeq: 'error',
/**
* https://eslint.org/docs/rules/no-plusplus
*/
'no-plusplus': 'off',
/**
* https://eslint.org/docs/rules/object-shorthand
*/
'object-shorthand': 'error',
/**
* https://eslint.org/docs/rules/prefer-const
*/
'prefer-const': 'error',
/**
* https://eslint.org/docs/rules/prefer-spread
*/
'prefer-spread': 'error',
// ----------------------------------
// import
// ----------------------------------
/**
* https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/prefer-default-export.md
*/
'import/prefer-default-export': 'off',
},
},
{
files: ['./packages/nodes-base/credentials/*.credentials.ts'],
plugins: ['eslint-plugin-n8n-nodes-base'],
rules: {
'n8n-nodes-base/cred-class-field-display-name-missing-oauth2': 'error',
'n8n-nodes-base/cred-class-field-name-missing-oauth2': 'error',
'n8n-nodes-base/cred-class-field-name-unsuffixed': 'error',
'n8n-nodes-base/cred-class-field-name-uppercase-first-char': 'error',
'n8n-nodes-base/cred-class-name-missing-oauth2-suffix': 'error',
'n8n-nodes-base/cred-class-name-unsuffixed': 'error',
'n8n-nodes-base/cred-filename-against-convention': 'error',
},
},
{
files: ['./packages/nodes-base/nodes/**/*.ts'],
plugins: ['eslint-plugin-n8n-nodes-base'],
rules: {
'n8n-nodes-base/node-class-description-credentials-name-unsuffixed': 'error',
'n8n-nodes-base/node-class-description-display-name-unsuffixed-trigger-node': 'error',
'n8n-nodes-base/node-class-description-empty-string': 'error',
'n8n-nodes-base/node-class-description-icon-not-svg': 'error',
'n8n-nodes-base/node-class-description-inputs-wrong-regular-node': 'error',
'n8n-nodes-base/node-class-description-inputs-wrong-trigger-node': 'error',
'n8n-nodes-base/node-class-description-missing-subtitle': 'error',
'n8n-nodes-base/node-class-description-name-unsuffixed-trigger-node': 'error',
'n8n-nodes-base/node-class-description-outputs-wrong': 'error',
'n8n-nodes-base/node-dirname-against-convention': 'error',
'n8n-nodes-base/node-execute-block-double-assertion-for-items': 'error',
'n8n-nodes-base/node-execute-block-wrong-error-thrown': 'error',
'n8n-nodes-base/node-filename-against-convention': 'error',
'n8n-nodes-base/node-param-array-type-assertion': 'error',
'n8n-nodes-base/node-param-collection-type-unsorted-items': 'error',
'n8n-nodes-base/node-param-color-type-unused': 'error',
'n8n-nodes-base/node-param-default-missing': 'error',
'n8n-nodes-base/node-param-default-wrong-for-boolean': 'error',
'n8n-nodes-base/node-param-default-wrong-for-collection': 'error',
'n8n-nodes-base/node-param-default-wrong-for-fixed-collection': 'error',
'n8n-nodes-base/node-param-default-wrong-for-fixed-collection': 'error',
'n8n-nodes-base/node-param-default-wrong-for-multi-options': 'error',
'n8n-nodes-base/node-param-default-wrong-for-number': 'error',
'n8n-nodes-base/node-param-default-wrong-for-simplify': 'error',
'n8n-nodes-base/node-param-default-wrong-for-string': 'error',
'n8n-nodes-base/node-param-description-boolean-without-whether': 'error',
'n8n-nodes-base/node-param-description-comma-separated-hyphen': 'error',
'n8n-nodes-base/node-param-description-empty-string': 'error',
'n8n-nodes-base/node-param-description-excess-final-period': 'error',
'n8n-nodes-base/node-param-description-excess-inner-whitespace': 'error',
'n8n-nodes-base/node-param-description-identical-to-display-name': 'error',
'n8n-nodes-base/node-param-description-line-break-html-tag': 'error',
'n8n-nodes-base/node-param-description-lowercase-first-char': 'error',
'n8n-nodes-base/node-param-description-miscased-id': 'error',
'n8n-nodes-base/node-param-description-miscased-json': 'error',
'n8n-nodes-base/node-param-description-miscased-url': 'error',
'n8n-nodes-base/node-param-description-missing-final-period': 'error',
'n8n-nodes-base/node-param-description-missing-for-ignore-ssl-issues': 'error',
'n8n-nodes-base/node-param-description-missing-for-return-all': 'error',
'n8n-nodes-base/node-param-description-missing-for-simplify': 'error',
'n8n-nodes-base/node-param-description-missing-from-dynamic-multi-options': 'error',
'n8n-nodes-base/node-param-description-missing-from-dynamic-options': 'error',
'n8n-nodes-base/node-param-description-missing-from-limit': 'error',
'n8n-nodes-base/node-param-description-unencoded-angle-brackets': 'error',
'n8n-nodes-base/node-param-description-unneeded-backticks': 'error',
'n8n-nodes-base/node-param-description-untrimmed': 'error',
'n8n-nodes-base/node-param-description-url-missing-protocol': 'error',
'n8n-nodes-base/node-param-description-weak': 'error',
'n8n-nodes-base/node-param-description-wrong-for-dynamic-multi-options': 'error',
'n8n-nodes-base/node-param-description-wrong-for-dynamic-options': 'error',
'n8n-nodes-base/node-param-description-wrong-for-ignore-ssl-issues': 'error',
'n8n-nodes-base/node-param-description-wrong-for-limit': 'error',
'n8n-nodes-base/node-param-description-wrong-for-return-all': 'error',
'n8n-nodes-base/node-param-description-wrong-for-simplify': 'error',
'n8n-nodes-base/node-param-description-wrong-for-upsert': 'error',
'n8n-nodes-base/node-param-display-name-excess-inner-whitespace': 'error',
'n8n-nodes-base/node-param-display-name-miscased': 'error',
'n8n-nodes-base/node-param-display-name-miscased-id': 'error',
'n8n-nodes-base/node-param-display-name-untrimmed': 'error',
'n8n-nodes-base/node-param-display-name-wrong-for-dynamic-multi-options': 'error',
'n8n-nodes-base/node-param-display-name-wrong-for-dynamic-options': 'error',
'n8n-nodes-base/node-param-display-name-wrong-for-simplify': 'error',
'n8n-nodes-base/node-param-display-name-wrong-for-update-fields': 'error',
'n8n-nodes-base/node-param-min-value-wrong-for-limit': 'error',
'n8n-nodes-base/node-param-multi-options-type-unsorted-items': 'error',
'n8n-nodes-base/node-param-operation-without-no-data-expression': 'error',
'n8n-nodes-base/node-param-operation-option-without-action': 'error',
'n8n-nodes-base/node-param-option-description-identical-to-name': 'error',
'n8n-nodes-base/node-param-option-name-containing-star': 'error',
'n8n-nodes-base/node-param-option-name-duplicate': 'error',
'n8n-nodes-base/node-param-option-name-wrong-for-get-all': 'error',
'n8n-nodes-base/node-param-option-name-wrong-for-upsert': 'error',
'n8n-nodes-base/node-param-option-value-duplicate': 'error',
'n8n-nodes-base/node-param-options-type-unsorted-items': 'error',
'n8n-nodes-base/node-param-placeholder-miscased-id': 'error',
'n8n-nodes-base/node-param-placeholder-missing-email': 'error',
'n8n-nodes-base/node-param-required-false': 'error',
'n8n-nodes-base/node-param-resource-with-plural-option': 'error',
'n8n-nodes-base/node-param-resource-without-no-data-expression': 'error',
'n8n-nodes-base/node-param-type-options-missing-from-limit': 'error',
},
},
],
};

View File

@ -4,7 +4,6 @@ about: Create a report to help us improve
title: ''
labels: ''
assignees: ''
---
**Describe the bug**
@ -12,6 +11,7 @@ A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
@ -21,11 +21,12 @@ Steps to reproduce the behavior:
A clear and concise description of what you expected to happen.
**Environment (please complete the following information):**
- OS: [e.g. Ubuntu Linux 18.04]
- n8n Version [e.g. 0.119.0]
- Node.js Version [e.g. 14.16.0]
- Database system [e.g. SQLite; n8n uses SQLite as default otherwise changed]
- Operation mode [e.g. own; operation modes are `own`, `main` and `queue`. Default is `own`]
- OS: [e.g. Ubuntu Linux 18.04]
- n8n Version [e.g. 0.119.0]
- Node.js Version [e.g. 14.16.0]
- Database system [e.g. SQLite; n8n uses SQLite as default otherwise changed]
- Operation mode [e.g. own; operation modes are `own`, `main` and `queue`. Default is `own`]
**Additional context**
Add any other context about the problem here.

32
.github/workflows/check-pr-title.yml vendored Normal file
View File

@ -0,0 +1,32 @@
name: Test Pull Request Semantics
on:
pull_request:
types:
- opened
- edited
- synchronize
jobs:
check-pr-title:
runs-on: ubuntu-latest
permissions:
checks: write
pull-requests: read
contents: read
steps:
- uses: amannn/action-semantic-pull-request@v4
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
# https://www.notion.so/n8n/Release-Process-fce65faea3d5403a85210f7e7a60d0f8
types: |
feat
fix
perf
test
docs
refactor
build
ci
requireScope: false

37
.github/workflows/ci-master.yml vendored Normal file
View File

@ -0,0 +1,37 @@
name: Test Master
on:
push:
branches:
- master
jobs:
build:
runs-on: ubuntu-latest
timeout-minutes: 30
strategy:
matrix:
node-version: [14.x, 16.x]
steps:
- uses: actions/checkout@v3
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}
cache: 'npm'
- name: Install npm and dependencies
run: npm install -g npm@latest && npm install
- name: Build
run: npm run build --if-present
- name: Test
run: npm run test
- name: Lint
run: npm run lint

39
.github/workflows/ci-pull-requests.yml vendored Normal file
View File

@ -0,0 +1,39 @@
name: Test Pull Requests
on: [pull_request]
jobs:
build:
runs-on: ubuntu-latest
timeout-minutes: 30
strategy:
matrix:
node-version: [14.x, 16.x]
steps:
- uses: actions/checkout@v3
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}
cache: 'npm'
- name: Install npm and dependencies
run: npm install -g npm@latest && npm install
- name: Build
run: npm run build --if-present
- name: Test
run: npm run test
- name: Fetch base branch for `git diff`
run: git fetch origin ${{ github.event.pull_request.base.ref }}:${{ github.event.pull_request.base.ref }}
- name: Run ESLint on changes only
env:
ESLINT_PLUGIN_DIFF_COMMIT: ${{ github.event.pull_request.base.ref }}
run: npm run lint

39
.github/workflows/docker-base-image.yml vendored Normal file
View File

@ -0,0 +1,39 @@
name: Docker Base Image CI
on:
workflow_dispatch:
inputs:
node_version:
description: 'Node.js version to build this image with.'
type: string
required: true
default: '16'
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up QEMU
uses: docker/setup-qemu-action@v2
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Login to DockerHub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Build
uses: docker/build-push-action@v2
with:
context: ./docker/images/n8n-base
build-args: |
NODE_VERSION=${{github.event.inputs.node_version}}
platforms: linux/amd64,linux/arm64,linux/arm/v7
push: true
tags: |
${{ secrets.DOCKER_USERNAME }}/base:${{ github.event.inputs.node_version }}

View File

@ -33,23 +33,28 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v2
uses: actions/checkout@v3
with:
repository: ${{ github.event.inputs.repository || 'n8n-io/n8n' }}
ref: ${{ github.event.inputs.branch || 'master' }}
- name: Set up QEMU
uses: docker/setup-qemu-action@v1
uses: docker/setup-qemu-action@v2
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
uses: docker/setup-buildx-action@v2
- name: Login to DockerHub
uses: docker/login-action@v1
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Merge Master - optionally
run: |
[[ "${{github.event.inputs.merge-master}}" == "true" ]] && git remote add upstream https://github.com/n8n-io/n8n.git -f; git merge upstream/master --allow-unrelated-histories || echo ""
shell: bash
- name: Build and push
uses: docker/build-push-action@v2
with:
@ -57,8 +62,9 @@ jobs:
file: ./docker/images/n8n-custom/Dockerfile
platforms: linux/amd64
push: true
tags: n8nio/n8n:${{ github.event.inputs.tag || 'nightly' }}
tags: ${{ secrets.DOCKER_USERNAME }}/n8n:${{ github.event.inputs.tag || 'nightly' }}
no-cache: true
- name: Call Success URL - optionally
run: |
[[ "${{github.event.inputs.success-url}}" != "" ]] && curl -v ${{github.event.inputs.success-url}} || echo ""

View File

@ -9,38 +9,44 @@ jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: Get the version
id: vars
run: echo ::set-output name=tag::$(echo ${GITHUB_REF:14})
- name: Set up QEMU
uses: docker/setup-qemu-action@v1
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
- name: Login to DockerHub
uses: docker/login-action@v1
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Build
uses: docker/build-push-action@v2
with:
context: ./docker/images/n8n
build-args: |
N8N_VERSION=${{steps.vars.outputs.tag}}
platforms: linux/amd64,linux/arm64,linux/arm/v7
push: true
tags: |
${{ secrets.DOCKER_USERNAME }}/n8n:${{ steps.vars.outputs.tag }}
${{ secrets.DOCKER_USERNAME }}/n8n:latest
- name: Build (debian)
uses: docker/build-push-action@v2
with:
context: ./docker/images/n8n-debian
build-args: |
N8N_VERSION=${{ steps.vars.outputs.tag }}
platforms: linux/amd64,linux/arm64,linux/arm/v7
push: true
tags: |
${{ secrets.DOCKER_USERNAME }}/n8n:${{ steps.vars.outputs.tag }}-debian
${{ secrets.DOCKER_USERNAME }}/n8n:latest-debian
- uses: actions/checkout@v3
- name: Get the version
id: vars
run: echo ::set-output name=tag::$(echo ${GITHUB_REF:14})
- name: Set up QEMU
uses: docker/setup-qemu-action@v2
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Login to DockerHub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Build
uses: docker/build-push-action@v2
with:
context: ./docker/images/n8n
build-args: |
N8N_VERSION=${{steps.vars.outputs.tag}}
platforms: linux/amd64,linux/arm64,linux/arm/v7
push: true
tags: |
${{ secrets.DOCKER_USERNAME }}/n8n:${{ steps.vars.outputs.tag }}
${{ secrets.DOCKER_USERNAME }}/n8n:latest
- name: Build (debian)
uses: docker/build-push-action@v2
with:
context: ./docker/images/n8n-debian
build-args: |
N8N_VERSION=${{ steps.vars.outputs.tag }}
platforms: linux/amd64,linux/arm64,linux/arm/v7
push: true
tags: |
${{ secrets.DOCKER_USERNAME }}/n8n:${{ steps.vars.outputs.tag }}-debian
${{ secrets.DOCKER_USERNAME }}/n8n:latest-debian

View File

@ -2,13 +2,11 @@ name: Run test workflows
on:
schedule:
- cron: "0 2 * * *"
- cron: '0 2 * * *'
workflow_dispatch:
jobs:
run-test-workflows:
runs-on: ubuntu-latest
timeout-minutes: 30
@ -17,62 +15,61 @@ jobs:
matrix:
node-version: [16.x]
steps:
-
name: Checkout
uses: actions/checkout@v2
- name: Checkout
uses: actions/checkout@v3
with:
path: n8n
-
name: Checkout workflows repo
uses: actions/checkout@v2
- name: Checkout workflows repo
uses: actions/checkout@v3
with:
repository: n8n-io/test-workflows
path: test-workflows
-
name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}
-
name: Install dependencies
cache: 'npm'
cache-dependency-path: 'n8n/package-lock.json'
- name: Install dependencies
run: |
sudo apt update -y
echo 'tzdata tzdata/Areas select Europe' | sudo debconf-set-selections
echo 'tzdata tzdata/Zones/Europe select Paris' | sudo debconf-set-selections
DEBIAN_FRONTEND="noninteractive" sudo apt-get install -y graphicsmagick
shell: bash
-
name: npm install and build
- name: npm install and build
working-directory: n8n
run: |
cd n8n
npm install -g npm@latest
npm install
npm run bootstrap
npm run build --if-present
env:
CI: true
shell: bash
-
name: Import credentials
- name: Import credentials
run: n8n/packages/cli/bin/n8n import:credentials --input=test-workflows/credentials.json
shell: bash
env:
N8N_ENCRYPTION_KEY: ${{secrets.ENCRYPTION_KEY}}
-
name: Import workflows
- name: Import workflows
run: n8n/packages/cli/bin/n8n import:workflow --separate --input=test-workflows/workflows
shell: bash
env:
N8N_ENCRYPTION_KEY: ${{secrets.ENCRYPTION_KEY}}
-
name: Copy static assets
- name: Copy static assets
run: |
cp n8n/assets/n8n-logo.png /tmp/n8n-logo.png
cp n8n/assets/n8n-screenshot.png /tmp/n8n-screenshot.png
cp n8n/node_modules/pdf-parse/test/data/05-versions-space.pdf /tmp/05-versions-space.pdf
cp n8n/node_modules/pdf-parse/test/data/04-valid.pdf /tmp/04-valid.pdf
shell: bash
-
name: Run tests
- name: Run tests
run: n8n/packages/cli/bin/n8n executeBatch --shallow --ids=test-workflows/safeList.txt --shortOutput --concurrency=16 --compare=test-workflows/snapshots
shell: bash
env:

View File

@ -1,30 +0,0 @@
name: Node CI
on: [push]
jobs:
build:
runs-on: ubuntu-latest
timeout-minutes: 30
strategy:
matrix:
node-version: [14.x, 16.x]
steps:
- uses: actions/checkout@v1
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}
- name: npm install, build, and test
run: |
npm install
npm run bootstrap
npm run build --if-present
npm test
npm run lint
env:
CI: true

4
.gitignore vendored
View File

@ -4,13 +4,15 @@ node_modules
tmp
dist
npm-debug.log*
lerna-debug.log
yarn.lock
google-generated-credentials.json
_START_PACKAGE
.env
.vscode/*
!.vscode/extensions.json
!.vscode/settings.default.json
.idea
nodelinter.config.json
packages/*/package-lock.json
packages/*/.turbo
*.swp

28
.npmignore Normal file
View File

@ -0,0 +1,28 @@
dist/test
dist/**/*.{js.map,d.ts}
.DS_Store
# local env files
.env.local
.env.*.local
# Log files
yarn-debug.log*
yarn-error.log*
# Editor directories and files
.idea
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw*
.editorconfig
.eslintrc.js
tsconfig.json
tslint.json
.turbo

View File

@ -1,574 +1,10 @@
dist
packages/editor-ui
packages/design-system
*package.json
package*.json
!packages/nodes-base/src
!packages/nodes-base/test
!packages/nodes-base/nodes
!packages/nodes-base/credentials
packages/nodes-base/nodes/ActionNetwork
packages/nodes-base/nodes/ActiveCampaign
packages/nodes-base/nodes/AcuityScheduling
packages/nodes-base/nodes/Affinity
packages/nodes-base/nodes/AgileCrm
packages/nodes-base/nodes/Airtable
packages/nodes-base/nodes/Amqp
packages/nodes-base/nodes/ApiTemplateIo
packages/nodes-base/nodes/Asana
packages/nodes-base/nodes/Automizy
packages/nodes-base/nodes/Autopilot
packages/nodes-base/nodes/Aws
packages/nodes-base/nodes/BambooHr
packages/nodes-base/nodes/Bannerbear
packages/nodes-base/nodes/Baserow
packages/nodes-base/nodes/Beeminder
packages/nodes-base/nodes/Bitbucket
packages/nodes-base/nodes/Bitly
packages/nodes-base/nodes/Bitwarden
packages/nodes-base/nodes/Box
packages/nodes-base/nodes/Brandfetch
packages/nodes-base/nodes/Bubble
packages/nodes-base/nodes/Cal
packages/nodes-base/nodes/Calendly
packages/nodes-base/nodes/Chargebee
packages/nodes-base/nodes/CircleCi
packages/nodes-base/nodes/Cisco
packages/nodes-base/nodes/Clearbit
packages/nodes-base/nodes/ClickUp
packages/nodes-base/nodes/Clockify
packages/nodes-base/nodes/Cockpit
packages/nodes-base/nodes/Coda
packages/nodes-base/nodes/CoinGecko
packages/nodes-base/nodes/Compression
packages/nodes-base/nodes/Contentful
packages/nodes-base/nodes/ConvertKit
packages/nodes-base/nodes/Copper
packages/nodes-base/nodes/Cortex
packages/nodes-base/nodes/CrateDb
packages/nodes-base/nodes/Cron
packages/nodes-base/nodes/Crypto
packages/nodes-base/nodes/CustomerIo
packages/nodes-base/nodes/DateTime
packages/nodes-base/nodes/DeepL
packages/nodes-base/nodes/Demio
packages/nodes-base/nodes/Dhl
packages/nodes-base/nodes/Discord
packages/nodes-base/nodes/Discourse
packages/nodes-base/nodes/Disqus
packages/nodes-base/nodes/Drift
packages/nodes-base/nodes/Dropbox
packages/nodes-base/nodes/Dropcontact
packages/nodes-base/nodes/EditImage
packages/nodes-base/nodes/Egoi
packages/nodes-base/nodes/Elastic
packages/nodes-base/nodes/EmailReadImap
packages/nodes-base/nodes/EmailSend
packages/nodes-base/nodes/Emelia
packages/nodes-base/nodes/ERPNext
packages/nodes-base/nodes/ErrorTrigger
packages/nodes-base/nodes/Eventbrite
packages/nodes-base/nodes/ExecuteCommand
packages/nodes-base/nodes/ExecuteWorkflow
packages/nodes-base/nodes/Facebook
packages/nodes-base/nodes/Figma
packages/nodes-base/nodes/FileMaker
packages/nodes-base/nodes/Flow
packages/nodes-base/nodes/FormIo
packages/nodes-base/nodes/Formstack
packages/nodes-base/nodes/Freshdesk
packages/nodes-base/nodes/Freshservice
packages/nodes-base/nodes/FreshworksCrm
packages/nodes-base/nodes/Ftp
packages/nodes-base/nodes/Function
packages/nodes-base/nodes/FunctionItem
packages/nodes-base/nodes/GetResponse
packages/nodes-base/nodes/Ghost
packages/nodes-base/nodes/Git
packages/nodes-base/nodes/Github
packages/nodes-base/nodes/Gitlab
packages/nodes-base/nodes/Google
packages/nodes-base/nodes/Gotify
packages/nodes-base/nodes/GoToWebinar
packages/nodes-base/nodes/Grafana
packages/nodes-base/nodes/GraphQL
packages/nodes-base/nodes/Grist
packages/nodes-base/nodes/Gumroad
packages/nodes-base/nodes/HackerNews
packages/nodes-base/nodes/HaloPSA
packages/nodes-base/nodes/Harvest
packages/nodes-base/nodes/HelpScout
packages/nodes-base/nodes/HomeAssistant
packages/nodes-base/nodes/HtmlExtract
packages/nodes-base/nodes/HttpRequest
packages/nodes-base/nodes/Hubspot
packages/nodes-base/nodes/HumanticAI
packages/nodes-base/nodes/Hunter
packages/nodes-base/nodes/ICalendar
packages/nodes-base/nodes/If
packages/nodes-base/nodes/Intercom
packages/nodes-base/nodes/Interval
packages/nodes-base/nodes/InvoiceNinja
packages/nodes-base/nodes/ItemLists
packages/nodes-base/nodes/Iterable
packages/nodes-base/nodes/Jenkins
packages/nodes-base/nodes/Jira
packages/nodes-base/nodes/JotForm
packages/nodes-base/nodes/Kafka
packages/nodes-base/nodes/Keap
packages/nodes-base/nodes/Kitemaker
packages/nodes-base/nodes/KoBoToolbox
packages/nodes-base/nodes/Lemlist
packages/nodes-base/nodes/Line
packages/nodes-base/nodes/Linear
packages/nodes-base/nodes/LingvaNex
packages/nodes-base/nodes/LinkedIn
packages/nodes-base/nodes/LocalFileTrigger
packages/nodes-base/nodes/Magento
packages/nodes-base/nodes/Mailcheck
packages/nodes-base/nodes/Mailchimp
packages/nodes-base/nodes/MailerLite
packages/nodes-base/nodes/Mailgun
packages/nodes-base/nodes/Mailjet
packages/nodes-base/nodes/Mandrill
packages/nodes-base/nodes/Markdown
packages/nodes-base/nodes/Marketstack
packages/nodes-base/nodes/Matrix
packages/nodes-base/nodes/Mattermost
packages/nodes-base/nodes/Mautic
packages/nodes-base/nodes/Medium
packages/nodes-base/nodes/Merge
packages/nodes-base/nodes/MessageBird
packages/nodes-base/nodes/Microsoft
packages/nodes-base/nodes/Mindee
packages/nodes-base/nodes/Misp
packages/nodes-base/nodes/Mocean
packages/nodes-base/nodes/MondayCom
packages/nodes-base/nodes/MongoDb
packages/nodes-base/nodes/MonicaCrm
packages/nodes-base/nodes/MoveBinaryData
packages/nodes-base/nodes/MQTT
packages/nodes-base/nodes/Msg91
packages/nodes-base/nodes/MySql
packages/nodes-base/nodes/N8nTrainingCustomerDatastore
packages/nodes-base/nodes/N8nTrainingCustomerMessenger
packages/nodes-base/nodes/N8nTrigger
packages/nodes-base/nodes/Nasa
packages/nodes-base/nodes/Netlify
packages/nodes-base/nodes/NextCloud
packages/nodes-base/nodes/NocoDB
packages/nodes-base/nodes/NoOp
packages/nodes-base/nodes/Notion
packages/nodes-base/nodes/Odoo
packages/nodes-base/nodes/OneSimpleApi
packages/nodes-base/nodes/Onfleet
packages/nodes-base/nodes/OpenThesaurus
packages/nodes-base/nodes/OpenWeatherMap
packages/nodes-base/nodes/Orbit
packages/nodes-base/nodes/Oura
packages/nodes-base/nodes/Paddle
packages/nodes-base/nodes/PagerDuty
packages/nodes-base/nodes/PayPal
packages/nodes-base/nodes/Peekalink
packages/nodes-base/nodes/Phantombuster
packages/nodes-base/nodes/PhilipsHue
packages/nodes-base/nodes/Pipedrive
packages/nodes-base/nodes/Plivo
packages/nodes-base/nodes/PostBin
packages/nodes-base/nodes/Postgres
packages/nodes-base/nodes/PostHog
packages/nodes-base/nodes/Postmark
packages/nodes-base/nodes/ProfitWell
packages/nodes-base/nodes/Pushbullet
packages/nodes-base/nodes/Pushcut
packages/nodes-base/nodes/Pushover
packages/nodes-base/nodes/QuestDb
packages/nodes-base/nodes/QuickBase
packages/nodes-base/nodes/QuickBooks
packages/nodes-base/nodes/RabbitMQ
packages/nodes-base/nodes/Raindrop
packages/nodes-base/nodes/ReadBinaryFile
packages/nodes-base/nodes/ReadBinaryFiles
packages/nodes-base/nodes/ReadPdf
packages/nodes-base/nodes/Reddit
packages/nodes-base/nodes/Redis
packages/nodes-base/nodes/RenameKeys
packages/nodes-base/nodes/RespondToWebhook
packages/nodes-base/nodes/Rocketchat
packages/nodes-base/nodes/RssFeedRead
packages/nodes-base/nodes/Rundeck
packages/nodes-base/nodes/S3
packages/nodes-base/nodes/Salesforce
packages/nodes-base/nodes/Salesmate
packages/nodes-base/nodes/SeaTable
packages/nodes-base/nodes/SecurityScorecard
packages/nodes-base/nodes/Segment
packages/nodes-base/nodes/SendGrid
packages/nodes-base/nodes/Sendy
packages/nodes-base/nodes/SentryIo
packages/nodes-base/nodes/ServiceNow
packages/nodes-base/nodes/Set
packages/nodes-base/nodes/Shopify
packages/nodes-base/nodes/Signl4
packages/nodes-base/nodes/Slack
packages/nodes-base/nodes/Sms77
packages/nodes-base/nodes/Snowflake
packages/nodes-base/nodes/SplitInBatches
packages/nodes-base/nodes/Splunk
packages/nodes-base/nodes/Spontit
packages/nodes-base/nodes/Spotify
packages/nodes-base/nodes/SpreadsheetFile
packages/nodes-base/nodes/SseTrigger
packages/nodes-base/nodes/Ssh
packages/nodes-base/nodes/Stackby
packages/nodes-base/nodes/Start
packages/nodes-base/nodes/StickyNote
packages/nodes-base/nodes/StopAndError
packages/nodes-base/nodes/Storyblok
packages/nodes-base/nodes/Strapi
packages/nodes-base/nodes/Strava
packages/nodes-base/nodes/Stripe
packages/nodes-base/nodes/Supabase
packages/nodes-base/nodes/SurveyMonkey
packages/nodes-base/nodes/Switch
packages/nodes-base/nodes/SyncroMSP
packages/nodes-base/nodes/Taiga
packages/nodes-base/nodes/Tapfiliate
packages/nodes-base/nodes/Telegram
packages/nodes-base/nodes/TheHive
packages/nodes-base/nodes/TimescaleDb
packages/nodes-base/nodes/Todoist
packages/nodes-base/nodes/Toggl
packages/nodes-base/nodes/TravisCi
packages/nodes-base/nodes/Trello
packages/nodes-base/nodes/Twake
packages/nodes-base/nodes/Twilio
packages/nodes-base/nodes/Twist
packages/nodes-base/nodes/Twitter
packages/nodes-base/nodes/Typeform
packages/nodes-base/nodes/UnleashedSoftware
packages/nodes-base/nodes/Uplead
packages/nodes-base/nodes/UProc
packages/nodes-base/nodes/UptimeRobot
packages/nodes-base/nodes/UrlScanIo
packages/nodes-base/nodes/utils
packages/nodes-base/nodes/Vero
packages/nodes-base/nodes/Vonage
packages/nodes-base/nodes/Wait
packages/nodes-base/nodes/Webflow
packages/nodes-base/nodes/Webhook
packages/nodes-base/nodes/Wekan
packages/nodes-base/nodes/Wise
packages/nodes-base/nodes/WooCommerce
packages/nodes-base/nodes/Wordpress
packages/nodes-base/nodes/Workable
packages/nodes-base/nodes/WorkflowTrigger
packages/nodes-base/nodes/WriteBinaryFile
packages/nodes-base/nodes/Wufoo
packages/nodes-base/nodes/Xero
packages/nodes-base/nodes/Xml
packages/nodes-base/nodes/Yourls
packages/nodes-base/nodes/Zammad
packages/nodes-base/nodes/Zendesk
packages/nodes-base/nodes/Zoho
packages/nodes-base/nodes/Zoom
packages/nodes-base/nodes/Zulip
packages/nodes-base/credentials/ActionNetworkApi.credentials.ts
packages/nodes-base/credentials/ActiveCampaignApi.credentials.ts
packages/nodes-base/credentials/AcuitySchedulingApi.credentials.ts
packages/nodes-base/credentials/AcuitySchedulingOAuth2Api.credentials.ts
packages/nodes-base/credentials/AffinityApi.credentials.ts
packages/nodes-base/credentials/AgileCrmApi.credentials.ts
packages/nodes-base/credentials/AirtableApi.credentials.ts
packages/nodes-base/credentials/Amqp.credentials.ts
packages/nodes-base/credentials/ApiTemplateIoApi.credentials.ts
packages/nodes-base/credentials/AsanaApi.credentials.ts
packages/nodes-base/credentials/AsanaOAuth2Api.credentials.ts
packages/nodes-base/credentials/AutomizyApi.credentials.ts
packages/nodes-base/credentials/AutopilotApi.credentials.ts
packages/nodes-base/credentials/Aws.credentials.ts
packages/nodes-base/credentials/AWS.svg
packages/nodes-base/credentials/BambooHrApi.credentials.ts
packages/nodes-base/credentials/BannerbearApi.credentials.ts
packages/nodes-base/credentials/BaserowApi.credentials.ts
packages/nodes-base/credentials/BeeminderApi.credentials.ts
packages/nodes-base/credentials/BitbucketApi.credentials.ts
packages/nodes-base/credentials/BitlyApi.credentials.ts
packages/nodes-base/credentials/BitlyOAuth2Api.credentials.ts
packages/nodes-base/credentials/BitwardenApi.credentials.ts
packages/nodes-base/credentials/BoxOAuth2Api.credentials.ts
packages/nodes-base/credentials/BrandfetchApi.credentials.ts
packages/nodes-base/credentials/BubbleApi.credentials.ts
packages/nodes-base/credentials/CalApi.credentials.ts
packages/nodes-base/credentials/CalendlyApi.credentials.ts
packages/nodes-base/credentials/ChargebeeApi.credentials.ts
packages/nodes-base/credentials/CircleCiApi.credentials.ts
packages/nodes-base/credentials/CiscoWebexOAuth2Api.credentials.ts
packages/nodes-base/credentials/ClearbitApi.credentials.ts
packages/nodes-base/credentials/ClickUpApi.credentials.ts
packages/nodes-base/credentials/ClickUpOAuth2Api.credentials.ts
packages/nodes-base/credentials/ClockifyApi.credentials.ts
packages/nodes-base/credentials/CockpitApi.credentials.ts
packages/nodes-base/credentials/CodaApi.credentials.ts
packages/nodes-base/credentials/ContentfulApi.credentials.ts
packages/nodes-base/credentials/ConvertKitApi.credentials.ts
packages/nodes-base/credentials/CopperApi.credentials.ts
packages/nodes-base/credentials/CortexApi.credentials.ts
packages/nodes-base/credentials/CrateDb.credentials.ts
packages/nodes-base/credentials/CustomerIoApi.credentials.ts
packages/nodes-base/credentials/DeepLApi.credentials.ts
packages/nodes-base/credentials/DemioApi.credentials.ts
packages/nodes-base/credentials/DhlApi.credentials.ts
packages/nodes-base/credentials/DiscourseApi.credentials.ts
packages/nodes-base/credentials/DisqusApi.credentials.ts
packages/nodes-base/credentials/DriftApi.credentials.ts
packages/nodes-base/credentials/DriftOAuth2Api.credentials.ts
packages/nodes-base/credentials/DropboxApi.credentials.ts
packages/nodes-base/credentials/DropboxOAuth2Api.credentials.ts
packages/nodes-base/credentials/DropcontactApi.credentials.ts
packages/nodes-base/credentials/EgoiApi.credentials.ts
packages/nodes-base/credentials/ElasticsearchApi.credentials.ts
packages/nodes-base/credentials/ElasticSecurityApi.credentials.ts
packages/nodes-base/credentials/EmeliaApi.credentials.ts
packages/nodes-base/credentials/ERPNextApi.credentials.ts
packages/nodes-base/credentials/EventbriteApi.credentials.ts
packages/nodes-base/credentials/EventbriteOAuth2Api.credentials.ts
packages/nodes-base/credentials/FacebookGraphApi.credentials.ts
packages/nodes-base/credentials/FacebookGraphAppApi.credentials.ts
packages/nodes-base/credentials/FigmaApi.credentials.ts
packages/nodes-base/credentials/FileMaker.credentials.ts
packages/nodes-base/credentials/FlowApi.credentials.ts
packages/nodes-base/credentials/FormIoApi.credentials.ts
packages/nodes-base/credentials/FormstackApi.credentials.ts
packages/nodes-base/credentials/FormstackOAuth2Api.credentials.ts
packages/nodes-base/credentials/FreshdeskApi.credentials.ts
packages/nodes-base/credentials/FreshserviceApi.credentials.ts
packages/nodes-base/credentials/FreshworksCrmApi.credentials.ts
packages/nodes-base/credentials/Ftp.credentials.ts
packages/nodes-base/credentials/GetResponseApi.credentials.ts
packages/nodes-base/credentials/GetResponseOAuth2Api.credentials.ts
packages/nodes-base/credentials/GhostAdminApi.credentials.ts
packages/nodes-base/credentials/GhostContentApi.credentials.ts
packages/nodes-base/credentials/GithubApi.credentials.ts
packages/nodes-base/credentials/GithubOAuth2Api.credentials.ts
packages/nodes-base/credentials/GitlabApi.credentials.ts
packages/nodes-base/credentials/GitlabOAuth2Api.credentials.ts
packages/nodes-base/credentials/GitPassword.credentials.ts
packages/nodes-base/credentials/GmailOAuth2Api.credentials.ts
packages/nodes-base/credentials/Google.svg
packages/nodes-base/credentials/GoogleAnalyticsOAuth2Api.credentials.ts
packages/nodes-base/credentials/GoogleApi.credentials.ts
packages/nodes-base/credentials/GoogleBigQueryOAuth2Api.credentials.ts
packages/nodes-base/credentials/GoogleBooksOAuth2Api.credentials.ts
packages/nodes-base/credentials/GoogleCalendarOAuth2Api.credentials.ts
packages/nodes-base/credentials/GoogleCloudNaturalLanguageOAuth2Api.credentials.ts
packages/nodes-base/credentials/GoogleContactsOAuth2Api.credentials.ts
packages/nodes-base/credentials/GoogleDocsOAuth2Api.credentials.ts
packages/nodes-base/credentials/GoogleDriveOAuth2Api.credentials.ts
packages/nodes-base/credentials/GoogleFirebaseCloudFirestoreOAuth2Api.credentials.ts
packages/nodes-base/credentials/GoogleFirebaseRealtimeDatabaseOAuth2Api.credentials.ts
packages/nodes-base/credentials/GoogleOAuth2Api.credentials.ts
packages/nodes-base/credentials/GooglePerspectiveOAuth2Api.credentials.ts
packages/nodes-base/credentials/GoogleSheetsOAuth2Api.credentials.ts
packages/nodes-base/credentials/GoogleSlidesOAuth2Api.credentials.ts
packages/nodes-base/credentials/GoogleTasksOAuth2Api.credentials.ts
packages/nodes-base/credentials/GoogleTranslateOAuth2Api.credentials.ts
packages/nodes-base/credentials/GotifyApi.credentials.ts
packages/nodes-base/credentials/GoToWebinarOAuth2Api.credentials.ts
packages/nodes-base/credentials/GrafanaApi.credentials.ts
packages/nodes-base/credentials/GristApi.credentials.ts
packages/nodes-base/credentials/GSuiteAdminOAuth2Api.credentials.ts
packages/nodes-base/credentials/GumroadApi.credentials.ts
packages/nodes-base/credentials/HaloPSAApi.credentials.ts
packages/nodes-base/credentials/HarvestApi.credentials.ts
packages/nodes-base/credentials/HarvestOAuth2Api.credentials.ts
packages/nodes-base/credentials/HelpScoutOAuth2Api.credentials.ts
packages/nodes-base/credentials/HomeAssistantApi.credentials.ts
packages/nodes-base/credentials/HttpBasicAuth.credentials.ts
packages/nodes-base/credentials/HttpDigestAuth.credentials.ts
packages/nodes-base/credentials/HttpHeaderAuth.credentials.ts
packages/nodes-base/credentials/HttpQueryAuth.credentials.ts
packages/nodes-base/credentials/HubspotApi.credentials.ts
packages/nodes-base/credentials/HubspotAppToken.credentials.ts
packages/nodes-base/credentials/HubspotDeveloperApi.credentials.ts
packages/nodes-base/credentials/HubspotOAuth2Api.credentials.ts
packages/nodes-base/credentials/HumanticAiApi.credentials.ts
packages/nodes-base/credentials/HunterApi.credentials.ts
packages/nodes-base/credentials/Imap.credentials.ts
packages/nodes-base/credentials/IntercomApi.credentials.ts
packages/nodes-base/credentials/InvoiceNinjaApi.credentials.ts
packages/nodes-base/credentials/IterableApi.credentials.ts
packages/nodes-base/credentials/JenkinsApi.credentials.ts
packages/nodes-base/credentials/JiraSoftwareCloudApi.credentials.ts
packages/nodes-base/credentials/JiraSoftwareServerApi.credentials.ts
packages/nodes-base/credentials/JotFormApi.credentials.ts
packages/nodes-base/credentials/Kafka.credentials.ts
packages/nodes-base/credentials/KeapOAuth2Api.credentials.ts
packages/nodes-base/credentials/KitemakerApi.credentials.ts
packages/nodes-base/credentials/KoBoToolboxApi.credentials.ts
packages/nodes-base/credentials/LemlistApi.credentials.ts
packages/nodes-base/credentials/LinearApi.credentials.ts
packages/nodes-base/credentials/LineNotifyOAuth2Api.credentials.ts
packages/nodes-base/credentials/LingvaNexApi.credentials.ts
packages/nodes-base/credentials/LinkedInOAuth2Api.credentials.ts
packages/nodes-base/credentials/Magento2Api.credentials.ts
packages/nodes-base/credentials/MailcheckApi.credentials.ts
packages/nodes-base/credentials/MailchimpApi.credentials.ts
packages/nodes-base/credentials/MailchimpOAuth2Api.credentials.ts
packages/nodes-base/credentials/MailerLiteApi.credentials.ts
packages/nodes-base/credentials/MailgunApi.credentials.ts
packages/nodes-base/credentials/MailjetEmailApi.credentials.ts
packages/nodes-base/credentials/MailjetSmsApi.credentials.ts
packages/nodes-base/credentials/MandrillApi.credentials.ts
packages/nodes-base/credentials/MarketstackApi.credentials.ts
packages/nodes-base/credentials/MatrixApi.credentials.ts
packages/nodes-base/credentials/MattermostApi.credentials.ts
packages/nodes-base/credentials/MauticApi.credentials.ts
packages/nodes-base/credentials/MauticOAuth2Api.credentials.ts
packages/nodes-base/credentials/MediumApi.credentials.ts
packages/nodes-base/credentials/MediumOAuth2Api.credentials.ts
packages/nodes-base/credentials/MessageBirdApi.credentials.ts
packages/nodes-base/credentials/Microsoft.svg
packages/nodes-base/credentials/MicrosoftDynamicsOAuth2Api.credentials.ts
packages/nodes-base/credentials/MicrosoftExcelOAuth2Api.credentials.ts
packages/nodes-base/credentials/MicrosoftGraphSecurityOAuth2Api.credentials.ts
packages/nodes-base/credentials/MicrosoftOAuth2Api.credentials.ts
packages/nodes-base/credentials/MicrosoftOneDriveOAuth2Api.credentials.ts
packages/nodes-base/credentials/MicrosoftOutlookOAuth2Api.credentials.ts
packages/nodes-base/credentials/MicrosoftSql.credentials.ts
packages/nodes-base/credentials/MicrosoftTeamsOAuth2Api.credentials.ts
packages/nodes-base/credentials/MicrosoftToDoOAuth2Api.credentials.ts
packages/nodes-base/credentials/MindeeInvoiceApi.credentials.ts
packages/nodes-base/credentials/MindeeReceiptApi.credentials.ts
packages/nodes-base/credentials/MispApi.credentials.ts
packages/nodes-base/credentials/MoceanApi.credentials.ts
packages/nodes-base/credentials/MondayComApi.credentials.ts
packages/nodes-base/credentials/MondayComOAuth2Api.credentials.ts
packages/nodes-base/credentials/MongoDb.credentials.ts
packages/nodes-base/credentials/MonicaCrmApi.credentials.ts
packages/nodes-base/credentials/Mqtt.credentials.ts
packages/nodes-base/credentials/Msg91Api.credentials.ts
packages/nodes-base/credentials/MySql.credentials.ts
packages/nodes-base/credentials/NasaApi.credentials.ts
packages/nodes-base/credentials/NetlifyApi.credentials.ts
packages/nodes-base/credentials/NetlifyOAuth2Api.credentials.ts
packages/nodes-base/credentials/NextCloudApi.credentials.ts
packages/nodes-base/credentials/NextCloudOAuth2Api.credentials.ts
packages/nodes-base/credentials/NocoDb.credentials.ts
packages/nodes-base/credentials/NotionApi.credentials.ts
packages/nodes-base/credentials/NotionOAuth2Api.credentials.ts
packages/nodes-base/credentials/OAuth1Api.credentials.ts
packages/nodes-base/credentials/OAuth2Api.credentials.ts
packages/nodes-base/credentials/OdooApi.credentials.ts
packages/nodes-base/credentials/OneSimpleApi.credentials.ts
packages/nodes-base/credentials/OnfleetApi.credentials.ts
packages/nodes-base/credentials/OpenWeatherMapApi.credentials.ts
packages/nodes-base/credentials/OrbitApi.credentials.ts
packages/nodes-base/credentials/OuraApi.credentials.ts
packages/nodes-base/credentials/PaddleApi.credentials.ts
packages/nodes-base/credentials/PagerDutyApi.credentials.ts
packages/nodes-base/credentials/PagerDutyOAuth2Api.credentials.ts
packages/nodes-base/credentials/PayPalApi.credentials.ts
packages/nodes-base/credentials/PeekalinkApi.credentials.ts
packages/nodes-base/credentials/PhantombusterApi.credentials.ts
packages/nodes-base/credentials/PhilipsHueOAuth2Api.credentials.ts
packages/nodes-base/credentials/PipedriveApi.credentials.ts
packages/nodes-base/credentials/PipedriveOAuth2Api.credentials.ts
packages/nodes-base/credentials/PlivoApi.credentials.ts
packages/nodes-base/credentials/Postgres.credentials.ts
packages/nodes-base/credentials/PostHogApi.credentials.ts
packages/nodes-base/credentials/PostmarkApi.credentials.ts
packages/nodes-base/credentials/ProfitWellApi.credentials.ts
packages/nodes-base/credentials/PushbulletOAuth2Api.credentials.ts
packages/nodes-base/credentials/PushcutApi.credentials.ts
packages/nodes-base/credentials/PushoverApi.credentials.ts
packages/nodes-base/credentials/QuestDb.credentials.ts
packages/nodes-base/credentials/QuickBaseApi.credentials.ts
packages/nodes-base/credentials/QuickBooksOAuth2Api.credentials.ts
packages/nodes-base/credentials/RabbitMQ.credentials.ts
packages/nodes-base/credentials/RaindropOAuth2Api.credentials.ts
packages/nodes-base/credentials/RedditOAuth2Api.credentials.ts
packages/nodes-base/credentials/Redis.credentials.ts
packages/nodes-base/credentials/RocketchatApi.credentials.ts
packages/nodes-base/credentials/RundeckApi.credentials.ts
packages/nodes-base/credentials/S3.credentials.ts
packages/nodes-base/credentials/SalesforceJwtApi.credentials.ts
packages/nodes-base/credentials/SalesforceOAuth2Api.credentials.ts
packages/nodes-base/credentials/SalesmateApi.credentials.ts
packages/nodes-base/credentials/SeaTableApi.credentials.ts
packages/nodes-base/credentials/SecurityScorecardApi.credentials.ts
packages/nodes-base/credentials/SegmentApi.credentials.ts
packages/nodes-base/credentials/SendGridApi.credentials.ts
packages/nodes-base/credentials/SendyApi.credentials.ts
packages/nodes-base/credentials/SentryIoApi.credentials.ts
packages/nodes-base/credentials/SentryIoOAuth2Api.credentials.ts
packages/nodes-base/credentials/SentryIoServerApi.credentials.ts
packages/nodes-base/credentials/ServiceNowBasicApi.credentials.ts
packages/nodes-base/credentials/ServiceNowOAuth2Api.credentials.ts
packages/nodes-base/credentials/Sftp.credentials.ts
packages/nodes-base/credentials/ShopifyApi.credentials.ts
packages/nodes-base/credentials/Signl4Api.credentials.ts
packages/nodes-base/credentials/SlackApi.credentials.ts
packages/nodes-base/credentials/SlackOAuth2Api.credentials.ts
packages/nodes-base/credentials/Sms77Api.credentials.ts
packages/nodes-base/credentials/Smtp.credentials.ts
packages/nodes-base/credentials/Snowflake.credentials.ts
packages/nodes-base/credentials/SplunkApi.credentials.ts
packages/nodes-base/credentials/SpontitApi.credentials.ts
packages/nodes-base/credentials/SpotifyOAuth2Api.credentials.ts
packages/nodes-base/credentials/SshPassword.credentials.ts
packages/nodes-base/credentials/SshPrivateKey.credentials.ts
packages/nodes-base/credentials/StackbyApi.credentials.ts
packages/nodes-base/credentials/StoryblokContentApi.credentials.ts
packages/nodes-base/credentials/StoryblokManagementApi.credentials.ts
packages/nodes-base/credentials/StrapiApi.credentials.ts
packages/nodes-base/credentials/StravaOAuth2Api.credentials.ts
packages/nodes-base/credentials/StripeApi.credentials.ts
packages/nodes-base/credentials/SupabaseApi.credentials.ts
packages/nodes-base/credentials/SurveyMonkeyApi.credentials.ts
packages/nodes-base/credentials/SurveyMonkeyOAuth2Api.credentials.ts
packages/nodes-base/credentials/SyncroMspApi.credentials.ts
packages/nodes-base/credentials/TaigaApi.credentials.ts
packages/nodes-base/credentials/TapfiliateApi.credentials.ts
packages/nodes-base/credentials/TelegramApi.credentials.ts
packages/nodes-base/credentials/TheHiveApi.credentials.ts
packages/nodes-base/credentials/TimescaleDb.credentials.ts
packages/nodes-base/credentials/TodoistApi.credentials.ts
packages/nodes-base/credentials/TodoistOAuth2Api.credentials.ts
packages/nodes-base/credentials/TogglApi.credentials.ts
packages/nodes-base/credentials/TravisCiApi.credentials.ts
packages/nodes-base/credentials/TrelloApi.credentials.ts
packages/nodes-base/credentials/TwakeCloudApi.credentials.ts
packages/nodes-base/credentials/TwakeServerApi.credentials.ts
packages/nodes-base/credentials/TwilioApi.credentials.ts
packages/nodes-base/credentials/TwistOAuth2Api.credentials.ts
packages/nodes-base/credentials/TwitterOAuth1Api.credentials.ts
packages/nodes-base/credentials/TypeformApi.credentials.ts
packages/nodes-base/credentials/TypeformOAuth2Api.credentials.ts
packages/nodes-base/credentials/UnleashedSoftwareApi.credentials.ts
packages/nodes-base/credentials/UpleadApi.credentials.ts
packages/nodes-base/credentials/UProcApi.credentials.ts
packages/nodes-base/credentials/UptimeRobotApi.credentials.ts
packages/nodes-base/credentials/UrlScanIoApi.credentials.ts
packages/nodes-base/credentials/VeroApi.credentials.ts
packages/nodes-base/credentials/VonageApi.credentials.ts
packages/nodes-base/credentials/WebflowApi.credentials.ts
packages/nodes-base/credentials/WebflowOAuth2Api.credentials.ts
packages/nodes-base/credentials/WekanApi.credentials.ts
packages/nodes-base/credentials/WiseApi.credentials.ts
packages/nodes-base/credentials/WooCommerceApi.credentials.ts
packages/nodes-base/credentials/WordpressApi.credentials.ts
packages/nodes-base/credentials/WorkableApi.credentials.ts
packages/nodes-base/credentials/WufooApi.credentials.ts
packages/nodes-base/credentials/XeroOAuth2Api.credentials.ts
packages/nodes-base/credentials/YourlsApi.credentials.ts
packages/nodes-base/credentials/YouTubeOAuth2Api.credentials.ts
packages/nodes-base/credentials/ZammadBasicAuthApi.credentials.ts
packages/nodes-base/credentials/ZammadTokenAuthApi.credentials.ts
packages/nodes-base/credentials/ZendeskApi.credentials.ts
packages/nodes-base/credentials/ZendeskOAuth2Api.credentials.ts
packages/nodes-base/credentials/ZohoOAuth2Api.credentials.ts
packages/nodes-base/credentials/ZoomApi.credentials.ts
packages/nodes-base/credentials/ZoomOAuth2Api.credentials.ts
packages/nodes-base/credentials/ZulipApi.credentials.ts
packages/nodes-base/nodes/UProc/Json/Tools.ts

10
.vscode/DEBUGGER.md vendored
View File

@ -18,7 +18,7 @@ Breakpoints are noted with a red dot in front of the line, meaning that whenever
## What if I change the code?
You might need to restart the debugger if you make changes to your code, since the running process will be executing an oudated version of the code.
You might need to restart the debugger if you make changes to your code, since the running process will be executing an outdated version of the code.
In order to make this process easier you can simply run `npm run watch` in another terminal window, so you don't have to fully build the project. Please note that restarting n8n is still required, but this is much faster.
@ -26,13 +26,13 @@ In order to make this process easier you can simply run `npm run watch` in anoth
Docker debugging is currently not functional. We offer 2 other methods:
1) Launch n8n from inside VSCode:
1. Launch n8n from inside VSCode:
From the "Run and Debug" section in VSCode you can choose the option named "Launch n8n with debug".
This will start n8n to run as normal, but with debugger attached.
2) Another possibility is if n8n is already running, say, in your terminal.
This will start n8n to run as normal, but with debugger attached.
2. Another possibility is if n8n is already running, say, in your terminal.
You can attach the debugger to it.
This is done by choosing the option "Attach to running n8n".
VSCode will present you with a prompt to select the n8n process. It usually is displayed with `node ./n8n`
VSCode will present you with a prompt to select the n8n process. It usually is displayed with `node ./n8n`
## What can be debugged?

View File

@ -1,5 +1,6 @@
{
"recommendations": [
"dangmai.workspace-default-settings",
"dbaeumer.vscode-eslint",
"EditorConfig.EditorConfig",
"esbenp.prettier-vscode",

25
.vscode/launch.json vendored
View File

@ -8,23 +8,32 @@
"name": "Attach to running n8n",
"processId": "${command:PickProcess}",
"request": "attach",
"skipFiles": [
"<node_internals>/**"
],
"skipFiles": ["<node_internals>/**"],
"type": "node"
},
{
"name": "Launch n8n with debug",
"program": "${workspaceFolder}/packages/cli/bin/n8n",
"request": "launch",
"skipFiles": [
"<node_internals>/**"
],
"skipFiles": ["<node_internals>/**"],
"type": "node",
"env": {
// "N8N_PORT": "5679",
}
}
},
},
{
"name": "Debug CLI tests",
"cwd": "${workspaceFolder}/packages/cli",
"runtimeExecutable": "npm",
"args": [
"run",
"test",
// "--",
// "ActiveExecutions"
],
"type": "node",
"request": "launch"
},
]
/**

11
.vscode/settings.default.json vendored Normal file
View File

@ -0,0 +1,11 @@
{
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.formatOnSave": true,
"search.exclude": {
"node_modules": true,
"dist": true,
"package-lock.json": true
},
"typescript.tsdk": "node_modules/typescript/lib",
"workspace-default-settings.runOnActivation": true
}

View File

@ -1,174 +1,613 @@
## [0.186.1](https://github.com/n8n-io/n8n/compare/n8n@0.186.0...n8n@0.186.1) (2022-07-14)
## [0.197.1](https://github.com/n8n-io/n8n/compare/n8n@0.197.0...n8n@0.197.1) (2022-10-10)
### Bug Fixes
* **Airtable Node:** Fix authentication issue ([#3709](https://github.com/n8n-io/n8n/issues/3709)) ([33d8042](https://github.com/n8n-io/n8n/commit/33d804284ae02140749ab94eecfca1699e13afee))
* **editor:** Fix resource locator width for trigger nodes ([#4302](https://github.com/n8n-io/n8n/issues/4302)) ([845d1f8](https://github.com/n8n-io/n8n/commit/845d1f8bd9763e9b886ac70c7ccbd37ff1c24b43))
# [0.197.0](https://github.com/n8n-io/n8n/compare/n8n@0.196.0...n8n@0.197.0) (2022-10-10)
### Bug Fixes
* **cli:** Cache generated assets in user writable directory instead ([#4275](https://github.com/n8n-io/n8n/issues/4275)) ([e63eee2](https://github.com/n8n-io/n8n/commit/e63eee28e00ae01fe4db92ac1235d7be7f25b76d))
* **core:** Fix excess run for pinned trigger in partial execution ([#4185](https://github.com/n8n-io/n8n/issues/4185)) ([a751fd3](https://github.com/n8n-io/n8n/commit/a751fd3ce762df99490889153d36029ff4cd00da))
* **core:** Fix hooks URLs no longer added to `index.html` ([#4262](https://github.com/n8n-io/n8n/issues/4262)) ([cc2a2e4](https://github.com/n8n-io/n8n/commit/cc2a2e438b0dee703b40dab67b4770dc06c76a7e))
* **editor:** Fix `pairedItem` in combination with pinned data ([#4257](https://github.com/n8n-io/n8n/issues/4257)) ([e30c78f](https://github.com/n8n-io/n8n/commit/e30c78febeac8bfcfbe5f1c4c13122594d8a518e))
* **Github Trigger Node:** Fix issue with trigger not always activating ([#4284](https://github.com/n8n-io/n8n/issues/4284)) ([694f1ba](https://github.com/n8n-io/n8n/commit/694f1ba4f5780b2e9821db52e579883bbc289df4))
* **Microsoft Excel Node:** Fix issue with pagination when getting all items ([#4247](https://github.com/n8n-io/n8n/issues/4247)) ([1067ec0](https://github.com/n8n-io/n8n/commit/1067ec0f5bd8e57650ccd9924e01fc52fbf0c43c))
* **Microsoft ToDo Node:** Fix pagination issue when getting all items ([#4222](https://github.com/n8n-io/n8n/issues/4222)) ([4595b54](https://github.com/n8n-io/n8n/commit/4595b54e562c50c48bdfe8049cb170196713cc8b))
### Features
* **AWS Certificate Manager Node:** Add AWS Certificate Manager node ([#4263](https://github.com/n8n-io/n8n/issues/4263)) ([9b3f30d](https://github.com/n8n-io/n8n/commit/9b3f30d584901e7dc5fa87854e72f438f2557665))
* **AWS Elastic Load Balancer Node:** Add Elastic Load Balancer node ([#4264](https://github.com/n8n-io/n8n/issues/4264)) ([fac6efb](https://github.com/n8n-io/n8n/commit/fac6efbb4158aa713bf5472d27b6fe341db8047d))
* **Citrix ADC Node:** Add Citrix ADC node ([#4274](https://github.com/n8n-io/n8n/issues/4274)) ([7abc7e6](https://github.com/n8n-io/n8n/commit/7abc7e64082b60fa48f99f4b1f41d176fbb6d6ad))
* **Cloudflare Node:** Add Cloudflare node ([#4271](https://github.com/n8n-io/n8n/issues/4271)) ([94a02c6](https://github.com/n8n-io/n8n/commit/94a02c64928205c441af5515739fe8eab7160b33))
* **core:** Improve light versioning support in declarative node design ([#4254](https://github.com/n8n-io/n8n/issues/4254)) ([1b320cd](https://github.com/n8n-io/n8n/commit/1b320cd8c9b1e00257c03f92a175e3c9ab9f8030))
* **Crypto Node:** Add SHA3 support ([#4285](https://github.com/n8n-io/n8n/issues/4285)) ([9407fdd](https://github.com/n8n-io/n8n/commit/9407fddd21295b7bdf2757736b69b046a02e798c))
* **editor:** JSON mapping ([#4270](https://github.com/n8n-io/n8n/issues/4270)) ([19e333e](https://github.com/n8n-io/n8n/commit/19e333e6602648feacd80277e170d8af38ce06c4))
* **Venafi TLS Protect Cloud Node:** Add Venafi TLS Protect Cloud ([#4253](https://github.com/n8n-io/n8n/issues/4253)) ([d36e920](https://github.com/n8n-io/n8n/commit/d36e920997d55957385e4ab4d6734639a4c28648))
* **Venafi TLS Protect Datacenter Node:** Add Venafi TLS Protect Datacenter node ([#4255](https://github.com/n8n-io/n8n/issues/4255)) ([a14110e](https://github.com/n8n-io/n8n/commit/a14110e663caca8e886312a116805c41020ba812))
### Performance Improvements
* **tooling:** Upgrade to TypeScript 4.8 ([#4207](https://github.com/n8n-io/n8n/issues/4207)) ([9089dbe](https://github.com/n8n-io/n8n/commit/9089dbe94220f1789d2cea74608352a070e09bac))
# [0.196.0](https://github.com/n8n-io/n8n/compare/n8n@0.195.5...n8n@0.196.0) (2022-09-30)
### Bug Fixes
* **build:** Add typing for SSE channel ([#4196](https://github.com/n8n-io/n8n/issues/4196)) ([eaf13cd](https://github.com/n8n-io/n8n/commit/eaf13cdf759497816255926ccc4a60f176d36a1a))
* **build:** Fix lint issue to fix build ([#4232](https://github.com/n8n-io/n8n/issues/4232)) ([40795d6](https://github.com/n8n-io/n8n/commit/40795d6adf383ec09290ca2a9da7e6ebeeaffb03))
* **Trello Node:** cardId property not showing up for completed checklist in Trello ([#4186](https://github.com/n8n-io/n8n/issues/4186)) ([05d2275](https://github.com/n8n-io/n8n/commit/05d227571d53a93380aab05444c5de38e448a317))
* **cli:** Add git to all docker images ([#4189](https://github.com/n8n-io/n8n/issues/4189)) ([0b6a958](https://github.com/n8n-io/n8n/commit/0b6a9585d41992f5dcc1a5683adc3f36e43955af))
* **cli:** Disable `X-Powered-By: Express` Header ([#4224](https://github.com/n8n-io/n8n/issues/4224)) ([a8da9c3](https://github.com/n8n-io/n8n/commit/a8da9c31a95dabbbdc4eb67e5157dd5631ff3031))
* **cli:** Disable CORS on SSE connections in production ([#4190](https://github.com/n8n-io/n8n/issues/4190)) ([e6e4f29](https://github.com/n8n-io/n8n/commit/e6e4f297c697c3371743bc1e1b2524235c4aea19))
* **core:** Remove commented out lines ([6ac442a](https://github.com/n8n-io/n8n/commit/6ac442a2accdeb4e51a3333ac6c45c8bfde0608d))
* delete unused dependencies ([#4231](https://github.com/n8n-io/n8n/issues/4231)) ([737cbf9](https://github.com/n8n-io/n8n/commit/737cbf9694296b76bc6c19716ffd6d4dcccf1c18))
* **editor:** Add missing event handler to accordion component ([#4179](https://github.com/n8n-io/n8n/issues/4179)) ([e709cb5](https://github.com/n8n-io/n8n/commit/e709cb5fe28839cf314a511a5a40f374a8ad4647))
* **editor:** Fix storybook setup ([#4234](https://github.com/n8n-io/n8n/issues/4234)) ([43dc8e6](https://github.com/n8n-io/n8n/commit/43dc8e6da1970d7ea4bb67635c8b20354150c87d))
* **editor:** Fix `BASE_URL` replacement on windows ([#4202](https://github.com/n8n-io/n8n/issues/4202)) ([5f0c656](https://github.com/n8n-io/n8n/commit/5f0c65690b8dddd21f5a694d6e74980296c7fbb8))
* **editor:** Fix ParameterInput inputField ref focus ([#4215](https://github.com/n8n-io/n8n/issues/4215)) ([ed40397](https://github.com/n8n-io/n8n/commit/ed403972a929c710180b2ac47fa4057ec47c4a35))
* **editor:** Make lodash aliases work on case-sensitive filesystems ([#4233](https://github.com/n8n-io/n8n/issues/4233)) ([a381729](https://github.com/n8n-io/n8n/commit/a3817291d7795345542b63641e265fe8f29e8750))
* **editor:** Fix copy-pasting workflow into pin data code editor ([#4193](https://github.com/n8n-io/n8n/issues/4193)) ([a4f9f04](https://github.com/n8n-io/n8n/commit/a4f9f041a07bea641c09d517942393c24d5e4a37))
* **editor:** Fix run data footer overflow ([#4175](https://github.com/n8n-io/n8n/issues/4175)) ([20b0e14](https://github.com/n8n-io/n8n/commit/20b0e14f728cd9b77e993ee15e3bd276b102e427))
* **editor:** Fix run data pagination selector not showing ([#4187](https://github.com/n8n-io/n8n/issues/4187)) ([2b3a090](https://github.com/n8n-io/n8n/commit/2b3a0901aa07046dc68cc6ece6c015819835cfd4))
* **editor:** Fix run selector not opening ([#4199](https://github.com/n8n-io/n8n/issues/4199)) ([67513e1](https://github.com/n8n-io/n8n/commit/67513e191d82dfa97a477e38770fe610dd9fca65))
* **editor:** Updating leftover i18n references in NodeView ([#4236](https://github.com/n8n-io/n8n/issues/4236)) ([068c5db](https://github.com/n8n-io/n8n/commit/068c5db1eecd60d650c3646f62eeadfad42df470))
* **editor:** Updating wrong i18n string reference ([#4209](https://github.com/n8n-io/n8n/issues/4209)) ([80e2d65](https://github.com/n8n-io/n8n/commit/80e2d65933101e69dee98ba69e80156f2ad3b7a9))
* **editor:** Fix slow loading times for nodeTypes, node creator vuex reference, and pushConnection in settings views ([#4230](https://github.com/n8n-io/n8n/issues/4230)) ([d3c0d99](https://github.com/n8n-io/n8n/commit/d3c0d998679965f53fb170e0f476f7bd17665645))
* **Merge Node:** Update description in merge node ([47eb531](https://github.com/n8n-io/n8n/commit/47eb531e980b1998fdaaece5cf533dc3903dc796))
* **core:** Fix and harmonize all primaryDocumentation links ([#4191](https://github.com/n8n-io/n8n/issues/4191)) ([6e8e4f5](https://github.com/n8n-io/n8n/commit/6e8e4f5937eb257efcbb4ff37c6b9403a044eecf))
* **core:** Remove --forceExit flag from cli tests ([#4211](https://github.com/n8n-io/n8n/issues/4211)) ([faaeb52](https://github.com/n8n-io/n8n/commit/faaeb52a14a40b30ffe90cddb84c45af55acdf93))
* **Wekan Node:** Fix authentication with new versions of Wekan ([#4088](https://github.com/n8n-io/n8n/issues/4088)) ([764bd35](https://github.com/n8n-io/n8n/commit/764bd3522b72d6188f2425df0710d16c5b34a20b))
* **Wufoo Trigger Node:** Fix form names not being listed correctly ([#4151](https://github.com/n8n-io/n8n/issues/4151)) ([616d62a](https://github.com/n8n-io/n8n/commit/616d62aa8ef64952eb248b162176460a7ac65cc3))
### Features
* **editor:** Add support for unit testing using vitest in editor-ui ([#4184](https://github.com/n8n-io/n8n/issues/4184)) ([bb66e60](https://github.com/n8n-io/n8n/commit/bb66e60afcbf120f3f916339c983b881ea185487))
* **cli:** Optimise serving static assets ([#4182](https://github.com/n8n-io/n8n/issues/4182)) ([8b0ccc0](https://github.com/n8n-io/n8n/commit/8b0ccc017bab28903d57a91602331981e45077d9))
* **core:** Improve paired item and add additional variables ([#3765](https://github.com/n8n-io/n8n/issues/3765)) ([5526057](https://github.com/n8n-io/n8n/commit/5526057efc7d27a1373dc2c46beda2737ed54689))
* **editor:** Update ResourceLocator error text ([#4242](https://github.com/n8n-io/n8n/issues/4242)) ([b0397f0](https://github.com/n8n-io/n8n/commit/b0397f0262f8a921a0552179ca95cba5f03295ce))
* **editor:** Main navigation redesign ([#4144](https://github.com/n8n-io/n8n/issues/4144)) ([3db53a1](https://github.com/n8n-io/n8n/commit/3db53a193418db2554e00d7499457d7f400663e1)), closes [#4060](https://github.com/n8n-io/n8n/issues/4060)
* **HTTP Request Node:** Redesign and add the ability to import cURL commands ([#3860](https://github.com/n8n-io/n8n/issues/3860)) ([f37d6ba](https://github.com/n8n-io/n8n/commit/f37d6ba03bcac82a50b2e9ee60c29d6a1a4be911))
* **editor:** Migrate editor-ui to Vite.js and various DX improvements (N8N-2277) ([#4061](https://github.com/n8n-io/n8n/issues/4061)) ([27e2ce0](https://github.com/n8n-io/n8n/commit/27e2ce047060ca8bfdef43cb7fe50b58c9508375)), closes [#4069](https://github.com/n8n-io/n8n/issues/4069)
* **n8n Api node:** Add core node for consuming the n8n API ([#4076](https://github.com/n8n-io/n8n/issues/4076)) ([929315f](https://github.com/n8n-io/n8n/commit/929315f9e4b56d975783b7d069bdb163218aa7d5))
* **RabbitMQ Trigger Node:** Automatically reconnect on disconnect ([#4019](https://github.com/n8n-io/n8n/issues/4019)) ([23bd71b](https://github.com/n8n-io/n8n/commit/23bd71b82aafb4d894091a115a168a049c5f594c))
* **core:** Share unshared credentials with owner on reset ([#4216](https://github.com/n8n-io/n8n/issues/4216)) ([3b7de6d](https://github.com/n8n-io/n8n/commit/3b7de6db725cffbd5ee9f06aee00029d984fe7b8))
* **Slack Node:** Add operation get many for user resource ([#3150](https://github.com/n8n-io/n8n/issues/3150)) ([2714b4c](https://github.com/n8n-io/n8n/commit/2714b4ced786212906f79c11fae28819aae420e4))
* **WhatsApp Business node:** Add WhatsApp node ([#3659](https://github.com/n8n-io/n8n/issues/3659)) ([f63710a](https://github.com/n8n-io/n8n/commit/f63710a8923bd742f3259822870f3a2f0b7e04aa))
## [0.195.5](https://github.com/n8n-io/n8n/compare/n8n@0.195.4...n8n@0.195.5) (2022-09-23)
### Bug Fixes
* **editor:** Fix extract value logic for expressions ([#4178](https://github.com/n8n-io/n8n/issues/4178)) ([46f9562](https://github.com/n8n-io/n8n/commit/46f95622e38e0327c01927bc41f4ea3c413db466))
## [0.195.4](https://github.com/n8n-io/n8n/compare/n8n@0.195.3...n8n@0.195.4) (2022-09-22)
### Bug Fixes
* **core:** Fix resolve RL values in expressions ([#4173](https://github.com/n8n-io/n8n/issues/4173)) ([469c391](https://github.com/n8n-io/n8n/commit/469c391fee70479d8095a90e6eb525032a0e02a5))
### Features
* **editor-ui:** Resizable main panel ([#3980](https://github.com/n8n-io/n8n/issues/3980)) ([d01f7d4](https://github.com/n8n-io/n8n/commit/d01f7d4d93366054075fdfcadfdff5cf03913472)), closes [#3930](https://github.com/n8n-io/n8n/issues/3930)
## [0.195.3](https://github.com/n8n-io/n8n/compare/n8n@0.195.2...n8n@0.195.3) (2022-09-22)
### Bug Fixes
* **editor:** Fix expressions bug with numbers and booleans ([#4169](https://github.com/n8n-io/n8n/issues/4169)) ([19d08e6](https://github.com/n8n-io/n8n/commit/19d08e641896fa9b1c9edf04505eac213e1de71a))
* **MSSQL Node:** Support tdsVersion option ([89d2d10](https://github.com/n8n-io/n8n/commit/89d2d10c520482f47ddd755e76b0bdf3d45e6008))
## [0.195.2](https://github.com/n8n-io/n8n/compare/n8n@0.195.1...n8n@0.195.2) (2022-09-22)
### Bug Fixes
* **core:** Fix mysql migration ([#4166](https://github.com/n8n-io/n8n/issues/4166)) ([0aeb55d](https://github.com/n8n-io/n8n/commit/0aeb55dcfd6c107c67e4c974e3371e29e188310b))
## [0.195.1](https://github.com/n8n-io/n8n/compare/n8n@0.195.0...n8n@0.195.1) (2022-09-21)
### Bug Fixes
* **core:** Fix postgres migration ([#4164](https://github.com/n8n-io/n8n/issues/4164)) ([2598ec8](https://github.com/n8n-io/n8n/commit/2598ec8a3e7a7d4e444cd4767d5944fa691dd9e1))
# [0.195.0](https://github.com/n8n-io/n8n/compare/n8n@0.194.0...n8n@0.195.0) (2022-09-21)
### Bug Fixes
* **Box Node:** Fix issue with response data not being returned ([#4147](https://github.com/n8n-io/n8n/issues/4147)) ([3cfc5b5](https://github.com/n8n-io/n8n/commit/3cfc5b55abe6aba3b68ae27846cd18e3ec79b518))
* **cli:** Fix issue with n8n crashing when error in poll method ([#4008](https://github.com/n8n-io/n8n/issues/4008)) ([6c41b29](https://github.com/n8n-io/n8n/commit/6c41b29ad2c1fffc5710d06250037e2a278b9b4a))
* **editor:** Fix broken output panel for wait node executions ([#4156](https://github.com/n8n-io/n8n/issues/4156)) ([40ebbea](https://github.com/n8n-io/n8n/commit/40ebbeaefc3a8c0e730468cd8171590dc823106c))
* **core:** Prevent calls to constructor to forbid arbitrary code execution ([#4139](https://github.com/n8n-io/n8n/issues/4139)) ([a8030db](https://github.com/n8n-io/n8n/commit/a8030dbda5b17ee158ac7ef7f586f212698252f7))
* **HTTP Node:** Fix instance crashing when batching enabled ([#3902](https://github.com/n8n-io/n8n/issues/3902)) ([0ab89ad](https://github.com/n8n-io/n8n/commit/0ab89ad5d66c1082ec2464813a9622431fa7f230))
* **public-api:** Create correct OAuth2 credential schema ([#4111](https://github.com/n8n-io/n8n/issues/4111)) ([28ab4f6](https://github.com/n8n-io/n8n/commit/28ab4f66f096eb6ec483e344bffe98b9a81520c6))
* **Xero Node:** fix line amount types being ignored when creating new invoices ([#4146](https://github.com/n8n-io/n8n/issues/4146)) ([3e2e9e6](https://github.com/n8n-io/n8n/commit/3e2e9e6009301006be7c7e96444ff4bbf824358c))
### Features
* **editor:** Add resource locator parameter ([#3932](https://github.com/n8n-io/n8n/issues/3932)) ([ad73f89](https://github.com/n8n-io/n8n/commit/ad73f8995c34a664391dcc467aca55f44f4bde71))
* **cli:** User Management and Credentials sharing ([#3602](https://github.com/n8n-io/n8n/issues/3602)) ([97cd564](https://github.com/n8n-io/n8n/commit/97cd564f7b4c5ba1472e517e0d54897b2cabcc26))
### Performance Improvements
* **ci:** Cache npm dependencies ([#4138](https://github.com/n8n-io/n8n/issues/4138)) ([1bdc102](https://github.com/n8n-io/n8n/commit/1bdc102892e77f2723ffed383874092cf4e07810))
# [0.194.0](https://github.com/n8n-io/n8n/compare/n8n@0.193.5...n8n@0.194.0) (2022-09-15)
### Bug Fixes
* AWS credential testing issue ([#4107](https://github.com/n8n-io/n8n/issues/4107)) ([5130529](https://github.com/n8n-io/n8n/commit/51305290663dc4bc05cdbb075d685673217081f9))
* **cli,core:** Address Dependabot warnings [N8N-4121] ([#3883](https://github.com/n8n-io/n8n/issues/3883)) ([461848f](https://github.com/n8n-io/n8n/commit/461848fcc4a33b0adf9958bebb2557bfa15100d6))
* **cli:** Avoid scanning unnecessary directories on windows ([#4082](https://github.com/n8n-io/n8n/issues/4082)) ([84b56eb](https://github.com/n8n-io/n8n/commit/84b56eb48e727389189c517598aadadd6f2ccf23)), closes [#4007](https://github.com/n8n-io/n8n/issues/4007)
* **cli:** Load nodes and credentials on windows using the correct file-path ([#4084](https://github.com/n8n-io/n8n/issues/4084)) ([b6c1187](https://github.com/n8n-io/n8n/commit/b6c1187922ab6552e303c98341c5732ffa96c55f))
* **cli:** Password reset should trigger internal and external hooks ([#4066](https://github.com/n8n-io/n8n/issues/4066)) ([12507d3](https://github.com/n8n-io/n8n/commit/12507d39d68a2961c6e567b6b7d83759010918b0))
* **cli:** Use absolute paths for loading custom nodes and credentials ([#4099](https://github.com/n8n-io/n8n/issues/4099)) ([43c9f01](https://github.com/n8n-io/n8n/commit/43c9f019bd3e25215134970570c574da663dd3e0)), closes [#4082](https://github.com/n8n-io/n8n/issues/4082)
* **core & Function nodes:** Update function nodes to work with binary-data-mode 'filesystem'. ([#3845](https://github.com/n8n-io/n8n/issues/3845)) ([f6064ef](https://github.com/n8n-io/n8n/commit/f6064ef278bb481a78942af3af9675f29e59045b)), closes [#1](https://github.com/n8n-io/n8n/issues/1)
* **core:** Fix issue with returnJsonArray helper breaking nodes that return no data ([3de0e22](https://github.com/n8n-io/n8n/commit/3de0e228cb78f292ead4d0103040d2c00943deae))
* **core:** Fix node renaming in expressions ([381c09f](https://github.com/n8n-io/n8n/commit/381c09fa47212a12f6c7bc166ac641afd97c9681))
* **core:** Update oauth endpoints to use instance base url ([dd3ba96](https://github.com/n8n-io/n8n/commit/dd3ba963723fbdef7d4239f0890c0776bffd062e))
* **eslint:** Setup eslint to run on every package ([#4050](https://github.com/n8n-io/n8n/issues/4050)) ([69eb979](https://github.com/n8n-io/n8n/commit/69eb97999da0543308285ebc834f3454c2eea727))
* **GoogleBigQuery Node:** Fix empty response when creating records ([#4056](https://github.com/n8n-io/n8n/issues/4056)) ([9f92a4d](https://github.com/n8n-io/n8n/commit/9f92a4d681918cb8d9f0d5b0bd322b93da0ba3ef))
* **Hubspot Node:** Correct canvas name of HubSpot node ([#4054](https://github.com/n8n-io/n8n/issues/4054)) ([e1025e8](https://github.com/n8n-io/n8n/commit/e1025e888c56995d284e0b5889af2e93b57ad3eb))
* Issue with versioned nodes not loading properly ([#4094](https://github.com/n8n-io/n8n/issues/4094)) ([9e1fa4c](https://github.com/n8n-io/n8n/commit/9e1fa4c0459b0bebe725f5e6db84104bcd37690d))
* **MongoDB Node:** Update mongo driver to 4.9.1 ([#4095](https://github.com/n8n-io/n8n/issues/4095)) ([f70e6d2](https://github.com/n8n-io/n8n/commit/f70e6d23455b5b380ffb607100e0090203e31047))
* **node:** Google Cloud Storage linting rules ([36ec81f](https://github.com/n8n-io/n8n/commit/36ec81f62489a7bc3442e46048f92d2ae9de1ce7))
* **public-api:** Fix error updating workflow with property not defined in the schema ([#4089](https://github.com/n8n-io/n8n/issues/4089)) ([f40ae50](https://github.com/n8n-io/n8n/commit/f40ae501b4dca8f00db41d8fc07b496ad06cf10f))
* **typescript:** Use consistent typescript configs ([#4049](https://github.com/n8n-io/n8n/issues/4049)) ([9267e8f](https://github.com/n8n-io/n8n/commit/9267e8fb1283794e7ebc109772e584b0471bef27))
* **workflow:** Remove a few `ts-ignore` and `eslint-disable` ([#3958](https://github.com/n8n-io/n8n/issues/3958)) ([a73ac1d](https://github.com/n8n-io/n8n/commit/a73ac1d94f5081051d1280b7ebc467f22e3d100d))
### Features
* **Adalo Node:** Add Adalo node ([#3102](https://github.com/n8n-io/n8n/issues/3102)) ([9a59d0a](https://github.com/n8n-io/n8n/commit/9a59d0a5d10b83ed4642e59c16310a436fd92a7a))
* **cli:** Load all nodes and credentials code in isolation ([#3906](https://github.com/n8n-io/n8n/issues/3906)) ([b450e97](https://github.com/n8n-io/n8n/commit/b450e977a32944a5289db2553bf12bdef4e1d3b3))
* **core, editor-ui:** Introduce node deprecation ([#4103](https://github.com/n8n-io/n8n/issues/4103)) ([98ed207](https://github.com/n8n-io/n8n/commit/98ed2076072858109f5ed512786af61dff0314d6))
* **editor:** Implement HTML sanitization for Notification and Message components ([#4081](https://github.com/n8n-io/n8n/issues/4081)) ([ea2d18b](https://github.com/n8n-io/n8n/commit/ea2d18b66dba1393a0425b5074884b782f959e5c))
* **editor:** Show input number for multi-input nodes ([#4000](https://github.com/n8n-io/n8n/issues/4000)) ([8c95d6e](https://github.com/n8n-io/n8n/commit/8c95d6ec53b735cc322a3b5f2a5a78002ae8441a))
* **gmail:** Overhaul Gmail node + create gmail trigger ([#3734](https://github.com/n8n-io/n8n/issues/3734)) ([74304db](https://github.com/n8n-io/n8n/commit/74304db4e2ae66b82695244d07c6ff8a9ffe37cf))
* **Google Cloud Storage Node:** Add GCS Node with Bucket and Object operations ([1e963d8](https://github.com/n8n-io/n8n/commit/1e963d8e1ed6956e8af02e70da304211aa725ea1))
* **Merge Node:** Overhaul of merge node ([f1a5697](https://github.com/n8n-io/n8n/commit/f1a569791d5289ced8ac78d97452f6ad5bf8d1b8))
* **typescript:** Setup Typescript incremental builds ([#3876](https://github.com/n8n-io/n8n/issues/3876)) ([799676b](https://github.com/n8n-io/n8n/commit/799676b24d9ba5628dc875de1c0bbcf7e51a51cc))
## [0.193.5](https://github.com/n8n-io/n8n/compare/n8n@0.193.4...n8n@0.193.5) (2022-09-07)
### Bug Fixes
* **editor:** Disable editing in Function nodes in executions view ([#4041](https://github.com/n8n-io/n8n/issues/4041)) ([772836a](https://github.com/n8n-io/n8n/commit/772836abc7d81fce74547dd3644c45eaea9c0a75))
* **editor:** use correct attribute on button to make it full width ([#4048](https://github.com/n8n-io/n8n/issues/4048)) ([b26545d](https://github.com/n8n-io/n8n/commit/b26545d94c9b718e20580e511aab676e98de66dc))
* **editor:** Wrong popup title when "Click To Copy" on OAuth2 Redirect Url credentials ([#4043](https://github.com/n8n-io/n8n/issues/4043)) ([0acac35](https://github.com/n8n-io/n8n/commit/0acac355e1bfff326d3bb575d5b21f0004a0c792))
* **Gmail Node:** Fix node and improve helper so to avoid double wrapping in json key ([#4052](https://github.com/n8n-io/n8n/issues/4052)) ([fbd044b](https://github.com/n8n-io/n8n/commit/fbd044bf874f270c9f9e7cda9aaecdc235ddc677))
## [0.193.4](https://github.com/n8n-io/n8n/compare/n8n@0.193.3...n8n@0.193.4) (2022-09-06)
### Bug Fixes
* **AWS Nodes:** Handle query string and body properly for AWS related requests ([#4039](https://github.com/n8n-io/n8n/issues/4039)) ([103f04e](https://github.com/n8n-io/n8n/commit/103f04e4eba08a1cd888e71073cf24178a2b52ba))
* **AWS Lambda Node:** Fix json data being sent to AWS Lambda as string ([#4029](https://github.com/n8n-io/n8n/issues/4029)) ([c28f69b](https://github.com/n8n-io/n8n/commit/c28f69b276fe46c42dfb62753b565ebae37431f5))
* **Beeminder Node:** Fix request id not being sent when creating a new datapoint ([73c5210](https://github.com/n8n-io/n8n/commit/73c52102949274c4c67ae34c458a6afa9520c150))
* **cli:** Include "auth-excluded" endpoints on the history middleware as well ([#4028](https://github.com/n8n-io/n8n/issues/4028)) ([d554128](https://github.com/n8n-io/n8n/commit/d55412845784fda4d42a1dcaca60515ad10d2aa0))
* **core:** Fix MySQL migration issue with table prefix ([#4013](https://github.com/n8n-io/n8n/issues/4013)) ([fc6484b](https://github.com/n8n-io/n8n/commit/fc6484ba4d48363fd846d5c800a25a207082f58d))
* Correct all the spelling typos ([#3960](https://github.com/n8n-io/n8n/issues/3960)) ([49c85a1](https://github.com/n8n-io/n8n/commit/49c85a1df8417918797c3fe6db46f35f9fe86bdf))
* Fix n8n-square-button import. ([#4024](https://github.com/n8n-io/n8n/issues/4024)) ([bbd967b](https://github.com/n8n-io/n8n/commit/bbd967bbdfb744874eeae5aced7ce122039b59d5))
* **GitHub Node:** Fix binary data not being returned ([#4017](https://github.com/n8n-io/n8n/issues/4017)) ([5753110](https://github.com/n8n-io/n8n/commit/575311040261be2982a3c7107bf1ea8b7b63fbb5))
* **GraphQL Node:** Fix issue with return items ([#4016](https://github.com/n8n-io/n8n/issues/4016)) ([6216132](https://github.com/n8n-io/n8n/commit/6216132ae2f3b908aacf266f4a34143bb8a74f0a))
* **Postgres Node:** Fix ssue with postgres insert and paired item ([#4020](https://github.com/n8n-io/n8n/issues/4020)) ([9314086](https://github.com/n8n-io/n8n/commit/9314086b6a84ce0f24992827ab316dee4709d118))
* **Kafka Trigger Node:** fix kafka trigger not working with default max requests value ([71cae90](https://github.com/n8n-io/n8n/commit/71cae90679d9d6fe4cf0dc898827cc9cd4457873))
* **MonicaCrm Node:** Fix pagination when using return all ([82827d0](https://github.com/n8n-io/n8n/commit/82827d0a12e889b2fdebd422bd1fcb483860599e))
* **Node Gmail:** Fix bug related to paired items ([2746905](https://github.com/n8n-io/n8n/commit/2746905570c2056abf9c388cc28c7d1d7b9f5102))
* **Raindrop Node:** Fix issue refreshing OAuth2 credentials ([3163742](https://github.com/n8n-io/n8n/commit/3163742fd7ae0afa86919e5f473be3d2bd88282b))
* **Shopify Node:** Fix pagination when empty fields are sent ([071ab40](https://github.com/n8n-io/n8n/commit/071ab40c9fa523b8ee47c9428ee6078e43985816))
### Features
* Add possibility to configure stop time for workers ([#4012](https://github.com/n8n-io/n8n/issues/4012)) ([a3791c2](https://github.com/n8n-io/n8n/commit/a3791c22b3f0be16324e1223aa719e6f122a51c1))
* **cli:** Add external hooks for when members are added or deleted ([#3988](https://github.com/n8n-io/n8n/issues/3988)) ([6be9997](https://github.com/n8n-io/n8n/commit/6be999714f62f22ec5d8ab82f91f7fc5a2b55c4d))
* **editor:** Use i18n component instead od v-html for localization ([287533e](https://github.com/n8n-io/n8n/commit/287533e6c819329dc84f2e23a33faed66181d07a))
## [0.193.3](https://github.com/n8n-io/n8n/compare/n8n@0.193.2...n8n@0.193.3) (2022-09-01)
### Bug Fixes
* **cli:** Initialize mailer just if connection can be verified ([#3997](https://github.com/n8n-io/n8n/issues/3997)) ([936cb11](https://github.com/n8n-io/n8n/commit/936cb117895695f9519f0debb3bcac275d98eda8))
* **core:** Fix disabled parent output in partial execution ([#3946](https://github.com/n8n-io/n8n/issues/3946)) ([c8743ff](https://github.com/n8n-io/n8n/commit/c8743ff6cad1563d31d4d39ffa742726830a4f38))
* **nodes:** Remove duplicate wrap of paired item data ([#4001](https://github.com/n8n-io/n8n/issues/4001)) ([54efe20](https://github.com/n8n-io/n8n/commit/54efe20ee4834fbf9306be161b36f115b9eb0834))
### Features
* **nodes:** Add database and non http credentials test ([d82e879](https://github.com/n8n-io/n8n/commit/d82e87979dc0fe47e264b0e7bb46c325157d9603))
* **Mongo DB Node:** Add MongoDB credential testing and two operations ([#3901](https://github.com/n8n-io/n8n/issues/3901)) ([b5511e5](https://github.com/n8n-io/n8n/commit/b5511e5ac7745c6b4a20aa49d2633f2f91bdbb7b))
## [0.193.2](https://github.com/n8n-io/n8n/compare/n8n@0.193.1...n8n@0.193.2) (2022-09-01)
### Bug Fixes
* **docker:** n8n docker image needs su-exec ([#3993](https://github.com/n8n-io/n8n/issues/3993)) ([aec2489](https://github.com/n8n-io/n8n/commit/aec2489aefb8fca522302bdcaa002fa62393b70a))
* **docker:** Revert docker `USER` and `WORKDIR` changes ([#3992](https://github.com/n8n-io/n8n/issues/3992)) ([34a99fd](https://github.com/n8n-io/n8n/commit/34a99fd089a754170ed4f2b9bdc02fc951d7e9bc))
* **core:** Fix OAuth2 issues ([#3391](https://github.com/n8n-io/n8n/pull/3991))
## [0.193.1](https://github.com/n8n-io/n8n/compare/n8n@0.193.0...n8n@0.193.1) (2022-08-31)
### Bug Fixes
* **editor:** Fix bug where col headers don't show ([#3985](https://github.com/n8n-io/n8n/issues/3985)) ([bee3840](https://github.com/n8n-io/n8n/commit/bee38400505b8862a4e1e5bf28b18088ff8ced8f))
# [0.193.0](https://github.com/n8n-io/n8n/compare/n8n@0.192.2...n8n@0.193.0) (2022-08-31)
### Bug Fixes
* **ci:** Setup a separate workflow action to test for pushes on master ([#3951](https://github.com/n8n-io/n8n/issues/3951)) ([1f9bdd0](https://github.com/n8n-io/n8n/commit/1f9bdd09a29a5e0564ddc874814eaf36d9380ee7))
* **core:** Make digest auth work with query params ([087d3f9](https://github.com/n8n-io/n8n/commit/087d3f99f1f5c38db763686c10c6181e20c08307))
* **editor:** Sending data as query on DELETE method ([#3972](https://github.com/n8n-io/n8n/issues/3972)) ([fc2ff35](https://github.com/n8n-io/n8n/commit/fc2ff35c412b1c10471659c91dc0fe11a3363495))
* Fix credentials_entity table migration for mysql ([#3979](https://github.com/n8n-io/n8n/issues/3979)) ([349826e](https://github.com/n8n-io/n8n/commit/349826e87fdb03a9f378422ecfac83d42bb5a376))
* **npm:** Improve .npmignore to reduce the size of the published packages ([#3970](https://github.com/n8n-io/n8n/issues/3970)) ([15d5ac6](https://github.com/n8n-io/n8n/commit/15d5ac6f3c7732374f07726c5697ba341eb9aa70))
### Features
* **design-system,editor-ui:** Upgrade some of the frontend dev dependencies ([#3978](https://github.com/n8n-io/n8n/issues/3978)) ([b428e9f](https://github.com/n8n-io/n8n/commit/b428e9fb9ffb506c97f91d45072e32241a3b07d6))
* **docker:** Reduce the size of alpine docker images ([#3973](https://github.com/n8n-io/n8n/issues/3973)) ([398adb2](https://github.com/n8n-io/n8n/commit/398adb23e8785c92478c4d80c944e60e9278ffdf))
* **editor:** Limit when to show mapping tooltip ([#3976](https://github.com/n8n-io/n8n/issues/3976)) ([8fc9f07](https://github.com/n8n-io/n8n/commit/8fc9f07f39edf8944214200dd787b2d0c9b6caff))
* **HighLevel Node:** Add HighLevel node ([c2e97a8](https://github.com/n8n-io/n8n/commit/c2e97a89f923bbebe0a6d882e86d792fcda3116d))
## [0.192.2](https://github.com/n8n-io/n8n/compare/n8n@0.192.1...n8n@0.192.2) (2022-08-25)
### Bug Fixes
* **editor:** Fix feature flag check when PH is unavailable ([#3944](https://github.com/n8n-io/n8n/issues/3944)) ([93c26da](https://github.com/n8n-io/n8n/commit/93c26dac286e8fa984cb6fb6fecd6167fc4143f3))
* **editor:** fix mapping bug when val is null ([#3942](https://github.com/n8n-io/n8n/issues/3942)) ([a21dbdc](https://github.com/n8n-io/n8n/commit/a21dbdc45b6f434f7ecd8b541bb32d397fd95c89))
## [0.192.1](https://github.com/n8n-io/n8n/compare/n8n@0.192.0...n8n@0.192.1) (2022-08-25)
### Bug Fixes
* **cli:** Account for non-array in pindata migration ([#3938](https://github.com/n8n-io/n8n/issues/3938)) ([f052187](https://github.com/n8n-io/n8n/commit/f0521873e1acf8c6491b75f37be1dd824bb355bc))
# [0.192.0](https://github.com/n8n-io/n8n/compare/n8n@0.191.1...n8n@0.192.0) (2022-08-24)
### Bug Fixes
* **cli:** Account for unparseable string in JSON key migration ([#3927](https://github.com/n8n-io/n8n/issues/3927)) ([ab45898](https://github.com/n8n-io/n8n/commit/ab45898a69dd9354cdb365187dec0d58a1836418))
* **cli:** Fix excessive instantiation type error for flattened execution ([#3921](https://github.com/n8n-io/n8n/issues/3921)) ([1d4f92a](https://github.com/n8n-io/n8n/commit/1d4f92a6575a7af6dbd4f03b61202cb56badf6a1))
* **cli:** Init nodes dir to ensure `npm install` succeeds ([#3934](https://github.com/n8n-io/n8n/issues/3934)) ([2d6eea8](https://github.com/n8n-io/n8n/commit/2d6eea82d324d4560f7445d87647ce0d5e87c678))
* **cli:** tsc build errors should fail turborepo builds as well ([#3923](https://github.com/n8n-io/n8n/issues/3923)) ([f22bd28](https://github.com/n8n-io/n8n/commit/f22bd2805d87c552d92d0da0313bf7f9c498f103))
* **core:** Account for enabled state in first pinned trigger ([#3912](https://github.com/n8n-io/n8n/issues/3912)) ([6bd7a09](https://github.com/n8n-io/n8n/commit/6bd7a09a455b61eae5edad1d93e8a7e00c0c68b3))
* **core:** Fix pinned trigger execution ([#3895](https://github.com/n8n-io/n8n/issues/3895)) ([17799cd](https://github.com/n8n-io/n8n/commit/17799cda46ad764f537d9546346ab4e04e36e681))
* **NextCloud Node:** Fix issue with credential verification and sharing file ([2b4f5c6](https://github.com/n8n-io/n8n/commit/2b4f5c6c785ab6ffc7198f60369886c44dea6ef2))
* **Freshdesk Node:** Fix issue when getAll operation requires non existent options ([329fe95](https://github.com/n8n-io/n8n/commit/329fe9581f63fe44daba5ef79724d9339cb8c813))
### Features
* **cli:** Notify external hooks about user profile and password changes ([#3919](https://github.com/n8n-io/n8n/issues/3919)) ([7d74dda](https://github.com/n8n-io/n8n/commit/7d74ddab29e05a81962fd80469248e8cee8bf9bf))
* **core, editor:** Support `pairedItem` for pinned data ([#3843](https://github.com/n8n-io/n8n/issues/3843)) ([b1e7152](https://github.com/n8n-io/n8n/commit/b1e715299d8a78188fad413392babdea7d044049))
* **core:** Add command to scripts for easy launch n8n with tunnel ([725a567](https://github.com/n8n-io/n8n/commit/725a567f07c08767f58d4ceb88386a9be694bfd2))
* **editor, core:** Integrate PostHog ([#3865](https://github.com/n8n-io/n8n/issues/3865)) ([43e054f](https://github.com/n8n-io/n8n/commit/43e054f5abae87b989ffe391a251961a2bc05542))
* **editor:** Map expressions from input table ([#3864](https://github.com/n8n-io/n8n/issues/3864)) ([ce076dc](https://github.com/n8n-io/n8n/commit/ce076dca48847562067c5149ecdd529fcc014e3f))
## [0.191.1](https://github.com/n8n-io/n8n/compare/n8n@0.191.0...n8n@0.191.1) (2022-08-19)
### Bug Fixes
* **editor:** Fix issue with disappearing connections after rename ([#3899](https://github.com/n8n-io/n8n/issues/3899)) ([ad0c214](https://github.com/n8n-io/n8n/commit/ad0c214f8ec2088ff30f408fe5ec51216468cdff))
# [0.191.0](https://github.com/n8n-io/n8n/compare/n8n@0.190.0...n8n@0.191.0) (2022-08-17)
### Bug Fixes
* **cli:** Fix community nodes tests on Postgres and MySQL ([#3861](https://github.com/n8n-io/n8n/issues/3861)) ([620525e](https://github.com/n8n-io/n8n/commit/620525ea85b7de24c0c5f3d3b57350a0a578d9b4))
* **core:** Fix issue with not displayed child workflow executions ([#3867](https://github.com/n8n-io/n8n/issues/3867)) ([f782bcd](https://github.com/n8n-io/n8n/commit/f782bcd52dbe364d1fca1bd29c9222f434df90ae))
* **editor:** Handling errors when opening settings and executions ([#3877](https://github.com/n8n-io/n8n/issues/3877)) ([762b422](https://github.com/n8n-io/n8n/commit/762b4224888cc5949eced048729fe313ec055f1c))
* **editor:** Improve expression and parameters performance ([#3874](https://github.com/n8n-io/n8n/issues/3874)) ([3608d13](https://github.com/n8n-io/n8n/commit/3608d132c0fbdb193758ba9a9c0f1da725d2313a))
* **public-api:** Fix executions pagination in Postgres and Mysql ([52015a6](https://github.com/n8n-io/n8n/commit/52015a6f033eae5c2ea9ac125a7c947d96ce7463))
### Features
* **cli:** Enable community nodes based on npm availability ([#3871](https://github.com/n8n-io/n8n/issues/3871)) ([936264b](https://github.com/n8n-io/n8n/commit/936264b3c6506cdc25b9ad55a23b314b2582275b))
* **editor:** Added animated tooltips to draggable columns in input panel ([054cc01](https://github.com/n8n-io/n8n/commit/054cc010edfc9f0f5cc72ac94f26afe52a66a192))
# [0.190.0](https://github.com/n8n-io/n8n/compare/n8n@0.189.1...n8n@0.190.0) (2022-08-10)
### Bug Fixes
* **core:** Fix crash caused by parallel test-webhook calls ([#3756](https://github.com/n8n-io/n8n/issues/3756)) ([8fe71db](https://github.com/n8n-io/n8n/commit/8fe71dba4bf568e70ed740ac3413aae77559ca3c))
* **core:** Fix issue that static data did not get saved for poll-triggers ([#3853](https://github.com/n8n-io/n8n/issues/3853)) ([8311abc](https://github.com/n8n-io/n8n/commit/8311abcf9d453f0d253c269e7d1c3842fcf8e256))
* **GitHub Trigger:** Fix typo ([#3859](https://github.com/n8n-io/n8n/issues/3859)) ([7b3d6de](https://github.com/n8n-io/n8n/commit/7b3d6de44eeb6cb066fb378c52fcc5aec60c4fdf))
* **public-api:** fix issue paginating executions ([b9fe707](https://github.com/n8n-io/n8n/commit/b9fe707cbd9df4a33b6040215826375bef238b65))
### Features
* Synchronize default VSCode settings ([#3833](https://github.com/n8n-io/n8n/issues/3833)) ([11461fd](https://github.com/n8n-io/n8n/commit/11461fda5fae10077ea9804b5cc9581074107005))
## [0.189.1](https://github.com/n8n-io/n8n/compare/n8n@0.189.0...n8n@0.189.1) (2022-08-05)
### Bug Fixes
- Fix issue with MySQL/MariaDB migration ([#3832](https://github.com/n8n-io/n8n/issues/3832))
# [0.189.0](https://github.com/n8n-io/n8n/compare/n8n@0.188.0...n8n@0.189.0) (2022-08-03)
### Bug Fixes
- **editor:** Fix label cut off ([#3820](https://github.com/n8n-io/n8n/issues/3820)) ([0f27be4](https://github.com/n8n-io/n8n/commit/0f27be4447662056a2ba13c027280830f7eab09b))
- Fix problem saving workflow when tags disabled ([#3792](https://github.com/n8n-io/n8n/issues/3792)) ([f0dddaa](https://github.com/n8n-io/n8n/commit/f0dddaa2a585715b35e26b16e1003e1683ab9402))
### Features
- **NocoDB Node:** Add support v0.90.0+ ([#3146](https://github.com/n8n-io/n8n/issues/3146)) ([d65a9ed](https://github.com/n8n-io/n8n/commit/d65a9ed118ff16c67b6d69d68108d8b7da1814d9))
- **SendInBlue Node:** Add SendInBlue Regular + Trigger Node ([#3746](https://github.com/n8n-io/n8n/issues/3746)) ([74cedd9](https://github.com/n8n-io/n8n/commit/74cedd94a82f0c053a24b6e925d9e3bcadcebfbc))
- Support community nodes on Windows ([#3823](https://github.com/n8n-io/n8n/issues/3823)) ([e8eda74](https://github.com/n8n-io/n8n/commit/e8eda7470a17deec1f5eab8cded6e74a8e3aee39))
# [0.188.0](https://github.com/n8n-io/n8n/compare/n8n@0.187.2...n8n@0.188.0) (2022-07-27)
### Bug Fixes
- **AWS DynamoDB Node:** Fix expression attribute names ([#3763](https://github.com/n8n-io/n8n/issues/3763)) ([88cb265](https://github.com/n8n-io/n8n/commit/88cb26556c162aa1281dfa6a9fa8eca4cd071e9d))
- **core:** Add windows support to import:credentials --separate ([#3589](https://github.com/n8n-io/n8n/issues/3589)) ([2fb590e](https://github.com/n8n-io/n8n/commit/2fb590e8440ac35567fdbf745b294d79feb8c5a9))
- **editor:** Fix linking buttons color ([#3770](https://github.com/n8n-io/n8n/issues/3770)) ([deb510a](https://github.com/n8n-io/n8n/commit/deb510a8e0057280da43f3b3e72d8acca5829745))
- **editor:** Fix pin data in executions when pinData is null. ([#3787](https://github.com/n8n-io/n8n/issues/3787)) ([30c0f21](https://github.com/n8n-io/n8n/commit/30c0f21b3f37280403848592877cb8658367b85e))
- **editor:** Fix spaces bug ([#3774](https://github.com/n8n-io/n8n/issues/3774)) ([02549e3](https://github.com/n8n-io/n8n/commit/02549e3ba9233a6d9f75fc1f9ff138e2aff7f4b9))
- **editor:** Fix sticky duplication and position bug ([#3755](https://github.com/n8n-io/n8n/issues/3755)) ([92614c8](https://github.com/n8n-io/n8n/commit/92614c81abfdbca51d4901b364467d3505870255))
- **editor:** Restore pindata header colors ([#3758](https://github.com/n8n-io/n8n/issues/3758)) ([1a7318b](https://github.com/n8n-io/n8n/commit/1a7318b4cf6081e5ba743117cf90ef6920625aa0))
- Fix node_type property in all events ([#3759](https://github.com/n8n-io/n8n/issues/3759)) ([1f1a63c](https://github.com/n8n-io/n8n/commit/1f1a63c39adc673259c951af3e5152c5edc34968))
- **Fix Rocketchat Node:** Fix authentication issue ([#3778](https://github.com/n8n-io/n8n/issues/3778)) ([2710061](https://github.com/n8n-io/n8n/commit/271006152386511c19feb54e438fa60966dbf705))
- **Mautic Node:** Fix authentication issue ([#3761](https://github.com/n8n-io/n8n/issues/3761)) ([fe58769](https://github.com/n8n-io/n8n/commit/fe58769b4830f388ad67ae1c32fcaa55aa0b848e))
### Features
- Improvements to pairedItem ([1348349](https://github.com/n8n-io/n8n/commit/13483497484e205975ef71091e3892f757f608e1))
- **Item List Node:** Add operation for creating array from input items ([#3149](https://github.com/n8n-io/n8n/issues/3149)) ([553b14a](https://github.com/n8n-io/n8n/commit/553b14a13c7c9056447ef0b18c9427f26221b44d))
- **Kafka Trigger Node:** Add additional options ([#3600](https://github.com/n8n-io/n8n/issues/3600)) ([3496a39](https://github.com/n8n-io/n8n/commit/3496a39788b654b46485955ba5cce5e5865babc7))
- **Metabase Node:** Add Metabase Node ([#3033](https://github.com/n8n-io/n8n/issues/3033)) ([81b5828](https://github.com/n8n-io/n8n/commit/81b58285588f142c0b1cc148f0092c462eefdd73))
## [0.187.2](https://github.com/n8n-io/n8n/compare/n8n@0.187.1...n8n@0.187.2) (2022-07-21)
### Bug Fixes
- **editor:** Fix console error ([#3751](https://github.com/n8n-io/n8n/issues/3751)) ([3a98028](https://github.com/n8n-io/n8n/commit/3a98028722d634f604a650d891cf6fabf722993d))
- **editor:** Fix login issue for non-admin users ([#3754](https://github.com/n8n-io/n8n/issues/3754)) ([ccd1ed2](https://github.com/n8n-io/n8n/commit/ccd1ed2c4c5153637a7900a79a40b1c4f53e7635))
- **editor:** Fix problems with credentials modal if no node is opened ([#3749](https://github.com/n8n-io/n8n/issues/3749)) ([5efe4a4](https://github.com/n8n-io/n8n/commit/5efe4a4c54211f1d395202c420403be3cc7e4446))
- **NocoDB Node:** Fix authentication issue ([#3750](https://github.com/n8n-io/n8n/issues/3750)) ([e65016c](https://github.com/n8n-io/n8n/commit/e65016c861176a7b17f23c5fbf3c0a3fcc1e5e1d))
## [0.187.1](https://github.com/n8n-io/n8n/compare/n8n@0.187.0...n8n@0.187.1) (2022-07-20)
### Bug Fixes
- **editor:** Fix issue that new nodes did not get automatically displayed in all connected browsers ([#3745](https://github.com/n8n-io/n8n/issues/3745)) ([34a9bee](https://github.com/n8n-io/n8n/commit/34a9beefa5b0f169f38ca48d3444af8f160c85a2))
# [0.187.0](https://github.com/n8n-io/n8n/compare/n8n@0.186.1...n8n@0.187.0) (2022-07-20)
### Bug Fixes
- **api:** Add missing node settings parameters ([#3737](https://github.com/n8n-io/n8n/issues/3737)) ([803e009](https://github.com/n8n-io/n8n/commit/803e0097fada1bf0385ac37965f0cc47bed28948))
- **api:** Validate static data value for resource workflow ([#3736](https://github.com/n8n-io/n8n/issues/3736)) ([7ba9a05](https://github.com/n8n-io/n8n/commit/7ba9a055cdeb2b0713857747a5b722dab65d3678))
- **Baserow Node:** Fix issue that table names are not getting pulled in new version ([#3721](https://github.com/n8n-io/n8n/issues/3721)) ([f65a5db](https://github.com/n8n-io/n8n/commit/f65a5db478da0da65735bdc5bb09774f1d473ec9))
- **editor:** Hide 'Execute previous node' button in readonly mode ([#3714](https://github.com/n8n-io/n8n/issues/3714)) ([7fb81dc](https://github.com/n8n-io/n8n/commit/7fb81dcd8a6c56e6e104be94278c690caf35c846))
- **editor:** Hide tabs if only 1 branch ([#3743](https://github.com/n8n-io/n8n/issues/3743)) ([fb67543](https://github.com/n8n-io/n8n/commit/fb67543b2f10c558abcacc5454d6fa0687ee4702))
- Fix broken links in nodes ([#3716](https://github.com/n8n-io/n8n/issues/3716)) ([c9b7b6d](https://github.com/n8n-io/n8n/commit/c9b7b6d30fe822bddb3d68e1b4757ffe654e918b))
### Features
- Add more credentials tests ([#3668](https://github.com/n8n-io/n8n/issues/3668)) ([683d2df](https://github.com/n8n-io/n8n/commit/683d2dfc98136503971a4beb1692e5ca191d5016))
- Add support for preAuthentication and add Metabase credentials ([#3399](https://github.com/n8n-io/n8n/issues/3399)) ([994c89a](https://github.com/n8n-io/n8n/commit/994c89a6c6ade5b99d6218c9776adc15c286b619))
- **core:** Autofix pairedItem information if inputItems(n) === outputItems(n) ([68fb1c6](https://github.com/n8n-io/n8n/commit/68fb1c64dca99fb603fe6d52fd50c4749a2ca898))
- **editor:** Add data pinning functionality ([#3511](https://github.com/n8n-io/n8n/issues/3511)) ([15693b0](https://github.com/n8n-io/n8n/commit/15693b0056097129a57dfc600807dbc5e1cc07f1)
- **editor:** Add drag and drop data mapping ([#3708](https://github.com/n8n-io/n8n/issues/3708)) ([577c73e](https://github.com/n8n-io/n8n/commit/577c73ee25c5bfc943ef5ed1de550fcb489f4998))
- **ERPNext Node:** Add credential test and add support for unauthorized certs ([#3732](https://github.com/n8n-io/n8n/issues/3732)) ([a02b206](https://github.com/n8n-io/n8n/commit/a02b20617071e1ca398735456cb416d6ab3f34a0)), closes [#3739](https://github.com/n8n-io/n8n/issues/3739)
- **Google Drive Node:** Add move to trash support ([#3693](https://github.com/n8n-io/n8n/issues/3693)) ([7406432](https://github.com/n8n-io/n8n/commit/74064325c892c5b506260e650d3361636b578b1e))
- Make it possible to dynamically load community nodes ([#2849](https://github.com/n8n-io/n8n/issues/2849)) ([c85faff](https://github.com/n8n-io/n8n/commit/c85faff4f1c6ba11c02cf5c14122d2c7341f3ec3)), closes [#3497](https://github.com/n8n-io/n8n/issues/3497) [#3501](https://github.com/n8n-io/n8n/issues/3501) [#3527](https://github.com/n8n-io/n8n/issues/3527) [#3562](https://github.com/n8n-io/n8n/issues/3562)
- **Mindee Node:** Add support for new version ([#3596](https://github.com/n8n-io/n8n/issues/3596)) ([1965407](https://github.com/n8n-io/n8n/commit/1965407030638cc309c99d344121f47805c93799))
- **Notion Node:** Allow to ignore Notion URL properties if empty ([#3564](https://github.com/n8n-io/n8n/issues/3564)) ([6cb9aef](https://github.com/n8n-io/n8n/commit/6cb9aefb0b3e4d17382042371a20e63f23641581))
- **Shopify Node:** Add OAuth support ([#3389](https://github.com/n8n-io/n8n/issues/3389)) ([945e25a](https://github.com/n8n-io/n8n/commit/945e25a77cf9ba33bc3e4b70053319ea86230cf7))
## [0.186.1](https://github.com/n8n-io/n8n/compare/n8n@0.186.0...n8n@0.186.1) (2022-07-14)
### Bug Fixes
- **Airtable Node:** Fix authentication issue ([#3709](https://github.com/n8n-io/n8n/issues/3709)) ([33d8042](https://github.com/n8n-io/n8n/commit/33d804284ae02140749ab94eecfca1699e13afee))
# [0.186.0](https://github.com/n8n-io/n8n/compare/n8n@0.185.0...n8n@0.186.0) (2022-07-13)
### Bug Fixes
* **editor:** Fix error after multiple executions ([#3697](https://github.com/n8n-io/n8n/issues/3697)) ([d200661](https://github.com/n8n-io/n8n/commit/d200661b84c36b3f04d812cf022bb338f9664392))
* **EmailReadImap Node:** Improve handling of network problems ([#3406](https://github.com/n8n-io/n8n/issues/3406)) ([6f5809e](https://github.com/n8n-io/n8n/commit/6f5809edb3f9cac0c29d448300b37ab9b6e74c08))
* **Google Drive Node:** Process all input items with List operation ([#3525](https://github.com/n8n-io/n8n/issues/3525)) ([ece1836](https://github.com/n8n-io/n8n/commit/ece1836c45707d349330f742eb3b83fa1f4eaebb))
* **Telegram Node:** Fix sending binaryData media (photo, document, video etc.) ([#3408](https://github.com/n8n-io/n8n/issues/3408)) ([af45a07](https://github.com/n8n-io/n8n/commit/af45a07f21d8448bad5c12ed702b7aa983017a2b))
- **editor:** Fix error after multiple executions ([#3697](https://github.com/n8n-io/n8n/issues/3697)) ([d200661](https://github.com/n8n-io/n8n/commit/d200661b84c36b3f04d812cf022bb338f9664392))
- **EmailReadImap Node:** Improve handling of network problems ([#3406](https://github.com/n8n-io/n8n/issues/3406)) ([6f5809e](https://github.com/n8n-io/n8n/commit/6f5809edb3f9cac0c29d448300b37ab9b6e74c08))
- **Google Drive Node:** Process all input items with List operation ([#3525](https://github.com/n8n-io/n8n/issues/3525)) ([ece1836](https://github.com/n8n-io/n8n/commit/ece1836c45707d349330f742eb3b83fa1f4eaebb))
- **Telegram Node:** Fix sending binaryData media (photo, document, video etc.) ([#3408](https://github.com/n8n-io/n8n/issues/3408)) ([af45a07](https://github.com/n8n-io/n8n/commit/af45a07f21d8448bad5c12ed702b7aa983017a2b))
### Features
* Add item information to more node errors ([#3681](https://github.com/n8n-io/n8n/issues/3681)) ([2a8043c](https://github.com/n8n-io/n8n/commit/2a8043cd27968b92b1857135d130e3ee54aae779))
* **AWS DynamoDB Node:** Improve error handling + add optional GetAll Scan FilterExpression ([#3318](https://github.com/n8n-io/n8n/issues/3318)) ([732c8fc](https://github.com/n8n-io/n8n/commit/732c8fcf8488fc35839855499f75202436fc4c9a))
* **Customer.io Node:** Add support for tracking API region selection ([#3378](https://github.com/n8n-io/n8n/issues/3378)) ([82a254a](https://github.com/n8n-io/n8n/commit/82a254a8d9295901e42ec999432a7f5b40f38281))
* **Elasticsearch Node:** Add 'Source Excludes' and 'Source Includes' options on 'Document: getAll' operation ([#3660](https://github.com/n8n-io/n8n/issues/3660)) ([8999403](https://github.com/n8n-io/n8n/commit/899940322831612bdf6e59db7f696c34f96cd496))
* **Elasticsearch Node:** Add credential tests, index pipelines and index refresh ([#2420](https://github.com/n8n-io/n8n/issues/2420))
* **Freshworks CRM Node:** Add Search + Lookup functionality ([#3131](https://github.com/n8n-io/n8n/issues/3131)) ([dbc0280](https://github.com/n8n-io/n8n/commit/dbc02803db5351d759b1420e94b14f2c7c8b1bef))
* **Jira Trigger Node:** Add optional query auth for security ([#3172](https://github.com/n8n-io/n8n/issues/3172)) ([25093b6](https://github.com/n8n-io/n8n/commit/25093b64e693a33a76efd1bd12f00ce0d4cc0f3c))
* **Postgres Node:** Improvement handling of large numbers ([#3360](https://github.com/n8n-io/n8n/issues/3360)) ([9f908e7](https://github.com/n8n-io/n8n/commit/9f908e7405d687bf57391e503ad724d58caaac07))
* **Redis Node:** Add push and pop operations ([#3127](https://github.com/n8n-io/n8n/issues/3127)) ([32c68eb](https://github.com/n8n-io/n8n/commit/32c68eb126f8411d1a3261dc8a900c109b99da6f))
* **Rename Node:** Add regex replace ([#2576](https://github.com/n8n-io/n8n/issues/2576)) ([eae9a60](https://github.com/n8n-io/n8n/commit/eae9a60a431bc08fb58016e3249328abb90716b0))
* **SpreadsheetFile Node:** Allow skipping headers when writing spreadsheets ([#3234](https://github.com/n8n-io/n8n/issues/3234)) ([dbfb8d5](https://github.com/n8n-io/n8n/commit/dbfb8d56dc6290837701dea5957d4e73db418892))
* Updated multiple credentials with tests and allow to be used on HTTP Request Node ([#3670](https://github.com/n8n-io/n8n/issues/3670)) ([d5d4dd3](https://github.com/n8n-io/n8n/commit/d5d4dd38450b788ee0ce3ed8ad0eb714c86977d2))
- Add item information to more node errors ([#3681](https://github.com/n8n-io/n8n/issues/3681)) ([2a8043c](https://github.com/n8n-io/n8n/commit/2a8043cd27968b92b1857135d130e3ee54aae779))
- **AWS DynamoDB Node:** Improve error handling + add optional GetAll Scan FilterExpression ([#3318](https://github.com/n8n-io/n8n/issues/3318)) ([732c8fc](https://github.com/n8n-io/n8n/commit/732c8fcf8488fc35839855499f75202436fc4c9a))
- **Customer.io Node:** Add support for tracking API region selection ([#3378](https://github.com/n8n-io/n8n/issues/3378)) ([82a254a](https://github.com/n8n-io/n8n/commit/82a254a8d9295901e42ec999432a7f5b40f38281))
- **Elasticsearch Node:** Add 'Source Excludes' and 'Source Includes' options on 'Document: getAll' operation ([#3660](https://github.com/n8n-io/n8n/issues/3660)) ([8999403](https://github.com/n8n-io/n8n/commit/899940322831612bdf6e59db7f696c34f96cd496))
- **Elasticsearch Node:** Add credential tests, index pipelines and index refresh ([#2420](https://github.com/n8n-io/n8n/issues/2420))
- **Freshworks CRM Node:** Add Search + Lookup functionality ([#3131](https://github.com/n8n-io/n8n/issues/3131)) ([dbc0280](https://github.com/n8n-io/n8n/commit/dbc02803db5351d759b1420e94b14f2c7c8b1bef))
- **Jira Trigger Node:** Add optional query auth for security ([#3172](https://github.com/n8n-io/n8n/issues/3172)) ([25093b6](https://github.com/n8n-io/n8n/commit/25093b64e693a33a76efd1bd12f00ce0d4cc0f3c))
- **Postgres Node:** Improvement handling of large numbers ([#3360](https://github.com/n8n-io/n8n/issues/3360)) ([9f908e7](https://github.com/n8n-io/n8n/commit/9f908e7405d687bf57391e503ad724d58caaac07))
- **Redis Node:** Add push and pop operations ([#3127](https://github.com/n8n-io/n8n/issues/3127)) ([32c68eb](https://github.com/n8n-io/n8n/commit/32c68eb126f8411d1a3261dc8a900c109b99da6f))
- **Rename Node:** Add regex replace ([#2576](https://github.com/n8n-io/n8n/issues/2576)) ([eae9a60](https://github.com/n8n-io/n8n/commit/eae9a60a431bc08fb58016e3249328abb90716b0))
- **SpreadsheetFile Node:** Allow skipping headers when writing spreadsheets ([#3234](https://github.com/n8n-io/n8n/issues/3234)) ([dbfb8d5](https://github.com/n8n-io/n8n/commit/dbfb8d56dc6290837701dea5957d4e73db418892))
- Updated multiple credentials with tests and allow to be used on HTTP Request Node ([#3670](https://github.com/n8n-io/n8n/issues/3670)) ([d5d4dd3](https://github.com/n8n-io/n8n/commit/d5d4dd38450b788ee0ce3ed8ad0eb714c86977d2))
# [0.185.0](https://github.com/n8n-io/n8n/compare/n8n@0.184.0...n8n@0.185.0) (2022-07-05)
### Bug Fixes
* **Hubspot Node:** Fix search endpoints ([#3640](https://github.com/n8n-io/n8n/issues/3640)) ([16b9926](https://github.com/n8n-io/n8n/commit/16b9926cd25abf4a2ae4c9eba494340eab58082f))
* **KoboToolbox Node:** Improve attachment matching logic and GeoJSON Polygon format ([#3535](https://github.com/n8n-io/n8n/issues/3535)) ([637e815](https://github.com/n8n-io/n8n/commit/637e81552f86788058567342cf69e2784e3d6b2f))
* **Odoo Node:** Prevent possible issues with some custom fields ([#3496](https://github.com/n8n-io/n8n/issues/3496)) ([7d968ec](https://github.com/n8n-io/n8n/commit/7d968ec202ceccc6a009ec150747cc927273f841))
* **Sticky Node:** Fix main header hiding ([#3654](https://github.com/n8n-io/n8n/issues/3654)) ([88486bc](https://github.com/n8n-io/n8n/commit/88486bc778786d4a47ef1bb5c743c9fb206aee01))
* **Todoist Node:** Fix multiple item support ([#3614](https://github.com/n8n-io/n8n/issues/3614)) ([7ba85c4](https://github.com/n8n-io/n8n/commit/7ba85c4ab910ed02696078ece12c88f2141cccad))
- **Hubspot Node:** Fix search endpoints ([#3640](https://github.com/n8n-io/n8n/issues/3640)) ([16b9926](https://github.com/n8n-io/n8n/commit/16b9926cd25abf4a2ae4c9eba494340eab58082f))
- **KoboToolbox Node:** Improve attachment matching logic and GeoJSON Polygon format ([#3535](https://github.com/n8n-io/n8n/issues/3535)) ([637e815](https://github.com/n8n-io/n8n/commit/637e81552f86788058567342cf69e2784e3d6b2f))
- **Odoo Node:** Prevent possible issues with some custom fields ([#3496](https://github.com/n8n-io/n8n/issues/3496)) ([7d968ec](https://github.com/n8n-io/n8n/commit/7d968ec202ceccc6a009ec150747cc927273f841))
- **Sticky Node:** Fix main header hiding ([#3654](https://github.com/n8n-io/n8n/issues/3654)) ([88486bc](https://github.com/n8n-io/n8n/commit/88486bc778786d4a47ef1bb5c743c9fb206aee01))
- **Todoist Node:** Fix multiple item support ([#3614](https://github.com/n8n-io/n8n/issues/3614)) ([7ba85c4](https://github.com/n8n-io/n8n/commit/7ba85c4ab910ed02696078ece12c88f2141cccad))
### Features
* **core:** Add `action` to `INodePropertyOptions` ([#3610](https://github.com/n8n-io/n8n/issues/3610)) ([3c65968](https://github.com/n8n-io/n8n/commit/3c659682e94cdd01fd6f267a468a031b028cf690))
* **DeepL Node:** Add support for longer texts + Credential tests ([#3651](https://github.com/n8n-io/n8n/issues/3651)) ([88d6cfc](https://github.com/n8n-io/n8n/commit/88d6cfc07bfd2be64a39f285d235e22aae8c1522))
* **Facebook Node:** Add support for Facebook Graph API versions 14 ([#3656](https://github.com/n8n-io/n8n/issues/3656)) ([174d063](https://github.com/n8n-io/n8n/commit/174d06383191e6e70ba27bc3e6e46527731c80b5))
* **Google Ads Node:** Add new node ([#3526](https://github.com/n8n-io/n8n/issues/3526)) ([088daf9](https://github.com/n8n-io/n8n/commit/088daf952ea7340a3101362bce18668147b8431f))
* **Jira Node:** Use Jira rendered fields with simplify option ([#3323](https://github.com/n8n-io/n8n/issues/3323)) ([07b6cff](https://github.com/n8n-io/n8n/commit/07b6cffdba55a48bfed629a1faec8cf88bee88bc))
* **Webflow Trigger Node:** Reduce chance of webhook duplication and add credential test ([#3594](https://github.com/n8n-io/n8n/issues/3594)) ([224e008](https://github.com/n8n-io/n8n/commit/224e008fb64dabef99998508eb4385e1b872c5ad))
* **Wordpress Node:** Add post template option ([#3139](https://github.com/n8n-io/n8n/issues/3139)) ([02bc3da](https://github.com/n8n-io/n8n/commit/02bc3da78545de4771edf6fdc68720b0e7d596b9))
- **core:** Add `action` to `INodePropertyOptions` ([#3610](https://github.com/n8n-io/n8n/issues/3610)) ([3c65968](https://github.com/n8n-io/n8n/commit/3c659682e94cdd01fd6f267a468a031b028cf690))
- **DeepL Node:** Add support for longer texts + Credential tests ([#3651](https://github.com/n8n-io/n8n/issues/3651)) ([88d6cfc](https://github.com/n8n-io/n8n/commit/88d6cfc07bfd2be64a39f285d235e22aae8c1522))
- **Facebook Node:** Add support for Facebook Graph API versions 14 ([#3656](https://github.com/n8n-io/n8n/issues/3656)) ([174d063](https://github.com/n8n-io/n8n/commit/174d06383191e6e70ba27bc3e6e46527731c80b5))
- **Google Ads Node:** Add new node ([#3526](https://github.com/n8n-io/n8n/issues/3526)) ([088daf9](https://github.com/n8n-io/n8n/commit/088daf952ea7340a3101362bce18668147b8431f))
- **Jira Node:** Use Jira rendered fields with simplify option ([#3323](https://github.com/n8n-io/n8n/issues/3323)) ([07b6cff](https://github.com/n8n-io/n8n/commit/07b6cffdba55a48bfed629a1faec8cf88bee88bc))
- **Webflow Trigger Node:** Reduce chance of webhook duplication and add credential test ([#3594](https://github.com/n8n-io/n8n/issues/3594)) ([224e008](https://github.com/n8n-io/n8n/commit/224e008fb64dabef99998508eb4385e1b872c5ad))
- **Wordpress Node:** Add post template option ([#3139](https://github.com/n8n-io/n8n/issues/3139)) ([02bc3da](https://github.com/n8n-io/n8n/commit/02bc3da78545de4771edf6fdc68720b0e7d596b9))
# [0.184.0](https://github.com/n8n-io/n8n/compare/n8n@0.183.0...n8n@0.184.0) (2022-06-29)
### Bug Fixes
* **core:** Fix logger error when logging circular json ([#3583](https://github.com/n8n-io/n8n/issues/3583)) ([3cb693d](https://github.com/n8n-io/n8n/commit/3cb693d5d4b8aaf800df70e62c1b2ca2ff208c4d))
* Correct misfix from `node-param-display-name-wrong-for-dynamic-multi-options` ([#3575](https://github.com/n8n-io/n8n/issues/3575)) ([2ccc7fb](https://github.com/n8n-io/n8n/commit/2ccc7fbc9d1df3f044cf42fe1af72bc7352caa9f))
* **Cortex Node:** Fix issue that not all Analyzers got returned ([#3606](https://github.com/n8n-io/n8n/issues/3606)) ([6e595c7](https://github.com/n8n-io/n8n/commit/6e595c72760f47107f67c1fd2bdbe76c31af4a8b))
* **editor:** Display full text of long error messages ([#3561](https://github.com/n8n-io/n8n/issues/3561)) ([8db4405](https://github.com/n8n-io/n8n/commit/8db44057f2101698ef4869fca436862e4dd39fc1))
* **editor:** Fix credentials rendering when the node has no parameters ([#3563](https://github.com/n8n-io/n8n/issues/3563)) ([55bab19](https://github.com/n8n-io/n8n/commit/55bab19eb440ed9d58137f4334a37d5f731afe0f))
* Fix issue with required optional parameters ([#3577](https://github.com/n8n-io/n8n/issues/3577)) ([42d2959](https://github.com/n8n-io/n8n/commit/42d2959f47f33defda4239a4d2fbba6927d98617))
* Fix issue with required optional parameters ([#3597](https://github.com/n8n-io/n8n/issues/3597)) ([848fcfd](https://github.com/n8n-io/n8n/commit/848fcfde5d95d952170e9a3d51b629971a13b832))
* **HTTP Request Node:** Make all OAuth2 credentials work with HTTP Request Node ([#3503](https://github.com/n8n-io/n8n/issues/3503)) ([acdb4d9](https://github.com/n8n-io/n8n/commit/acdb4d92c8ef95646e69694b2451a9111a81c52f))
* **LinkedIn Node:** Fix LinkedIn image preview ([#3528](https://github.com/n8n-io/n8n/issues/3528)) ([32f245d](https://github.com/n8n-io/n8n/commit/32f245da53c186a03172dbb23761a05b5e301532))
* **Salesforce Node:** Fix issue with lead status not using name on update ([#3599](https://github.com/n8n-io/n8n/issues/3599)) ([7ccae7c](https://github.com/n8n-io/n8n/commit/7ccae7c9b22f2848a8aa357227d145241801ba82))
- **core:** Fix logger error when logging circular json ([#3583](https://github.com/n8n-io/n8n/issues/3583)) ([3cb693d](https://github.com/n8n-io/n8n/commit/3cb693d5d4b8aaf800df70e62c1b2ca2ff208c4d))
- Correct misfix from `node-param-display-name-wrong-for-dynamic-multi-options` ([#3575](https://github.com/n8n-io/n8n/issues/3575)) ([2ccc7fb](https://github.com/n8n-io/n8n/commit/2ccc7fbc9d1df3f044cf42fe1af72bc7352caa9f))
- **Cortex Node:** Fix issue that not all Analyzers got returned ([#3606](https://github.com/n8n-io/n8n/issues/3606)) ([6e595c7](https://github.com/n8n-io/n8n/commit/6e595c72760f47107f67c1fd2bdbe76c31af4a8b))
- **editor:** Display full text of long error messages ([#3561](https://github.com/n8n-io/n8n/issues/3561)) ([8db4405](https://github.com/n8n-io/n8n/commit/8db44057f2101698ef4869fca436862e4dd39fc1))
- **editor:** Fix credentials rendering when the node has no parameters ([#3563](https://github.com/n8n-io/n8n/issues/3563)) ([55bab19](https://github.com/n8n-io/n8n/commit/55bab19eb440ed9d58137f4334a37d5f731afe0f))
- Fix issue with required optional parameters ([#3577](https://github.com/n8n-io/n8n/issues/3577)) ([42d2959](https://github.com/n8n-io/n8n/commit/42d2959f47f33defda4239a4d2fbba6927d98617))
- Fix issue with required optional parameters ([#3597](https://github.com/n8n-io/n8n/issues/3597)) ([848fcfd](https://github.com/n8n-io/n8n/commit/848fcfde5d95d952170e9a3d51b629971a13b832))
- **HTTP Request Node:** Make all OAuth2 credentials work with HTTP Request Node ([#3503](https://github.com/n8n-io/n8n/issues/3503)) ([acdb4d9](https://github.com/n8n-io/n8n/commit/acdb4d92c8ef95646e69694b2451a9111a81c52f))
- **LinkedIn Node:** Fix LinkedIn image preview ([#3528](https://github.com/n8n-io/n8n/issues/3528)) ([32f245d](https://github.com/n8n-io/n8n/commit/32f245da53c186a03172dbb23761a05b5e301532))
- **Salesforce Node:** Fix issue with lead status not using name on update ([#3599](https://github.com/n8n-io/n8n/issues/3599)) ([7ccae7c](https://github.com/n8n-io/n8n/commit/7ccae7c9b22f2848a8aa357227d145241801ba82))
### Features
* **Clockify Node:** Add more resources and improvements ([#3411](https://github.com/n8n-io/n8n/issues/3411)) ([447d190](https://github.com/n8n-io/n8n/commit/447d19024c512eea8e290d8ebc6c3ce82a53f002))
* **core:** Expose item index being processed ([#3590](https://github.com/n8n-io/n8n/issues/3590)) ([1e4fd9e](https://github.com/n8n-io/n8n/commit/1e4fd9e4df524fdee8195de7be244ff03d97f917))
* **core:** Give access to getBinaryDataBuffer in preSend method ([#3588](https://github.com/n8n-io/n8n/issues/3588)) ([522b31a](https://github.com/n8n-io/n8n/commit/522b31a47b4f4e9990e07dcc504ef2821a1fd0a5))
* Migrated to npm release of riot-tmpl fork ([#3581](https://github.com/n8n-io/n8n/issues/3581)) ([891844e](https://github.com/n8n-io/n8n/commit/891844ea8b3248195355f736d7331fd967ee99e1))
- **Clockify Node:** Add more resources and improvements ([#3411](https://github.com/n8n-io/n8n/issues/3411)) ([447d190](https://github.com/n8n-io/n8n/commit/447d19024c512eea8e290d8ebc6c3ce82a53f002))
- **core:** Expose item index being processed ([#3590](https://github.com/n8n-io/n8n/issues/3590)) ([1e4fd9e](https://github.com/n8n-io/n8n/commit/1e4fd9e4df524fdee8195de7be244ff03d97f917))
- **core:** Give access to getBinaryDataBuffer in preSend method ([#3588](https://github.com/n8n-io/n8n/issues/3588)) ([522b31a](https://github.com/n8n-io/n8n/commit/522b31a47b4f4e9990e07dcc504ef2821a1fd0a5))
- Migrated to npm release of riot-tmpl fork ([#3581](https://github.com/n8n-io/n8n/issues/3581)) ([891844e](https://github.com/n8n-io/n8n/commit/891844ea8b3248195355f736d7331fd967ee99e1))
# [0.183.0](https://github.com/n8n-io/n8n/compare/n8n@0.182.1...n8n@0.183.0) (2022-06-21)
### Bug Fixes
* **core:** Do allow OPTIONS requests from any source ([#3555](https://github.com/n8n-io/n8n/issues/3555)) ([74e6b06](https://github.com/n8n-io/n8n/commit/74e6b06467f8d0059c8cc45154e2d2822dc9b0c5))
* **core:** Fix issue that GET /workflows/:id does not return tags ([#3522](https://github.com/n8n-io/n8n/issues/3522)) ([f75f5d7](https://github.com/n8n-io/n8n/commit/f75f5d711f886892a1afcebff722ab476390f4f0))
* **core:** Fix issue that some predefined credentials do not show up on HTTP Request Node ([#3556](https://github.com/n8n-io/n8n/issues/3556)) ([d417ea7](https://github.com/n8n-io/n8n/commit/d417ea7ffad9e2210f3b2b5e7122ffbe70f2ba27))
* **core:** Return correct error message if Axios error ([#3478](https://github.com/n8n-io/n8n/issues/3478)) ([1bef4df](https://github.com/n8n-io/n8n/commit/1bef4df75f999ac2e413b6c179baab3321c52fa2))
* **core:** Updated expressions allowlist and denylist. ([#3424](https://github.com/n8n-io/n8n/issues/3424)) ([d18a29d](https://github.com/n8n-io/n8n/commit/d18a29d5882fb8f4475258189f6badcd0a573b34))
- **core:** Do allow OPTIONS requests from any source ([#3555](https://github.com/n8n-io/n8n/issues/3555)) ([74e6b06](https://github.com/n8n-io/n8n/commit/74e6b06467f8d0059c8cc45154e2d2822dc9b0c5))
- **core:** Fix issue that GET /workflows/:id does not return tags ([#3522](https://github.com/n8n-io/n8n/issues/3522)) ([f75f5d7](https://github.com/n8n-io/n8n/commit/f75f5d711f886892a1afcebff722ab476390f4f0))
- **core:** Fix issue that some predefined credentials do not show up on HTTP Request Node ([#3556](https://github.com/n8n-io/n8n/issues/3556)) ([d417ea7](https://github.com/n8n-io/n8n/commit/d417ea7ffad9e2210f3b2b5e7122ffbe70f2ba27))
- **core:** Return correct error message if Axios error ([#3478](https://github.com/n8n-io/n8n/issues/3478)) ([1bef4df](https://github.com/n8n-io/n8n/commit/1bef4df75f999ac2e413b6c179baab3321c52fa2))
- **core:** Updated expressions allowlist and denylist. ([#3424](https://github.com/n8n-io/n8n/issues/3424)) ([d18a29d](https://github.com/n8n-io/n8n/commit/d18a29d5882fb8f4475258189f6badcd0a573b34))
### Features
* **editor:** Improve trigger panel ([#3509](https://github.com/n8n-io/n8n/issues/3509)) ([a2f6289](https://github.com/n8n-io/n8n/commit/a2f628927dff7ea6741ef8e4a60bcafd95dac7bf))
* **Hubspot Node:** Allow to set Stage on Ticket Update ([#3317](https://github.com/n8n-io/n8n/issues/3317)) ([0ac9e3f](https://github.com/n8n-io/n8n/commit/0ac9e3f975b73e88acabb66de8b8565f881f64ec))
* **Todoist Node:** Make it possible to move tasks between sections ([#3074](https://github.com/n8n-io/n8n/issues/3074)) ([049e454](https://github.com/n8n-io/n8n/commit/049e4544d9ccc0acce2a596aced06ec86992e09a))
* **Twake Node:** Update icon, add cred test and custom operation support ([#3431](https://github.com/n8n-io/n8n/issues/3431)) ([6d64e84](https://github.com/n8n-io/n8n/commit/6d64e84f5e19d5f6d83ccc0a55cdcbd256e5804f))
- **editor:** Improve trigger panel ([#3509](https://github.com/n8n-io/n8n/issues/3509)) ([a2f6289](https://github.com/n8n-io/n8n/commit/a2f628927dff7ea6741ef8e4a60bcafd95dac7bf))
- **Hubspot Node:** Allow to set Stage on Ticket Update ([#3317](https://github.com/n8n-io/n8n/issues/3317)) ([0ac9e3f](https://github.com/n8n-io/n8n/commit/0ac9e3f975b73e88acabb66de8b8565f881f64ec))
- **Todoist Node:** Make it possible to move tasks between sections ([#3074](https://github.com/n8n-io/n8n/issues/3074)) ([049e454](https://github.com/n8n-io/n8n/commit/049e4544d9ccc0acce2a596aced06ec86992e09a))
- **Twake Node:** Update icon, add cred test and custom operation support ([#3431](https://github.com/n8n-io/n8n/issues/3431)) ([6d64e84](https://github.com/n8n-io/n8n/commit/6d64e84f5e19d5f6d83ccc0a55cdcbd256e5804f))
## [0.182.1](https://github.com/n8n-io/n8n/compare/n8n@0.182.0...n8n@0.182.1) (2022-06-16)
### Bug Fixes
* **core:** Fix issue with restarting waiting executions ([#3531](https://github.com/n8n-io/n8n/issues/3531)) ([c9273bc](https://github.com/n8n-io/n8n/commit/c9273bcd3862217b4918ac8abb37fae9c2e64622))
- **core:** Fix issue with restarting waiting executions ([#3531](https://github.com/n8n-io/n8n/issues/3531)) ([c9273bc](https://github.com/n8n-io/n8n/commit/c9273bcd3862217b4918ac8abb37fae9c2e64622))
# [0.182.0](https://github.com/n8n-io/n8n/compare/n8n@0.181.2...n8n@0.182.0) (2022-06-14)
### Bug Fixes
* **core:** Fix issue that parameters got lost in some edge cases ([04f0bf5](https://github.com/n8n-io/n8n/commit/04f0bf5b65c8224a4fdfd3c9d2c896f63dfbcc1d))
* **core:** Fix issue with combined expression not resolving if one is invalid ([#3506](https://github.com/n8n-io/n8n/issues/3506)) ([9ff5762](https://github.com/n8n-io/n8n/commit/9ff57629c5afb2f0fd4aee84cda79c9a6f7962d0))
* **core:** Fix Public API failing to build on Windows ([#3499](https://github.com/n8n-io/n8n/issues/3499)) ([c121952](https://github.com/n8n-io/n8n/commit/c121952324619434e8a7be540970c167df715b13))
* **editor:** Fix issue that some errors did not show up correctly ([#3507](https://github.com/n8n-io/n8n/issues/3507)) ([955db0a](https://github.com/n8n-io/n8n/commit/955db0ab101feb17efffe760c79ec2820e1d4c3b))
* **HTTP Request Node:** Fix issue with requests that return null ([#3498](https://github.com/n8n-io/n8n/issues/3498)) ([7346da0](https://github.com/n8n-io/n8n/commit/7346da0b34b5fdf7ab630ccc5cda102cf80c8036))
* **Pipedrive Node:** Fix limit issue with Lead -> GetAll ([#3436](https://github.com/n8n-io/n8n/issues/3436)) ([34e891c](https://github.com/n8n-io/n8n/commit/34e891c0f8c987c9be9cff463422b9972f02269f))
* **PostBin Node:** Fix issue with it throwing unnecessary error ([#3494](https://github.com/n8n-io/n8n/issues/3494)) ([9df3e30](https://github.com/n8n-io/n8n/commit/9df3e30d36104d8e31972c773cb71f4cc82f6970))
- **core:** Fix issue that parameters got lost in some edge cases ([04f0bf5](https://github.com/n8n-io/n8n/commit/04f0bf5b65c8224a4fdfd3c9d2c896f63dfbcc1d))
- **core:** Fix issue with combined expression not resolving if one is invalid ([#3506](https://github.com/n8n-io/n8n/issues/3506)) ([9ff5762](https://github.com/n8n-io/n8n/commit/9ff57629c5afb2f0fd4aee84cda79c9a6f7962d0))
- **core:** Fix Public API failing to build on Windows ([#3499](https://github.com/n8n-io/n8n/issues/3499)) ([c121952](https://github.com/n8n-io/n8n/commit/c121952324619434e8a7be540970c167df715b13))
- **editor:** Fix issue that some errors did not show up correctly ([#3507](https://github.com/n8n-io/n8n/issues/3507)) ([955db0a](https://github.com/n8n-io/n8n/commit/955db0ab101feb17efffe760c79ec2820e1d4c3b))
- **HTTP Request Node:** Fix issue with requests that return null ([#3498](https://github.com/n8n-io/n8n/issues/3498)) ([7346da0](https://github.com/n8n-io/n8n/commit/7346da0b34b5fdf7ab630ccc5cda102cf80c8036))
- **Pipedrive Node:** Fix limit issue with Lead -> GetAll ([#3436](https://github.com/n8n-io/n8n/issues/3436)) ([34e891c](https://github.com/n8n-io/n8n/commit/34e891c0f8c987c9be9cff463422b9972f02269f))
- **PostBin Node:** Fix issue with it throwing unnecessary error ([#3494](https://github.com/n8n-io/n8n/issues/3494)) ([9df3e30](https://github.com/n8n-io/n8n/commit/9df3e30d36104d8e31972c773cb71f4cc82f6970))
### Features
* **core:** Add "Client Credentials" grant type to OAuth2 ([#3489](https://github.com/n8n-io/n8n/issues/3489)) ([e29c597](https://github.com/n8n-io/n8n/commit/e29c5975e1f1ad089167df46021203e9f67c8ef1))
* **Twilio Node:** Add ability to make a voice call using TTS ([#3467](https://github.com/n8n-io/n8n/issues/3467)) ([eff97e8](https://github.com/n8n-io/n8n/commit/eff97e8d67cd3f0342bbb9648503b351f4691f46))
* **Wise Node:** Add Support to download statements as JSON, CSV or PDF ([#3468](https://github.com/n8n-io/n8n/issues/3468)) ([51663c1](https://github.com/n8n-io/n8n/commit/51663c1fcbe879e29790af942b73318e95065d8f))
- **core:** Add "Client Credentials" grant type to OAuth2 ([#3489](https://github.com/n8n-io/n8n/issues/3489)) ([e29c597](https://github.com/n8n-io/n8n/commit/e29c5975e1f1ad089167df46021203e9f67c8ef1))
- **Twilio Node:** Add ability to make a voice call using TTS ([#3467](https://github.com/n8n-io/n8n/issues/3467)) ([eff97e8](https://github.com/n8n-io/n8n/commit/eff97e8d67cd3f0342bbb9648503b351f4691f46))
- **Wise Node:** Add Support to download statements as JSON, CSV or PDF ([#3468](https://github.com/n8n-io/n8n/issues/3468)) ([51663c1](https://github.com/n8n-io/n8n/commit/51663c1fcbe879e29790af942b73318e95065d8f))
## [0.181.2](https://github.com/n8n-io/n8n/compare/n8n@0.181.1...n8n@0.181.2) (2022-06-09)
### Bug Fixes
* **core:** Fix issue when a node does not return data ([5eea3cd](https://github.com/n8n-io/n8n/commit/5eea3cd6d0b59963dc7c7a9e1ca597137cf3ce98))
- **core:** Fix issue when a node does not return data ([5eea3cd](https://github.com/n8n-io/n8n/commit/5eea3cd6d0b59963dc7c7a9e1ca597137cf3ce98))
## [0.181.1](https://github.com/n8n-io/n8n/compare/n8n@0.181.0...n8n@0.181.1) (2022-06-09)
### Bug Fixes
* **core:** Fix another possible issue with multi input nodes ([e88fab5](https://github.com/n8n-io/n8n/commit/e88fab5ee2b82665c3d68c52894a5479ce6eccf6))
* **core:** Fix issue with multi input nodes ([f79675d](https://github.com/n8n-io/n8n/commit/f79675d5c7876875065fc29504eb0590678d67d3))
- **core:** Fix another possible issue with multi input nodes ([e88fab5](https://github.com/n8n-io/n8n/commit/e88fab5ee2b82665c3d68c52894a5479ce6eccf6))
- **core:** Fix issue with multi input nodes ([f79675d](https://github.com/n8n-io/n8n/commit/f79675d5c7876875065fc29504eb0590678d67d3))
# [0.181.0](https://github.com/n8n-io/n8n/compare/n8n@0.180.0...n8n@0.181.0) (2022-06-08)
### Bug Fixes
* **core:** Properly resolve expressions in declarative node design ([1999f4b](https://github.com/n8n-io/n8n/commit/1999f4b066784cc1dd6a962f51d7c11641577a8b))
- **core:** Properly resolve expressions in declarative node design ([1999f4b](https://github.com/n8n-io/n8n/commit/1999f4b066784cc1dd6a962f51d7c11641577a8b))
### Features
* Add n8n Public API ([#3064](https://github.com/n8n-io/n8n/issues/3064)) ([a18081d](https://github.com/n8n-io/n8n/commit/a18081d749c51d497645d43614fdccb220344607))
* **core:** Make it possible to block access to environment variables ([ddb3baa](https://github.com/n8n-io/n8n/commit/ddb3baa4eddeb85e2f7abe4465ac4ff4058e1ece))
- Add n8n Public API ([#3064](https://github.com/n8n-io/n8n/issues/3064)) ([a18081d](https://github.com/n8n-io/n8n/commit/a18081d749c51d497645d43614fdccb220344607))
- **core:** Make it possible to block access to environment variables ([ddb3baa](https://github.com/n8n-io/n8n/commit/ddb3baa4eddeb85e2f7abe4465ac4ff4058e1ece))
# [0.180.0](https://github.com/n8n-io/n8n/compare/n8n@0.179.0...n8n@0.180.0) (2022-06-07)
@ -193,7 +632,6 @@
- **GitHub Node:**: Add Organization -> Get All operation ([#3247](https://github.com/n8n-io/n8n/pull/3247))
- **QuickBooks Node:** Add optional Tax item field ([#3404](https://github.com/n8n-io/n8n/issues/3404)) ([c341b45](https://github.com/n8n-io/n8n/commit/c341b45396c7282da087046ade16265c99c8d9dd))
# [0.179.0](https://github.com/n8n-io/n8n/compare/n8n@0.178.2...n8n@0.179.0) (2022-05-30)
### Bug Fixes
@ -217,93 +655,71 @@
- **ServiceNow Node:** Add attachment functionality ([#3137](https://github.com/n8n-io/n8n/issues/3137)) ([c38f6af](https://github.com/n8n-io/n8n/commit/c38f6af4993cd695888ff18b3f95e0d900e65711))
- **Todoist Node:** Add support for specifying the parent task when adding and listing tasks ([#3161](https://github.com/n8n-io/n8n/issues/3161)) ([dc77594](https://github.com/n8n-io/n8n/commit/dc77594a1eaec73fa34ed09c52d108482002ffff))
## [0.178.2](https://github.com/n8n-io/n8n/compare/n8n@0.178.1...n8n@0.178.2) (2022-05-25)
### Bug Fixes
* **editor:** Fix parameter loading bug ([#3374](https://github.com/n8n-io/n8n/issues/3374)) ([c7c2061](https://github.com/n8n-io/n8n/commit/c7c2061590493a1b24a8ab4e2615d6d9eb2641e1))
- **editor:** Fix parameter loading bug ([#3374](https://github.com/n8n-io/n8n/issues/3374)) ([c7c2061](https://github.com/n8n-io/n8n/commit/c7c2061590493a1b24a8ab4e2615d6d9eb2641e1))
## [0.178.1](https://github.com/n8n-io/n8n/compare/n8n@0.178.0...n8n@0.178.1) (2022-05-24)
### Bug Fixes
* **editor:** Fix problem with HTTP Request Node 1 credentials to be set ([#3371](https://github.com/n8n-io/n8n/issues/3371)) ([c5fc3bc](https://github.com/n8n-io/n8n/commit/c5fc3bc45e80eec47f4c06b950ab8b3ddaf66f2f))
- **editor:** Fix problem with HTTP Request Node 1 credentials to be set ([#3371](https://github.com/n8n-io/n8n/issues/3371)) ([c5fc3bc](https://github.com/n8n-io/n8n/commit/c5fc3bc45e80eec47f4c06b950ab8b3ddaf66f2f))
# [0.178.0](https://github.com/n8n-io/n8n/compare/n8n@0.177.0...n8n@0.178.0) (2022-05-24)
### Bug Fixes
* **editor:** Do not display diving line unless necessary ([68db12c](https://github.com/n8n-io/n8n/commit/68db12ce6d8bfc99cd0891cfa44f8b64674dada7))
* **editor:** Do not display welcome sticky in template workflows ([#3320](https://github.com/n8n-io/n8n/issues/3320)) ([29ddac3](https://github.com/n8n-io/n8n/commit/29ddac30d33caff1cf8a061d619742fdb3402d49))
* **Slack Node:** Fix Channel->Kick ([#3365](https://github.com/n8n-io/n8n/issues/3365)) ([0212d65](https://github.com/n8n-io/n8n/commit/0212d65dae885a6a153c67095f04215f5e1f8278))
- **editor:** Do not display diving line unless necessary ([68db12c](https://github.com/n8n-io/n8n/commit/68db12ce6d8bfc99cd0891cfa44f8b64674dada7))
- **editor:** Do not display welcome sticky in template workflows ([#3320](https://github.com/n8n-io/n8n/issues/3320)) ([29ddac3](https://github.com/n8n-io/n8n/commit/29ddac30d33caff1cf8a061d619742fdb3402d49))
- **Slack Node:** Fix Channel->Kick ([#3365](https://github.com/n8n-io/n8n/issues/3365)) ([0212d65](https://github.com/n8n-io/n8n/commit/0212d65dae885a6a153c67095f04215f5e1f8278))
### Features
* **core:** Allow credential reuse on HTTP Request node ([#3228](https://github.com/n8n-io/n8n/issues/3228)) ([336fc9e](https://github.com/n8n-io/n8n/commit/336fc9e2a820476931a9e9b482e4be284c0337d0)), closes [#3230](https://github.com/n8n-io/n8n/issues/3230) [#3231](https://github.com/n8n-io/n8n/issues/3231) [#3222](https://github.com/n8n-io/n8n/issues/3222) [#3229](https://github.com/n8n-io/n8n/issues/3229) [#3304](https://github.com/n8n-io/n8n/issues/3304) [#3282](https://github.com/n8n-io/n8n/issues/3282) [#3359](https://github.com/n8n-io/n8n/issues/3359)
* **editor:** Add input panel to NDV ([#3204](https://github.com/n8n-io/n8n/issues/3204)) ([3af0abd](https://github.com/n8n-io/n8n/commit/3af0abd9e066a721ac873f255eeb9311ebe6dd27))
* **Salesforce Node:** Add country field ([#3314](https://github.com/n8n-io/n8n/issues/3314)) ([90a1bc1](https://github.com/n8n-io/n8n/commit/90a1bc120bc2e291432c977768929da773dcb96e))
- **core:** Allow credential reuse on HTTP Request node ([#3228](https://github.com/n8n-io/n8n/issues/3228)) ([336fc9e](https://github.com/n8n-io/n8n/commit/336fc9e2a820476931a9e9b482e4be284c0337d0)), closes [#3230](https://github.com/n8n-io/n8n/issues/3230) [#3231](https://github.com/n8n-io/n8n/issues/3231) [#3222](https://github.com/n8n-io/n8n/issues/3222) [#3229](https://github.com/n8n-io/n8n/issues/3229) [#3304](https://github.com/n8n-io/n8n/issues/3304) [#3282](https://github.com/n8n-io/n8n/issues/3282) [#3359](https://github.com/n8n-io/n8n/issues/3359)
- **editor:** Add input panel to NDV ([#3204](https://github.com/n8n-io/n8n/issues/3204)) ([3af0abd](https://github.com/n8n-io/n8n/commit/3af0abd9e066a721ac873f255eeb9311ebe6dd27))
- **Salesforce Node:** Add country field ([#3314](https://github.com/n8n-io/n8n/issues/3314)) ([90a1bc1](https://github.com/n8n-io/n8n/commit/90a1bc120bc2e291432c977768929da773dcb96e))
# [0.177.0](https://github.com/n8n-io/n8n/compare/n8n@0.176.0...n8n@0.177.0) (2022-05-16)
### Bug Fixes
* **core:** Fix call to `/executions-current` with unsaved workflow ([#3280](https://github.com/n8n-io/n8n/issues/3280)) ([7090a79](https://github.com/n8n-io/n8n/commit/7090a79b5da611d829da4d027a0194fcb60b4755))
* **core:** Fix issue with fixedCollection having all default values ([7ced654](https://github.com/n8n-io/n8n/commit/7ced65484fa7c91e10e96f70d6791b689a5686d3))
* **Edit Image Node:** Fix font selection ([#3287](https://github.com/n8n-io/n8n/issues/3287)) ([8a8feb1](https://github.com/n8n-io/n8n/commit/8a8feb11c8e22e6a548e077b55e40702f2fb724a))
* **Ghost Node:** Fix post tags and add credential tests ([#3278](https://github.com/n8n-io/n8n/issues/3278)) ([a14d85e](https://github.com/n8n-io/n8n/commit/a14d85ea481b8227ba306f07e13263f45eafa6ca))
* **Google Calendar Node:** Make it work with public calendars and clean up ([#3283](https://github.com/n8n-io/n8n/issues/3283)) ([a7d960c](https://github.com/n8n-io/n8n/commit/a7d960c56122bd3b602f0e9a121919916e5d6174))
* **KoBoToolbox Node:** Fix query and sort + use question name in attachments ([#3017](https://github.com/n8n-io/n8n/issues/3017)) ([c885115](https://github.com/n8n-io/n8n/commit/c8851157684fe15c77db1fe716fa4333b54450cb))
* **Mailjet Trigger Node:** Fix issue that node could not get activated ([#3281](https://github.com/n8n-io/n8n/issues/3281)) ([e09e349](https://github.com/n8n-io/n8n/commit/e09e349fedfe067929556e328a70a32d30759e4d))
* **Pipedrive Node:** Fix resolve properties when multi option field is used ([#3277](https://github.com/n8n-io/n8n/issues/3277)) ([7eb1261](https://github.com/n8n-io/n8n/commit/7eb12615cf3eebac29e3561a079451017f80de5c))
- **core:** Fix call to `/executions-current` with unsaved workflow ([#3280](https://github.com/n8n-io/n8n/issues/3280)) ([7090a79](https://github.com/n8n-io/n8n/commit/7090a79b5da611d829da4d027a0194fcb60b4755))
- **core:** Fix issue with fixedCollection having all default values ([7ced654](https://github.com/n8n-io/n8n/commit/7ced65484fa7c91e10e96f70d6791b689a5686d3))
- **Edit Image Node:** Fix font selection ([#3287](https://github.com/n8n-io/n8n/issues/3287)) ([8a8feb1](https://github.com/n8n-io/n8n/commit/8a8feb11c8e22e6a548e077b55e40702f2fb724a))
- **Ghost Node:** Fix post tags and add credential tests ([#3278](https://github.com/n8n-io/n8n/issues/3278)) ([a14d85e](https://github.com/n8n-io/n8n/commit/a14d85ea481b8227ba306f07e13263f45eafa6ca))
- **Google Calendar Node:** Make it work with public calendars and clean up ([#3283](https://github.com/n8n-io/n8n/issues/3283)) ([a7d960c](https://github.com/n8n-io/n8n/commit/a7d960c56122bd3b602f0e9a121919916e5d6174))
- **KoBoToolbox Node:** Fix query and sort + use question name in attachments ([#3017](https://github.com/n8n-io/n8n/issues/3017)) ([c885115](https://github.com/n8n-io/n8n/commit/c8851157684fe15c77db1fe716fa4333b54450cb))
- **Mailjet Trigger Node:** Fix issue that node could not get activated ([#3281](https://github.com/n8n-io/n8n/issues/3281)) ([e09e349](https://github.com/n8n-io/n8n/commit/e09e349fedfe067929556e328a70a32d30759e4d))
- **Pipedrive Node:** Fix resolve properties when multi option field is used ([#3277](https://github.com/n8n-io/n8n/issues/3277)) ([7eb1261](https://github.com/n8n-io/n8n/commit/7eb12615cf3eebac29e3561a079451017f80de5c))
### Features
* **core:** Automatically convert Luxon Dates to string ([#3266](https://github.com/n8n-io/n8n/issues/3266)) ([3fcee14](https://github.com/n8n-io/n8n/commit/3fcee14bf5c61ec11fc1d4f30256f5ceba09e7f4))
* **editor:** Improve n8n welcome experience ([#3289](https://github.com/n8n-io/n8n/issues/3289)) ([35f2ce2](https://github.com/n8n-io/n8n/commit/35f2ce2359bb84437ad6fc68a7115081daeb46fe))
* **Google Drive Node:** Add Shared Drive support for operations upload, delete and share ([#3294](https://github.com/n8n-io/n8n/issues/3294)) ([03cdb1f](https://github.com/n8n-io/n8n/commit/03cdb1fea4fa4967eaafa861f3a9ff4ff7ca625a))
* **Microsoft OneDrive Node:** Add rename option for files and folders ([#3224](https://github.com/n8n-io/n8n/issues/3224)) ([50246d1](https://github.com/n8n-io/n8n/commit/50246d174a274fc9ba3dea44fc83c3605b4db691))
- **core:** Automatically convert Luxon Dates to string ([#3266](https://github.com/n8n-io/n8n/issues/3266)) ([3fcee14](https://github.com/n8n-io/n8n/commit/3fcee14bf5c61ec11fc1d4f30256f5ceba09e7f4))
- **editor:** Improve n8n welcome experience ([#3289](https://github.com/n8n-io/n8n/issues/3289)) ([35f2ce2](https://github.com/n8n-io/n8n/commit/35f2ce2359bb84437ad6fc68a7115081daeb46fe))
- **Google Drive Node:** Add Shared Drive support for operations upload, delete and share ([#3294](https://github.com/n8n-io/n8n/issues/3294)) ([03cdb1f](https://github.com/n8n-io/n8n/commit/03cdb1fea4fa4967eaafa861f3a9ff4ff7ca625a))
- **Microsoft OneDrive Node:** Add rename option for files and folders ([#3224](https://github.com/n8n-io/n8n/issues/3224)) ([50246d1](https://github.com/n8n-io/n8n/commit/50246d174a274fc9ba3dea44fc83c3605b4db691))
# [0.176.0](https://github.com/n8n-io/n8n/compare/n8n@0.175.1...n8n@0.176.0) (2022-05-10)
### Bug Fixes
* **core:** Fix executions list filtering by waiting status ([#3241](https://github.com/n8n-io/n8n/issues/3241)) ([71afcd6](https://github.com/n8n-io/n8n/commit/71afcd6314a73ab6cc04e22afd69e86ca764bd42))
* **core:** Improve webhook error messages ([49d0e3e](https://github.com/n8n-io/n8n/commit/49d0e3e885003b11092cf3c890847154426dee41))
* **Edit Image Node:** Make node work with binary-data-mode 'filesystem' ([#3274](https://github.com/n8n-io/n8n/issues/3274)) ([a4db0d0](https://github.com/n8n-io/n8n/commit/a4db0d051b18bc224c6cd69faeabf03cf5fba659))
- **core:** Fix executions list filtering by waiting status ([#3241](https://github.com/n8n-io/n8n/issues/3241)) ([71afcd6](https://github.com/n8n-io/n8n/commit/71afcd6314a73ab6cc04e22afd69e86ca764bd42))
- **core:** Improve webhook error messages ([49d0e3e](https://github.com/n8n-io/n8n/commit/49d0e3e885003b11092cf3c890847154426dee41))
- **Edit Image Node:** Make node work with binary-data-mode 'filesystem' ([#3274](https://github.com/n8n-io/n8n/issues/3274)) ([a4db0d0](https://github.com/n8n-io/n8n/commit/a4db0d051b18bc224c6cd69faeabf03cf5fba659))
### Features
* **Pipedrive Node:** Add support for filters to getAll:organization ([#3211](https://github.com/n8n-io/n8n/issues/3211)) ([1ef10dd](https://github.com/n8n-io/n8n/commit/1ef10dd23fef0b2e3e0ef76c8116d3bebc36bc4e))
* **Pushover Node:** Add 'HTML Formatting' option and credential test ([#3082](https://github.com/n8n-io/n8n/issues/3082)) ([b3dc6d9](https://github.com/n8n-io/n8n/commit/b3dc6d9d9c640f1e0f04cb56d0fabe2aafb948b6))
* **UProc Node:** Add new tools ([#3104](https://github.com/n8n-io/n8n/issues/3104)) ([ff2bf11](https://github.com/n8n-io/n8n/commit/ff2bf1112f07b7c3fd75f60e8faefdef4e2a02af))
- **Pipedrive Node:** Add support for filters to getAll:organization ([#3211](https://github.com/n8n-io/n8n/issues/3211)) ([1ef10dd](https://github.com/n8n-io/n8n/commit/1ef10dd23fef0b2e3e0ef76c8116d3bebc36bc4e))
- **Pushover Node:** Add 'HTML Formatting' option and credential test ([#3082](https://github.com/n8n-io/n8n/issues/3082)) ([b3dc6d9](https://github.com/n8n-io/n8n/commit/b3dc6d9d9c640f1e0f04cb56d0fabe2aafb948b6))
- **UProc Node:** Add new tools ([#3104](https://github.com/n8n-io/n8n/issues/3104)) ([ff2bf11](https://github.com/n8n-io/n8n/commit/ff2bf1112f07b7c3fd75f60e8faefdef4e2a02af))
## [0.175.1](https://github.com/n8n-io/n8n/compare/n8n@0.175.0...n8n@0.175.1) (2022-05-03)
### Bug Fixes
* **editor:** Fix bug with node version ([ed56481](https://github.com/n8n-io/n8n/commit/ed564812435a279760a32e76f3935f492f84f487))
- **editor:** Fix bug with node version ([ed56481](https://github.com/n8n-io/n8n/commit/ed564812435a279760a32e76f3935f492f84f487))
# [0.175.0](https://github.com/n8n-io/n8n/compare/n8n@0.174.0...n8n@0.175.0) (2022-05-02)

View File

@ -14,22 +14,22 @@ appearance, race, religion, or sexual identity and orientation.
Examples of behavior that contributes to creating a positive environment
include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
- Using welcoming and inclusive language
- Being respectful of differing viewpoints and experiences
- Gracefully accepting constructive criticism
- Focusing on what is best for the community
- Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or
advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic
address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
- The use of sexualized language or imagery and unwelcome sexual attention or
advances
- Trolling, insulting/derogatory comments, and personal or political attacks
- Public or private harassment
- Publishing others' private information, such as a physical or electronic
address, without explicit permission
- Other conduct which could reasonably be considered inappropriate in a
professional setting
## Our Responsibilities

View File

@ -27,20 +27,20 @@ n8n is split up in different modules which are all in a single mono repository.
The most important directories:
- [/docker/image](/docker/images) - Dockerfiles to create n8n containers
- [/docker/compose](/docker/compose) - Examples Docker Setups
- [/packages](/packages) - The different n8n modules
- [/packages/cli](/packages/cli) - CLI code to run front- & backend
- [/packages/core](/packages/core) - Core code which handles workflow
execution, active webhooks and
workflows. **Contact n8n before
starting on any changes here**
- [/packages/design-system](/packages/design-system) - Vue frontend components
- [/packages/editor-ui](/packages/editor-ui) - Vue frontend workflow editor
- [/packages/node-dev](/packages/node-dev) - CLI to create new n8n-nodes
- [/packages/nodes-base](/packages/nodes-base) - Base n8n nodes
- [/packages/workflow](/packages/workflow) - Workflow code with interfaces which
get used by front- & backend
- [/docker/image](/docker/images) - Dockerfiles to create n8n containers
- [/docker/compose](/docker/compose) - Examples Docker Setups
- [/packages](/packages) - The different n8n modules
- [/packages/cli](/packages/cli) - CLI code to run front- & backend
- [/packages/core](/packages/core) - Core code which handles workflow
execution, active webhooks and
workflows. **Contact n8n before
starting on any changes here**
- [/packages/design-system](/packages/design-system) - Vue frontend components
- [/packages/editor-ui](/packages/editor-ui) - Vue frontend workflow editor
- [/packages/node-dev](/packages/node-dev) - CLI to create new n8n-nodes
- [/packages/nodes-base](/packages/nodes-base) - Base n8n nodes
- [/packages/workflow](/packages/workflow) - Workflow code with interfaces which
get used by front- & backend
## Development setup
@ -51,40 +51,37 @@ dependencies are installed and the packages get linked correctly. Here a short g
#### Node.js
We suggest using the current [Node.js](https://nodejs.org/en/) LTS version (14.18.0 which includes npm 6.14.15) for development purposes.
We suggest using [Node.js](https://nodejs.org/en/) version 16 for development purposes.
#### Build tools
The packages which n8n uses depend on a few build tools:
Debian/Ubuntu:
```
apt-get install -y build-essential python
```
CentOS:
```
yum install gcc gcc-c++ make
```
Windows:
```
npm install -g windows-build-tools
```
#### lerna
#### npm workspaces
n8n is split up in different modules which are all in a single mono repository.
To facilitate those modules management, [lerna](https://lerna.js.org) gets
used. It automatically sets up file-links between modules which depend on each
To facilitate the module management, [npm workspaces](https://docs.npmjs.com/cli/v7/using-npm/workspaces) are
used. This automatically sets up file-links between modules which depend on each
other.
So for the setup to work correctly lerna has to be installed globally like this:
```
npm install -g lerna
```
### Actual n8n setup
> **IMPORTANT**: All the steps below have to get executed at least once to get the development setup up and running!
@ -94,30 +91,34 @@ checked out and set up:
1. [Fork](https://guides.github.com/activities/forking/#fork) the n8n repository
1. Clone your forked repository
```
git clone https://github.com/<your_github_username>/n8n.git
```
2. Clone your forked repository
1. Add the original n8n repository as `upstream` to your forked repository
```
git remote add upstream https://github.com/n8n-io/n8n.git
```
```
git clone https://github.com/<your_github_username>/n8n.git
```
1. Go into repository folder
```
cd n8n
```
3. Go into repository folder
1. Install all dependencies of all modules and link them together:
```
lerna bootstrap --hoist
```
```
cd n8n
```
1. Build all the code:
```
npm run build
```
4. Add the original n8n repository as `upstream` to your forked repository
```
git remote add upstream https://github.com/n8n-io/n8n.git
```
5. Install all dependencies of all modules and link them together:
```
npm install
```
6. Build all the code:
```
npm run build
```
### Start
@ -128,6 +129,7 @@ npm run start
```
To start n8n with tunnel:
```
./packages/cli/bin/n8n start --tunnel
```
@ -139,25 +141,26 @@ automatically build your code, restart the backend and refresh the frontend
(editor-ui) on every change you make.
1. Start n8n in development mode:
```
npm run dev
```
```
npm run dev
```
1. Hack, hack, hack
1. Check if everything still runs in production mode
```
npm run build
npm run start
```
```
npm run build
npm run start
```
1. Create tests
1. Run all [tests](#test-suite)
```
npm run test
```
```
npm run test
```
1. Commit code and [create a pull request](https://docs.github.com/en/github/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-a-pull-request-from-a-fork)
### Test suite
The tests can be started via:
```
npm run test
```
@ -170,17 +173,17 @@ tests of all packages.
> **IMPORTANT**: Avoid use of external libraries to ensure your custom nodes can be reviewed and merged quickly.
Learn about [using the node dev CLI](https://docs.n8n.io/nodes/creating-nodes/node-dev-cli.html) to create custom nodes for n8n.
Learn about [using the node dev CLI](https://docs.n8n.io/integrations/creating-nodes/archive/node-developer-cli/) to create custom nodes for n8n.
More information can be found in the documentation of [n8n-node-dev](https://github.com/n8n-io/n8n/tree/master/packages/node-dev), a small CLI which helps with n8n-node-development.
## Create a new node to contribute to n8n
Follow this tutorial on [creating your first node](https://docs.n8n.io/nodes/creating-nodes/create-node.html) for n8n.
Follow this tutorial on [creating your first node](https://docs.n8n.io/integrations/creating-nodes/build/) for n8n.
## Checklist before submitting a new node
There are several things to keep in mind when creating a node. To help you, we prepared a [checklist](https://docs.n8n.io/nodes/creating-nodes/node-review-checklist.html) that covers the requirements for creating nodes, from preparation to submission. This will help us be quicker to review and merge your PR.
There are several things to keep in mind when creating a node. To help you, we prepared a [checklist](https://docs.n8n.io/integrations/creating-nodes/build/reference/) that covers the requirements for creating nodes, from preparation to submission. This will help us be quicker to review and merge your PR.
## Extend documentation

View File

@ -1,5 +1,5 @@
# n8n Contributor License Agreement
I give n8n permission to license my contributions on any terms they like. I am giving them this license in order to make it possible for them to accept my contributions into their project.
I give n8n permission to license my contributions on any terms they like. I am giving them this license in order to make it possible for them to accept my contributions into their project.
***As far as the law allows, my contributions come as is, without any warranty or condition, and I will not be liable to anyone for any damages related to this software or this license, under any kind of legal claim.***
**_As far as the law allows, my contributions come as is, without any warranty or condition, and I will not be liable to anyone for any damages related to this software or this license, under any kind of legal claim._**

View File

@ -1,43 +1,69 @@
# Sustainable Use License
# License
Portions of this software are licensed as follows:
- All source code files of this repository that contain ".ee." in their filename are licensed under the n8n Enterprise License defined in "LICENSE_EE.md".
- All third party components incorporated into the n8n Software are licensed under the original license
provided by the owner of the applicable component.
- Content outside of the above mentioned files or restrictions above is available under the "Sustainable Use
License" as defined below.
## Sustainable Use License
Version 1.0
## Acceptance
### Acceptance
By using the software, you agree to all of the terms and conditions below.
## Copyright License
### Copyright License
The licensor grants you a non-exclusive, royalty-free, worldwide, non-sublicensable, non-transferable license to use, copy, distribute, make available, and prepare derivative works of the software, in each case subject to the limitations below.
The licensor grants you a non-exclusive, royalty-free, worldwide, non-sublicensable, non-transferable license
to use, copy, distribute, make available, and prepare derivative works of the software, in each case subject
to the limitations below.
## Limitations
### Limitations
You may use or modify the software only for your own internal business purposes or for non-commercial or personal use.
You may distribute the software or provide it to others only if you do so free of charge for non-commercial purposes.
You may not alter, remove, or obscure any licensing, copyright, or other notices of the licensor in the software. Any use of the licensors trademarks is subject to applicable law.
You may use or modify the software only for your own internal business purposes or for non-commercial or
personal use. You may distribute the software or provide it to others only if you do so free of charge for
non-commercial purposes. You may not alter, remove, or obscure any licensing, copyright, or other notices of
the licensor in the software. Any use of the licensors trademarks is subject to applicable law.
## Patents
### Patents
The licensor grants you a license, under any patent claims the licensor can license, or becomes able to license, to make, have made, use, sell, offer for sale, import and have imported the software, in each case subject to the limitations and conditions in this license. This license does not cover any patent claims that you cause to be infringed by modifications or additions to the software. If you or your company make any written claim that the software infringes or contributes to infringement of any patent, your patent license for the software granted under these terms ends immediately. If your company makes such a claim, your patent license ends immediately for work on behalf of your company.
The licensor grants you a license, under any patent claims the licensor can license, or becomes able to
license, to make, have made, use, sell, offer for sale, import and have imported the software, in each case
subject to the limitations and conditions in this license. This license does not cover any patent claims that
you cause to be infringed by modifications or additions to the software. If you or your company make any
written claim that the software infringes or contributes to infringement of any patent, your patent license
for the software granted under these terms ends immediately. If your company makes such a claim, your patent
license ends immediately for work on behalf of your company.
## Notices
### Notices
You must ensure that anyone who gets a copy of any part of the software from you also gets a copy of these terms.
If you modify the software, you must include in any modified copies of the software a prominent notice stating that you have modified the software.
You must ensure that anyone who gets a copy of any part of the software from you also gets a copy of these
terms. If you modify the software, you must include in any modified copies of the software a prominent notice
stating that you have modified the software.
## No Other Rights
### No Other Rights
These terms do not imply any licenses other than those expressly granted in these terms.
## Termination
### Termination
If you use the software in violation of these terms, such use is not licensed, and your license will automatically terminate. If the licensor provides you with a notice of your violation, and you cease all violation of this license no later than 30 days after you receive that notice, your license will be reinstated retroactively. However, if you violate these terms after such reinstatement, any additional violation of these terms will cause your license to terminate automatically and permanently.
If you use the software in violation of these terms, such use is not licensed, and your license will
automatically terminate. If the licensor provides you with a notice of your violation, and you cease all
violation of this license no later than 30 days after you receive that notice, your license will be reinstated
retroactively. However, if you violate these terms after such reinstatement, any additional violation of these
terms will cause your license to terminate automatically and permanently.
## No Liability
### No Liability
As far as the law allows, the software comes as is, without any warranty or condition, and the licensor will not be liable to you for any damages arising out of these terms or the use or nature of the software, under any kind of legal claim.
As far as the law allows, the software comes as is, without any warranty or condition, and the licensor will
not be liable to you for any damages arising out of these terms or the use or nature of the software, under
any kind of legal claim.
## Definitions
### Definitions
The “licensor” is the entity offering these terms.
@ -45,7 +71,10 @@ The “software” is the software the licensor makes available under these term
“You” refers to the individual or entity agreeing to these terms.
“Your company” is any legal entity, sole proprietorship, or other kind of organization that you work for, plus all organizations that have control over, are under the control of, or are under common control with that organization. Control means ownership of substantially all the assets of an entity, or the power to direct its management and policies by vote, contract, or otherwise. Control can be direct or indirect.
“Your company” is any legal entity, sole proprietorship, or other kind of organization that you work for, plus
all organizations that have control over, are under the control of, or are under common control with that
organization. Control means ownership of substantially all the assets of an entity, or the power to direct its
management and policies by vote, contract, or otherwise. Control can be direct or indirect.
“Your license” is the license granted to you for the software under these terms.

27
LICENSE_EE.md Normal file
View File

@ -0,0 +1,27 @@
# The n8n Enterprise License (the “Enterprise License”)
Copyright (c) 2022-present n8n GmbH.
With regard to the n8n Software:
This software and associated documentation files (the "Software") may only be used in production, if
you (and any entity that you represent) hold a valid n8n Enterprise license corresponding to your
usage. Subject to the foregoing sentence, you are free to modify this Software and publish patches
to the Software. You agree that n8n and/or its licensors (as applicable) retain all right, title and
interest in and to all such modifications and/or patches, and all such modifications and/or patches
may only be used, copied, modified, displayed, distributed, or otherwise exploited with a valid n8n
Enterprise license for the corresponding usage. Notwithstanding the foregoing, you may copy and
modify the Software for development and testing purposes, without requiring a subscription. You
agree that n8n and/or its licensors (as applicable) retain all right, title and interest in and to
all such modifications. You are not granted any other rights beyond what is expressly stated herein.
Subject to the foregoing, it is forbidden to copy, merge, publish, distribute, sublicense, and/or
sell the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES
OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
For all third party components incorporated into the n8n Software, those components are licensed
under the original license provided by the owner of the applicable component.

View File

@ -2,17 +2,22 @@
# n8n - Workflow automation tool
n8n is an extendable workflow automation tool. With a [fair-code](http://faircode.io) distribution model, n8n will always have visible source code, be available to self-host, and allow you to add your own custom functions, logic and apps. n8n's node-based approach makes it highly versatile, enabling you to connect anything to everything.
n8n is an extendable workflow automation tool. With a [fair-code](http://faircode.io) distribution model, n8n
will always have visible source code, be available to self-host, and allow you to add your own custom
functions, logic and apps. n8n's node-based approach makes it highly versatile, enabling you to connect
anything to everything.
<a href="https://raw.githubusercontent.com/n8n-io/n8n/master/assets/n8n-screenshot.png"><img src="https://raw.githubusercontent.com/n8n-io/n8n/master/assets/n8n-screenshot.png" alt="n8n.io - Screenshot"></a>
![n8n.io - Screenshot](https://raw.githubusercontent.com/n8n-io/n8n/master/assets/n8n-screenshot.png)
## Demo
[:tv: A short video (< 4 min)](https://www.youtube.com/watch?v=RpjQTGKm-ok) that goes over key concepts of creating workflows in n8n.
[:tv: A short video (< 4 min)](https://www.youtube.com/watch?v=RpjQTGKm-ok) that goes over key concepts of
creating workflows in n8n.
## Available integrations
n8n has 200+ different nodes to automate workflows. The list can be found on: [https://n8n.io/integrations](https://n8n.io/integrations)
n8n has 200+ different nodes to automate workflows. The list can be found on:
[https://n8n.io/integrations](https://n8n.io/integrations)
## Documentation
@ -20,16 +25,19 @@ The official n8n documentation can be found under: [https://docs.n8n.io](https:/
Additional information and example workflows on the n8n.io website: [https://n8n.io](https://n8n.io)
The changelog can be found [here](https://docs.n8n.io/reference/changelog.html) and the list of breaking changes [here](https://github.com/n8n-io/n8n/blob/master/packages/cli/BREAKING-CHANGES.md).
The changelog can be found [here](https://docs.n8n.io/reference/changelog.html) and the list of breaking
changes [here](https://github.com/n8n-io/n8n/blob/master/packages/cli/BREAKING-CHANGES.md).
## Usage
- :books: Learn [how to **install** and **use** it from the command line](https://github.com/n8n-io/n8n/tree/master/packages/cli/README.md)
- :whale: Learn [how to run n8n in **Docker**](https://github.com/n8n-io/n8n/tree/master/docker/images/n8n/README.md)
- :books: Learn
[how to **install** and **use** it from the command line](https://github.com/n8n-io/n8n/tree/master/packages/cli/README.md)
- :whale: Learn
[how to run n8n in **Docker**](https://github.com/n8n-io/n8n/tree/master/docker/images/n8n/README.md)
## Start
Execute: `npm run start`
Execute: `npx n8n`
## n8n cloud
@ -49,29 +57,32 @@ If you have problems or questions go to our forum, we will then try to help you
## Jobs
If you are interested in working for n8n and so shape the future of the project
check out our [job posts](https://apply.workable.com/n8n/)
If you are interested in working for n8n and so shape the future of the project check out our
[job posts](https://apply.workable.com/n8n/)
## What does n8n mean and how do you pronounce it?
**Short answer:** It means "nodemation" and it is pronounced as n-eight-n.
**Long answer:** "I get that question quite often (more often than I expected)
so I decided it is probably best to answer it here. While looking for a
good name for the project with a free domain I realized very quickly that all the
good ones I could think of were already taken. So, in the end, I chose
nodemation. 'node-' in the sense that it uses a Node-View and that it uses
Node.js and '-mation' for 'automation' which is what the project is supposed to help with.
However, I did not like how long the name was and I could not imagine writing
something that long every time in the CLI. That is when I then ended up on
'n8n'." - **Jan Oberhauser, Founder and CEO, n8n.io**
**Long answer:** "I get that question quite often (more often than I expected) so I decided it is probably
best to answer it here. While looking for a good name for the project with a free domain I realized very
quickly that all the good ones I could think of were already taken. So, in the end, I chose nodemation.
'node-' in the sense that it uses a Node-View and that it uses Node.js and '-mation' for 'automation' which is
what the project is supposed to help with. However, I did not like how long the name was and I could not
imagine writing something that long every time in the CLI. That is when I then ended up on 'n8n'." - **Jan
Oberhauser, Founder and CEO, n8n.io**
## Development setup
Have you found a bug :bug: ? Or maybe you have a nice feature :sparkles: to contribute ? The [CONTRIBUTING guide](https://github.com/n8n-io/n8n/blob/master/CONTRIBUTING.md) will help you get your development environment ready in minutes.
Have you found a bug :bug: ? Or maybe you have a nice feature :sparkles: to contribute ? The
[CONTRIBUTING guide](https://github.com/n8n-io/n8n/blob/master/CONTRIBUTING.md) will help you get your
development environment ready in minutes.
## License
n8n is [fair-code](http://faircode.io) distributed under the [**Sustainable Use License**](https://github.com/n8n-io/n8n/blob/master/packages/cli/LICENSE.md).
n8n is [fair-code](http://faircode.io) distributed under the
[**Sustainable Use License**](https://github.com/n8n-io/n8n/blob/master/packages/cli/LICENSE.md) and the
[**n8n Enterprise License**](https://github.com/n8n-io/n8n/blob/master/packages/cli/LICENSE_EE.md).
Additional information about license can be found in the [FAQ](https://docs.n8n.io/#/faq?id=license).
Additional information about the license model can be found in the
[docs](https://docs.n8n.io/reference/license/).

View File

@ -1,14 +1,12 @@
# n8n on Subfolder with SSL
Starts n8n and deployes it on a subfolder
Starts n8n and deploys it on a subfolder
## Start
To start n8n in a subfolder simply start docker-compose by executing the following
command in the current folder.
**IMPORTANT:** But before you do that change the default users and passwords in the `.env` file!
```

View File

@ -1,36 +1,36 @@
version: "3"
version: '3'
services:
traefik:
image: "traefik"
image: 'traefik'
command:
- "--api=true"
- "--api.insecure=true"
- "--api.dashboard=true"
- "--providers.docker=true"
- "--providers.docker.exposedbydefault=false"
- "--entrypoints.websecure.address=:443"
- "--certificatesresolvers.mytlschallenge.acme.tlschallenge=true"
- "--certificatesresolvers.mytlschallenge.acme.email=${SSL_EMAIL}"
- "--certificatesresolvers.mytlschallenge.acme.storage=/letsencrypt/acme.json"
- '--api=true'
- '--api.insecure=true'
- '--api.dashboard=true'
- '--providers.docker=true'
- '--providers.docker.exposedbydefault=false'
- '--entrypoints.websecure.address=:443'
- '--certificatesresolvers.mytlschallenge.acme.tlschallenge=true'
- '--certificatesresolvers.mytlschallenge.acme.email=${SSL_EMAIL}'
- '--certificatesresolvers.mytlschallenge.acme.storage=/letsencrypt/acme.json'
ports:
- "443:443"
- "80:80"
- '443:443'
- '80:80'
volumes:
- ${DATA_FOLDER}/letsencrypt:/letsencrypt
- /var/run/docker.sock:/var/run/docker.sock:ro
n8n:
image: n8nio/n8n
ports:
- "127.0.0.1:5678:5678"
- '127.0.0.1:5678:5678'
labels:
- traefik.enable=true
- traefik.http.routers.n8n.rule=Host(`${DOMAIN_NAME}`)
- traefik.http.routers.n8n.tls=true
- traefik.http.routers.n8n.entrypoints=websecure
- "traefik.http.routers.n8n.rule=PathPrefix(`/${SUBFOLDER}{regex:$$|/.*}`)"
- "traefik.http.middlewares.n8n-stripprefix.stripprefix.prefixes=/${SUBFOLDER}"
- "traefik.http.routers.n8n.middlewares=n8n-stripprefix"
- 'traefik.http.routers.n8n.rule=PathPrefix(`/${SUBFOLDER}{regex:$$|/.*}`)'
- 'traefik.http.middlewares.n8n-stripprefix.stripprefix.prefixes=/${SUBFOLDER}'
- 'traefik.http.routers.n8n.middlewares=n8n-stripprefix'
- traefik.http.routers.n8n.tls.certresolver=mytlschallenge
- traefik.http.middlewares.n8n.headers.SSLRedirect=true
- traefik.http.middlewares.n8n.headers.STSSeconds=315360000

View File

@ -0,0 +1,8 @@
MARIADB_ROOT_PASSWORD=changePassword
MARIADB_DATABASE=n8n
MARIADB_USER=changeUser
MARIADB_PASSWORD=changePassword
N8N_BASIC_AUTH_USER=changeUser
N8N_BASIC_AUTH_PASSWORD=changePassword

View File

@ -0,0 +1,24 @@
# n8n with MariaDB
Starts n8n with MariaDB as database.
## Start
To start n8n with MariaDB simply start docker-compose by executing the following
command in the current folder.
**IMPORTANT:** But before you do that change the default users and passwords in the [`.env`](.env) file!
```
docker-compose up -d
```
To stop it execute:
```
docker-compose stop
```
## Configuration
The default name of the database, user and password for MariaDB can be changed in the [`.env`](.env) file in the current directory.

View File

@ -0,0 +1,43 @@
version: '3.8'
volumes:
db_storage:
n8n_storage:
services:
db:
image: mariadb:10.7
restart: always
environment:
- MARIADB_ROOT_PASSWORD
- MARIADB_DATABASE
- MARIADB_USER
- MARIADB_PASSWORD
- MARIADB_MYSQL_LOCALHOST_USER=true
volumes:
- db_storage:/var/lib/mysql
healthcheck:
test: "/usr/bin/mysql --user=${MARIADB_USER} --password=${MARIADB_PASSWORD} --execute 'SELECT 1;'"
interval: 10s
timeout: 5s
retries: 10
n8n:
image: n8nio/n8n
restart: always
environment:
- DB_TYPE=mariadb
- DB_MYSQLDB_HOST=db
- DB_MYSQLDB_DATABASE=${MARIADB_DATABASE}
- DB_MYSQLDB_USER=${MARIADB_USER}
- DB_MYSQLDB_PASSWORD=${MARIADB_PASSWORD}
ports:
- 5678:5678
links:
- db
volumes:
- n8n_storage:/home/node/
command: n8n start --tunnel
depends_on:
db:
condition: service_healthy

View File

@ -2,13 +2,11 @@
Starts n8n with PostgreSQL as database.
## Start
To start n8n with PostgreSQL simply start docker-compose by executing the following
command in the current folder.
**IMPORTANT:** But before you do that change the default users and passwords in the [`.env`](.env) file!
```

View File

@ -1,7 +1,10 @@
version: '3.1'
version: '3.8'
volumes:
db_storage:
n8n_storage:
services:
postgres:
image: postgres:11
restart: always
@ -12,7 +15,13 @@ services:
- POSTGRES_NON_ROOT_USER
- POSTGRES_NON_ROOT_PASSWORD
volumes:
- db_storage:/var/lib/postgresql/data
- ./init-data.sh:/docker-entrypoint-initdb.d/init-data.sh
healthcheck:
test: ["CMD-SHELL", "pg_isready -h localhost -U ${POSTGRES_USER} -d ${POSTGRES_DB}"]
interval: 5s
timeout: 5s
retries: 10
n8n:
image: n8nio/n8n
@ -32,7 +41,8 @@ services:
links:
- postgres
volumes:
- ~/.n8n:/home/node/.n8n
# Wait 5 seconds to start n8n to make sure that PostgreSQL is ready
# when n8n tries to connect to it
command: /bin/sh -c "sleep 5; n8n start"
- n8n_storage:/home/node/
command: /bin/sh -c "n8n start --tunnel"
depends_on:
postgres:
condition: service_healthy

View File

@ -0,0 +1,9 @@
POSTGRES_USER=changeUser
POSTGRES_PASSWORD=changePassword
POSTGRES_DB=n8n
POSTGRES_NON_ROOT_USER=changeUser
POSTGRES_NON_ROOT_PASSWORD=changePassword
N8N_BASIC_AUTH_USER=changeUser
N8N_BASIC_AUTH_PASSWORD=changePassword

View File

@ -0,0 +1,26 @@
# n8n with PostgreSQL and Worker
Starts n8n with PostgreSQL as database, and the Worker as a separate container.
## Start
To start n8n simply start docker-compose by executing the following
command in the current folder.
**IMPORTANT:** But before you do that change the default users and passwords in the [`.env`](.env) file!
```
docker-compose up -d
```
To stop it execute:
```
docker-compose stop
```
## Configuration
The default name of the database, user and password for PostgreSQL can be changed in the [`.env`](.env) file in the current directory.

View File

@ -0,0 +1,77 @@
version: '3.8'
volumes:
db_storage:
n8n_storage:
redis_storage:
x-shared: &shared
restart: always
environment:
- DB_TYPE=postgresdb
- DB_POSTGRESDB_HOST=postgres
- DB_POSTGRESDB_PORT=5432
- DB_POSTGRESDB_DATABASE=${POSTGRES_DB}
- DB_POSTGRESDB_USER=${POSTGRES_NON_ROOT_USER}
- DB_POSTGRESDB_PASSWORD=${POSTGRES_NON_ROOT_PASSWORD}
- EXECUTIONS_MODE=queue
- QUEUE_BULL_REDIS_HOST=redis
- QUEUE_HEALTH_CHECK_ACTIVE=true
- N8N_BASIC_AUTH_ACTIVE=true
- N8N_BASIC_AUTH_USER
- N8N_BASIC_AUTH_PASSWORD
links:
- postgres
- redis
volumes:
- n8n_storage:/home/node/
depends_on:
redis:
condition: service_healthy
postgres:
condition: service_healthy
services:
postgres:
image: postgres:11
restart: always
environment:
- POSTGRES_USER
- POSTGRES_PASSWORD
- POSTGRES_DB
- POSTGRES_NON_ROOT_USER
- POSTGRES_NON_ROOT_PASSWORD
volumes:
- db_storage:/var/lib/postgresql/data
- ./init-data.sh:/docker-entrypoint-initdb.d/init-data.sh
healthcheck:
test: ["CMD-SHELL", "pg_isready -h localhost -U ${POSTGRES_USER} -d ${POSTGRES_DB}"]
interval: 5s
timeout: 5s
retries: 10
redis:
image: redis:6-alpine
restart: always
volumes:
- redis_storage:/data
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
timeout: 5s
retries: 10
n8n:
<<: *shared
image: n8nio/n8n
command: /bin/sh -c "n8n start --tunnel"
ports:
- 5678:5678
n8n-worker:
<<: *shared
image: n8nio/n8n
command: /bin/sh -c "sleep 5; n8n worker"
depends_on:
- n8n

View File

@ -0,0 +1,12 @@
#!/bin/bash
set -e;
if [ -n "${POSTGRES_NON_ROOT_USER:-}" ] && [ -n "${POSTGRES_NON_ROOT_PASSWORD:-}" ]; then
psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" <<-EOSQL
CREATE USER ${POSTGRES_NON_ROOT_USER} WITH PASSWORD '${POSTGRES_NON_ROOT_PASSWORD}';
GRANT ALL PRIVILEGES ON DATABASE ${POSTGRES_DB} TO ${POSTGRES_NON_ROOT_USER};
EOSQL
else
echo "SETUP INFO: No Environment variables given!"
fi

View File

@ -0,0 +1,4 @@
audit = false
fund = false
loglevel = warn
update-notifier = false

View File

@ -0,0 +1,20 @@
ARG NODE_VERSION=16
FROM node:${NODE_VERSION}-alpine
WORKDIR /home/node
COPY .npmrc /usr/local/etc/npmrc
RUN \
apk add --update git graphicsmagick tini tzdata ca-certificates && \
npm install -g npm@latest full-icu && \
rm -rf /var/cache/apk/* /root/.npm /tmp/* && \
# Install fonts
apk --no-cache add --virtual fonts msttcorefonts-installer fontconfig && \
update-ms-fonts && \
fc-cache -f && \
apk del fonts && \
find /usr/share/fonts/truetype/msttcorefonts/ -type l -exec unlink {} \; && \
rm -rf /var/cache/apk/* /tmp/*
ENV NODE_ICU_DATA /usr/local/lib/node_modules/full-icu
EXPOSE 5678/tcp

View File

@ -1,55 +1,37 @@
ARG NODE_VERSION=16
# 1. Create an image to build n8n
FROM node:16-alpine as builder
FROM n8nio/base:${NODE_VERSION} as builder
# Update everything and install needed dependencies
USER root
RUN npm install -g run-script-os turbo@1.5.5
# Install all needed dependencies
RUN apk --update add --virtual build-dependencies python3 build-base ca-certificates && \
npm_config_user=root npm install -g lerna run-script-os
WORKDIR /data
COPY lerna.json .
COPY package.json .
COPY packages/cli/ ./packages/cli/
COPY packages/core/ ./packages/core/
COPY packages/design-system/ ./packages/design-system/
COPY packages/editor-ui/ ./packages/editor-ui/
COPY packages/nodes-base/ ./packages/nodes-base/
COPY packages/workflow/ ./packages/workflow/
RUN rm -rf node_modules packages/*/node_modules packages/*/dist
COPY turbo.json package.json package-lock.json tsconfig.json ./
COPY packages ./packages
COPY patches ./patches
RUN chown -R node:node .
RUN npm config set legacy-peer-deps true
RUN npm install --production --loglevel notice
RUN lerna bootstrap --hoist -- --production
RUN npm run build
USER node
RUN \
npm install && \
npm run build && \
# TODO: removing dev dependecies is deleting `bn.js`, which breaks the Snowflake node
npm prune --omit=dev && \
npm i --omit=dev bn.js && \
find . -type f -name "*.ts" -o -name "*.js.map" -o -name "*.vue" -o -name "tsconfig.json" | xargs rm &&\
rm -rf node_modules/.cache packages/*/node_modules/.cache packages/*/.turbo .config .npm /tmp/*
# 2. Start with a new clean image with just the code that is needed to run n8n
FROM node:16-alpine
FROM n8nio/base:${NODE_VERSION}
COPY --from=builder /home/node ./
COPY docker/images/n8n-custom/docker-entrypoint.sh ./
USER root
RUN apk add --update graphicsmagick tzdata tini su-exec git
WORKDIR /data
# Install all needed dependencies
RUN npm_config_user=root npm install -g full-icu
# Install fonts
RUN apk --no-cache add --virtual fonts msttcorefonts-installer fontconfig && \
update-ms-fonts && \
fc-cache -f && \
apk del fonts && \
find /usr/share/fonts/truetype/msttcorefonts/ -type l -exec unlink {} \;
ENV NODE_ICU_DATA /usr/local/lib/node_modules/full-icu
COPY --from=builder /data ./
COPY docker/images/n8n-custom/docker-entrypoint.sh /docker-entrypoint.sh
ENTRYPOINT ["tini", "--", "/docker-entrypoint.sh"]
EXPOSE 5678/tcp
RUN \
mkdir .n8n && \
chown node:node .n8n
USER node
ENV NODE_ENV=production
ENTRYPOINT ["tini", "--", "./docker-entrypoint.sh"]

View File

@ -3,10 +3,10 @@
Dockerfile which allows to package up the local n8n code into
a docker image.
## Usage
Execute the following in the n8n root folder:
```bash
docker build -t n8n-custom -f docker/images/n8n-custom/Dockerfile .
```

View File

@ -1,25 +1,16 @@
#!/bin/sh
if [ -d /root/.n8n ] ; then
chmod o+rx /root
chown -R node /root/.n8n
ln -s /root/.n8n /home/node/
fi
chown -R node /home/node
if [ "$#" -gt 0 ]; then
# Got started with arguments
COMMAND=$1;
if [[ "$COMMAND" == "n8n" ]]; then
shift
exec su-exec node ./packages/cli/bin/n8n "$@"
(cd packages/cli; exec node ./bin/n8n "$@")
else
exec su-exec node "$@"
exec node "$@"
fi
else
# Got started without arguments
exec su-exec node ./packages/cli/bin/n8n
cd packages/cli; exec node ./bin/n8n
fi

View File

@ -11,7 +11,7 @@ RUN \
# Set a custom user to not have n8n run as root
USER root
RUN npm_config_user=root npm install -g full-icu n8n@${N8N_VERSION}
RUN npm_config_user=root npm install -g npm@latest full-icu n8n@${N8N_VERSION}
ENV NODE_ICU_DATA /usr/local/lib/node_modules/full-icu

View File

@ -5,7 +5,6 @@ Dockerfile to build n8n with Debian.
For information about how to run n8n with Docker check the generic
[Docker-Readme](https://github.com/n8n-io/n8n/tree/master/docker/images/n8n/README.md)
```
docker build --build-arg N8N_VERSION=<VERSION> -t n8nio/n8n:<VERSION> .

View File

@ -16,7 +16,7 @@ RUN \
# Set a custom user to not have n8n run as root
USER root
RUN npm_config_user=root npm install -g n8n@${N8N_VERSION}
RUN npm_config_user=root npm install -g npm@latest n8n@${N8N_VERSION}
WORKDIR /data

View File

@ -7,7 +7,6 @@ docker build --build-arg N8N_VERSION=<VERSION> -t n8nio/n8n:<VERSION> .
docker build --build-arg N8N_VERSION=0.36.1 -t n8nio/n8n:0.36.1-rhel7 .
```
```
docker run -it --rm \
--name n8n \

View File

@ -1,36 +1,25 @@
FROM node:16-alpine
ARG NODE_VERSION=16
FROM n8nio/base:${NODE_VERSION}
ARG N8N_VERSION
RUN if [ -z "$N8N_VERSION" ] ; then echo "The N8N_VERSION argument is missing!" ; exit 1; fi
# Update everything and install needed dependencies
RUN apk add --update graphicsmagick tzdata git tini su-exec
ENV NODE_ENV=production
RUN set -eux; \
apkArch="$(apk --print-arch)"; \
case "$apkArch" in \
'armv7') apk --no-cache add --virtual build-dependencies python3 build-base;; \
esac && \
npm install -g --omit=dev n8n@${N8N_VERSION} && \
case "$apkArch" in \
'armv7') apk del build-dependencies;; \
esac && \
find /usr/local/lib/node_modules/n8n -type f -name "*.ts" -o -name "*.js.map" -o -name "*.vue" | xargs rm && \
rm -rf /root/.npm
# # Set a custom user to not have n8n run as root
# Set a custom user to not have n8n run as root
USER root
# Install n8n and the also temporary all the packages
# it needs to build it correctly.
RUN apk --update add --virtual build-dependencies python3 build-base ca-certificates && \
npm config set python "$(which python3)" && \
npm_config_user=root npm install -g full-icu n8n@${N8N_VERSION} && \
apk del build-dependencies \
&& rm -rf /root /tmp/* /var/cache/apk/* && mkdir /root;
# Install fonts
RUN apk --no-cache add --virtual fonts msttcorefonts-installer fontconfig && \
update-ms-fonts && \
fc-cache -f && \
apk del fonts && \
find /usr/share/fonts/truetype/msttcorefonts/ -type l -exec unlink {} \; \
&& rm -rf /root /tmp/* /var/cache/apk/* && mkdir /root
ENV NODE_ICU_DATA /usr/local/lib/node_modules/full-icu
WORKDIR /data
RUN apk --no-cache add su-exec
COPY docker-entrypoint.sh /docker-entrypoint.sh
ENTRYPOINT ["tini", "--", "/docker-entrypoint.sh"]
EXPOSE 5678/tcp

View File

@ -265,4 +265,4 @@ Before you upgrade to the latest version make sure to check here if there are an
n8n is [fair-code](http://faircode.io) distributed under the [**Sustainable Use License**](https://github.com/n8n-io/n8n/blob/master/packages/cli/LICENSE.md).
Additional information on the license can be found in the [FAQ](https://docs.n8n.io/reference/faq.html#license)
Additional information about the license can be found in the [docs](https://docs.n8n.io/reference/license/).

View File

@ -1,6 +0,0 @@
{
"packages": [
"packages/*"
],
"version": "independent"
}

195125
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,29 +1,41 @@
{
"name": "n8n",
"version": "0.186.1",
"version": "0.197.1",
"private": true,
"homepage": "https://n8n.io",
"scripts": {
"bootstrap": "lerna bootstrap --hoist --no-ci",
"build": "lerna exec npm run build",
"dev": "lerna exec npm run dev --parallel",
"clean:dist": "lerna exec -- rimraf ./dist",
"format": "lerna exec npm run format",
"lint": "lerna exec npm run lint",
"lintfix": "lerna exec npm run lintfix",
"build": "turbo run build",
"dev": "turbo run dev --parallel",
"clean:dist": "npm exec -ws -- rimraf ./dist",
"format": "turbo run format && node scripts/format.mjs",
"lint": "turbo run lint",
"lintfix": "turbo run lintfix",
"optimize-svg": "find ./packages -name '*.svg' ! -name 'pipedrive.svg' -print0 | xargs -0 -P16 -L20 npx svgo",
"postinstall": "patch-package",
"start": "run-script-os",
"start:default": "cd packages/cli/bin && ./n8n",
"start:tunnel": "./packages/cli/bin/n8n start --tunnel",
"start:windows": "cd packages/cli/bin && n8n",
"test": "lerna run test",
"watch": "lerna run --parallel watch",
"test": "turbo run test",
"watch": "turbo run watch",
"webhook": "./packages/cli/bin/n8n webhook",
"worker": "./packages/cli/bin/n8n worker"
},
"devDependencies": {
"lerna": "^3.13.1",
"patch-package": "^6.4.7",
"rimraf": "^3.0.2",
"run-script-os": "^1.0.7"
"run-script-os": "^1.0.7",
"turbo": "1.2.15"
},
"postcss": {}
"postcss": {},
"workspaces": [
"packages/*",
"packages/@n8n_io/*"
],
"overrides": {
"browserslist": "^4.21.3",
"ejs": "^3.1.8",
"fork-ts-checker-webpack-plugin": "^6.0.4",
"globby": "^11.0.2"
}
}

View File

@ -0,0 +1,396 @@
/**
* @type {import('@types/eslint').ESLint.ConfigData}
*/
const config = (module.exports = {
parser: '@typescript-eslint/parser',
parserOptions: {
sourceType: 'module',
project: ['./tsconfig.json'],
},
ignorePatterns: [
'.eslintrc.js', // TODO: remove this
'node_modules/**',
'dist/**',
'test/**', // TODO: remove this
],
plugins: [
/**
* Plugin with lint rules for import/export syntax
* https://github.com/import-js/eslint-plugin-import
*/
'eslint-plugin-import',
/**
* @typescript-eslint/eslint-plugin is required by eslint-config-airbnb-typescript
* See step 2: https://github.com/iamturns/eslint-config-airbnb-typescript#2-install-eslint-plugins
*/
'@typescript-eslint',
/**
* Plugin to report formatting violations as lint violations
* https://github.com/prettier/eslint-plugin-prettier
*/
'eslint-plugin-prettier',
/*
* Plugin to allow specifying local ESLint rules.
* https://github.com/ivov/eslint-plugin-n8n-local-rules
*/
'eslint-plugin-n8n-local-rules',
],
extends: [
/**
* Config for typescript-eslint recommended ruleset (without type checking)
*
* https://github.com/typescript-eslint/typescript-eslint/blob/1c1b572c3000d72cfe665b7afbada0ec415e7855/packages/eslint-plugin/src/configs/recommended.ts
*/
'plugin:@typescript-eslint/recommended',
/**
* Config for typescript-eslint recommended ruleset (with type checking)
*
* https://github.com/typescript-eslint/typescript-eslint/blob/1c1b572c3000d72cfe665b7afbada0ec415e7855/packages/eslint-plugin/src/configs/recommended-requiring-type-checking.ts
*/
'plugin:@typescript-eslint/recommended-requiring-type-checking',
/**
* Config for Airbnb style guide for TS, /base to remove React rules
*
* https://github.com/iamturns/eslint-config-airbnb-typescript
* https://github.com/airbnb/javascript/tree/master/packages/eslint-config-airbnb-base/rules
*/
'eslint-config-airbnb-typescript/base',
/**
* Config to disable ESLint rules covered by Prettier
*
* https://github.com/prettier/eslint-config-prettier
*/
'eslint-config-prettier',
],
rules: {
// ******************************************************************
// required by prettier plugin
// ******************************************************************
// The following rule enables eslint-plugin-prettier
// See: https://github.com/prettier/eslint-plugin-prettier#recommended-configuration
'prettier/prettier': ['error', { endOfLine: 'auto' }],
// The following two rules must be disabled when using eslint-plugin-prettier:
// See: https://github.com/prettier/eslint-plugin-prettier#arrow-body-style-and-prefer-arrow-callback-issue
/**
* https://eslint.org/docs/rules/arrow-body-style
*/
'arrow-body-style': 'off',
/**
* https://eslint.org/docs/rules/prefer-arrow-callback
*/
'prefer-arrow-callback': 'off',
// ******************************************************************
// additions to base ruleset
// ******************************************************************
// ----------------------------------
// ESLint
// ----------------------------------
/**
* https://eslint.org/docs/rules/id-denylist
*/
'id-denylist': [
'error',
'err',
'cb',
'callback',
'any',
'Number',
'number',
'String',
'string',
'Boolean',
'boolean',
'Undefined',
'undefined',
],
'no-void': ['error', { allowAsStatement: true }],
// ----------------------------------
// @typescript-eslint
// ----------------------------------
/**
* https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/array-type.md
*/
'@typescript-eslint/array-type': ['error', { default: 'array-simple' }],
/**
* https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/ban-ts-comment.md
*/
'@typescript-eslint/ban-ts-comment': 'off',
/**
* https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/ban-types.md
*/
'@typescript-eslint/ban-types': [
'error',
{
types: {
Object: {
message: 'Use object instead',
fixWith: 'object',
},
String: {
message: 'Use string instead',
fixWith: 'string',
},
Boolean: {
message: 'Use boolean instead',
fixWith: 'boolean',
},
Number: {
message: 'Use number instead',
fixWith: 'number',
},
Symbol: {
message: 'Use symbol instead',
fixWith: 'symbol',
},
Function: {
message: [
'The `Function` type accepts any function-like value.',
'It provides no type safety when calling the function, which can be a common source of bugs.',
'It also accepts things like class declarations, which will throw at runtime as they will not be called with `new`.',
'If you are expecting the function to accept certain arguments, you should explicitly define the function shape.',
].join('\n'),
},
},
extendDefaults: false,
},
],
/**
* https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/consistent-type-assertions.md
*/
'@typescript-eslint/consistent-type-assertions': 'error',
/**
* https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/explicit-member-accessibility.md
*/
'@typescript-eslint/explicit-member-accessibility': ['error', { accessibility: 'no-public' }],
/**
* https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/member-delimiter-style.md
*/
'@typescript-eslint/member-delimiter-style': [
'error',
{
multiline: {
delimiter: 'semi',
requireLast: true,
},
singleline: {
delimiter: 'semi',
requireLast: false,
},
},
],
/**
* https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/naming-convention.md
*/
'@typescript-eslint/naming-convention': [
'error',
{
selector: 'default',
format: ['camelCase'],
},
{
selector: 'variable',
format: ['camelCase', 'snake_case', 'UPPER_CASE'],
leadingUnderscore: 'allowSingleOrDouble',
trailingUnderscore: 'allowSingleOrDouble',
},
{
selector: 'property',
format: ['camelCase', 'snake_case'],
leadingUnderscore: 'allowSingleOrDouble',
trailingUnderscore: 'allowSingleOrDouble',
},
{
selector: 'typeLike',
format: ['PascalCase'],
},
{
selector: ['method', 'function'],
format: ['camelCase'],
leadingUnderscore: 'allowSingleOrDouble',
},
],
/**
* https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-duplicate-imports.md
*/
'@typescript-eslint/no-duplicate-imports': 'error',
/**
* https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-invalid-void-type.md
*/
'@typescript-eslint/no-invalid-void-type': 'error',
/**
* https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-misused-promises.md
*/
'@typescript-eslint/no-misused-promises': ['error', { checksVoidReturn: false }],
/**
* https://github.com/typescript-eslint/typescript-eslint/blob/v4.30.0/packages/eslint-plugin/docs/rules/no-floating-promises.md
*/
'@typescript-eslint/no-floating-promises': ['error', { ignoreVoid: true }],
/**
* https://github.com/typescript-eslint/typescript-eslint/blob/v4.33.0/packages/eslint-plugin/docs/rules/no-namespace.md
*/
'@typescript-eslint/no-namespace': 'off',
/**
* https://eslint.org/docs/1.0.0/rules/no-throw-literal
*/
'@typescript-eslint/no-throw-literal': 'error',
/**
* https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-unnecessary-boolean-literal-compare.md
*/
'@typescript-eslint/no-unnecessary-boolean-literal-compare': 'error',
/**
* https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-unnecessary-qualifier.md
*/
'@typescript-eslint/no-unnecessary-qualifier': 'error',
/**
* https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-unused-expressions.md
*/
'@typescript-eslint/no-unused-expressions': 'error',
/**
* https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-unused-vars.md
*/
'@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '_' }],
/**
* https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/prefer-nullish-coalescing.md
*/
'@typescript-eslint/prefer-nullish-coalescing': 'error',
/**
* https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/prefer-optional-chain.md
*/
'@typescript-eslint/prefer-optional-chain': 'error',
/**
* https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/promise-function-async.md
*/
'@typescript-eslint/promise-function-async': 'error',
// ----------------------------------
// eslint-plugin-import
// ----------------------------------
/**
* https://github.com/import-js/eslint-plugin-import/blob/master/docs/rules/no-default-export.md
*/
'import/no-default-export': 'error',
/**
* https://github.com/import-js/eslint-plugin-import/blob/master/docs/rules/order.md
*/
'import/order': 'error',
// ----------------------------------
// eslint-plugin-n8n-local-rules
// ----------------------------------
// TODO: set to `error` and fix offenses
'n8n-local-rules/no-uncaught-json-parse': 'warn',
// ******************************************************************
// overrides to base ruleset
// ******************************************************************
// ----------------------------------
// ESLint
// ----------------------------------
/**
* https://eslint.org/docs/rules/class-methods-use-this
*/
'class-methods-use-this': 'off',
/**
* https://eslint.org/docs/rules/eqeqeq
*/
eqeqeq: 'error',
/**
* https://eslint.org/docs/rules/no-plusplus
*/
'no-plusplus': 'off',
/**
* https://eslint.org/docs/rules/object-shorthand
*/
'object-shorthand': 'error',
/**
* https://eslint.org/docs/rules/prefer-const
*/
'prefer-const': 'error',
/**
* https://eslint.org/docs/rules/prefer-spread
*/
'prefer-spread': 'error',
/**
* https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/docs/rules/no-unused-vars.md
*
* Disabled because eslint-plugin-diff fails to catch it. TODO: Revisit.
*/
'@typescript-eslint/no-unused-vars': 'warn',
// ----------------------------------
// import
// ----------------------------------
/**
* https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/prefer-default-export.md
*/
'import/prefer-default-export': 'off',
},
});
if ('ESLINT_PLUGIN_DIFF_COMMIT' in process.env) {
/**
* Plugin to lint only changes
*
* https://github.com/paleite/eslint-plugin-diff#plugindiffdiff-recommended
*/
config.plugins.push('eslint-plugin-diff');
/**
* Config for eslint-plugin-diff
*
* https://github.com/paleite/eslint-plugin-diff#plugindiffdiff-recommended
*/
config.extends.push('plugin:diff/diff');
}

View File

@ -0,0 +1,39 @@
/**
* @type {import('@types/eslint').ESLint.ConfigData}
*/
module.exports = {
plugins: ['vue'],
extends: [
'plugin:vue/essential',
'@vue/typescript',
'@n8n_io/eslint-config/base',
],
env: {
browser: true,
es6: true,
node: true,
},
parser: 'vue-eslint-parser',
parserOptions: {
parser: '@typescript-eslint/parser',
},
ignorePatterns: [
'**/*.js',
'**/*.d.ts',
'vite.config.ts',
],
rules: {
'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off',
'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off',
semi: [2, 'always'],
indent: ['error', 'tab'],
'comma-dangle': ['error', 'always-multiline'],
'no-tabs': 0,
'no-labels': 0,
},
};

View File

@ -0,0 +1,86 @@
'use strict';
/**
* This file contains any locally defined ESLint rules. They are picked up by
* eslint-plugin-n8n-local-rules and exposed as 'n8n-local-rules/<rule-name>'.
*/
module.exports = {
/**
* A rule to detect calls to JSON.parse() that are not wrapped inside try/catch blocks.
*
* Valid:
* ```js
* try { JSON.parse(foo) } catch(err) { baz() }
* ```
*
* Invalid:
* ```js
* JSON.parse(foo)
* ```
*
* The pattern where an object is cloned with JSON.parse(JSON.stringify()) is allowed
* (abundant in the n8n codebase):
*
* Valid:
* ```js
* JSON.parse(JSON.stringify(foo))
* ```
*/
'no-uncaught-json-parse': {
meta: {
type: 'problem',
docs: {
description: 'Calls to JSON.parse() must be surrounded with a try/catch block.',
recommended: 'error',
},
schema: [],
messages: {
noUncaughtJsonParse: 'Surround the JSON.parse() call with a try/catch block.',
},
},
defaultOptions: [],
create(context) {
return {
CallExpression(node) {
if (!isJsonParseCall(node)) {
return;
}
if (isDeepCloneOperation(node)) {
return;
}
if (context.getAncestors().find((node) => node.type === 'TryStatement') !== undefined) {
return;
}
// Found a JSON.parse() call not wrapped into a try/catch, so report it
context.report({
messageId: 'noUncaughtJsonParse',
node,
});
},
};
},
},
};
const isJsonParseCall = (node) =>
node.callee.type === 'MemberExpression' &&
node.callee.object.type === 'Identifier' &&
node.callee.object.name === 'JSON' &&
node.callee.property.type === 'Identifier' &&
node.callee.property.name === 'parse';
const isDeepCloneOperation = (node) => {
const parseArg = node.arguments?.[0];
return (
parseArg !== undefined &&
parseArg.type === 'CallExpression' &&
parseArg.callee.type === 'MemberExpression' &&
parseArg.callee.object.type === 'Identifier' &&
parseArg.callee.object.name === 'JSON' &&
parseArg.callee.property.type === 'Identifier' &&
parseArg.callee.property.name === 'stringify'
);
};

View File

@ -0,0 +1,23 @@
'use strict';
const rules = require('./local-rules'),
RuleTester = require('eslint').RuleTester;
const ruleTester = new RuleTester();
ruleTester.run('no-uncaught-json-parse', rules['no-uncaught-json-parse'], {
valid: [
{
code: 'try { JSON.parse(foo) } catch (e) {}',
},
{
code: 'JSON.parse(JSON.stringify(foo))',
},
],
invalid: [
{
code: 'JSON.parse(foo)',
errors: [{ messageId: 'noUncaughtJsonParse' }],
},
],
});

View File

@ -0,0 +1,11 @@
/**
* @type {import('@types/eslint').ESLint.ConfigData}
*/
module.exports = {
extends: ['@n8n_io/eslint-config/base'],
env: {
es6: true,
node: true,
},
};

View File

@ -0,0 +1,22 @@
{
"name": "@n8n_io/eslint-config",
"private": true,
"devDependencies": {
"@types/eslint": "8.4.6",
"@typescript-eslint/eslint-plugin": "^5.36.2",
"@typescript-eslint/parser": "^5.36.2",
"@vue/eslint-config-typescript": "^11.0.0",
"eslint": "8.23.0",
"eslint-config-airbnb-typescript": "^17.0.0",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-diff": "^2.0.1",
"eslint-plugin-import": "^2.26.0",
"eslint-plugin-n8n-local-rules": "^1.0.0",
"eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-vue": "^9.4.0",
"jest": "^28.1.3"
},
"scripts": {
"test": "jest"
}
}

16
packages/cli/.eslintrc.js Normal file
View File

@ -0,0 +1,16 @@
/**
* @type {import('@types/eslint').ESLint.ConfigData}
*/
module.exports = {
extends: ['@n8n_io/eslint-config/node'],
ignorePatterns: [
'jest.config.js',
// TODO: Remove these
'src/databases/migrations/**',
'src/databases/ormconfig.ts',
],
rules: {
// TODO: Remove this
'import/order': 'off',
},
};

View File

@ -1,43 +1,69 @@
# Sustainable Use License
# License
Portions of this software are licensed as follows:
- All source code files of this repository that contain ".ee." in their filename are licensed under the n8n Enterprise License defined in "LICENSE_EE.md".
- All third party components incorporated into the n8n Software are licensed under the original license
provided by the owner of the applicable component.
- Content outside of the above mentioned files or restrictions above is available under the "Sustainable Use
License" as defined below.
## Sustainable Use License
Version 1.0
## Acceptance
### Acceptance
By using the software, you agree to all of the terms and conditions below.
## Copyright License
### Copyright License
The licensor grants you a non-exclusive, royalty-free, worldwide, non-sublicensable, non-transferable license to use, copy, distribute, make available, and prepare derivative works of the software, in each case subject to the limitations below.
The licensor grants you a non-exclusive, royalty-free, worldwide, non-sublicensable, non-transferable license
to use, copy, distribute, make available, and prepare derivative works of the software, in each case subject
to the limitations below.
## Limitations
### Limitations
You may use or modify the software only for your own internal business purposes or for non-commercial or personal use.
You may distribute the software or provide it to others only if you do so free of charge for non-commercial purposes.
You may not alter, remove, or obscure any licensing, copyright, or other notices of the licensor in the software. Any use of the licensors trademarks is subject to applicable law.
You may use or modify the software only for your own internal business purposes or for non-commercial or
personal use. You may distribute the software or provide it to others only if you do so free of charge for
non-commercial purposes. You may not alter, remove, or obscure any licensing, copyright, or other notices of
the licensor in the software. Any use of the licensors trademarks is subject to applicable law.
## Patents
### Patents
The licensor grants you a license, under any patent claims the licensor can license, or becomes able to license, to make, have made, use, sell, offer for sale, import and have imported the software, in each case subject to the limitations and conditions in this license. This license does not cover any patent claims that you cause to be infringed by modifications or additions to the software. If you or your company make any written claim that the software infringes or contributes to infringement of any patent, your patent license for the software granted under these terms ends immediately. If your company makes such a claim, your patent license ends immediately for work on behalf of your company.
The licensor grants you a license, under any patent claims the licensor can license, or becomes able to
license, to make, have made, use, sell, offer for sale, import and have imported the software, in each case
subject to the limitations and conditions in this license. This license does not cover any patent claims that
you cause to be infringed by modifications or additions to the software. If you or your company make any
written claim that the software infringes or contributes to infringement of any patent, your patent license
for the software granted under these terms ends immediately. If your company makes such a claim, your patent
license ends immediately for work on behalf of your company.
## Notices
### Notices
You must ensure that anyone who gets a copy of any part of the software from you also gets a copy of these terms.
If you modify the software, you must include in any modified copies of the software a prominent notice stating that you have modified the software.
You must ensure that anyone who gets a copy of any part of the software from you also gets a copy of these
terms. If you modify the software, you must include in any modified copies of the software a prominent notice
stating that you have modified the software.
## No Other Rights
### No Other Rights
These terms do not imply any licenses other than those expressly granted in these terms.
## Termination
### Termination
If you use the software in violation of these terms, such use is not licensed, and your license will automatically terminate. If the licensor provides you with a notice of your violation, and you cease all violation of this license no later than 30 days after you receive that notice, your license will be reinstated retroactively. However, if you violate these terms after such reinstatement, any additional violation of these terms will cause your license to terminate automatically and permanently.
If you use the software in violation of these terms, such use is not licensed, and your license will
automatically terminate. If the licensor provides you with a notice of your violation, and you cease all
violation of this license no later than 30 days after you receive that notice, your license will be reinstated
retroactively. However, if you violate these terms after such reinstatement, any additional violation of these
terms will cause your license to terminate automatically and permanently.
## No Liability
### No Liability
As far as the law allows, the software comes as is, without any warranty or condition, and the licensor will not be liable to you for any damages arising out of these terms or the use or nature of the software, under any kind of legal claim.
As far as the law allows, the software comes as is, without any warranty or condition, and the licensor will
not be liable to you for any damages arising out of these terms or the use or nature of the software, under
any kind of legal claim.
## Definitions
### Definitions
The “licensor” is the entity offering these terms.
@ -45,7 +71,10 @@ The “software” is the software the licensor makes available under these term
“You” refers to the individual or entity agreeing to these terms.
“Your company” is any legal entity, sole proprietorship, or other kind of organization that you work for, plus all organizations that have control over, are under the control of, or are under common control with that organization. Control means ownership of substantially all the assets of an entity, or the power to direct its management and policies by vote, contract, or otherwise. Control can be direct or indirect.
“Your company” is any legal entity, sole proprietorship, or other kind of organization that you work for, plus
all organizations that have control over, are under the control of, or are under common control with that
organization. Control means ownership of substantially all the assets of an entity, or the power to direct its
management and policies by vote, contract, or otherwise. Control can be direct or indirect.
“Your license” is the license granted to you for the software under these terms.

View File

@ -0,0 +1,27 @@
# The n8n Enterprise License (the “Enterprise License”)
Copyright (c) 2022-present n8n GmbH.
With regard to the n8n Software:
This software and associated documentation files (the "Software") may only be used in production, if
you (and any entity that you represent) hold a valid n8n Enterprise license corresponding to your
usage. Subject to the foregoing sentence, you are free to modify this Software and publish patches
to the Software. You agree that n8n and/or its licensors (as applicable) retain all right, title and
interest in and to all such modifications and/or patches, and all such modifications and/or patches
may only be used, copied, modified, displayed, distributed, or otherwise exploited with a valid n8n
Enterprise license for the corresponding usage. Notwithstanding the foregoing, you may copy and
modify the Software for development and testing purposes, without requiring a subscription. You
agree that n8n and/or its licensors (as applicable) retain all right, title and interest in and to
all such modifications. You are not granted any other rights beyond what is expressly stated herein.
Subject to the foregoing, it is forbidden to copy, merge, publish, distribute, sublicense, and/or
sell the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES
OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
For all third party components incorporated into the n8n Software, those components are licensed
under the original license provided by the owner of the applicable component.

View File

@ -113,7 +113,7 @@ You can find additional information and example workflows on the [n8n.io](https:
## Create Custom Nodes
You can create custom nodes for n8n. Follow the instructions mentioned in the documentation to create your node: [Creating nodes](https://docs.n8n.io/nodes/creating-nodes/create-node.html)
You can create custom nodes for n8n. Follow the instructions mentioned in the documentation to create your node: [Creating nodes](https://docs.n8n.io/integrations/creating-nodes/build/)
## Contributing
@ -151,4 +151,4 @@ You can also find breaking changes here: [Breaking Changes](./BREAKING-CHANGES.m
n8n is [fair-code](http://faircode.io) distributed under the [**Sustainable Use License**](https://github.com/n8n-io/n8n/blob/master/packages/cli/LICENSE.md).
Additional information on the license can be found in the [FAQ](https://docs.n8n.io/reference/faq.html#license)
Additional information about the license can be found in the [docs](https://docs.n8n.io/reference/license/).

View File

@ -1,13 +1,13 @@
#!/usr/bin/env node
var path = require('path'); // tslint:disable-line:no-var-keyword
var path = require('path');
// Make sure that it also find the config folder when it
// did get started from another folder that the root one.
process.env.NODE_CONFIG_DIR = process.env.NODE_CONFIG_DIR || path.join(__dirname, 'config');
// Check if version should be displayed
var versionFlags = [ // tslint:disable-line:no-var-keyword
var versionFlags = [
'-v',
'-V',
'--version',

View File

@ -15,7 +15,7 @@ interface IResult {
interface IExecutionResult {
workflowId: string | number;
workflowName: string;
executionTime: number; // Given in seconds with decimals for milisseconds
executionTime: number; // Given in seconds with decimals for milliseconds
finished: boolean;
executionStatus: ExecutionStatus;
error?: string;

View File

@ -52,6 +52,7 @@ export class DbRevertMigrationCommand extends Command {
if (connection) await connection.close();
console.error('Error reverting last migration. See log messages for details.');
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
logger.error(error.message);
this.exit(1);
}

View File

@ -1,3 +1,4 @@
/* eslint-disable @typescript-eslint/no-unsafe-argument */
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
/* eslint-disable no-console */
import { promises as fs } from 'fs';

View File

@ -98,7 +98,7 @@ export class ExecuteBatch extends Command {
}),
shallow: flags.boolean({
description:
'Compares only if attributes output from node are the same, with no regards to neste JSON objects.',
'Compares only if attributes output from node are the same, with no regards to nested JSON objects.',
}),
skipList: flags.string({
description: 'File containing a comma separated list of workflow IDs to skip.',
@ -152,7 +152,7 @@ export class ExecuteBatch extends Command {
executingWorkflows = activeExecutionsInstance.getActiveExecutions();
}
// We may receive true but when called from `process.on`
// we get the signal (SIGNIT, etc.)
// we get the signal (SIGINT, etc.)
if (skipExit !== true) {
process.exit(0);
}
@ -864,7 +864,7 @@ export class ExecuteBatch extends Command {
}
}
// Save snapshots only after comparing - this is to make sure we're updating
// After comparing to existing verion.
// After comparing to existing version.
if (ExecuteBatch.snapshot !== undefined) {
const fileName = `${
ExecuteBatch.snapshot.endsWith(sep)

View File

@ -1,3 +1,4 @@
/* eslint-disable @typescript-eslint/no-unsafe-argument */
/* eslint-disable @typescript-eslint/restrict-plus-operands */
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
/* eslint-disable no-console */
@ -85,7 +86,7 @@ export class ExportCredentialsCommand extends Command {
if (fs.existsSync(flags.output)) {
if (!fs.lstatSync(flags.output).isDirectory()) {
console.info(`The paramenter --output must be a directory`);
console.info(`The parameter --output must be a directory`);
return;
}
} else {
@ -104,7 +105,7 @@ export class ExportCredentialsCommand extends Command {
} else if (flags.output) {
if (fs.existsSync(flags.output)) {
if (fs.lstatSync(flags.output).isDirectory()) {
console.info(`The paramenter --output must be a writeble file`);
console.info(`The parameter --output must be a writeable file`);
return;
}
}

View File

@ -1,3 +1,4 @@
/* eslint-disable @typescript-eslint/no-unsafe-argument */
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
/* eslint-disable no-console */
import { Command, flags } from '@oclif/command';
@ -77,7 +78,7 @@ export class ExportWorkflowsCommand extends Command {
if (fs.existsSync(flags.output)) {
if (!fs.lstatSync(flags.output).isDirectory()) {
console.info(`The paramenter --output must be a directory`);
console.info(`The parameter --output must be a directory`);
return;
}
} else {
@ -96,7 +97,7 @@ export class ExportWorkflowsCommand extends Command {
} else if (flags.output) {
if (fs.existsSync(flags.output)) {
if (fs.lstatSync(flags.output).isDirectory()) {
console.info(`The paramenter --output must be a writeble file`);
console.info(`The parameter --output must be a writeable file`);
return;
}
}

View File

@ -1,3 +1,4 @@
/* eslint-disable @typescript-eslint/no-unsafe-argument */
/* eslint-disable no-restricted-syntax */
/* eslint-disable @typescript-eslint/no-shadow */
/* eslint-disable @typescript-eslint/no-unsafe-call */
@ -13,7 +14,6 @@ import { LoggerProxy } from 'n8n-workflow';
import fs from 'fs';
import glob from 'fast-glob';
import path from 'path';
import { EntityManager, getConnection } from 'typeorm';
import { getLogger } from '../../src/Logger';
import { Db } from '../../src';
@ -87,9 +87,16 @@ export class ImportCredentialsCommand extends Command {
const encryptionKey = await UserSettings.getEncryptionKey();
if (flags.separate) {
const files = await glob(
`${flags.input.endsWith(path.sep) ? flags.input : flags.input + path.sep}*.json`,
);
let { input: inputPath } = flags;
if (process.platform === 'win32') {
inputPath = inputPath.replace(/\\/g, '/');
}
const files = await glob('*.json', {
cwd: inputPath,
absolute: true,
});
totalImported = files.length;

View File

@ -1,3 +1,4 @@
/* eslint-disable @typescript-eslint/no-unsafe-argument */
/* eslint-disable no-restricted-syntax */
/* eslint-disable @typescript-eslint/restrict-template-expressions */
/* eslint-disable @typescript-eslint/no-shadow */
@ -16,6 +17,7 @@ import fs from 'fs';
import glob from 'fast-glob';
import { UserSettings } from 'n8n-core';
import { EntityManager, getConnection } from 'typeorm';
import { v4 as uuid } from 'uuid';
import { getLogger } from '../../src/Logger';
import { Db, ICredentialsDb, IWorkflowToImport } from '../../src';
import { SharedWorkflow } from '../../src/databases/entities/SharedWorkflow';
@ -113,9 +115,10 @@ export class ImportWorkflowsCommand extends Command {
inputPath = inputPath.replace(/\\/g, '/');
}
inputPath = inputPath.replace(/\/$/g, '');
const files = await glob(`${inputPath}/*.json`);
const files = await glob('*.json', {
cwd: inputPath,
absolute: true,
});
totalImported = files.length;
@ -128,6 +131,11 @@ export class ImportWorkflowsCommand extends Command {
if (credentials.length > 0) {
workflow.nodes.forEach((node: INode) => {
this.transformCredentials(node, credentials);
if (!node.id) {
// eslint-disable-next-line no-param-reassign
node.id = uuid();
}
});
}
@ -156,6 +164,11 @@ export class ImportWorkflowsCommand extends Command {
if (credentials.length > 0) {
workflow.nodes.forEach((node: INode) => {
this.transformCredentials(node, credentials);
if (!node.id) {
// eslint-disable-next-line no-param-reassign
node.id = uuid();
}
});
}

View File

@ -33,6 +33,7 @@ import {
} from '../src';
import { getLogger } from '../src/Logger';
import { getAllInstalledPackages } from '../src/CommunityNodes/packageModel';
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-var-requires
const open = require('open');
@ -60,6 +61,10 @@ export class Start extends Command {
description:
'runs the webhooks via a hooks.n8n.cloud tunnel server. Use only for testing and development!',
}),
reinstallMissingPackages: flags.boolean({
description:
'Attempts to self heal n8n if packages with nodes are missing. Might drastically increase startup times.',
}),
};
/**
@ -87,6 +92,9 @@ export class Start extends Command {
getLogger().info('\nStopping n8n...');
try {
// Stop with trying to activate workflows that could not be activated
activeWorkflowRunner?.removeAllQueuedWorkflowActivations();
const externalHooks = ExternalHooks();
await externalHooks.run('n8n.stop', []);
@ -206,6 +214,23 @@ export class Start extends Command {
// Wait till the database is ready
await startDbInitPromise;
const installedPackages = await getAllInstalledPackages();
const missingPackages = new Set<{
packageName: string;
version: string;
}>();
installedPackages.forEach((installedpackage) => {
installedpackage.installedNodes.forEach((installedNode) => {
if (!loadNodesAndCredentials.nodeTypes[installedNode.type]) {
// Leave the list ready for installing in case we need.
missingPackages.add({
packageName: installedpackage.packageName,
version: installedpackage.installedVersion,
});
}
});
});
await UserSettings.getEncryptionKey();
// Load settings from database and set them to config.
@ -214,6 +239,42 @@ export class Start extends Command {
config.set(setting.key, JSON.parse(setting.value));
});
config.set('nodes.packagesMissing', '');
if (missingPackages.size) {
LoggerProxy.error(
'n8n detected that some packages are missing. For more information, visit https://docs.n8n.io/integrations/community-nodes/troubleshooting/',
);
if (flags.reinstallMissingPackages || process.env.N8N_REINSTALL_MISSING_PACKAGES) {
LoggerProxy.info('Attempting to reinstall missing packages', { missingPackages });
try {
// Optimistic approach - stop if any installation fails
// eslint-disable-next-line no-restricted-syntax
for (const missingPackage of missingPackages) {
// eslint-disable-next-line no-await-in-loop
void (await loadNodesAndCredentials.loadNpmModule(
missingPackage.packageName,
missingPackage.version,
));
missingPackages.delete(missingPackage);
}
LoggerProxy.info(
'Packages reinstalled successfully. Resuming regular initialization.',
);
} catch (error) {
LoggerProxy.error('n8n was unable to install the missing packages.');
}
}
}
if (missingPackages.size) {
config.set(
'nodes.packagesMissing',
Array.from(missingPackages)
.map((missingPackage) => `${missingPackage.packageName}@${missingPackage.version}`)
.join(' '),
);
}
if (config.getEnv('executions.mode') === 'queue') {
const redisHost = config.getEnv('queue.bull.redis.host');
const redisPassword = config.getEnv('queue.bull.redis.password');
@ -269,6 +330,7 @@ export class Start extends Command {
if (error.toString().includes('ECONNREFUSED') === true) {
logger.warn('Redis unavailable - trying to reconnect...');
} else {
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
logger.warn('Error with Redis: ', error);
}
});
@ -357,6 +419,7 @@ export class Start extends Command {
process.stdin.setRawMode(true);
process.stdin.resume();
process.stdin.setEncoding('utf8');
// eslint-disable-next-line @typescript-eslint/no-unused-vars
let inputText = '';
if (flags.open) {

View File

@ -1,3 +1,4 @@
/* eslint-disable @typescript-eslint/no-unsafe-argument */
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
/* eslint-disable no-console */
import { Command, flags } from '@oclif/command';

View File

@ -1,5 +1,6 @@
import { Not } from 'typeorm';
import { Db } from '../../src';
import { CredentialsEntity } from '../../src/databases/entities/CredentialsEntity';
import { BaseCommand } from '../BaseCommand';
export class Reset extends BaseCommand {
@ -31,6 +32,20 @@ export class Reset extends BaseCommand {
await Db.collections.User.delete({ id: Not(owner.id) });
await Db.collections.User.save(Object.assign(owner, this.defaultUserProps));
const danglingCredentials: CredentialsEntity[] =
(await Db.collections.Credentials.createQueryBuilder('credentials')
.leftJoinAndSelect('credentials.shared', 'shared')
.where('shared.credentialsId is null')
.getMany()) as CredentialsEntity[];
const newSharedCredentials = danglingCredentials.map((credentials) =>
Db.collections.SharedCredentials.create({
credentials,
user: owner,
role: ownerCredentialRole,
}),
);
await Db.collections.SharedCredentials.save(newSharedCredentials);
await Db.collections.Settings.update(
{ key: 'userManagement.isInstanceOwnerSetUp' },
{ value: 'false' },

View File

@ -1,3 +1,4 @@
/* eslint-disable @typescript-eslint/no-unsafe-argument */
/* eslint-disable no-console */
/* eslint-disable @typescript-eslint/no-unsafe-call */
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
@ -105,7 +106,7 @@ export class Webhook extends Command {
* as it is unable to determine if it is still running or crashed
* - You cannot stop currently executing jobs from webhook processes
* when running without queues as the main process cannot talk to
* the wehbook processes to communicate workflow execution interruption.
* the webhook processes to communicate workflow execution interruption.
*/
this.error('Webhook processes can only run with execution mode as queue.');

View File

@ -1,3 +1,4 @@
/* eslint-disable @typescript-eslint/no-unsafe-argument */
/* eslint-disable no-console */
/* eslint-disable @typescript-eslint/no-shadow */
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
@ -12,23 +13,18 @@ import http from 'http';
import PCancelable from 'p-cancelable';
import { Command, flags } from '@oclif/command';
import { BinaryDataManager, IBinaryDataConfig, UserSettings, WorkflowExecute } from 'n8n-core';
import { BinaryDataManager, UserSettings, WorkflowExecute } from 'n8n-core';
import { IExecuteResponsePromiseData, INodeTypes, IRun, Workflow, LoggerProxy } from 'n8n-workflow';
import { FindOneOptions, getConnectionManager } from 'typeorm';
import Bull from 'bull';
import {
CredentialsOverwrites,
CredentialTypes,
Db,
ExternalHooks,
GenericHelpers,
IBullJobData,
IBullJobResponse,
IBullWebhookResponse,
IExecutionFlattedDb,
InternalHooksManager,
LoadNodesAndCredentials,
NodeTypes,
@ -45,6 +41,7 @@ import {
checkPermissionsForExecution,
getWorkflowOwner,
} from '../src/UserManagement/UserManagementHelper';
import { generateFailedExecutionFromError } from '../src/WorkflowHelpers';
export class Worker extends Command {
static description = '\nStarts a n8n worker';
@ -63,7 +60,7 @@ export class Worker extends Command {
[key: string]: PCancelable<IRun>;
} = {};
static jobQueue: Bull.Queue;
static jobQueue: Queue.JobQueue;
static processExistCode = 0;
// static activeExecutions = ActiveExecutions.getInstance();
@ -84,7 +81,7 @@ export class Worker extends Command {
const externalHooks = ExternalHooks();
await externalHooks.run('n8n.stop', []);
const maxStopTime = 30000;
const maxStopTime = config.getEnv('queue.bull.gracefulShutdownTimeout') * 1000;
const stopTime = new Date().getTime() + maxStopTime;
@ -117,30 +114,28 @@ export class Worker extends Command {
process.exit(Worker.processExistCode);
}
async runJob(job: Bull.Job, nodeTypes: INodeTypes): Promise<IBullJobResponse> {
const jobData = job.data as IBullJobData;
const executionDb = await Db.collections.Execution.findOne(jobData.executionId);
async runJob(job: Queue.Job, nodeTypes: INodeTypes): Promise<Queue.JobResponse> {
const { executionId, loadStaticData } = job.data;
const executionDb = await Db.collections.Execution.findOne(executionId);
if (!executionDb) {
LoggerProxy.error(
`Worker failed to find data of execution "${jobData.executionId}" in database. Cannot continue.`,
{
executionId: jobData.executionId,
},
`Worker failed to find data of execution "${executionId}" in database. Cannot continue.`,
{ executionId },
);
throw new Error(
`Unable to find data of execution "${jobData.executionId}" in database. Aborting execution.`,
`Unable to find data of execution "${executionId}" in database. Aborting execution.`,
);
}
const currentExecutionDb = ResponseHelper.unflattenExecutionData(executionDb);
LoggerProxy.info(
`Start job: ${job.id} (Workflow ID: ${currentExecutionDb.workflowData.id} | Execution: ${jobData.executionId})`,
`Start job: ${job.id} (Workflow ID: ${currentExecutionDb.workflowData.id} | Execution: ${executionId})`,
);
const workflowOwner = await getWorkflowOwner(currentExecutionDb.workflowData.id!.toString());
let { staticData } = currentExecutionDb.workflowData;
if (jobData.loadStaticData) {
if (loadStaticData) {
const findOptions = {
select: ['id', 'staticData'],
} as FindOneOptions;
@ -153,7 +148,7 @@ export class Worker extends Command {
'Worker execution failed because workflow could not be found in database.',
{
workflowId: currentExecutionDb.workflowData.id,
executionId: jobData.executionId,
executionId,
},
);
throw new Error(
@ -189,8 +184,6 @@ export class Worker extends Command {
settings: currentExecutionDb.workflowData.settings,
});
await checkPermissionsForExecution(workflow, workflowOwner.id);
const additionalData = await WorkflowExecuteAdditionalData.getBase(
workflowOwner.id,
undefined,
@ -203,16 +196,31 @@ export class Worker extends Command {
{ retryOf: currentExecutionDb.retryOf as string },
);
try {
await checkPermissionsForExecution(workflow, workflowOwner.id);
} catch (error) {
const failedExecution = generateFailedExecutionFromError(
currentExecutionDb.mode,
error,
error.node,
);
await additionalData.hooks.executeHookFunctions('workflowExecuteAfter', [failedExecution]);
return {
success: true,
};
}
additionalData.hooks.hookFunctions.sendResponse = [
async (response: IExecuteResponsePromiseData): Promise<void> => {
await job.progress({
executionId: job.data.executionId as string,
const progress: Queue.WebhookResponse = {
executionId,
response: WebhookHelpers.encodeWebhookResponse(response),
} as IBullWebhookResponse);
};
await job.progress(progress);
},
];
additionalData.executionId = jobData.executionId;
additionalData.executionId = executionId;
let workflowExecute: WorkflowExecute;
let workflowRun: PCancelable<IRun>;
@ -362,6 +370,8 @@ export class Worker extends Command {
const port = config.getEnv('queue.health.port');
const app = express();
app.disable('x-powered-by');
const server = http.createServer(app);
app.get(
@ -390,7 +400,7 @@ export class Worker extends Command {
}
// Just to be complete, generally will the worker stop automatically
// if it loses the conection to redis
// if it loses the connection to redis
try {
// Redis ping
await Worker.jobQueue.client.ping();

View File

@ -151,7 +151,7 @@ export const schema = {
// Allows to set default values for credentials which
// get automatically prefilled and the user does not get
// displayed and can not change.
// Format: { CREDENTIAL_NAME: { PARAMTER: VALUE }}
// Format: { CREDENTIAL_NAME: { PARAMETER: VALUE }}
doc: 'Overwrites for credentials',
format: '*',
default: '{}',
@ -248,7 +248,7 @@ export const schema = {
env: 'EXECUTIONS_DATA_SAVE_ON_SUCCESS',
},
saveExecutionProgress: {
doc: 'Wether or not to save progress for each node executed',
doc: 'Whether or not to save progress for each node executed',
format: 'Boolean',
default: false,
env: 'EXECUTIONS_DATA_SAVE_ON_PROGRESS',
@ -351,13 +351,19 @@ export const schema = {
default: 60,
env: 'QUEUE_RECOVERY_INTERVAL',
},
gracefulShutdownTimeout: {
doc: 'How long should n8n wait for running executions before exiting worker process',
format: Number,
default: 30,
env: 'QUEUE_WORKER_TIMEOUT',
},
},
},
generic: {
// The timezone to use. Is important for nodes like "Cron" which start the
// workflow automatically at a specified time. This setting can also be
// overwritten on a per worfklow basis in the workflow settings in the
// overwritten on a per workflow basis in the workflow settings in the
// editor.
timezone: {
doc: 'The timezone to use',
@ -601,7 +607,7 @@ export const schema = {
format: Boolean,
default: false,
env: 'N8N_WORKFLOW_TAGS_DISABLED',
doc: 'Disable worfklow tags.',
doc: 'Disable workflow tags.',
},
userManagement: {
@ -681,6 +687,13 @@ export const schema = {
},
},
externalFrontendHooksUrls: {
doc: 'URLs to external frontend hooks files, ; separated',
format: String,
default: 'https://public.n8n.cloud/posthog-hooks.js',
env: 'EXTERNAL_FRONTEND_HOOKS_URLS',
},
externalHookFiles: {
doc: 'Files containing external hooks. Multiple files can be separated by colon (":")',
format: String,
@ -740,6 +753,14 @@ export const schema = {
default: 'n8n-nodes-base.errorTrigger',
env: 'NODES_ERROR_TRIGGER_TYPE',
},
communityPackages: {
enabled: {
doc: 'Allows you to disable the usage of community packages for nodes',
format: Boolean,
default: true,
env: 'N8N_COMMUNITY_PACKAGES_ENABLED',
},
},
},
logs: {
@ -854,6 +875,21 @@ export const schema = {
},
},
enterprise: {
features: {
sharing: {
format: Boolean,
default: false,
},
},
// This is a temporary flag (acting as feature toggle)
// Will be removed when feature goes live
workflowSharingEnabled: {
format: Boolean,
default: false,
},
},
hiringBanner: {
enabled: {
doc: 'Whether hiring banner in browser console is enabled.',
@ -880,6 +916,26 @@ export const schema = {
env: 'N8N_DIAGNOSTICS_ENABLED',
},
config: {
posthog: {
apiKey: {
doc: 'API key for PostHog',
format: String,
default: 'phc_4URIAm1uYfJO7j8kWSe0J8lc8IqnstRLS7Jx8NcakHo',
env: 'N8N_DIAGNOSTICS_POSTHOG_API_KEY',
},
apiHost: {
doc: 'API host for PostHog',
format: String,
default: 'https://app.posthog.com',
env: 'N8N_DIAGNOSTICS_POSTHOG_API_HOST',
},
disableSessionRecording: {
doc: 'Disable posthog session recording',
format: Boolean,
default: true,
env: 'N8N_DIAGNOSTICS_POSTHOG_DISABLE_RECORDING',
},
},
frontend: {
doc: 'Diagnostics config for frontend.',
format: String,
@ -901,4 +957,13 @@ export const schema = {
default: 'en',
env: 'N8N_DEFAULT_LOCALE',
},
onboardingCallPrompt: {
enabled: {
doc: 'Whether onboarding call prompt feature is available',
format: Boolean,
default: true,
env: 'N8N_ONBOARDING_CALL_PROMPTS_ENABLED',
},
},
};

View File

@ -1,3 +1,4 @@
/* eslint-disable @typescript-eslint/naming-convention */
/* eslint-disable @typescript-eslint/no-unused-vars */
import { IBinaryDataConfig } from '../../core/dist/src';

View File

@ -1,7 +1,7 @@
module.exports = {
verbose: true,
transform: {
'^.+\\.ts?$': 'ts-jest',
'^.+\\.ts$': 'ts-jest',
},
testURL: 'http://localhost/',
testRegex: '(/__tests__/.*|(\\.|/)(test))\\.ts$',

View File

@ -1,6 +1,6 @@
{
"name": "n8n",
"version": "0.186.1",
"version": "0.197.1",
"description": "n8n Workflow Automation Tool",
"license": "SEE LICENSE IN LICENSE.md",
"homepage": "https://n8n.io",
@ -22,18 +22,18 @@
"build": "node scripts/build.mjs",
"dev": "concurrently -k -n \"TypeScript,Node\" -c \"yellow.bold,cyan.bold\" \"npm run watch\" \"nodemon\"",
"format": "cd ../.. && node_modules/prettier/bin-prettier.js packages/cli/**/**.ts --write",
"lint": "cd ../.. && node_modules/eslint/bin/eslint.js packages/cli",
"lintfix": "cd ../.. && node_modules/eslint/bin/eslint.js packages/cli --fix",
"lint": "eslint .",
"lintfix": "eslint . --fix",
"postpack": "rm -f oclif.manifest.json",
"prepack": "oclif-dev manifest",
"start": "run-script-os",
"start:default": "cd bin && ./n8n",
"start:windows": "cd bin && n8n",
"test": "npm run test:sqlite",
"test:sqlite": "export N8N_LOG_LEVEL=silent && export DB_TYPE=sqlite && jest --forceExit",
"test:postgres": "export N8N_LOG_LEVEL=silent && export DB_TYPE=postgresdb && jest",
"test:postgres:alt-schema": "export DB_POSTGRESDB_SCHEMA=alt_schema && npm run test:postgres",
"test:mysql": "export N8N_LOG_LEVEL=silent && export DB_TYPE=mysqldb && jest",
"test:sqlite": "N8N_LOG_LEVEL=silent DB_TYPE=sqlite jest",
"test:postgres": "N8N_LOG_LEVEL=silent DB_TYPE=postgresdb jest",
"test:postgres:alt-schema": "DB_POSTGRESDB_SCHEMA=alt_schema npm run test:postgres",
"test:mysql": "N8N_LOG_LEVEL=silent DB_TYPE=mysqldb jest",
"watch": "tsc --watch",
"typeorm": "ts-node -T ../../node_modules/typeorm/cli.js"
},
@ -58,6 +58,8 @@
"oclif.manifest.json"
],
"devDependencies": {
"@apidevtools/swagger-cli": "4.0.0",
"@n8n_io/eslint-config": "",
"@oclif/dev-cli": "^1.22.2",
"@types/basic-auth": "^1.1.2",
"@types/bcryptjs": "^2.4.2",
@ -66,49 +68,47 @@
"@types/connect-history-api-fallback": "^1.3.1",
"@types/convict": "^4.2.1",
"@types/cookie-parser": "^1.4.2",
"@types/dotenv": "^8.2.0",
"@types/express": "^4.17.6",
"@types/jest": "^27.4.0",
"@types/json-diff": "^0.5.1",
"@types/jsonwebtoken": "^8.5.2",
"@types/localtunnel": "^1.9.0",
"@types/lodash.get": "^4.4.6",
"@types/lodash.intersection": "^4.4.7",
"@types/lodash.merge": "^4.6.6",
"@types/lodash.omit": "^4.5.7",
"@types/lodash.pick": "^4.4.7",
"@types/lodash.set": "^4.3.6",
"@types/lodash.split": "^4.4.7",
"@types/lodash.unset": "^4.5.7",
"@types/node": "^16.11.22",
"@types/open": "^6.1.0",
"@types/parseurl": "^1.3.1",
"@types/passport-jwt": "^3.0.6",
"@types/psl": "^1.1.0",
"@types/request-promise-native": "~1.0.15",
"@types/send": "^0.17.1",
"@types/shelljs": "^0.8.11",
"@types/superagent": "4.1.13",
"@types/supertest": "^2.0.11",
"@types/uuid": "^8.3.0",
"@types/swagger-ui-express": "^4.1.3",
"@types/uuid": "^8.3.2",
"@types/validator": "^13.7.0",
"axios": "^0.21.1",
"@types/yamljs": "^0.2.31",
"concurrently": "^5.1.0",
"jest": "^27.4.7",
"jest-mock": "^28.1.3",
"nodemon": "^2.0.2",
"run-script-os": "^1.0.7",
"supertest": "^6.2.2",
"ts-jest": "^27.1.3",
"ts-node": "^8.9.1",
"tslint": "^6.1.2",
"typescript": "~4.6.0"
"typescript": "~4.8.0"
},
"dependencies": {
"@oclif/core": "^1.9.3",
"@apidevtools/swagger-cli": "4.0.0",
"@oclif/command": "^1.5.18",
"@oclif/core": "^1.9.3",
"@oclif/errors": "^1.2.2",
"@rudderstack/rudder-sdk-node": "1.0.6",
"@types/json-diff": "^0.5.1",
"@types/jsonwebtoken": "^8.5.2",
"@types/lodash.intersection": "^4.4.7",
"@types/shelljs": "^0.8.11",
"@types/swagger-ui-express": "^4.1.3",
"@types/yamljs": "^0.2.31",
"axios": "^0.21.1",
"basic-auth": "^2.0.1",
"bcryptjs": "^2.4.3",
"body-parser": "^1.18.3",
@ -122,14 +122,16 @@
"connect-history-api-fallback": "^1.6.0",
"convict": "^6.0.1",
"cookie-parser": "^1.4.6",
"crypto-js": "^4.1.1",
"crypto-js": "~4.1.1",
"csrf": "^3.1.0",
"curlconverter": "^3.0.0",
"dotenv": "^8.0.0",
"express": "^4.16.4",
"express-openapi-validator": "^4.13.6",
"fast-glob": "^3.2.5",
"flatted": "^3.2.4",
"google-timezones-json": "^1.0.2",
"handlebars": "4.7.7",
"inquirer": "^7.0.1",
"json-diff": "^0.5.4",
"jsonschema": "^1.4.1",
@ -140,33 +142,34 @@
"lodash.intersection": "^4.4.0",
"lodash.merge": "^4.6.2",
"lodash.omit": "^4.5.0",
"lodash.pick": "^4.4.0",
"lodash.set": "^4.3.2",
"lodash.split": "^4.4.2",
"lodash.unset": "^4.5.2",
"mysql2": "~2.3.0",
"n8n-core": "~0.126.0",
"n8n-editor-ui": "~0.152.0",
"n8n-nodes-base": "~0.184.1",
"n8n-workflow": "~0.108.0",
"n8n-core": "~0.137.0",
"n8n-editor-ui": "~0.163.1",
"n8n-nodes-base": "~0.195.1",
"n8n-workflow": "~0.119.0",
"nodemailer": "^6.7.1",
"oauth-1.0a": "^2.2.6",
"open": "^7.0.0",
"openapi-types": "^10.0.0",
"p-cancelable": "^2.0.0",
"passport": "^0.5.0",
"passport": "^0.6.0",
"passport-cookie": "^1.0.9",
"passport-jwt": "^4.0.0",
"pg": "^8.3.0",
"posthog-node": "^1.3.0",
"prom-client": "^13.1.0",
"psl": "^1.8.0",
"request-promise-native": "^1.0.7",
"shelljs": "^0.8.5",
"sqlite3": "^5.0.2",
"sse-channel": "^3.1.1",
"swagger-ui-express": "^4.3.0",
"tslib": "1.14.1",
"typeorm": "0.2.45",
"uuid": "^8.3.0",
"uuid": "^8.3.2",
"validator": "13.7.0",
"winston": "^3.3.3",
"yamljs": "^0.3.0"

View File

@ -14,7 +14,12 @@ const publicApiEnabled = process.env.N8N_PUBLIC_API_DISABLED !== 'true';
shell.rm('-rf', path.resolve(ROOT_DIR, 'dist'));
shell.exec('tsc');
const tscCompilation = shell.exec('tsc', { silent: true })
if (tscCompilation.code !== 0) {
shell.echo('Typescript Compilation failed:');
shell.echo(tscCompilation.stdout);
shell.exit(1);
}
if (userManagementEnabled) {
copyUserManagementEmailTemplates();

View File

@ -36,10 +36,6 @@ export class ActiveExecutions {
/**
* Add a new active execution
*
* @param {ChildProcess} process
* @param {IWorkflowExecutionDataProcess} executionData
* @returns {string}
* @memberof ActiveExecutions
*/
async add(
executionData: IWorkflowExecutionDataProcess,
@ -103,9 +99,6 @@ export class ActiveExecutions {
/**
* Attaches an execution
*
* @param {string} executionId
* @param {PCancelable<IRun>} workflowExecution
* @memberof ActiveExecutions
*/
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
attachWorkflowExecution(executionId: string, workflowExecution: PCancelable<IRun>) {
@ -143,10 +136,6 @@ export class ActiveExecutions {
/**
* Remove an active execution
*
* @param {string} executionId
* @param {IRun} fullRunData
* @returns {void}
* @memberof ActiveExecutions
*/
remove(executionId: string, fullRunData?: IRun): void {
if (this.activeExecutions[executionId] === undefined) {
@ -168,8 +157,6 @@ export class ActiveExecutions {
*
* @param {string} executionId The id of the execution to stop
* @param {string} timeout String 'timeout' given if stop due to timeout
* @returns {(Promise<IRun | undefined>)}
* @memberof ActiveExecutions
*/
async stopExecution(executionId: string, timeout?: string): Promise<IRun | undefined> {
if (this.activeExecutions[executionId] === undefined) {
@ -204,8 +191,6 @@ export class ActiveExecutions {
* with the given id
*
* @param {string} executionId The id of the execution to wait for
* @returns {Promise<IRun>}
* @memberof ActiveExecutions
*/
async getPostExecutePromise(executionId: string): Promise<IRun | undefined> {
// Create the promise which will be resolved when the execution finished
@ -224,8 +209,6 @@ export class ActiveExecutions {
/**
* Returns all the currently active executions
*
* @returns {IExecutionsCurrentSummary[]}
* @memberof ActiveExecutions
*/
getActiveExecutions(): IExecutionsCurrentSummary[] {
const returnData: IExecutionsCurrentSummary[] = [];

View File

@ -40,6 +40,7 @@ import express from 'express';
import {
Db,
IActivationError,
IQueuedWorkflowActivations,
IResponseCallbackData,
IWebhookDb,
IWorkflowDb,
@ -57,6 +58,8 @@ import { User } from './databases/entities/User';
import { whereClause } from './WorkflowHelpers';
import { WorkflowEntity } from './databases/entities/WorkflowEntity';
import * as ActiveExecutions from './ActiveExecutions';
import { createErrorExecution } from './GenericHelpers';
import { WORKFLOW_REACTIVATE_INITIAL_TIMEOUT, WORKFLOW_REACTIVATE_MAX_TIMEOUT } from './constants';
const activeExecutions = ActiveExecutions.getInstance();
@ -69,13 +72,17 @@ export class ActiveWorkflowRunner {
[key: string]: IActivationError;
} = {};
private queuedWorkflowActivations: {
[key: string]: IQueuedWorkflowActivations;
} = {};
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
async init() {
// Get the active workflows from database
// NOTE
// Here I guess we can have a flag on the workflow table like hasTrigger
// so intead of pulling all the active wehhooks just pull the actives that have a trigger
// so instead of pulling all the active webhooks just pull the actives that have a trigger
const workflowsData: IWorkflowDb[] = (await Db.collections.Workflow.find({
where: { active: true },
relations: ['shared', 'shared.user', 'shared.user.globalRole'],
@ -101,7 +108,7 @@ export class ActiveWorkflowRunner {
console.info(' ================================');
for (const workflowData of workflowsData) {
console.log(` - ${workflowData.name}`);
console.log(` - ${workflowData.name} (ID: ${workflowData.id})`);
Logger.debug(`Initializing active workflow "${workflowData.name}" (startup)`, {
workflowName: workflowData.name,
workflowId: workflowData.id,
@ -114,14 +121,23 @@ export class ActiveWorkflowRunner {
});
console.log(` => Started`);
} catch (error) {
console.log(` => ERROR: Workflow could not be activated`);
console.log(
` => ERROR: Workflow could not be activated on first try, keep on trying`,
);
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
console.log(` ${error.message}`);
Logger.error(`Unable to initialize workflow "${workflowData.name}" (startup)`, {
workflowName: workflowData.name,
workflowId: workflowData.id,
});
Logger.error(
`Issue on intital workflow activation try "${workflowData.name}" (startup)`,
{
workflowName: workflowData.name,
workflowId: workflowData.id,
},
);
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
this.executeErrorWorkflow(error, workflowData, 'internal');
// Keep on trying to activate the workflow
this.addQueuedWorkflowActivation('init', workflowData);
}
}
Logger.verbose('Finished initializing active workflows (startup)');
@ -138,8 +154,6 @@ export class ActiveWorkflowRunner {
/**
* Removes all the currently active workflows
*
* @returns {Promise<void>}
* @memberof ActiveWorkflowRunner
*/
async removeAll(): Promise<void> {
let activeWorkflowIds: string[] = [];
@ -169,12 +183,6 @@ export class ActiveWorkflowRunner {
/**
* Checks if a webhook for the given method and path exists and executes the workflow.
*
* @param {WebhookHttpMethod} httpMethod
* @param {string} path
* @param {express.Request} req
* @param {express.Response} res
* @returns {Promise<object>}
* @memberof ActiveWorkflowRunner
*/
async executeWebhook(
httpMethod: WebhookHttpMethod,
@ -182,7 +190,7 @@ export class ActiveWorkflowRunner {
req: express.Request,
res: express.Response,
): Promise<IResponseCallbackData> {
Logger.debug(`Received webhoook "${httpMethod}" for path "${path}"`);
Logger.debug(`Received webhook "${httpMethod}" for path "${path}"`);
if (this.activeWorkflows === null) {
throw new ResponseHelper.ResponseError(
'The "activeWorkflows" instance did not get initialized yet.',
@ -338,8 +346,6 @@ export class ActiveWorkflowRunner {
* Gets all request methods associated with a single webhook
*
* @param {string} path webhook path
* @returns {Promise<string[]>}
* @memberof ActiveWorkflowRunner
*/
async getWebhookMethods(path: string): Promise<string[]> {
const webhooks = await Db.collections.Webhook.find({ webhookPath: path });
@ -352,8 +358,6 @@ export class ActiveWorkflowRunner {
/**
* Returns the ids of the currently active workflows
*
* @returns {string[]}
* @memberof ActiveWorkflowRunner
*/
async getActiveWorkflows(user?: User): Promise<IWorkflowDb[]> {
let activeWorkflows: WorkflowEntity[] = [];
@ -385,8 +389,6 @@ export class ActiveWorkflowRunner {
* Returns if the workflow is active
*
* @param {string} id The id of the workflow to check
* @returns {boolean}
* @memberof ActiveWorkflowRunner
*/
async isActive(id: string): Promise<boolean> {
const workflow = await Db.collections.Workflow.findOne(id);
@ -397,8 +399,6 @@ export class ActiveWorkflowRunner {
* Return error if there was a problem activating the workflow
*
* @param {string} id The id of the workflow to return the error of
* @returns {(IActivationError | undefined)}
* @memberof ActiveWorkflowRunner
*/
getActivationError(id: string): IActivationError | undefined {
if (this.activationErrors[id] === undefined) {
@ -411,11 +411,6 @@ export class ActiveWorkflowRunner {
/**
* Adds all the webhooks of the workflow
*
* @param {Workflow} workflow
* @param {IWorkflowExecuteAdditionalDataWorkflow} additionalData
* @param {WorkflowExecuteMode} mode
* @returns {Promise<void>}
* @memberof ActiveWorkflowRunner
*/
async addWorkflowWebhooks(
workflow: Workflow,
@ -479,7 +474,7 @@ export class ActiveWorkflowRunner {
config.getEnv('endpoints.skipWebhoooksDeregistrationOnShutdown') &&
error.name === 'QueryFailedError'
) {
// When skipWebhoooksDeregistrationOnShutdown is enabled,
// When skipWebhooksDeregistrationOnShutdown is enabled,
// n8n does not remove the registered webhooks on exit.
// This means that further initializations will always fail
// when inserting to database. This is why we ignore this error
@ -503,7 +498,7 @@ export class ActiveWorkflowRunner {
if (error.name === 'QueryFailedError') {
error.message = `The URL path that the "${webhook.node}" node uses is already taken. Please change it to something else.`;
} else if (error.detail) {
// it's a error runnig the webhook methods (checkExists, create)
// it's a error running the webhook methods (checkExists, create)
error.message = error.detail;
}
@ -517,9 +512,6 @@ export class ActiveWorkflowRunner {
/**
* Remove all the webhooks of the workflow
*
* @param {string} workflowId
* @returns
* @memberof ActiveWorkflowRunner
*/
async removeWorkflowWebhooks(workflowId: string): Promise<void> {
const workflowData = await Db.collections.Workflow.findOne(workflowId, {
@ -572,13 +564,6 @@ export class ActiveWorkflowRunner {
/**
* Runs the given workflow
*
* @param {IWorkflowDb} workflowData
* @param {INode} node
* @param {INodeExecutionData[][]} data
* @param {IWorkflowExecuteAdditionalDataWorkflow} additionalData
* @param {WorkflowExecuteMode} mode
* @returns
* @memberof ActiveWorkflowRunner
*/
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
async runWorkflow(
@ -628,11 +613,6 @@ export class ActiveWorkflowRunner {
* Return poll function which gets the global functions from n8n-core
* and overwrites the __emit to be able to start it in subprocess
*
* @param {IWorkflowDb} workflowData
* @param {IWorkflowExecuteAdditionalDataWorkflow} additionalData
* @param {WorkflowExecuteMode} mode
* @returns {IGetExecutePollFunctions}
* @memberof ActiveWorkflowRunner
*/
getExecutePollFunctions(
workflowData: IWorkflowDb,
@ -649,9 +629,17 @@ export class ActiveWorkflowRunner {
activation,
);
// eslint-disable-next-line no-underscore-dangle
returnFunctions.__emit = (data: INodeExecutionData[][]): void => {
returnFunctions.__emit = async (
data: INodeExecutionData[][] | ExecutionError,
): Promise<void> => {
if (data instanceof Error) {
await createErrorExecution(data, node, workflowData, workflow, mode);
this.executeErrorWorkflow(data, workflowData, mode);
return;
}
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
Logger.debug(`Received event to trigger execution for workflow "${workflow.name}"`);
WorkflowHelpers.saveStaticData(workflow);
this.runWorkflow(workflowData, node, data, additionalData, mode);
};
return returnFunctions;
@ -662,11 +650,6 @@ export class ActiveWorkflowRunner {
* Return trigger function which gets the global functions from n8n-core
* and overwrites the emit to be able to start it in subprocess
*
* @param {IWorkflowDb} workflowData
* @param {IWorkflowExecuteAdditionalDataWorkflow} additionalData
* @param {WorkflowExecuteMode} mode
* @returns {IGetExecuteTriggerFunctions}
* @memberof ActiveWorkflowRunner
*/
getExecuteTriggerFunctions(
workflowData: IWorkflowDb,
@ -712,6 +695,17 @@ export class ActiveWorkflowRunner {
}
};
returnFunctions.emitError = async (error: Error): Promise<void> => {
Logger.info(
`The trigger node "${node.name}" of workflow "${workflowData.name}" failed with the error: "${error.message}". Will try to reactivate.`,
{
nodeName: node.name,
workflowId: workflowData.id.toString(),
workflowName: workflowData.name,
},
);
// Remove the workflow as "active"
await this.activeWorkflows?.remove(workflowData.id.toString());
this.activationErrors[workflowData.id.toString()] = {
time: new Date().getTime(),
@ -719,13 +713,16 @@ export class ActiveWorkflowRunner {
message: error.message,
},
};
// Run Error Workflow if defined
const activationError = new WorkflowActivationError(
'There was a problem with the trigger, for that reason did the workflow had to be deactivated',
`There was a problem with the trigger node "${node.name}", for that reason did the workflow had to be deactivated`,
error,
node,
);
this.executeErrorWorkflow(activationError, workflowData, mode);
this.addQueuedWorkflowActivation(activation, workflowData);
};
return returnFunctions;
};
@ -757,8 +754,6 @@ export class ActiveWorkflowRunner {
*
* @param {string} workflowId The id of the workflow to activate
* @param {IWorkflowDb} [workflowData] If workflowData is given it saves the DB query
* @returns {Promise<void>}
* @memberof ActiveWorkflowRunner
*/
async add(
workflowId: string,
@ -841,6 +836,9 @@ export class ActiveWorkflowRunner {
});
}
// Workflow got now successfully activated so make sure nothing is left in the queue
this.removeQueuedWorkflowActivation(workflowId);
if (this.activationErrors[workflowId] !== undefined) {
// If there were activation errors delete them
delete this.activationErrors[workflowId];
@ -864,12 +862,86 @@ export class ActiveWorkflowRunner {
await WorkflowHelpers.saveStaticData(workflowInstance!);
}
/**
* Add a workflow to the activation queue.
* Meaning it will keep on trying to activate it in regular
* amounts indefinetly.
*/
addQueuedWorkflowActivation(
activationMode: WorkflowActivateMode,
workflowData: IWorkflowDb,
): void {
const workflowId = workflowData.id.toString();
const workflowName = workflowData.name;
const retryFunction = async () => {
Logger.info(`Try to activate workflow "${workflowName}" (${workflowId})`, {
workflowId,
workflowName,
});
try {
await this.add(workflowId, activationMode, workflowData);
} catch (error) {
let lastTimeout = this.queuedWorkflowActivations[workflowId].lastTimeout;
if (lastTimeout < WORKFLOW_REACTIVATE_MAX_TIMEOUT) {
lastTimeout = Math.min(lastTimeout * 2, WORKFLOW_REACTIVATE_MAX_TIMEOUT);
}
Logger.info(
` -> Activation of workflow "${workflowName}" (${workflowId}) did fail with error: "${
error.message as string
}" | retry in ${Math.floor(lastTimeout / 1000)} seconds`,
{
workflowId,
workflowName,
},
);
this.queuedWorkflowActivations[workflowId].lastTimeout = lastTimeout;
this.queuedWorkflowActivations[workflowId].timeout = setTimeout(retryFunction, lastTimeout);
return;
}
Logger.info(` -> Activation of workflow "${workflowName}" (${workflowId}) was successful!`, {
workflowId,
workflowName,
});
};
// Just to be sure that there is not chance that for any reason
// multiple run in parallel
this.removeQueuedWorkflowActivation(workflowId);
this.queuedWorkflowActivations[workflowId] = {
activationMode,
lastTimeout: WORKFLOW_REACTIVATE_INITIAL_TIMEOUT,
timeout: setTimeout(retryFunction, WORKFLOW_REACTIVATE_INITIAL_TIMEOUT),
workflowData,
};
}
/**
* Remove a workflow from the activation queue
*/
removeQueuedWorkflowActivation(workflowId: string): void {
if (this.queuedWorkflowActivations[workflowId]) {
clearTimeout(this.queuedWorkflowActivations[workflowId].timeout);
delete this.queuedWorkflowActivations[workflowId];
}
}
/**
* Remove all workflows from the activation queue
*/
removeAllQueuedWorkflowActivations(): void {
for (const workflowId in this.queuedWorkflowActivations) {
this.removeQueuedWorkflowActivation(workflowId);
}
}
/**
* Makes a workflow inactive
*
* @param {string} workflowId The id of the workflow to deactivate
* @returns {Promise<void>}
* @memberof ActiveWorkflowRunner
*/
async remove(workflowId: string): Promise<void> {
if (this.activeWorkflows !== null) {
@ -888,6 +960,10 @@ export class ActiveWorkflowRunner {
delete this.activationErrors[workflowId];
}
if (this.queuedWorkflowActivations[workflowId] !== undefined) {
this.removeQueuedWorkflowActivation(workflowId);
}
// if it's active in memory then it's a trigger
// so remove from list of actives workflows
if (this.activeWorkflows.isActive(workflowId)) {

View File

@ -0,0 +1,247 @@
/* eslint-disable no-restricted-syntax */
/* eslint-disable import/no-cycle */
/* eslint-disable @typescript-eslint/naming-convention */
import { promisify } from 'util';
import { exec } from 'child_process';
import { access as fsAccess, mkdir as fsMkdir } from 'fs/promises';
import { createContext, Script } from 'vm';
import axios from 'axios';
import { UserSettings } from 'n8n-core';
import { LoggerProxy, PublicInstalledPackage } from 'n8n-workflow';
import {
NODE_PACKAGE_PREFIX,
NPM_COMMAND_TOKENS,
NPM_PACKAGE_STATUS_GOOD,
RESPONSE_ERROR_MESSAGES,
UNKNOWN_FAILURE_REASON,
} from '../constants';
import { InstalledPackages } from '../databases/entities/InstalledPackages';
import config from '../../config';
import type { CommunityPackages } from '../Interfaces';
const {
PACKAGE_NAME_NOT_PROVIDED,
DISK_IS_FULL,
PACKAGE_FAILED_TO_INSTALL,
PACKAGE_VERSION_NOT_FOUND,
PACKAGE_DOES_NOT_CONTAIN_NODES,
PACKAGE_NOT_FOUND,
} = RESPONSE_ERROR_MESSAGES;
const {
NPM_PACKAGE_NOT_FOUND_ERROR,
NPM_NO_VERSION_AVAILABLE,
NPM_DISK_NO_SPACE,
NPM_DISK_INSUFFICIENT_SPACE,
NPM_PACKAGE_VERSION_NOT_FOUND_ERROR,
} = NPM_COMMAND_TOKENS;
const execAsync = promisify(exec);
const INVALID_OR_SUSPICIOUS_PACKAGE_NAME = /[^0-9a-z@\-./]/;
export const parseNpmPackageName = (rawString?: string): CommunityPackages.ParsedPackageName => {
if (!rawString) throw new Error(PACKAGE_NAME_NOT_PROVIDED);
if (INVALID_OR_SUSPICIOUS_PACKAGE_NAME.test(rawString))
throw new Error('Package name must be a single word');
const scope = rawString.includes('/') ? rawString.split('/')[0] : undefined;
const packageNameWithoutScope = scope ? rawString.replace(`${scope}/`, '') : rawString;
if (!packageNameWithoutScope.startsWith(NODE_PACKAGE_PREFIX)) {
throw new Error(`Package name must start with ${NODE_PACKAGE_PREFIX}`);
}
const version = packageNameWithoutScope.includes('@')
? packageNameWithoutScope.split('@')[1]
: undefined;
const packageName = version ? rawString.replace(`@${version}`, '') : rawString;
return {
packageName,
scope,
version,
rawString,
};
};
export const sanitizeNpmPackageName = parseNpmPackageName;
export const executeCommand = async (
command: string,
options?: { doNotHandleError?: boolean },
): Promise<string> => {
const downloadFolder = UserSettings.getUserN8nFolderDowloadedNodesPath();
const execOptions = {
cwd: downloadFolder,
env: {
NODE_PATH: process.env.NODE_PATH,
PATH: process.env.PATH,
APPDATA: process.env.APPDATA,
},
};
try {
await fsAccess(downloadFolder);
} catch (_) {
await fsMkdir(downloadFolder);
// Also init the folder since some versions
// of npm complain if the folder is empty
await execAsync('npm init -y', execOptions);
}
try {
const commandResult = await execAsync(command, execOptions);
return commandResult.stdout;
} catch (error) {
if (options?.doNotHandleError) throw error;
const errorMessage = error instanceof Error ? error.message : UNKNOWN_FAILURE_REASON;
const map = {
[NPM_PACKAGE_NOT_FOUND_ERROR]: PACKAGE_NOT_FOUND,
[NPM_NO_VERSION_AVAILABLE]: PACKAGE_NOT_FOUND,
[NPM_PACKAGE_VERSION_NOT_FOUND_ERROR]: PACKAGE_VERSION_NOT_FOUND,
[NPM_DISK_NO_SPACE]: DISK_IS_FULL,
[NPM_DISK_INSUFFICIENT_SPACE]: DISK_IS_FULL,
};
Object.entries(map).forEach(([npmMessage, n8nMessage]) => {
if (errorMessage.includes(npmMessage)) throw new Error(n8nMessage);
});
LoggerProxy.warn('npm command failed', { errorMessage });
throw new Error(PACKAGE_FAILED_TO_INSTALL);
}
};
export function matchPackagesWithUpdates(
packages: InstalledPackages[],
updates?: CommunityPackages.AvailableUpdates,
): PublicInstalledPackage[] {
if (!updates) return packages;
return packages.reduce<PublicInstalledPackage[]>((acc, cur) => {
const publicPackage: PublicInstalledPackage = { ...cur };
const update = updates[cur.packageName];
if (update) publicPackage.updateAvailable = update.latest;
acc.push(publicPackage);
return acc;
}, []);
}
export function matchMissingPackages(
installedPackages: PublicInstalledPackage[],
missingPackages: string,
): PublicInstalledPackage[] {
const missingPackageNames = missingPackages.split(' ');
const missingPackagesList = missingPackageNames.map((missingPackageName: string) => {
// Strip away versions but maintain scope and package name
try {
const parsedPackageData = parseNpmPackageName(missingPackageName);
return parsedPackageData.packageName;
// eslint-disable-next-line no-empty
} catch (_) {}
return undefined;
});
const hydratedPackageList = [] as PublicInstalledPackage[];
installedPackages.forEach((installedPackage) => {
const hydratedInstalledPackage = { ...installedPackage };
if (missingPackagesList.includes(hydratedInstalledPackage.packageName)) {
hydratedInstalledPackage.failedLoading = true;
}
hydratedPackageList.push(hydratedInstalledPackage);
});
return hydratedPackageList;
}
export async function checkNpmPackageStatus(
packageName: string,
): Promise<CommunityPackages.PackageStatusCheck> {
const N8N_BACKEND_SERVICE_URL = 'https://api.n8n.io/api/package';
try {
const response = await axios.post<CommunityPackages.PackageStatusCheck>(
N8N_BACKEND_SERVICE_URL,
{ name: packageName },
{ method: 'POST' },
);
if (response.data.status !== NPM_PACKAGE_STATUS_GOOD) return response.data;
} catch (error) {
// Do nothing if service is unreachable
}
return { status: NPM_PACKAGE_STATUS_GOOD };
}
export function hasPackageLoaded(packageName: string): boolean {
const missingPackages = config.get('nodes.packagesMissing') as string | undefined;
if (!missingPackages) return true;
return !missingPackages
.split(' ')
.some(
(packageNameAndVersion) =>
packageNameAndVersion.startsWith(packageName) &&
packageNameAndVersion.replace(packageName, '').startsWith('@'),
);
}
export function removePackageFromMissingList(packageName: string): void {
try {
const failedPackages = (config.get('nodes.packagesMissing') as string).split(' ');
const packageFailedToLoad = failedPackages.filter(
(packageNameAndVersion) =>
!packageNameAndVersion.startsWith(packageName) ||
!packageNameAndVersion.replace(packageName, '').startsWith('@'),
);
config.set('nodes.packagesMissing', packageFailedToLoad.join(' '));
} catch (_error) {
// Do nothing
}
}
export const isClientError = (error: Error): boolean => {
const clientErrors = [
PACKAGE_VERSION_NOT_FOUND,
PACKAGE_DOES_NOT_CONTAIN_NODES,
PACKAGE_NOT_FOUND,
];
return clientErrors.some((message) => error.message.includes(message));
};
export function isNpmError(error: unknown): error is { code: number; stdout: string } {
return typeof error === 'object' && error !== null && 'code' in error && 'stdout' in error;
}
const context = createContext({ require });
export const loadClassInIsolation = (filePath: string, className: string) => {
if (process.platform === 'win32') {
filePath = filePath.replace(/\\/g, '/');
}
const script = new Script(`new (require('${filePath}').${className})()`);
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
return script.runInContext(context);
};

View File

@ -0,0 +1,76 @@
/* eslint-disable import/no-cycle */
import { INodeTypeData, INodeTypeNameVersion, LoggerProxy } from 'n8n-workflow';
import { Db } from '..';
import { InstalledNodes } from '../databases/entities/InstalledNodes';
import { InstalledPackages } from '../databases/entities/InstalledPackages';
export async function findInstalledPackage(
packageName: string,
): Promise<InstalledPackages | undefined> {
return Db.collections.InstalledPackages.findOne(packageName, { relations: ['installedNodes'] });
}
export async function isPackageInstalled(packageName: string): Promise<boolean> {
const installedPackage = await findInstalledPackage(packageName);
return installedPackage !== undefined;
}
export async function getAllInstalledPackages(): Promise<InstalledPackages[]> {
return Db.collections.InstalledPackages.find({ relations: ['installedNodes'] });
}
export async function removePackageFromDatabase(
packageName: InstalledPackages,
): Promise<InstalledPackages> {
return Db.collections.InstalledPackages.remove(packageName);
}
export async function persistInstalledPackageData(
installedPackageName: string,
installedPackageVersion: string,
installedNodes: INodeTypeNameVersion[],
loadedNodeTypes: INodeTypeData,
authorName?: string,
authorEmail?: string,
): Promise<InstalledPackages> {
let installedPackage: InstalledPackages;
try {
await Db.transaction(async (transactionManager) => {
const promises = [];
const installedPackagePayload = Object.assign(new InstalledPackages(), {
packageName: installedPackageName,
installedVersion: installedPackageVersion,
authorName,
authorEmail,
});
installedPackage = await transactionManager.save<InstalledPackages>(installedPackagePayload);
installedPackage.installedNodes = [];
promises.push(
...installedNodes.map(async (loadedNode) => {
const installedNodePayload = Object.assign(new InstalledNodes(), {
name: loadedNodeTypes[loadedNode.name].type.description.displayName,
type: loadedNode.name,
latestVersion: loadedNode.version,
package: installedPackageName,
});
installedPackage.installedNodes.push(installedNodePayload);
return transactionManager.save<InstalledNodes>(installedNodePayload);
}),
);
return promises;
});
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
return installedPackage!;
} catch (error) {
LoggerProxy.error('Failed to save installed packages and nodes', {
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
error,
packageName: installedPackageName,
});
throw error;
}
}

View File

@ -1,3 +1,4 @@
/* eslint-disable @typescript-eslint/no-unsafe-argument */
/* eslint-disable @typescript-eslint/no-non-null-assertion */
/* eslint-disable no-restricted-syntax */
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
@ -91,7 +92,6 @@ export class CredentialsHelper extends ICredentialsHelper {
if (credentialType.authenticate) {
if (typeof credentialType.authenticate === 'function') {
// Special authentication function is defined
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
return credentialType.authenticate(credentials, requestOptions as IHttpRequestOptions);
}
@ -250,8 +250,6 @@ export class CredentialsHelper extends ICredentialsHelper {
*
* @param {INodeCredentialsDetails} nodeCredential id and name to return instance of
* @param {string} type Type of the credential to return instance of
* @returns {Credentials}
* @memberof CredentialsHelper
*/
async getCredentials(
nodeCredential: INodeCredentialsDetails,
@ -287,8 +285,6 @@ export class CredentialsHelper extends ICredentialsHelper {
* Returns all the properties of the credentials with the given name
*
* @param {string} type The name of the type to return credentials off
* @returns {INodeProperties[]}
* @memberof CredentialsHelper
*/
getCredentialsProperties(type: string): INodeProperties[] {
const credentialTypeData = this.credentialTypes.getByName(type);
@ -307,7 +303,7 @@ export class CredentialsHelper extends ICredentialsHelper {
NodeHelpers.mergeNodeProperties(combineProperties, mergeCredentialProperties);
}
// The properties defined on the parent credentials take presidence
// The properties defined on the parent credentials take precedence
NodeHelpers.mergeNodeProperties(combineProperties, credentialTypeData.properties);
return combineProperties;
@ -319,8 +315,6 @@ export class CredentialsHelper extends ICredentialsHelper {
* @param {INodeCredentialsDetails} nodeCredentials id and name to return instance of
* @param {string} type Type of the credentials to return data of
* @param {boolean} [raw] Return the data as supplied without defaults or overwrites
* @returns {ICredentialDataDecryptedObject}
* @memberof CredentialsHelper
*/
async getDecrypted(
nodeCredentials: INodeCredentialsDetails,
@ -351,8 +345,6 @@ export class CredentialsHelper extends ICredentialsHelper {
*
* @param {ICredentialDataDecryptedObject} decryptedDataOriginal The credential data to overwrite data on
* @param {string} type Type of the credentials to overwrite data of
* @returns {ICredentialDataDecryptedObject}
* @memberof CredentialsHelper
*/
applyDefaultsAndOverwrites(
decryptedDataOriginal: ICredentialDataDecryptedObject,
@ -443,8 +435,6 @@ export class CredentialsHelper extends ICredentialsHelper {
* @param {string} name Name of the credentials to set data of
* @param {string} type Type of the credentials to set data of
* @param {ICredentialDataDecryptedObject} data The data to set
* @returns {Promise<void>}
* @memberof CredentialsHelper
*/
async updateCredentials(
nodeCredentials: INodeCredentialsDetails,
@ -526,11 +516,11 @@ export class CredentialsHelper extends ICredentialsHelper {
}
}
}
// Test is defined as string which links to a functoin
// Test is defined as string which links to a function
return (node as unknown as INodeType).methods?.credentialTest![credential.testedBy];
}
// Test is defined as JSON with a defintion for the request to make
// Test is defined as JSON with a definition for the request to make
return {
nodeType,
testRequest: credential.testedBy,
@ -558,7 +548,6 @@ export class CredentialsHelper extends ICredentialsHelper {
nodeToTestWith?: string,
): Promise<INodeCredentialTestResult> {
const credentialTestFunction = this.getCredentialTestFunction(credentialType, nodeToTestWith);
if (credentialTestFunction === undefined) {
return Promise.resolve({
status: 'Error',
@ -575,7 +564,7 @@ export class CredentialsHelper extends ICredentialsHelper {
// Credentials get tested via request instructions
// TODO: Temp worfklows get created at multiple locations (for example also LoadNodeParameterOptions),
// TODO: Temp workflows get created at multiple locations (for example also LoadNodeParameterOptions),
// check if some of them are identical enough that it can be combined
let nodeType: INodeType;
@ -587,6 +576,7 @@ export class CredentialsHelper extends ICredentialsHelper {
}
const node: INode = {
id: 'temp',
parameters: {},
name: 'Temp-Node',
type: nodeType.description.name,
@ -689,7 +679,6 @@ export class CredentialsHelper extends ICredentialsHelper {
statusCode: error.cause.response.status,
statusMessage: error.cause.response.statusText,
};
if (credentialTestFunction.testRequest.rules) {
// Special testing rules are defined so check all in order
for (const rule of credentialTestFunction.testRequest.rules) {
@ -715,6 +704,11 @@ export class CredentialsHelper extends ICredentialsHelper {
`Received HTTP status code: ${errorResponseData.statusCode}`,
};
}
} else if (error.cause.code) {
return {
status: 'Error',
message: error.cause.code,
};
}
Logger.debug('Credential test failed', error);
return {
@ -801,7 +795,7 @@ export async function getCredentialWithoutUser(
return credential;
}
export function createCredentiasFromCredentialsEntity(
export function createCredentialsFromCredentialsEntity(
credential: CredentialsEntity,
encrypt = false,
): Credentials {

View File

@ -1,3 +1,4 @@
/* eslint-disable @typescript-eslint/no-unsafe-argument */
/* eslint-disable no-underscore-dangle */
import { ICredentialDataDecryptedObject } from 'n8n-workflow';

5
packages/cli/src/CurlConverter.d.ts vendored Normal file
View File

@ -0,0 +1,5 @@
/* eslint-disable @typescript-eslint/naming-convention */
/* eslint-disable import/no-default-export */
declare module 'curlconverter' {
export function toJsonString(data: string): string;
}

View File

@ -0,0 +1,466 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
import curlconverter from 'curlconverter';
import get from 'lodash.get';
interface CurlJson {
url: string;
raw_url?: string;
method: string;
contentType?: string;
cookies?: {
[key: string]: string;
};
auth?: {
user: string;
password: string;
};
headers?: {
[key: string]: string;
};
files?: {
[key: string]: string;
};
queries: {
[key: string]: string;
};
data?: {
[key: string]: string;
};
}
interface Parameter {
parameterType?: string;
name: string;
value: string;
}
export interface HttpNodeParameters {
url?: string;
method: string;
sendBody?: boolean;
authentication: string;
contentType?: 'form-urlencoded' | 'multipart-form-data' | 'json' | 'raw' | 'binaryData';
rawContentType?: string;
specifyBody?: 'json' | 'keypair';
bodyParameters?: {
parameters: Parameter[];
};
jsonBody?: object;
options: {
allowUnauthorizedCerts?: boolean;
proxy?: string;
timeout?: number;
redirect: {
redirect: {
followRedirects?: boolean;
maxRedirects?: number;
};
};
response: {
response: {
fullResponse?: boolean;
responseFormat?: string;
outputPropertyName?: string;
};
};
};
sendHeaders?: boolean;
headerParameters?: {
parameters: Parameter[];
};
sendQuery?: boolean;
queryParameters?: {
parameters: Parameter[];
};
}
type HttpNodeHeaders = Pick<HttpNodeParameters, 'sendHeaders' | 'headerParameters'>;
type HttpNodeQueries = Pick<HttpNodeParameters, 'sendQuery' | 'queryParameters'>;
enum ContentTypes {
applicationJson = 'application/json',
applicationFormUrlEncoded = 'application/x-www-form-urlencoded',
applicationMultipart = 'multipart/form-data',
}
const SUPPORTED_CONTENT_TYPES = [
ContentTypes.applicationJson,
ContentTypes.applicationFormUrlEncoded,
ContentTypes.applicationMultipart,
];
const CONTENT_TYPE_KEY = 'content-type';
const FOLLOW_REDIRECT_FLAGS = ['--location', '-L'];
const MAX_REDIRECT_FLAG = '--max-redirs';
const PROXY_FLAGS = ['-x', '--proxy'];
const INCLUDE_HEADERS_IN_OUTPUT_FLAGS = ['-i', '--include'];
const REQUEST_FLAGS = ['-X', '--request'];
const TIMEOUT_FLAGS = ['--connect-timeout'];
const DOWNLOAD_FILE_FLAGS = ['-O', '-o'];
const IGNORE_SSL_ISSUES_FLAGS = ['-k', '--insecure'];
const curlToJson = (curlCommand: string): CurlJson => {
// eslint-disable-next-line n8n-local-rules/no-uncaught-json-parse
return JSON.parse(curlconverter.toJsonString(curlCommand)) as CurlJson;
};
const isContentType = (headers: CurlJson['headers'], contentType: ContentTypes): boolean => {
return get(headers, CONTENT_TYPE_KEY) === contentType;
};
const isJsonRequest = (curlJson: CurlJson): boolean => {
if (isContentType(curlJson.headers, ContentTypes.applicationJson)) return true;
if (curlJson.data) {
const bodyKey = Object.keys(curlJson.data)[0];
try {
JSON.parse(bodyKey);
return true;
} catch (_) {
return false;
}
}
return false;
};
const isFormUrlEncodedRequest = (curlJson: CurlJson): boolean => {
if (isContentType(curlJson.headers, ContentTypes.applicationFormUrlEncoded)) return true;
if (curlJson.data && !curlJson.files) return true;
return false;
};
const isMultipartRequest = (curlJson: CurlJson): boolean => {
if (isContentType(curlJson.headers, ContentTypes.applicationMultipart)) return true;
// only multipart/form-data request include files
if (curlJson.files) return true;
return false;
};
const isBinaryRequest = (curlJson: CurlJson): boolean => {
if (curlJson?.headers?.[CONTENT_TYPE_KEY]) {
const contentType = curlJson?.headers?.[CONTENT_TYPE_KEY];
return ['image', 'video', 'audio'].some((d) => contentType.includes(d));
}
return false;
};
const sanatizeCurlCommand = (curlCommand: string) =>
curlCommand
.replace(/\r\n/g, ' ')
.replace(/\n/g, ' ')
.replace(/\\/g, ' ')
.replace(/[ ]{2,}/g, ' ');
const toKeyValueArray = ([key, value]: string[]) => ({ name: key, value });
const extractHeaders = (headers: CurlJson['headers'] = {}): HttpNodeHeaders => {
const emptyHeaders = !Object.keys(headers).length;
const onlyContentTypeHeaderDefined =
Object.keys(headers).length === 1 && headers[CONTENT_TYPE_KEY] !== undefined;
if (emptyHeaders || onlyContentTypeHeaderDefined) return { sendHeaders: false };
return {
sendHeaders: true,
headerParameters: {
parameters: Object.entries(headers)
.map(toKeyValueArray)
.filter((parameter) => parameter.name !== CONTENT_TYPE_KEY),
},
};
};
const extractQueries = (queries: CurlJson['queries'] = {}): HttpNodeQueries => {
const emptyQueries = !Object.keys(queries).length;
if (emptyQueries) return { sendQuery: false };
return {
sendQuery: true,
queryParameters: {
parameters: Object.entries(queries).map(toKeyValueArray),
},
};
};
const extractJson = (body: CurlJson['data']) =>
//@ts-ignore
// eslint-disable-next-line n8n-local-rules/no-uncaught-json-parse
JSON.parse(Object.keys(body)[0]) as { [key: string]: string };
const jsonBodyToNodeParameters = (body: CurlJson['data'] = {}): Parameter[] | [] => {
const data = extractJson(body);
return Object.entries(data).map(toKeyValueArray);
};
const multipartToNodeParameters = (
body: CurlJson['data'] = {},
files: CurlJson['files'] = {},
): Parameter[] | [] => {
return [
...Object.entries(body)
.map(toKeyValueArray)
.map((e) => ({ parameterType: 'formData', ...e })),
...Object.entries(files)
.map(toKeyValueArray)
.map((e) => ({ parameterType: 'formBinaryData', ...e })),
];
};
const keyValueBodyToNodeParameters = (body: CurlJson['data'] = {}): Parameter[] | [] => {
return Object.entries(body).map(toKeyValueArray);
};
const lowerCaseContentTypeKey = (obj: { [x: string]: string }): void => {
const regex = new RegExp(CONTENT_TYPE_KEY, 'gi');
const contentTypeKey = Object.keys(obj).find((key) => {
const group = Array.from(key.matchAll(regex));
if (group.length) return true;
return false;
});
if (!contentTypeKey) return;
const value = obj[contentTypeKey];
delete obj[contentTypeKey];
obj[CONTENT_TYPE_KEY] = value;
};
const encodeBasicAuthentication = (username: string, password: string) =>
Buffer.from(`${username}:${password}`).toString('base64');
const jsonHasNestedObjects = (json: { [key: string]: string | number | object }) =>
Object.values(json).some((e) => typeof e === 'object');
const extractGroup = (curlCommand: string, regex: RegExp) => curlCommand.matchAll(regex);
const mapCookies = (cookies: CurlJson['cookies']): { cookie: string } | {} => {
if (!cookies) return {};
const cookiesValues = Object.entries(cookies).reduce(
(accumulator: string, entry: [string, string]) => {
accumulator += `${entry[0]}=${entry[1]};`;
return accumulator;
},
'',
);
if (!cookiesValues) return {};
return {
cookie: cookiesValues,
};
};
export const toHttpNodeParameters = (curlCommand: string): HttpNodeParameters => {
const curlJson = curlToJson(curlCommand);
if (!curlJson.headers) curlJson.headers = {};
lowerCaseContentTypeKey(curlJson.headers);
// set basic authentication
if (curlJson.auth) {
const { user, password: pass } = curlJson.auth;
Object.assign(curlJson.headers, {
authorization: `Basic ${encodeBasicAuthentication(user, pass)}`,
});
}
const httpNodeParameters: HttpNodeParameters = {
url: curlJson.url,
authentication: 'none',
method: curlJson.method.toUpperCase(),
...extractHeaders({ ...curlJson.headers, ...mapCookies(curlJson.cookies) }),
...extractQueries(curlJson.queries),
options: {
redirect: {
redirect: {},
},
response: {
response: {},
},
},
};
//attempt to get the curl flags not supported by the library
const curl = sanatizeCurlCommand(curlCommand);
//check for follow redirect flags
if (FOLLOW_REDIRECT_FLAGS.some((flag) => curl.includes(` ${flag}`))) {
Object.assign(httpNodeParameters.options.redirect?.redirect, { followRedirects: true });
if (curl.includes(` ${MAX_REDIRECT_FLAG}`)) {
const extractedValue = Array.from(
extractGroup(curl, new RegExp(` ${MAX_REDIRECT_FLAG} (\\d+)`, 'g')),
);
if (extractedValue.length) {
const [_, maxRedirects] = extractedValue[0];
if (maxRedirects) {
Object.assign(httpNodeParameters.options.redirect?.redirect, { maxRedirects });
}
}
}
}
//check for proxy flags
if (PROXY_FLAGS.some((flag) => curl.includes(` ${flag}`))) {
const foundFlag = PROXY_FLAGS.find((flag) => curl.includes(` ${flag}`));
if (foundFlag) {
const extractedValue = Array.from(
extractGroup(curl, new RegExp(` ${foundFlag} (\\S*)`, 'g')),
);
if (extractedValue.length) {
const [_, proxy] = extractedValue[0];
Object.assign(httpNodeParameters.options, { proxy });
}
}
}
// check for "include header in output" flag
if (INCLUDE_HEADERS_IN_OUTPUT_FLAGS.some((flag) => curl.includes(` ${flag}`))) {
Object.assign(httpNodeParameters.options?.response?.response, {
fullResponse: true,
responseFormat: 'autodetect',
});
}
// check for request flag
if (REQUEST_FLAGS.some((flag) => curl.includes(` ${flag}`))) {
const foundFlag = REQUEST_FLAGS.find((flag) => curl.includes(` ${flag}`));
if (foundFlag) {
const extractedValue = Array.from(
extractGroup(curl, new RegExp(` ${foundFlag} (\\w+)`, 'g')),
);
if (extractedValue.length) {
const [_, request] = extractedValue[0];
httpNodeParameters.method = request.toUpperCase();
}
}
}
// check for timeout flag
if (TIMEOUT_FLAGS.some((flag) => curl.includes(` ${flag}`))) {
const foundFlag = TIMEOUT_FLAGS.find((flag) => curl.includes(` ${flag}`));
if (foundFlag) {
const extractedValue = Array.from(
extractGroup(curl, new RegExp(` ${foundFlag} (\\d+)`, 'g')),
);
if (extractedValue.length) {
const [_, timeout] = extractedValue[0];
Object.assign(httpNodeParameters.options, {
timeout: parseInt(timeout, 10) * 1000,
});
}
}
}
// check for download flag
if (DOWNLOAD_FILE_FLAGS.some((flag) => curl.includes(` ${flag}`))) {
const foundFlag = DOWNLOAD_FILE_FLAGS.find((flag) => curl.includes(` ${flag}`));
if (foundFlag) {
Object.assign(httpNodeParameters.options.response.response, {
responseFormat: 'file',
outputPropertyName: 'data',
});
}
}
if (IGNORE_SSL_ISSUES_FLAGS.some((flag) => curl.includes(` ${flag}`))) {
const foundFlag = IGNORE_SSL_ISSUES_FLAGS.find((flag) => curl.includes(` ${flag}`));
if (foundFlag) {
Object.assign(httpNodeParameters.options, {
allowUnauthorizedCerts: true,
});
}
}
const contentType = curlJson?.headers?.[CONTENT_TYPE_KEY] as ContentTypes;
if (isBinaryRequest(curlJson)) {
return Object.assign(httpNodeParameters, {
contentType: 'binaryData',
sendBody: true,
});
}
if (contentType && !SUPPORTED_CONTENT_TYPES.includes(contentType)) {
return Object.assign(httpNodeParameters, {
sendBody: true,
contentType: 'raw',
rawContentType: contentType,
body: Object.keys(curlJson?.data ?? {})[0],
});
}
if (isJsonRequest(curlJson)) {
Object.assign(httpNodeParameters, {
contentType: 'json',
sendBody: true,
});
const json = extractJson(curlJson.data);
if (jsonHasNestedObjects(json)) {
// json body
Object.assign(httpNodeParameters, {
specifyBody: 'json',
jsonBody: JSON.stringify(json),
});
} else {
// key-value body
Object.assign(httpNodeParameters, {
specifyBody: 'keypair',
bodyParameters: {
parameters: jsonBodyToNodeParameters(curlJson.data),
},
});
}
} else if (isFormUrlEncodedRequest(curlJson)) {
Object.assign(httpNodeParameters, {
contentType: 'form-urlencoded',
sendBody: true,
specifyBody: 'keypair',
bodyParameters: {
parameters: keyValueBodyToNodeParameters(curlJson.data),
},
});
} else if (isMultipartRequest(curlJson)) {
Object.assign(httpNodeParameters, {
contentType: 'multipart-form-data',
sendBody: true,
bodyParameters: {
parameters: multipartToNodeParameters(curlJson.data, curlJson.files),
},
});
} else {
// could not figure the content type so do not set the body
Object.assign(httpNodeParameters, {
sendBody: false,
});
}
if (!Object.keys(httpNodeParameters.options?.redirect.redirect).length) {
// @ts-ignore
delete httpNodeParameters.options.redirect;
}
if (!Object.keys(httpNodeParameters.options.response.response).length) {
// @ts-ignore
delete httpNodeParameters.options.response;
}
return httpNodeParameters;
};

View File

@ -13,6 +13,7 @@ import {
EntityTarget,
getRepository,
LoggerOptions,
ObjectLiteral,
Repository,
} from 'typeorm';
import { TlsOptions } from 'tls';
@ -38,7 +39,9 @@ export async function transaction<T>(fn: (entityManager: EntityManager) => Promi
return connection.transaction(fn);
}
export function linkRepository<Entity>(entityClass: EntityTarget<Entity>): Repository<Entity> {
export function linkRepository<Entity extends ObjectLiteral>(
entityClass: EntityTarget<Entity>,
): Repository<Entity> {
return getRepository(entityClass, connection.name);
}
@ -183,9 +186,12 @@ export async function init(
}
}
// @ts-ignore
collections.Credentials = linkRepository(entities.CredentialsEntity);
// @ts-ignore
collections.Execution = linkRepository(entities.ExecutionEntity);
collections.Workflow = linkRepository(entities.WorkflowEntity);
// @ts-ignore
collections.Webhook = linkRepository(entities.WebhookEntity);
collections.Tag = linkRepository(entities.TagEntity);
@ -194,6 +200,9 @@ export async function init(
collections.SharedCredentials = linkRepository(entities.SharedCredentials);
collections.SharedWorkflow = linkRepository(entities.SharedWorkflow);
collections.Settings = linkRepository(entities.Settings);
collections.InstalledPackages = linkRepository(entities.InstalledPackages);
collections.InstalledNodes = linkRepository(entities.InstalledNodes);
collections.CredentialUsage = linkRepository(entities.CredentialUsage);
isInitialized = true;

View File

@ -87,7 +87,7 @@ class ExternalHooksClass implements IExternalHooksClass {
}
for (const externalHookFunction of this.externalHooks[hookName]) {
// eslint-disable-next-line no-await-in-loop
// eslint-disable-next-line no-await-in-loop, @typescript-eslint/await-thenable
await externalHookFunction.apply(externalHookFunctions, hookParameters);
}
}

View File

@ -8,12 +8,27 @@
import express from 'express';
import { join as pathJoin } from 'path';
import { readFile as fsReadFile } from 'fs/promises';
import { IDataObject } from 'n8n-workflow';
import {
ExecutionError,
IDataObject,
INode,
IRunExecutionData,
Workflow,
WorkflowExecuteMode,
} from 'n8n-workflow';
import { validate } from 'class-validator';
import config from '../config';
// eslint-disable-next-line import/no-cycle
import { Db, ICredentialsDb, IPackageVersions, ResponseHelper } from '.';
import {
Db,
ICredentialsDb,
IExecutionDb,
IExecutionFlattedDb,
IPackageVersions,
IWorkflowDb,
ResponseHelper,
} from '.';
// eslint-disable-next-line import/order
import { Like } from 'typeorm';
// eslint-disable-next-line import/no-cycle
@ -27,8 +42,6 @@ let versionCache: IPackageVersions | undefined;
/**
* Returns the base URL n8n is reachable from
*
* @export
* @returns {string}
*/
export function getBaseUrl(): string {
const protocol = config.getEnv('protocol');
@ -45,9 +58,6 @@ export function getBaseUrl(): string {
/**
* Returns the session id if one is set
*
* @export
* @param {express.Request} req
* @returns {(string | undefined)}
*/
export function getSessionId(req: express.Request): string | undefined {
return req.headers.sessionid as string | undefined;
@ -56,8 +66,6 @@ export function getSessionId(req: express.Request): string | undefined {
/**
* Returns information which version of the packages are installed
*
* @export
* @returns {Promise<IPackageVersions>}
*/
export async function getVersions(): Promise<IPackageVersions> {
if (versionCache !== undefined) {
@ -79,9 +87,6 @@ export async function getVersions(): Promise<IPackageVersions> {
/**
* Extracts configuration schema for key
*
* @param {string} configKey
* @param {IDataObject} configSchema
* @returns {IDataObject} schema of the configKey
*/
function extractSchemaForKey(configKey: string, configSchema: IDataObject): IDataObject {
const configKeyParts = configKey.split('.');
@ -103,9 +108,7 @@ function extractSchemaForKey(configKey: string, configSchema: IDataObject): IDat
/**
* Gets value from config with support for "_FILE" environment variables
*
* @export
* @param {string} configKey The key of the config data to get
* @returns {(Promise<string | boolean | number | undefined>)}
*/
export async function getConfigValue(
configKey: string,
@ -121,7 +124,7 @@ export async function getConfigValue(
return config.getEnv(configKey);
}
// Check if special file enviroment variable exists
// Check if special file environment variable exists
const fileEnvironmentVariable = process.env[`${currentSchema.env}_FILE`];
if (fileEnvironmentVariable === undefined) {
// Does not exist, so return value from config
@ -214,4 +217,85 @@ export async function validateEntity(
}
}
/**
* Create an error execution
*
* @param {INode} node
* @param {IWorkflowDb} workflowData
* @param {Workflow} workflow
* @param {WorkflowExecuteMode} mode
* @returns
* @memberof ActiveWorkflowRunner
*/
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
export async function createErrorExecution(
error: ExecutionError,
node: INode,
workflowData: IWorkflowDb,
workflow: Workflow,
mode: WorkflowExecuteMode,
): Promise<void> {
const saveDataErrorExecutionDisabled = workflowData?.settings?.saveDataErrorExecution === 'none';
if (saveDataErrorExecutionDisabled) return;
const executionData: IRunExecutionData = {
startData: {
destinationNode: node.name,
runNodeFilter: [node.name],
},
executionData: {
contextData: {},
nodeExecutionStack: [
{
node,
data: {
main: [
[
{
json: {},
pairedItem: {
item: 0,
},
},
],
],
},
source: null,
},
],
waitingExecution: {},
waitingExecutionSource: {},
},
resultData: {
runData: {
[node.name]: [
{
startTime: 0,
executionTime: 0,
error,
source: [],
},
],
},
error,
lastNodeExecuted: node.name,
},
};
const fullExecutionData: IExecutionDb = {
data: executionData,
mode,
finished: false,
startedAt: new Date(),
workflowData,
workflowId: workflow.id,
stoppedAt: new Date(),
};
const execution = ResponseHelper.flattenExecutionData(fullExecutionData);
await Db.collections.Execution.save(execution as IExecutionFlattedDb);
}
export const DEFAULT_EXECUTIONS_GET_ALL_LIMIT = 20;

View File

@ -8,6 +8,7 @@ import {
IDataObject,
IDeferredPromise,
IExecuteResponsePromiseData,
IPinData,
IRun,
IRunData,
IRunExecutionData,
@ -16,6 +17,7 @@ import {
ITelemetryTrackProperties,
IWorkflowBase as IWorkflowBaseWorkflow,
Workflow,
WorkflowActivateMode,
WorkflowExecuteMode,
} from 'n8n-workflow';
@ -27,14 +29,18 @@ import { Repository } from 'typeorm';
import { ChildProcess } from 'child_process';
import { Url } from 'url';
import { Request } from 'express';
import { WorkflowEntity } from './databases/entities/WorkflowEntity';
import { TagEntity } from './databases/entities/TagEntity';
import { Role } from './databases/entities/Role';
import { User } from './databases/entities/User';
import { SharedCredentials } from './databases/entities/SharedCredentials';
import { SharedWorkflow } from './databases/entities/SharedWorkflow';
import { Settings } from './databases/entities/Settings';
import type { Request } from 'express';
import type { InstalledNodes } from './databases/entities/InstalledNodes';
import type { InstalledPackages } from './databases/entities/InstalledPackages';
import type { Role } from './databases/entities/Role';
import type { Settings } from './databases/entities/Settings';
import type { SharedCredentials } from './databases/entities/SharedCredentials';
import type { SharedWorkflow } from './databases/entities/SharedWorkflow';
import type { TagEntity } from './databases/entities/TagEntity';
import type { User } from './databases/entities/User';
import type { WorkflowEntity } from './databases/entities/WorkflowEntity';
import { CredentialUsage } from './databases/entities/CredentialUsage';
export interface IActivationError {
time: number;
@ -43,18 +49,11 @@ export interface IActivationError {
};
}
export interface IBullJobData {
executionId: string;
loadStaticData: boolean;
}
export interface IBullJobResponse {
success: boolean;
}
export interface IBullWebhookResponse {
executionId: string;
response: IExecuteResponsePromiseData;
export interface IQueuedWorkflowActivations {
activationMode: WorkflowActivateMode;
lastTimeout: number;
timeout: NodeJS.Timeout;
workflowData: IWorkflowDb;
}
export interface ICustomRequest extends Request {
@ -83,6 +82,9 @@ export interface IDatabaseCollections {
SharedCredentials: Repository<SharedCredentials>;
SharedWorkflow: Repository<SharedWorkflow>;
Settings: Repository<Settings>;
InstalledPackages: Repository<InstalledPackages>;
InstalledNodes: Repository<InstalledNodes>;
CredentialUsage: Repository<CredentialUsage>;
}
export interface IWebhookDb {
@ -139,7 +141,7 @@ export interface IWorkflowBase extends IWorkflowBaseWorkflow {
// Almost identical to editor-ui.Interfaces.ts
export interface IWorkflowDb extends IWorkflowBase {
id: number | string;
tags: ITagDb[];
tags?: ITagDb[];
}
export interface IWorkflowToImport extends IWorkflowBase {
@ -162,6 +164,7 @@ export interface ICredentialsBase {
export interface ICredentialsDb extends ICredentialsBase, ICredentialsEncrypted {
id: number | string;
name: string;
shared?: SharedCredentials[];
}
export interface ICredentialsResponse extends ICredentialsDb {
@ -211,7 +214,7 @@ export interface IExecutionResponse extends IExecutionBase {
workflowData: IWorkflowBase;
}
// Flatted data to save memory when saving in database or transfering
// Flatted data to save memory when saving in database or transferring
// via REST API
export interface IExecutionFlatted extends IExecutionBase {
data: string;
@ -222,7 +225,7 @@ export interface IExecutionFlattedDb extends IExecutionBase {
id: number | string;
data: string;
waitTill?: Date | null;
workflowData: IWorkflowBase;
workflowData: Omit<IWorkflowBase, 'pinData'>;
}
export interface IExecutionFlattedResponse extends IExecutionFlatted {
@ -461,6 +464,19 @@ export interface IVersionNotificationSettings {
infoUrl: string;
}
export interface IN8nNodePackageJson {
name: string;
version: string;
n8n?: {
credentials?: string[];
nodes?: string[];
};
author?: {
name?: string;
email?: string;
};
}
export interface IN8nUISettings {
endpointWebhook: string;
endpointWebhookTest: string;
@ -494,6 +510,18 @@ export interface IN8nUISettings {
enabled: boolean;
host: string;
};
onboardingCallPromptEnabled: boolean;
missingPackages?: boolean;
executionMode: 'regular' | 'queue';
communityNodesEnabled: boolean;
deployment: {
type: string;
};
isNpmAvailable: boolean;
enterprise: {
sharing: boolean;
workflowSharing: boolean;
};
}
export interface IPersonalizationSurveyAnswers {
@ -532,6 +560,8 @@ export type IPushData =
| PushDataExecuteAfter
| PushDataExecuteBefore
| PushDataConsoleMessage
| PushDataReloadNodeType
| PushDataRemoveNodeType
| PushDataTestWebhook;
type PushDataExecutionFinished = {
@ -559,6 +589,16 @@ type PushDataConsoleMessage = {
type: 'sendConsoleMessage';
};
type PushDataReloadNodeType = {
data: IPushDataReloadNodeType;
type: 'reloadNodeType';
};
type PushDataRemoveNodeType = {
data: IPushDataRemoveNodeType;
type: 'removeNodeType';
};
type PushDataTestWebhook = {
data: IPushDataTestWebhook;
type: 'testWebhookDeleted' | 'testWebhookReceived';
@ -590,6 +630,16 @@ export interface IPushDataNodeExecuteBefore {
nodeName: string;
}
export interface IPushDataReloadNodeType {
name: string;
version: number;
}
export interface IPushDataRemoveNodeType {
name: string;
version: number;
}
export interface IPushDataTestWebhook {
executionId: string;
workflowId: string;
@ -646,6 +696,7 @@ export interface IWorkflowExecutionDataProcess {
executionMode: WorkflowExecuteMode;
executionData?: IRunExecutionData;
runData?: IRunData;
pinData?: IPinData;
retryOf?: number | string;
sessionId?: string;
startNodes?: string[];
@ -669,6 +720,33 @@ export interface IWorkflowExecuteProcess {
export type WhereClause = Record<string, { id: string }>;
// ----------------------------------
// community nodes
// ----------------------------------
export namespace CommunityPackages {
export type ParsedPackageName = {
packageName: string;
rawString: string;
scope?: string;
version?: string;
};
export type AvailableUpdates = {
[packageName: string]: {
current: string;
wanted: string;
latest: string;
location: string;
};
};
export type PackageStatusCheck = {
status: 'OK' | 'Banned';
reason?: string;
};
}
// ----------------------------------
// telemetry
// ----------------------------------

View File

@ -1,5 +1,5 @@
/* eslint-disable import/no-cycle */
import { get as pslGet } from 'psl';
import { snakeCase } from 'change-case';
import { BinaryDataManager } from 'n8n-core';
import {
INodesGraphResult,
@ -8,7 +8,7 @@ import {
ITelemetryTrackProperties,
TelemetryHelpers,
} from 'n8n-workflow';
import { snakeCase } from 'change-case';
import { get as pslGet } from 'psl';
import {
IDiagnosticInfo,
IInternalHooksClass,
@ -16,15 +16,20 @@ import {
IWorkflowBase,
IWorkflowDb,
} from '.';
import { Telemetry } from './telemetry';
import { IExecutionTrackProperties } from './Interfaces';
import { Telemetry } from './telemetry';
export class InternalHooksClass implements IInternalHooksClass {
private versionCli: string;
private nodeTypes: INodeTypes;
constructor(private telemetry: Telemetry, versionCli: string, nodeTypes: INodeTypes) {
constructor(
private telemetry: Telemetry,
private instanceId: string,
versionCli: string,
nodeTypes: INodeTypes,
) {
this.versionCli = versionCli;
this.nodeTypes = nodeTypes;
}
@ -73,6 +78,7 @@ export class InternalHooksClass implements IInternalHooksClass {
return this.telemetry.track(
'User responded to personalization questions',
personalizationSurveyData,
{ withPostHog: true },
);
}
@ -106,16 +112,20 @@ export class InternalHooksClass implements IInternalHooksClass {
(note) => note.overlapping,
).length;
return this.telemetry.track('User saved workflow', {
user_id: userId,
workflow_id: workflow.id,
node_graph_string: JSON.stringify(nodeGraph),
notes_count_overlapping: overlappingCount,
notes_count_non_overlapping: notesCount - overlappingCount,
version_cli: this.versionCli,
num_tags: workflow.tags?.length ?? 0,
public_api: publicApi,
});
return this.telemetry.track(
'User saved workflow',
{
user_id: userId,
workflow_id: workflow.id,
node_graph_string: JSON.stringify(nodeGraph),
notes_count_overlapping: overlappingCount,
notes_count_non_overlapping: notesCount - overlappingCount,
version_cli: this.versionCli,
num_tags: workflow.tags?.length ?? 0,
public_api: publicApi,
},
{ withPostHog: true },
);
}
async onWorkflowPostExecute(
@ -150,8 +160,14 @@ export class InternalHooksClass implements IInternalHooksClass {
if (!properties.success && runData?.data.resultData.error) {
properties.error_message = runData?.data.resultData.error.message;
let errorNodeName = runData?.data.resultData.error.node?.name;
properties.error_node_type = runData?.data.resultData.error.node?.type;
let errorNodeName =
'node' in runData?.data.resultData.error
? runData?.data.resultData.error.node?.name
: undefined;
properties.error_node_type =
'node' in runData?.data.resultData.error
? runData?.data.resultData.error.node?.type
: undefined;
if (runData.data.resultData.lastNodeExecuted) {
const lastNode = TelemetryHelpers.getNodeTypeForName(
@ -182,6 +198,7 @@ export class InternalHooksClass implements IInternalHooksClass {
}
const manualExecEventProperties: ITelemetryTrackProperties = {
user_id: userId,
workflow_id: workflow.id.toString(),
status: properties.success ? 'success' : 'failed',
error_message: properties.error_message as string,
@ -197,14 +214,18 @@ export class InternalHooksClass implements IInternalHooksClass {
}
if (runData.data.startData?.destinationNode) {
const telemetryPayload = {
...manualExecEventProperties,
node_type: TelemetryHelpers.getNodeTypeForName(
workflow,
runData.data.startData?.destinationNode,
)?.type,
node_id: nodeGraphResult.nameIndices[runData.data.startData?.destinationNode],
};
promises.push(
this.telemetry.track('Manual node exec finished', {
...manualExecEventProperties,
node_type: TelemetryHelpers.getNodeTypeForName(
workflow,
runData.data.startData?.destinationNode,
)?.type,
node_id: nodeGraphResult.nameIndices[runData.data.startData?.destinationNode],
this.telemetry.track('Manual node exec finished', telemetryPayload, {
withPostHog: true,
}),
);
} else {
@ -219,7 +240,9 @@ export class InternalHooksClass implements IInternalHooksClass {
});
promises.push(
this.telemetry.track('Manual workflow exec finished', manualExecEventProperties),
this.telemetry.track('Manual workflow exec finished', manualExecEventProperties, {
withPostHog: true,
}),
);
}
}
@ -333,7 +356,7 @@ export class InternalHooksClass implements IInternalHooksClass {
public_api: boolean;
}): Promise<void> {
return this.telemetry.track(
'Instance sent transacptional email to user',
'Instance sent transactional email to user',
userTransactionalEmailData,
);
}
@ -386,4 +409,73 @@ export class InternalHooksClass implements IInternalHooksClass {
failedEmailData,
);
}
/**
* Credentials
*/
async onUserCreatedCredentials(userCreatedCredentialsData: {
credential_type: string;
credential_id: string;
public_api: boolean;
}): Promise<void> {
return this.telemetry.track('User created credentials', {
...userCreatedCredentialsData,
instance_id: this.instanceId,
});
}
async onUserSharedCredentials(userSharedCredentialsData: {
credential_type: string;
credential_id: string;
user_id_sharer: string;
user_ids_sharees_added: string[];
sharees_removed: number | null;
}): Promise<void> {
return this.telemetry.track('User updated cred sharing', {
...userSharedCredentialsData,
instance_id: this.instanceId,
});
}
/**
* Community nodes backend telemetry events
*/
async onCommunityPackageInstallFinished(installationData: {
user_id: string;
input_string: string;
package_name: string;
success: boolean;
package_version?: string;
package_node_names?: string[];
package_author?: string;
package_author_email?: string;
failure_reason?: string;
}): Promise<void> {
return this.telemetry.track('cnr package install finished', installationData);
}
async onCommunityPackageUpdateFinished(updateData: {
user_id: string;
package_name: string;
package_version_current: string;
package_version_new: string;
package_node_names: string[];
package_author?: string;
package_author_email?: string;
}): Promise<void> {
return this.telemetry.track('cnr package updated', updateData);
}
async onCommunityPackageDeleteFinished(updateData: {
user_id: string;
package_name: string;
package_version: string;
package_node_names: string[];
package_author?: string;
package_author_email?: string;
}): Promise<void> {
return this.telemetry.track('cnr package deleted', updateData);
}
}

View File

@ -18,6 +18,7 @@ export class InternalHooksManager {
if (!this.internalHooksInstance) {
this.internalHooksInstance = new InternalHooksClass(
new Telemetry(instanceId, versionCli),
instanceId,
versionCli,
nodeTypes,
);

View File

@ -1,3 +1,5 @@
/* eslint-disable import/no-cycle */
/* eslint-disable no-underscore-dangle */
/* eslint-disable @typescript-eslint/naming-convention */
/* eslint-disable no-prototype-builtins */
/* eslint-disable no-param-reassign */
@ -16,6 +18,7 @@ import {
ILogger,
INodeType,
INodeTypeData,
INodeTypeNameVersion,
INodeVersionedType,
LoggerProxy,
} from 'n8n-workflow';
@ -28,11 +31,30 @@ import {
} from 'fs/promises';
import glob from 'fast-glob';
import path from 'path';
import pick from 'lodash.pick';
import { IN8nNodePackageJson } from './Interfaces';
import { getLogger } from './Logger';
import config from '../config';
import { NodeTypes } from '.';
import { InstalledPackages } from './databases/entities/InstalledPackages';
import { InstalledNodes } from './databases/entities/InstalledNodes';
import { executeCommand, loadClassInIsolation } from './CommunityNodes/helpers';
import { RESPONSE_ERROR_MESSAGES } from './constants';
import {
persistInstalledPackageData,
removePackageFromDatabase,
} from './CommunityNodes/packageModel';
const CUSTOM_NODES_CATEGORY = 'Custom Nodes';
function toJSON() {
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
return {
...this,
authenticate: typeof this.authenticate === 'function' ? {} : this.authenticate,
};
}
class LoadNodesAndCredentialsClass {
nodeTypes: INodeTypeData = {};
@ -50,6 +72,30 @@ class LoadNodesAndCredentialsClass {
this.logger = getLogger();
LoggerProxy.init(this.logger);
// Make sure the imported modules can resolve dependencies fine.
const delimiter = process.platform === 'win32' ? ';' : ':';
process.env.NODE_PATH = module.paths.join(delimiter);
// @ts-ignore
module.constructor._initPaths();
this.nodeModulesPath = await this.getNodeModulesFolderLocation();
this.excludeNodes = config.getEnv('nodes.exclude');
this.includeNodes = config.getEnv('nodes.include');
// Get all the installed packages which contain n8n nodes
const nodePackages = await this.getN8nNodePackages(this.nodeModulesPath);
for (const packagePath of nodePackages) {
await this.loadDataFromPackage(packagePath);
}
await this.loadNodesFromDownloadedPackages();
await this.loadNodesFromCustomFolders();
}
async getNodeModulesFolderLocation(): Promise<string> {
// Get the path to the node-modules folder to be later able
// to load the credentials and nodes
const checkPaths = [
@ -58,34 +104,43 @@ class LoadNodesAndCredentialsClass {
// In case "n8n" package is the root and the packages are
// in the "node_modules" folder underneath it.
path.join(__dirname, '..', '..', 'node_modules', 'n8n-workflow'),
// In case "n8n" package is installed using npm/yarn workspaces
// the node_modules folder is in the root of the workspace.
path.join(__dirname, '..', '..', '..', '..', 'node_modules', 'n8n-workflow'),
];
for (const checkPath of checkPaths) {
try {
await fsAccess(checkPath);
// Folder exists, so use it.
this.nodeModulesPath = path.dirname(checkPath);
break;
} catch (error) {
return path.dirname(checkPath);
} catch (_) {
// Folder does not exist so get next one
// eslint-disable-next-line no-continue
continue;
}
}
throw new Error('Could not find "node_modules" folder!');
}
if (this.nodeModulesPath === '') {
throw new Error('Could not find "node_modules" folder!');
}
this.excludeNodes = config.getEnv('nodes.exclude');
this.includeNodes = config.getEnv('nodes.include');
// Get all the installed packages which contain n8n nodes
const packages = await this.getN8nNodePackages();
for (const packageName of packages) {
await this.loadDataFromPackage(packageName);
async loadNodesFromDownloadedPackages(): Promise<void> {
const nodePackages = [];
try {
// Read downloaded nodes and credentials
const downloadedNodesFolder = UserSettings.getUserN8nFolderDowloadedNodesPath();
const downloadedNodesFolderModules = path.join(downloadedNodesFolder, 'node_modules');
await fsAccess(downloadedNodesFolderModules);
const downloadedPackages = await this.getN8nNodePackages(downloadedNodesFolderModules);
nodePackages.push(...downloadedPackages);
// eslint-disable-next-line no-empty
} catch (error) {}
for (const packagePath of nodePackages) {
try {
await this.loadDataFromPackage(packagePath);
// eslint-disable-next-line no-empty
} catch (error) {}
}
}
async loadNodesFromCustomFolders(): Promise<void> {
// Read nodes and credentials from custom directories
const customDirectories = [];
@ -96,8 +151,7 @@ class LoadNodesAndCredentialsClass {
if (process.env[CUSTOM_EXTENSION_ENV] !== undefined) {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const customExtensionFolders = process.env[CUSTOM_EXTENSION_ENV]!.split(';');
// eslint-disable-next-line prefer-spread
customDirectories.push.apply(customDirectories, customExtensionFolders);
customDirectories.push(...customExtensionFolders);
}
for (const directory of customDirectories) {
@ -109,13 +163,11 @@ class LoadNodesAndCredentialsClass {
* Returns all the names of the packages which could
* contain n8n nodes
*
* @returns {Promise<string[]>}
* @memberof LoadNodesAndCredentialsClass
*/
async getN8nNodePackages(): Promise<string[]> {
async getN8nNodePackages(baseModulesPath: string): Promise<string[]> {
const getN8nNodePackagesRecursive = async (relativePath: string): Promise<string[]> => {
const results: string[] = [];
const nodeModulesPath = `${this.nodeModulesPath}/${relativePath}`;
const nodeModulesPath = `${baseModulesPath}/${relativePath}`;
for (const file of await fsReaddir(nodeModulesPath)) {
const isN8nNodesPackage = file.indexOf('n8n-nodes-') === 0;
const isNpmScopedPackage = file.indexOf('@') === 0;
@ -126,7 +178,7 @@ class LoadNodesAndCredentialsClass {
continue;
}
if (isN8nNodesPackage) {
results.push(`${relativePath}${file}`);
results.push(`${baseModulesPath}/${relativePath}${file}`);
}
if (isNpmScopedPackage) {
results.push(...(await getN8nNodePackagesRecursive(`${relativePath}${file}/`)));
@ -142,28 +194,17 @@ class LoadNodesAndCredentialsClass {
*
* @param {string} credentialName The name of the credentials
* @param {string} filePath The file to read credentials from
* @returns {Promise<void>}
*/
async loadCredentialsFromFile(credentialName: string, filePath: string): Promise<void> {
// eslint-disable-next-line import/no-dynamic-require, global-require, @typescript-eslint/no-var-requires
const tempModule = require(filePath);
loadCredentialsFromFile(credentialName: string, filePath: string): void {
let tempCredential: ICredentialType;
try {
tempCredential = loadClassInIsolation(filePath, credentialName);
// Add serializer method "toJSON" to the class so that authenticate method (if defined)
// gets mapped to the authenticate attribute before it is sent to the client.
// The authenticate property is used by the client to decide whether or not to
// include the credential type in the predifined credentials (HTTP node)
// eslint-disable-next-line func-names
tempModule[credentialName].prototype.toJSON = function () {
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
return {
...this,
authenticate: typeof this.authenticate === 'function' ? {} : this.authenticate,
};
};
tempCredential = new tempModule[credentialName]() as ICredentialType;
// include the credential type in the predefined credentials (HTTP node)
Object.assign(tempCredential, { toJSON });
if (tempCredential.icon && tempCredential.icon.startsWith('file:')) {
// If a file icon gets used add the full path
@ -188,32 +229,140 @@ class LoadNodesAndCredentialsClass {
};
}
async loadNpmModule(packageName: string, version?: string): Promise<InstalledPackages> {
const downloadFolder = UserSettings.getUserN8nFolderDowloadedNodesPath();
const command = `npm install ${packageName}${version ? `@${version}` : ''}`;
await executeCommand(command);
const finalNodeUnpackedPath = path.join(downloadFolder, 'node_modules', packageName);
const loadedNodes = await this.loadDataFromPackage(finalNodeUnpackedPath);
if (loadedNodes.length > 0) {
const packageFile = await this.readPackageJson(finalNodeUnpackedPath);
// Save info to DB
try {
const installedPackage = await persistInstalledPackageData(
packageFile.name,
packageFile.version,
loadedNodes,
this.nodeTypes,
packageFile.author?.name,
packageFile.author?.email,
);
this.attachNodesToNodeTypes(installedPackage.installedNodes);
return installedPackage;
} catch (error) {
LoggerProxy.error('Failed to save installed packages and nodes', { error, packageName });
throw error;
}
} else {
// Remove this package since it contains no loadable nodes
const removeCommand = `npm remove ${packageName}`;
try {
await executeCommand(removeCommand);
} catch (error) {
// Do nothing
}
throw new Error(RESPONSE_ERROR_MESSAGES.PACKAGE_DOES_NOT_CONTAIN_NODES);
}
}
async removeNpmModule(packageName: string, installedPackage: InstalledPackages): Promise<void> {
const command = `npm remove ${packageName}`;
await executeCommand(command);
void (await removePackageFromDatabase(installedPackage));
this.unloadNodes(installedPackage.installedNodes);
}
async updateNpmModule(
packageName: string,
installedPackage: InstalledPackages,
): Promise<InstalledPackages> {
const downloadFolder = UserSettings.getUserN8nFolderDowloadedNodesPath();
const command = `npm i ${packageName}@latest`;
try {
await executeCommand(command);
} catch (error) {
if (error.message === RESPONSE_ERROR_MESSAGES.PACKAGE_NOT_FOUND) {
throw new Error(`The npm package "${packageName}" could not be found.`);
}
throw error;
}
this.unloadNodes(installedPackage.installedNodes);
const finalNodeUnpackedPath = path.join(downloadFolder, 'node_modules', packageName);
const loadedNodes = await this.loadDataFromPackage(finalNodeUnpackedPath);
if (loadedNodes.length > 0) {
const packageFile = await this.readPackageJson(finalNodeUnpackedPath);
// Save info to DB
try {
await removePackageFromDatabase(installedPackage);
const newlyInstalledPackage = await persistInstalledPackageData(
packageFile.name,
packageFile.version,
loadedNodes,
this.nodeTypes,
packageFile.author?.name,
packageFile.author?.email,
);
this.attachNodesToNodeTypes(newlyInstalledPackage.installedNodes);
return newlyInstalledPackage;
} catch (error) {
LoggerProxy.error('Failed to save installed packages and nodes', { error, packageName });
throw error;
}
} else {
// Remove this package since it contains no loadable nodes
const removeCommand = `npm remove ${packageName}`;
try {
await executeCommand(removeCommand);
} catch (error) {
// Do nothing
}
throw new Error(RESPONSE_ERROR_MESSAGES.PACKAGE_DOES_NOT_CONTAIN_NODES);
}
}
/**
* Loads a node from a file
*
* @param {string} packageName The package name to set for the found nodes
* @param {string} nodeName Tha name of the node
* @param {string} filePath The file to read node from
* @returns {Promise<void>}
*/
async loadNodeFromFile(packageName: string, nodeName: string, filePath: string): Promise<void> {
loadNodeFromFile(
packageName: string,
nodeName: string,
filePath: string,
): INodeTypeNameVersion | undefined {
let tempNode: INodeType | INodeVersionedType;
let fullNodeName: string;
// eslint-disable-next-line import/no-dynamic-require, global-require, @typescript-eslint/no-var-requires
const tempModule = require(filePath);
let nodeVersion = 1;
try {
tempNode = new tempModule[nodeName]();
tempNode = loadClassInIsolation(filePath, nodeName);
this.addCodex({ node: tempNode, filePath, isCustom: packageName === 'CUSTOM' });
} catch (error) {
// eslint-disable-next-line no-console
console.error(`Error loading node "${nodeName}" from: "${filePath}"`);
// eslint-disable-next-line no-console, @typescript-eslint/restrict-template-expressions
console.error(`Error loading node "${nodeName}" from: "${filePath}" - ${error.message}`);
throw error;
}
// eslint-disable-next-line prefer-const
fullNodeName = `${packageName}.${tempNode.description.name}`;
const fullNodeName = `${packageName}.${tempNode.description.name}`;
tempNode.description.name = fullNodeName;
if (tempNode.description.icon !== undefined && tempNode.description.icon.startsWith('file:')) {
@ -224,16 +373,10 @@ class LoadNodesAndCredentialsClass {
)}`;
}
if (tempNode.hasOwnProperty('executeSingle')) {
this.logger.warn(
`"executeSingle" will get deprecated soon. Please update the code of node "${packageName}.${nodeName}" to use "execute" instead!`,
{ filePath },
);
}
if (tempNode.hasOwnProperty('nodeVersions')) {
const versionedNodeType = (tempNode as INodeVersionedType).getNodeType();
this.addCodex({ node: versionedNodeType, filePath, isCustom: packageName === 'CUSTOM' });
nodeVersion = (tempNode as INodeVersionedType).currentVersion;
if (
versionedNodeType.description.icon !== undefined &&
@ -252,13 +395,19 @@ class LoadNodesAndCredentialsClass {
{ filePath },
);
}
} else {
// Short renaming to avoid type issues
const tmpNode = tempNode as INodeType;
nodeVersion = Array.isArray(tmpNode.description.version)
? tmpNode.description.version.slice(-1)[0]
: tmpNode.description.version;
}
if (this.includeNodes !== undefined && !this.includeNodes.includes(fullNodeName)) {
return;
}
// Check if the node should be skiped
// Check if the node should be skipped
if (this.excludeNodes !== undefined && this.excludeNodes.includes(fullNodeName)) {
return;
}
@ -267,22 +416,31 @@ class LoadNodesAndCredentialsClass {
type: tempNode,
sourcePath: filePath,
};
// eslint-disable-next-line consistent-return
return {
name: fullNodeName,
version: nodeVersion,
} as INodeTypeNameVersion;
}
/**
* Retrieves `categories`, `subcategories` and alias (if defined)
* from the codex data for the node at the given file path.
* Retrieves `categories`, `subcategories`, partial `resources` and
* alias (if defined) from the codex data for the node at the given file path.
*
* @param {string} filePath The file path to a `*.node.js` file
* @returns {CodexData}
*/
getCodex(filePath: string): CodexData {
// eslint-disable-next-line global-require, import/no-dynamic-require, @typescript-eslint/no-var-requires
const { categories, subcategories, alias } = require(`${filePath}on`); // .js to .json
const { categories, subcategories, resources: allResources, alias } = require(`${filePath}on`); // .js to .json
const resources = pick(allResources, ['primaryDocumentation', 'credentialDocumentation']);
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
return {
...(categories && { categories }),
...(subcategories && { subcategories }),
...(resources && { resources }),
...(alias && { alias }),
};
}
@ -291,11 +449,9 @@ class LoadNodesAndCredentialsClass {
* Adds a node codex `categories` and `subcategories` (if defined)
* to a node description `codex` property.
*
* @param {object} obj
* @param obj.node Node to add categories to
* @param obj.filePath Path to the built node
* @param obj.isCustom Whether the node is custom
* @returns {void}
*/
addCodex({
node,
@ -317,8 +473,7 @@ class LoadNodesAndCredentialsClass {
node.description.codex = codex;
} catch (_) {
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
this.logger.debug(`No codex available for: ${filePath.split('/').pop()}`);
this.logger.debug(`No codex available for: ${filePath.split('/').pop() ?? ''}`);
if (isCustom) {
node.description.codex = {
@ -333,72 +488,87 @@ class LoadNodesAndCredentialsClass {
*
* @param {string} setPackageName The package name to set for the found nodes
* @param {string} directory The directory to look in
* @returns {Promise<void>}
*/
async loadDataFromDirectory(setPackageName: string, directory: string): Promise<void> {
const files = await glob(path.join(directory, '**/*.@(node|credentials).js'));
const files = await glob('**/*.@(node|credentials).js', {
cwd: directory,
absolute: true,
});
let fileName: string;
let type: string;
const loadPromises = [];
for (const filePath of files) {
[fileName, type] = path.parse(filePath).name.split('.');
const [fileName, type] = path.parse(filePath).name.split('.');
if (type === 'node') {
loadPromises.push(this.loadNodeFromFile(setPackageName, fileName, filePath));
this.loadNodeFromFile(setPackageName, fileName, filePath);
} else if (type === 'credentials') {
loadPromises.push(this.loadCredentialsFromFile(fileName, filePath));
this.loadCredentialsFromFile(fileName, filePath);
}
}
}
await Promise.all(loadPromises);
async readPackageJson(packagePath: string): Promise<IN8nNodePackageJson> {
// Get the absolute path of the package
const packageFileString = await fsReadFile(path.join(packagePath, 'package.json'), 'utf8');
return JSON.parse(packageFileString) as IN8nNodePackageJson;
}
/**
* Loads nodes and credentials from the package with the given name
*
* @param {string} packageName The name to read data from
* @returns {Promise<void>}
* @param {string} packagePath The path to read data from
*/
async loadDataFromPackage(packageName: string): Promise<void> {
async loadDataFromPackage(packagePath: string): Promise<INodeTypeNameVersion[]> {
// Get the absolute path of the package
const packagePath = path.join(this.nodeModulesPath, packageName);
// Read the data from the package.json file to see if any n8n data is defiend
const packageFileString = await fsReadFile(path.join(packagePath, 'package.json'), 'utf8');
const packageFile = JSON.parse(packageFileString);
if (!packageFile.hasOwnProperty('n8n')) {
return;
const packageFile = await this.readPackageJson(packagePath);
if (!packageFile.n8n) {
return [];
}
let tempPath: string;
let filePath: string;
const packageName = packageFile.name;
const { nodes, credentials } = packageFile.n8n;
const returnData: INodeTypeNameVersion[] = [];
// Read all node types
let fileName: string;
let type: string;
if (packageFile.n8n.hasOwnProperty('nodes') && Array.isArray(packageFile.n8n.nodes)) {
for (filePath of packageFile.n8n.nodes) {
tempPath = path.join(packagePath, filePath);
[fileName, type] = path.parse(filePath).name.split('.');
await this.loadNodeFromFile(packageName, fileName, tempPath);
if (Array.isArray(nodes)) {
for (const filePath of nodes) {
const tempPath = path.join(packagePath, filePath);
const [fileName] = path.parse(filePath).name.split('.');
const loadData = this.loadNodeFromFile(packageName, fileName, tempPath);
if (loadData) {
returnData.push(loadData);
}
}
}
// Read all credential types
if (
packageFile.n8n.hasOwnProperty('credentials') &&
Array.isArray(packageFile.n8n.credentials)
) {
for (filePath of packageFile.n8n.credentials) {
tempPath = path.join(packagePath, filePath);
// eslint-disable-next-line @typescript-eslint/no-unused-vars
[fileName, type] = path.parse(filePath).name.split('.');
// eslint-disable-next-line @typescript-eslint/no-floating-promises
if (Array.isArray(credentials)) {
for (const filePath of credentials) {
const tempPath = path.join(packagePath, filePath);
const [fileName] = path.parse(filePath).name.split('.');
this.loadCredentialsFromFile(fileName, tempPath);
}
}
return returnData;
}
unloadNodes(installedNodes: InstalledNodes[]): void {
const nodeTypes = NodeTypes();
installedNodes.forEach((installedNode) => {
nodeTypes.removeNodeType(installedNode.type);
delete this.nodeTypes[installedNode.type];
});
}
attachNodesToNodeTypes(installedNodes: InstalledNodes[]): void {
const nodeTypes = NodeTypes();
installedNodes.forEach((installedNode) => {
nodeTypes.attachNodeType(
installedNode.type,
this.nodeTypes[installedNode.type].type,
this.nodeTypes[installedNode.type].sourcePath,
);
});
}
}

View File

@ -40,6 +40,7 @@ export class Logger implements ILogger {
winston.format.printf(({ level, message, timestamp, metadata }) => {
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
return `${timestamp} | ${level.padEnd(18)} | ${message}${
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
Object.keys(metadata).length ? ` ${JSON.stringify(inspect(metadata))}` : ''
}`;
}),

View File

@ -57,6 +57,21 @@ class NodeTypesClass implements INodeTypes {
}
return NodeHelpers.getVersionedNodeType(this.nodeTypes[nodeType].type, version);
}
attachNodeType(
nodeTypeName: string,
nodeType: INodeType | INodeVersionedType,
sourcePath: string,
): void {
this.nodeTypes[nodeTypeName] = {
type: nodeType,
sourcePath,
};
}
removeNodeType(nodeType: string): void {
delete this.nodeTypes[nodeType];
}
}
let nodeTypesInstance: NodeTypesClass | undefined;

View File

@ -24,7 +24,7 @@ function createApiRouter(
): Router {
const n8nPath = config.getEnv('path');
const swaggerDocument = YAML.load(openApiSpecPath) as swaggerUi.JsonObject;
// add the server depeding on the config so the user can interact with the API
// add the server depending on the config so the user can interact with the API
// from the Swagger UI
swaggerDocument.server = [
{

View File

@ -152,7 +152,7 @@ export interface IRequired {
}
export interface IDependency {
if?: { properties: {} };
then?: { oneOf: IRequired[] };
then?: { allOf: IRequired[] };
else?: { allOf: IRequired[] };
}

View File

@ -1,3 +1,4 @@
/* eslint-disable @typescript-eslint/no-unsafe-argument */
import express from 'express';
import { CredentialsHelper } from '../../../../CredentialsHelper';

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