le epic
This commit is contained in:
commit
a44448d380
17 changed files with 721 additions and 0 deletions
20
.editorconfig
Normal file
20
.editorconfig
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
charset = utf-8
|
||||||
|
indent_style = tab
|
||||||
|
indent_size = 2
|
||||||
|
end_of_line = lf
|
||||||
|
insert_final_newline = true
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
|
||||||
|
[package.json]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
|
|
||||||
|
[*.md]
|
||||||
|
trim_trailing_whitespace = false
|
||||||
|
|
||||||
|
[*.yml]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
146
.eslintrc.js
Normal file
146
.eslintrc.js
Normal file
|
|
@ -0,0 +1,146 @@
|
||||||
|
/**
|
||||||
|
* @type {import('@types/eslint').ESLint.ConfigData}
|
||||||
|
*/
|
||||||
|
module.exports = {
|
||||||
|
root: true,
|
||||||
|
|
||||||
|
env: {
|
||||||
|
browser: true,
|
||||||
|
es6: true,
|
||||||
|
node: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
parser: '@typescript-eslint/parser',
|
||||||
|
|
||||||
|
parserOptions: {
|
||||||
|
project: ['./tsconfig.json'],
|
||||||
|
sourceType: 'module',
|
||||||
|
extraFileExtensions: ['.json'],
|
||||||
|
},
|
||||||
|
|
||||||
|
ignorePatterns: ['.eslintrc.js', '**/*.js', '**/node_modules/**', '**/dist/**'],
|
||||||
|
|
||||||
|
overrides: [
|
||||||
|
{
|
||||||
|
files: ['package.json'],
|
||||||
|
plugins: ['eslint-plugin-n8n-nodes-base'],
|
||||||
|
extends: ['plugin:n8n-nodes-base/community'],
|
||||||
|
rules: {
|
||||||
|
'n8n-nodes-base/community-package-json-name-still-default': 'off',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
files: ['./credentials/**/*.ts'],
|
||||||
|
plugins: ['eslint-plugin-n8n-nodes-base'],
|
||||||
|
extends: ['plugin:n8n-nodes-base/credentials'],
|
||||||
|
rules: {
|
||||||
|
'n8n-nodes-base/cred-class-field-authenticate-type-assertion': 'error',
|
||||||
|
'n8n-nodes-base/cred-class-field-display-name-missing-oauth2': 'error',
|
||||||
|
'n8n-nodes-base/cred-class-field-display-name-miscased': 'error',
|
||||||
|
'n8n-nodes-base/cred-class-field-documentation-url-missing': 'error',
|
||||||
|
'n8n-nodes-base/cred-class-field-documentation-url-miscased': 'off',
|
||||||
|
'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-field-properties-assertion': 'error',
|
||||||
|
'n8n-nodes-base/cred-class-field-type-options-password-missing': '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: ['./nodes/**/*.ts'],
|
||||||
|
plugins: ['eslint-plugin-n8n-nodes-base'],
|
||||||
|
extends: ['plugin:n8n-nodes-base/nodes'],
|
||||||
|
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': 'off',
|
||||||
|
'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-non-core-color-present': 'error',
|
||||||
|
'n8n-nodes-base/node-class-description-name-miscased': 'error',
|
||||||
|
'n8n-nodes-base/node-class-description-name-unsuffixed-trigger-node': 'error',
|
||||||
|
'n8n-nodes-base/node-class-description-outputs-wrong': 'off',
|
||||||
|
'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-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-id': 'error',
|
||||||
|
'n8n-nodes-base/node-param-display-name-miscased': 'error',
|
||||||
|
'n8n-nodes-base/node-param-display-name-not-first-position': '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-name-untrimmed': 'error',
|
||||||
|
'n8n-nodes-base/node-param-operation-option-action-wrong-for-get-many': 'error',
|
||||||
|
'n8n-nodes-base/node-param-operation-option-description-wrong-for-get-many': 'error',
|
||||||
|
'n8n-nodes-base/node-param-operation-option-without-action': 'error',
|
||||||
|
'n8n-nodes-base/node-param-operation-without-no-data-expression': '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-many': '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',
|
||||||
|
'n8n-nodes-base/node-param-type-options-password-missing': 'error',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
16
.eslintrc.prepublish.js
Normal file
16
.eslintrc.prepublish.js
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
/**
|
||||||
|
* @type {import('@types/eslint').ESLint.ConfigData}
|
||||||
|
*/
|
||||||
|
module.exports = {
|
||||||
|
extends: "./.eslintrc.js",
|
||||||
|
|
||||||
|
overrides: [
|
||||||
|
{
|
||||||
|
files: ['package.json'],
|
||||||
|
plugins: ['eslint-plugin-n8n-nodes-base'],
|
||||||
|
rules: {
|
||||||
|
'n8n-nodes-base/community-package-json-name-still-default': 'error',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
8
.gitignore
vendored
Normal file
8
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
node_modules
|
||||||
|
.DS_Store
|
||||||
|
.tmp
|
||||||
|
tmp
|
||||||
|
dist
|
||||||
|
npm-debug.log*
|
||||||
|
yarn.lock
|
||||||
|
.vscode/launch.json
|
||||||
2
.npmignore
Normal file
2
.npmignore
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
.DS_Store
|
||||||
|
*.tsbuildinfo
|
||||||
51
.prettierrc.js
Normal file
51
.prettierrc.js
Normal file
|
|
@ -0,0 +1,51 @@
|
||||||
|
module.exports = {
|
||||||
|
/**
|
||||||
|
* https://prettier.io/docs/en/options.html#semicolons
|
||||||
|
*/
|
||||||
|
semi: true,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://prettier.io/docs/en/options.html#trailing-commas
|
||||||
|
*/
|
||||||
|
trailingComma: 'all',
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://prettier.io/docs/en/options.html#bracket-spacing
|
||||||
|
*/
|
||||||
|
bracketSpacing: true,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://prettier.io/docs/en/options.html#tabs
|
||||||
|
*/
|
||||||
|
useTabs: true,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://prettier.io/docs/en/options.html#tab-width
|
||||||
|
*/
|
||||||
|
tabWidth: 2,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://prettier.io/docs/en/options.html#arrow-function-parentheses
|
||||||
|
*/
|
||||||
|
arrowParens: 'always',
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://prettier.io/docs/en/options.html#quotes
|
||||||
|
*/
|
||||||
|
singleQuote: true,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://prettier.io/docs/en/options.html#quote-props
|
||||||
|
*/
|
||||||
|
quoteProps: 'as-needed',
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://prettier.io/docs/en/options.html#end-of-line
|
||||||
|
*/
|
||||||
|
endOfLine: 'lf',
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://prettier.io/docs/en/options.html#print-width
|
||||||
|
*/
|
||||||
|
printWidth: 100,
|
||||||
|
};
|
||||||
7
.vscode/extensions.json
vendored
Normal file
7
.vscode/extensions.json
vendored
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
{
|
||||||
|
"recommendations": [
|
||||||
|
"dbaeumer.vscode-eslint",
|
||||||
|
"EditorConfig.EditorConfig",
|
||||||
|
"esbenp.prettier-vscode",
|
||||||
|
]
|
||||||
|
}
|
||||||
76
CODE_OF_CONDUCT.md
Normal file
76
CODE_OF_CONDUCT.md
Normal file
|
|
@ -0,0 +1,76 @@
|
||||||
|
# Contributor Covenant Code of Conduct
|
||||||
|
|
||||||
|
## Our Pledge
|
||||||
|
|
||||||
|
In the interest of fostering an open and welcoming environment, we as
|
||||||
|
contributors and maintainers pledge to making participation in our project and
|
||||||
|
our community a harassment-free experience for everyone, regardless of age, body
|
||||||
|
size, disability, ethnicity, sex characteristics, gender identity and expression,
|
||||||
|
level of experience, education, socio-economic status, nationality, personal
|
||||||
|
appearance, race, religion, or sexual identity and orientation.
|
||||||
|
|
||||||
|
## Our Standards
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
## Our Responsibilities
|
||||||
|
|
||||||
|
Project maintainers are responsible for clarifying the standards of acceptable
|
||||||
|
behavior and are expected to take appropriate and fair corrective action in
|
||||||
|
response to any instances of unacceptable behavior.
|
||||||
|
|
||||||
|
Project maintainers have the right and responsibility to remove, edit, or
|
||||||
|
reject comments, commits, code, wiki edits, issues, and other contributions
|
||||||
|
that are not aligned to this Code of Conduct, or to ban temporarily or
|
||||||
|
permanently any contributor for other behaviors that they deem inappropriate,
|
||||||
|
threatening, offensive, or harmful.
|
||||||
|
|
||||||
|
## Scope
|
||||||
|
|
||||||
|
This Code of Conduct applies both within project spaces and in public spaces
|
||||||
|
when an individual is representing the project or its community. Examples of
|
||||||
|
representing a project or community include using an official project e-mail
|
||||||
|
address, posting via an official social media account, or acting as an appointed
|
||||||
|
representative at an online or offline event. Representation of a project may be
|
||||||
|
further defined and clarified by project maintainers.
|
||||||
|
|
||||||
|
## Enforcement
|
||||||
|
|
||||||
|
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||||
|
reported by contacting the project team at jan@n8n.io. All
|
||||||
|
complaints will be reviewed and investigated and will result in a response that
|
||||||
|
is deemed necessary and appropriate to the circumstances. The project team is
|
||||||
|
obligated to maintain confidentiality with regard to the reporter of an incident.
|
||||||
|
Further details of specific enforcement policies may be posted separately.
|
||||||
|
|
||||||
|
Project maintainers who do not follow or enforce the Code of Conduct in good
|
||||||
|
faith may face temporary or permanent repercussions as determined by other
|
||||||
|
members of the project's leadership.
|
||||||
|
|
||||||
|
## Attribution
|
||||||
|
|
||||||
|
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
|
||||||
|
available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
|
||||||
|
|
||||||
|
[homepage]: https://www.contributor-covenant.org
|
||||||
|
|
||||||
|
For answers to common questions about this code of conduct, see
|
||||||
|
https://www.contributor-covenant.org/faq
|
||||||
19
LICENSE.md
Normal file
19
LICENSE.md
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
Copyright 2022 n8n
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
this software and associated documentation files (the "Software"), to deal in
|
||||||
|
the Software without restriction, including without limitation the rights to
|
||||||
|
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||||
|
of the Software, and to permit persons to whom the Software is furnished to do
|
||||||
|
so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of 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.
|
||||||
48
README.md
Normal file
48
README.md
Normal file
|
|
@ -0,0 +1,48 @@
|
||||||
|

|
||||||
|
|
||||||
|
# n8n-nodes-starter
|
||||||
|
|
||||||
|
This repo contains example nodes to help you get started building your own custom integrations for [n8n](https://n8n.io). It includes the node linter and other dependencies.
|
||||||
|
|
||||||
|
To make your custom node available to the community, you must create it as an npm package, and [submit it to the npm registry](https://docs.npmjs.com/packages-and-modules/contributing-packages-to-the-registry).
|
||||||
|
|
||||||
|
If you would like your node to be available on n8n cloud you can also [submit your node for verification](https://docs.n8n.io/integrations/creating-nodes/deploy/submit-community-nodes/).
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
You need the following installed on your development machine:
|
||||||
|
|
||||||
|
* [git](https://git-scm.com/downloads)
|
||||||
|
* Node.js and npm. Minimum version Node 20. You can find instructions on how to install both using nvm (Node Version Manager) for Linux, Mac, and WSL [here](https://github.com/nvm-sh/nvm). For Windows users, refer to Microsoft's guide to [Install NodeJS on Windows](https://docs.microsoft.com/en-us/windows/dev-environment/javascript/nodejs-on-windows).
|
||||||
|
* Install n8n with:
|
||||||
|
```
|
||||||
|
npm install n8n -g
|
||||||
|
```
|
||||||
|
* Recommended: follow n8n's guide to [set up your development environment](https://docs.n8n.io/integrations/creating-nodes/build/node-development-environment/).
|
||||||
|
|
||||||
|
## Using this starter
|
||||||
|
|
||||||
|
These are the basic steps for working with the starter. For detailed guidance on creating and publishing nodes, refer to the [documentation](https://docs.n8n.io/integrations/creating-nodes/).
|
||||||
|
|
||||||
|
1. [Generate a new repository](https://github.com/n8n-io/n8n-nodes-starter/generate) from this template repository.
|
||||||
|
2. Clone your new repo:
|
||||||
|
```
|
||||||
|
git clone https://github.com/<your organization>/<your-repo-name>.git
|
||||||
|
```
|
||||||
|
3. Run `npm i` to install dependencies.
|
||||||
|
4. Open the project in your editor.
|
||||||
|
5. Browse the examples in `/nodes` and `/credentials`. Modify the examples, or replace them with your own nodes.
|
||||||
|
6. Update the `package.json` to match your details.
|
||||||
|
7. Run `npm run lint` to check for errors or `npm run lintfix` to automatically fix errors when possible.
|
||||||
|
8. Test your node locally. Refer to [Run your node locally](https://docs.n8n.io/integrations/creating-nodes/test/run-node-locally/) for guidance.
|
||||||
|
9. Replace this README with documentation for your node. Use the [README_TEMPLATE](README_TEMPLATE.md) to get started.
|
||||||
|
10. Update the LICENSE file to use your details.
|
||||||
|
11. [Publish](https://docs.npmjs.com/packages-and-modules/contributing-packages-to-the-registry) your package to npm.
|
||||||
|
|
||||||
|
## More information
|
||||||
|
|
||||||
|
Refer to our [documentation on creating nodes](https://docs.n8n.io/integrations/creating-nodes/) for detailed information on building your own nodes.
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
[MIT](https://github.com/n8n-io/n8n-nodes-starter/blob/master/LICENSE.md)
|
||||||
48
README_TEMPLATE.md
Normal file
48
README_TEMPLATE.md
Normal file
|
|
@ -0,0 +1,48 @@
|
||||||
|
# n8n-nodes-_node-name_
|
||||||
|
|
||||||
|
This is an n8n community node. It lets you use _app/service name_ in your n8n workflows.
|
||||||
|
|
||||||
|
_App/service name_ is _one or two sentences describing the service this node integrates with_.
|
||||||
|
|
||||||
|
[n8n](https://n8n.io/) is a [fair-code licensed](https://docs.n8n.io/reference/license/) workflow automation platform.
|
||||||
|
|
||||||
|
[Installation](#installation)
|
||||||
|
[Operations](#operations)
|
||||||
|
[Credentials](#credentials) <!-- delete if no auth needed -->
|
||||||
|
[Compatibility](#compatibility)
|
||||||
|
[Usage](#usage) <!-- delete if not using this section -->
|
||||||
|
[Resources](#resources)
|
||||||
|
[Version history](#version-history) <!-- delete if not using this section -->
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
Follow the [installation guide](https://docs.n8n.io/integrations/community-nodes/installation/) in the n8n community nodes documentation.
|
||||||
|
|
||||||
|
## Operations
|
||||||
|
|
||||||
|
_List the operations supported by your node._
|
||||||
|
|
||||||
|
## Credentials
|
||||||
|
|
||||||
|
_If users need to authenticate with the app/service, provide details here. You should include prerequisites (such as signing up with the service), available authentication methods, and how to set them up._
|
||||||
|
|
||||||
|
## Compatibility
|
||||||
|
|
||||||
|
_State the minimum n8n version, as well as which versions you test against. You can also include any known version incompatibility issues._
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
_This is an optional section. Use it to help users with any difficult or confusing aspects of the node._
|
||||||
|
|
||||||
|
_By the time users are looking for community nodes, they probably already know n8n basics. But if you expect new users, you can link to the [Try it out](https://docs.n8n.io/try-it-out/) documentation to help them get started._
|
||||||
|
|
||||||
|
## Resources
|
||||||
|
|
||||||
|
* [n8n community nodes documentation](https://docs.n8n.io/integrations/#community-nodes)
|
||||||
|
* _Link to app/service documentation._
|
||||||
|
|
||||||
|
## Version history
|
||||||
|
|
||||||
|
_This is another optional section. If your node has multiple versions, include a short description of available versions and what changed, as well as any compatibility impact._
|
||||||
|
|
||||||
|
|
||||||
43
credentials/XmppApi.credentials.ts
Normal file
43
credentials/XmppApi.credentials.ts
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
import {
|
||||||
|
IAuthenticateGeneric,
|
||||||
|
ICredentialTestRequest,
|
||||||
|
ICredentialType,
|
||||||
|
INodeProperties,
|
||||||
|
} from 'n8n-workflow';
|
||||||
|
|
||||||
|
export class XmppApi implements ICredentialType {
|
||||||
|
name = 'xmppApi';
|
||||||
|
displayName = 'XMPP API';
|
||||||
|
properties: INodeProperties[] = [
|
||||||
|
{
|
||||||
|
displayName: 'Domain',
|
||||||
|
name: 'domain',
|
||||||
|
type: 'string',
|
||||||
|
default: '',
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'Username',
|
||||||
|
name: 'username',
|
||||||
|
type: 'string',
|
||||||
|
default: '',
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'Password',
|
||||||
|
name: 'password',
|
||||||
|
type: 'string',
|
||||||
|
typeOptions: {
|
||||||
|
password: true,
|
||||||
|
},
|
||||||
|
default: '',
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'Port',
|
||||||
|
name: 'port',
|
||||||
|
type: 'number',
|
||||||
|
default: 5222,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
16
gulpfile.js
Normal file
16
gulpfile.js
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
const path = require('path');
|
||||||
|
const { task, src, dest } = require('gulp');
|
||||||
|
|
||||||
|
task('build:icons', copyIcons);
|
||||||
|
|
||||||
|
function copyIcons() {
|
||||||
|
const nodeSource = path.resolve('nodes', '**', '*.{png,svg}');
|
||||||
|
const nodeDestination = path.resolve('dist', 'nodes');
|
||||||
|
|
||||||
|
src(nodeSource).pipe(dest(nodeDestination));
|
||||||
|
|
||||||
|
const credSource = path.resolve('credentials', '**', '*.{png,svg}');
|
||||||
|
const credDestination = path.resolve('dist', 'credentials');
|
||||||
|
|
||||||
|
return src(credSource).pipe(dest(credDestination));
|
||||||
|
}
|
||||||
0
index.js
Normal file
0
index.js
Normal file
139
nodes/Xmpp/Xmpp.node.ts
Normal file
139
nodes/Xmpp/Xmpp.node.ts
Normal file
|
|
@ -0,0 +1,139 @@
|
||||||
|
import { IExecuteFunctions } from 'n8n-core';
|
||||||
|
import {
|
||||||
|
INodeExecutionData,
|
||||||
|
INodeType,
|
||||||
|
INodeTypeDescription,
|
||||||
|
NodeOperationError,
|
||||||
|
} from 'n8n-workflow';
|
||||||
|
import { client, xml } from '@xmpp/client';
|
||||||
|
|
||||||
|
export class Xmpp implements INodeType {
|
||||||
|
description: INodeTypeDescription = {
|
||||||
|
displayName: 'XMPP',
|
||||||
|
name: 'xmpp',
|
||||||
|
icon: 'file:xmpp.svg',
|
||||||
|
group: ['communication'],
|
||||||
|
version: 1,
|
||||||
|
subtitle: '={{$parameter["operation"]}}',
|
||||||
|
description: 'Send messages via XMPP protocol',
|
||||||
|
defaults: {
|
||||||
|
name: 'XMPP',
|
||||||
|
},
|
||||||
|
inputs: ['main'],
|
||||||
|
outputs: ['main'],
|
||||||
|
credentials: [
|
||||||
|
{
|
||||||
|
name: 'xmppApi',
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
requestDefaults: {
|
||||||
|
headers: {
|
||||||
|
Accept: 'application/json',
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
properties: [
|
||||||
|
{
|
||||||
|
displayName: 'Operation',
|
||||||
|
name: 'operation',
|
||||||
|
type: 'options',
|
||||||
|
noDataExpression: false,
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
name: 'Send Message',
|
||||||
|
value: 'sendMessage',
|
||||||
|
description: 'Send a message to a user or room',
|
||||||
|
action: 'Send a message',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
default: 'sendMessage',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'To',
|
||||||
|
name: 'to',
|
||||||
|
type: 'string',
|
||||||
|
default: '',
|
||||||
|
placeholder: 'user@domain.com',
|
||||||
|
description: 'Recipient JID',
|
||||||
|
required: true,
|
||||||
|
displayOptions: {
|
||||||
|
show: {
|
||||||
|
operation: ['sendMessage'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'Message',
|
||||||
|
name: 'message',
|
||||||
|
type: 'string',
|
||||||
|
default: '',
|
||||||
|
description: 'Message to send',
|
||||||
|
required: true,
|
||||||
|
displayOptions: {
|
||||||
|
show: {
|
||||||
|
operation: ['sendMessage'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
|
||||||
|
const items = this.getInputData();
|
||||||
|
const returnData: INodeExecutionData[] = [];
|
||||||
|
|
||||||
|
for (let i = 0; i < items.length; i++) {
|
||||||
|
try {
|
||||||
|
const operation = this.getNodeParameter('operation', i) as string;
|
||||||
|
const credentials = await this.getCredentials('xmppApi', i);
|
||||||
|
|
||||||
|
if (operation === 'sendMessage') {
|
||||||
|
const to = this.getNodeParameter('to', i) as string;
|
||||||
|
const message = this.getNodeParameter('message', i) as string;
|
||||||
|
|
||||||
|
// Create XMPP client
|
||||||
|
const xmppClient = client({
|
||||||
|
service: `xmpp://${credentials.domain}:${credentials.port}`,
|
||||||
|
username: credentials.username,
|
||||||
|
password: credentials.password,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Connect
|
||||||
|
await xmppClient.start();
|
||||||
|
|
||||||
|
// Send message
|
||||||
|
const messageStanza = xml(
|
||||||
|
'message',
|
||||||
|
{ to, type: 'chat' },
|
||||||
|
xml('body', {}, message),
|
||||||
|
);
|
||||||
|
|
||||||
|
await xmppClient.send(messageStanza);
|
||||||
|
await xmppClient.stop();
|
||||||
|
|
||||||
|
returnData.push({
|
||||||
|
json: {
|
||||||
|
success: true,
|
||||||
|
to,
|
||||||
|
message,
|
||||||
|
timestamp: new Date().toISOString(),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
if (this.continueOnFail()) {
|
||||||
|
returnData.push({
|
||||||
|
json: {
|
||||||
|
error: error.message,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
throw new NodeOperationError(this.getNode(), error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return [returnData];
|
||||||
|
}
|
||||||
|
}
|
||||||
52
package.json
Normal file
52
package.json
Normal file
|
|
@ -0,0 +1,52 @@
|
||||||
|
{
|
||||||
|
"name": "n8n-nodes-xmpp",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "n8n node for XMPP (Prosody) communication",
|
||||||
|
"keywords": [
|
||||||
|
"n8n-community-node-package"
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"homepage": "",
|
||||||
|
"author": {
|
||||||
|
"name": "Ben de Wit",
|
||||||
|
"email": "ben@bendwit.com"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": ""
|
||||||
|
},
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"build": "tsc && gulp build:icons",
|
||||||
|
"dev": "tsc --watch",
|
||||||
|
"format": "prettier nodes credentials --write",
|
||||||
|
"lint": "eslint nodes credentials package.json",
|
||||||
|
"lintfix": "eslint nodes credentials package.json --fix",
|
||||||
|
"prepublishOnly": "npm run build && npm run lint -s"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"dist"
|
||||||
|
],
|
||||||
|
"n8n": {
|
||||||
|
"n8nNodesApiVersion": 1,
|
||||||
|
"credentials": [
|
||||||
|
"dist/credentials/XmppApi.credentials.js"
|
||||||
|
],
|
||||||
|
"nodes": [
|
||||||
|
"dist/nodes/Xmpp/Xmpp.node.js",
|
||||||
|
"dist/nodes/XmppTrigger/XmppTrigger.node.js"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@typescript-eslint/parser": "^5.45.0",
|
||||||
|
"eslint-plugin-n8n-nodes-base": "^1.11.0",
|
||||||
|
"n8n-workflow": "*",
|
||||||
|
"prettier": "^2.7.1",
|
||||||
|
"typescript": "^4.8.4"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@xmpp/client": "^0.13.1",
|
||||||
|
"@xmpp/xml": "^0.13.1",
|
||||||
|
"@xmpp/jid": "^0.13.1"
|
||||||
|
}
|
||||||
|
}
|
||||||
30
tsconfig.json
Normal file
30
tsconfig.json
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"strict": true,
|
||||||
|
"module": "commonjs",
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"target": "es2019",
|
||||||
|
"lib": ["es2019", "es2020", "es2022.error"],
|
||||||
|
"removeComments": true,
|
||||||
|
"useUnknownInCatchVariables": false,
|
||||||
|
"forceConsistentCasingInFileNames": true,
|
||||||
|
"noImplicitAny": true,
|
||||||
|
"noImplicitReturns": true,
|
||||||
|
"noUnusedLocals": true,
|
||||||
|
"strictNullChecks": true,
|
||||||
|
"preserveConstEnums": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"incremental": true,
|
||||||
|
"declaration": true,
|
||||||
|
"sourceMap": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"outDir": "./dist/",
|
||||||
|
},
|
||||||
|
"include": [
|
||||||
|
"credentials/**/*",
|
||||||
|
"nodes/**/*",
|
||||||
|
"nodes/**/*.json",
|
||||||
|
"package.json",
|
||||||
|
],
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue