migrate n8n integration (#3004)
This commit is contained in:
30
.github/workflows/n8n-ci.yml
vendored
30
.github/workflows/n8n-ci.yml
vendored
@@ -1,30 +0,0 @@
|
||||
name: Run n8n package CI
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
paths:
|
||||
- 'integrations/n8n/**'
|
||||
pull_request:
|
||||
branches: [main]
|
||||
paths:
|
||||
- 'integrations/n8n/**'
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set up Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version-file: .nvmrc
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@v2
|
||||
with:
|
||||
version: 9
|
||||
run_install: false
|
||||
- name: Install dependencies
|
||||
working-directory: integrations/n8n
|
||||
run: pnpm install --frozen-lockfile
|
||||
- name: Build and Lint
|
||||
working-directory: integrations/n8n
|
||||
run: pnpm prepublishOnly
|
||||
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
[submodule "integrations/n8n"]
|
||||
path = integrations/n8n
|
||||
url = https://github.com/Skyvern-AI/skyvern-n8n
|
||||
1
integrations/n8n
Submodule
1
integrations/n8n
Submodule
Submodule integrations/n8n added at c14752f27a
@@ -1,20 +0,0 @@
|
||||
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
|
||||
@@ -1,63 +0,0 @@
|
||||
/**
|
||||
* @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-documentation-url-missing": "off",
|
||||
"n8n-nodes-base/cred-class-field-documentation-url-miscased": "off",
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ["./nodes/**/*.ts"],
|
||||
plugins: ["eslint-plugin-n8n-nodes-base"],
|
||||
extends: ["plugin:n8n-nodes-base/nodes"],
|
||||
rules: {
|
||||
"n8n-nodes-base/node-execute-block-missing-continue-on-fail": "off",
|
||||
"n8n-nodes-base/node-resource-description-filename-against-convention":
|
||||
"off",
|
||||
"n8n-nodes-base/node-param-fixed-collection-type-unsorted-items": "off",
|
||||
"n8n-nodes-base/node-class-description-inputs-wrong-regular-node":
|
||||
"off",
|
||||
"n8n-nodes-base/node-class-description-outputs-wrong": "off",
|
||||
"n8n-nodes-base/node-param-description-wrong-for-dynamic-options":
|
||||
"off",
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
@@ -1,16 +0,0 @@
|
||||
/**
|
||||
* @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
integrations/n8n/.gitignore
vendored
8
integrations/n8n/.gitignore
vendored
@@ -1,8 +0,0 @@
|
||||
node_modules
|
||||
.DS_Store
|
||||
.tmp
|
||||
tmp
|
||||
dist
|
||||
npm-debug.log*
|
||||
yarn.lock
|
||||
.vscode/launch.json
|
||||
@@ -1,4 +0,0 @@
|
||||
.DS_Store
|
||||
*.tsbuildinfo
|
||||
node_modules/
|
||||
dist/
|
||||
@@ -1,51 +0,0 @@
|
||||
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,
|
||||
};
|
||||
@@ -1,89 +0,0 @@
|
||||
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
|
||||
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
|
||||
|
||||
- [Contributor Covenant Code of Conduct](#contributor-covenant-code-of-conduct)
|
||||
- [Our Pledge](#our-pledge)
|
||||
- [Our Standards](#our-standards)
|
||||
- [Our Responsibilities](#our-responsibilities)
|
||||
- [Scope](#scope)
|
||||
- [Enforcement](#enforcement)
|
||||
- [Attribution](#attribution)
|
||||
|
||||
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
|
||||
|
||||
# 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
|
||||
@@ -1,19 +0,0 @@
|
||||
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.
|
||||
@@ -1,45 +0,0 @@
|
||||
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
|
||||
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
|
||||
|
||||
- [n8n-nodes-skyvern](#n8n-nodes-skyvern)
|
||||
- [Installation](#installation)
|
||||
- [Operations](#operations)
|
||||
- [Credentials](#credentials)
|
||||
- [Resources](#resources)
|
||||
|
||||
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
|
||||
|
||||
# n8n-nodes-skyvern
|
||||
|
||||
This is an n8n community node. It lets you use [Skyvern](https://www.skyvern.com/) in your n8n workflows.
|
||||
|
||||
[Skyvern](https://www.skyvern.com/) is an [open-source](https://github.com/Skyvern-AI/skyvern) product. It automates browser-based workflows using LLMs and computer vision. It provides a simple API endpoint to fully automate manual workflows on a large number of websites, replacing brittle or unreliable automation solutions.
|
||||
|
||||
[n8n](https://n8n.io/) is a [fair-code licensed](https://docs.n8n.io/reference/license/) workflow automation platform.
|
||||
|
||||
[Installation](#installation)
|
||||
[Operations](#operations)
|
||||
[Credentials](#credentials)
|
||||
[Resources](#resources)
|
||||
|
||||
## Installation
|
||||
|
||||
Follow the [installation guide](https://docs.n8n.io/integrations/community-nodes/installation/) in the n8n community nodes documentation.
|
||||
|
||||
## Operations
|
||||
|
||||
- Task: interact with Skyvern task
|
||||
- Workflow: interact with Skyvern workflow
|
||||
|
||||
## Credentials
|
||||
|
||||
- API Token: Skyvern API token. You can get it from the Skyvern UI
|
||||
- Base URL: The endpoint for your Skyvern service. Default is Skyvern Cloud Service, you can also set it to your self-host Skyvern.
|
||||
|
||||
|
||||
## Resources
|
||||
|
||||
* [n8n community nodes documentation](https://docs.n8n.io/integrations/community-nodes/)
|
||||
* [Skyvern documentation](https://docs.skyvern.com/introduction)
|
||||
|
||||
* [n8n integration code](https://github.com/Skyvern-AI/skyvern/tree/main/integrations/n8n)
|
||||
@@ -1,45 +0,0 @@
|
||||
import {
|
||||
IAuthenticateGeneric,
|
||||
ICredentialTestRequest,
|
||||
ICredentialType,
|
||||
INodeProperties,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
export class SkyvernApi implements ICredentialType {
|
||||
name = 'skyvernApi';
|
||||
displayName = 'Skyvern API';
|
||||
// Uses the link to this tutorial as an example
|
||||
// Replace with your own docs links when building your own nodes
|
||||
documentationUrl = 'https://docs.skyvern.ai/';
|
||||
properties: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'API Key',
|
||||
name: 'apiKey',
|
||||
type: 'string',
|
||||
typeOptions: { password: true },
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Base URL',
|
||||
name: 'baseUrl',
|
||||
type: 'string',
|
||||
default: 'https://api.skyvern.com',
|
||||
placeholder: 'https://api.skyvern.com',
|
||||
},
|
||||
];
|
||||
authenticate: IAuthenticateGeneric = {
|
||||
type: 'generic',
|
||||
properties: {
|
||||
headers: {
|
||||
'x-api-key': '={{$credentials.apiKey}}',
|
||||
'Content-Type': 'application/json',
|
||||
}
|
||||
},
|
||||
};
|
||||
test: ICredentialTestRequest = {
|
||||
request: {
|
||||
baseURL: '={{$credentials?.baseUrl}}',
|
||||
url: '/api/v1/organizations',
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
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));
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
{
|
||||
"node": "n8n-nodes-skyvern",
|
||||
"nodeVersion": "1.0",
|
||||
"codexVersion": "1.0",
|
||||
"categories": [
|
||||
"Miscellaneous",
|
||||
"Utility"
|
||||
],
|
||||
"resources": {
|
||||
"credentialDocumentation": [
|
||||
{
|
||||
"url": ""
|
||||
}
|
||||
],
|
||||
"primaryDocumentation": [
|
||||
{
|
||||
"url": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -1,508 +0,0 @@
|
||||
import {
|
||||
FieldType,
|
||||
IDataObject,
|
||||
IExecuteSingleFunctions,
|
||||
IHttpRequestMethods,
|
||||
IHttpRequestOptions,
|
||||
ILoadOptionsFunctions,
|
||||
INodePropertyOptions,
|
||||
INodeType,
|
||||
INodeTypeDescription,
|
||||
NodeConnectionType,
|
||||
ResourceMapperField,
|
||||
ResourceMapperFields,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
async function skyvernApiRequest(
|
||||
this: IExecuteSingleFunctions | ILoadOptionsFunctions,
|
||||
method: IHttpRequestMethods,
|
||||
endpoint: string,
|
||||
body: IDataObject | undefined = undefined,
|
||||
): Promise<any> {
|
||||
const credentials = await this.getCredentials('skyvernApi');
|
||||
const options: IHttpRequestOptions = {
|
||||
baseURL: credentials.baseUrl as string,
|
||||
method,
|
||||
url: endpoint,
|
||||
body,
|
||||
json: true,
|
||||
};
|
||||
return this.helpers.requestWithAuthentication.call(this, 'skyvernApi', options);
|
||||
}
|
||||
|
||||
export class Skyvern implements INodeType {
|
||||
description: INodeTypeDescription = {
|
||||
displayName: 'Skyvern',
|
||||
name: 'skyvern',
|
||||
icon: 'file:skyvern.svg',
|
||||
group: ['transform'],
|
||||
description: 'Node to interact with Skyvern',
|
||||
defaults: {
|
||||
name: 'Skyvern',
|
||||
},
|
||||
inputs: [NodeConnectionType.Main],
|
||||
outputs: [NodeConnectionType.Main],
|
||||
credentials: [
|
||||
{
|
||||
name: 'skyvernApi',
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
properties: [
|
||||
{
|
||||
displayName: 'Resource',
|
||||
name: 'resource',
|
||||
type: 'options',
|
||||
noDataExpression: true,
|
||||
options: [
|
||||
{
|
||||
name: 'Task',
|
||||
value: 'task',
|
||||
},
|
||||
{
|
||||
name: 'Workflow',
|
||||
value: 'workflow',
|
||||
},
|
||||
],
|
||||
default: 'task',
|
||||
},
|
||||
// Task Operations
|
||||
{
|
||||
displayName: 'Operation',
|
||||
name: 'taskOperation',
|
||||
type: 'options',
|
||||
noDataExpression: true,
|
||||
required: true,
|
||||
default: 'dispatchTask',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['task'],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
name: 'Dispatch a Task',
|
||||
value: 'dispatchTask',
|
||||
action: 'Dispatch a task to execute asynchronously',
|
||||
description: 'Dispatch a task to execute asynchronously',
|
||||
},
|
||||
{
|
||||
name: 'Get a Task',
|
||||
value: 'getTask',
|
||||
action: 'Get a task by ID',
|
||||
description: 'Get a task by ID',
|
||||
},
|
||||
],
|
||||
routing: {
|
||||
request: {
|
||||
baseURL: '={{$credentials.baseUrl}}',
|
||||
method: '={{ $value === "dispatchTask" ? "POST" : "GET" }}' as IHttpRequestMethods,
|
||||
url: '={{"/v1/run/tasks"}}',
|
||||
},
|
||||
send: {
|
||||
preSend: [
|
||||
async function (
|
||||
this: IExecuteSingleFunctions,
|
||||
requestOptions: IHttpRequestOptions,
|
||||
): Promise<IHttpRequestOptions> {
|
||||
const taskOperation = this.getNodeParameter('taskOperation');
|
||||
if (taskOperation === "getTask") return requestOptions;
|
||||
|
||||
const taskOptions = this.getNodeParameter('taskOptions') as IDataObject;
|
||||
const legacy_engine = taskOptions['engine'] as string | null;
|
||||
if (legacy_engine === 'v1') {
|
||||
(requestOptions.body as IDataObject)['engine'] = 'skyvern-1.0';
|
||||
} else if (legacy_engine === 'v2') {
|
||||
(requestOptions.body as IDataObject)['engine'] = 'skyvern-2.0';
|
||||
}
|
||||
return requestOptions;
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
// Workflow Operations
|
||||
{
|
||||
displayName: 'Operation',
|
||||
name: 'workflowOperation',
|
||||
type: 'options',
|
||||
noDataExpression: true,
|
||||
required: true,
|
||||
default: 'getWorkflow',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['workflow'],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
name: 'Get a Workflow Run',
|
||||
value: 'getWorkflow',
|
||||
action: 'Get a workflow run by ID',
|
||||
description: 'Get a workflow run by ID',
|
||||
},
|
||||
{
|
||||
name: 'Dispatch a Workflow Run',
|
||||
value: 'dispatchWorkflow',
|
||||
action: 'Dispatch a workflow run to execute asynchronously',
|
||||
description: 'Dispatch a workflow run to execute asynchronously',
|
||||
},
|
||||
],
|
||||
routing: {
|
||||
request: {
|
||||
baseURL: '={{$credentials.baseUrl}}',
|
||||
method: '={{ $value === "dispatchWorkflow" ? "POST" : "GET" }}' as IHttpRequestMethods,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
displayName: 'User Prompt',
|
||||
description: 'The prompt for Skyvern to execute',
|
||||
name: 'userPrompt',
|
||||
type: 'string',
|
||||
required: true,
|
||||
default: '',
|
||||
placeholder: 'eg: Navigate to the Hacker News homepage and get the top 3 posts.',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['task'],
|
||||
taskOperation: ['dispatchTask'],
|
||||
},
|
||||
},
|
||||
routing: {
|
||||
request: {
|
||||
body: {
|
||||
prompt: '={{$value}}',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
displayName: 'URL',
|
||||
description: 'The URL to navigate to',
|
||||
name: 'url',
|
||||
type: 'string',
|
||||
default: '',
|
||||
placeholder: 'eg: https://news.ycombinator.com/',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['task'],
|
||||
taskOperation: ['dispatchTask'],
|
||||
},
|
||||
},
|
||||
routing: {
|
||||
request: {
|
||||
body: {
|
||||
url: '={{$value ? $value : null}}',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
displayName: 'Webhook Callback URL',
|
||||
description: 'Optional URL that Skyvern will call when the task finishes',
|
||||
name: 'webhookUrl',
|
||||
type: 'string',
|
||||
default: '',
|
||||
placeholder: 'https://example.com/webhook',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['task'],
|
||||
taskOperation: ['dispatchTask'],
|
||||
},
|
||||
},
|
||||
routing: {
|
||||
request: {
|
||||
body: {
|
||||
webhook_url: '={{$value ? $value : null}}',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
displayName: 'Task ID',
|
||||
description: 'The ID of the task',
|
||||
name: 'taskId',
|
||||
type: 'string',
|
||||
required: true,
|
||||
default: '',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['task'],
|
||||
taskOperation: ['getTask'],
|
||||
},
|
||||
},
|
||||
routing: {
|
||||
request: {
|
||||
method: 'GET',
|
||||
url: '={{"/v1/runs/" + $value}}',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
displayName: 'Task Options',
|
||||
name: 'taskOptions',
|
||||
type: 'collection',
|
||||
description: 'Optional Configuration for the task',
|
||||
placeholder: 'Add Task Options',
|
||||
default: {},
|
||||
options: [
|
||||
{
|
||||
displayName: 'Engine(Deprecated)',
|
||||
description: 'Deprecated: please migrate to use "Engine" option',
|
||||
name: 'engine',
|
||||
type: 'options',
|
||||
default: '',
|
||||
options: [
|
||||
{
|
||||
name: 'TaskV1',
|
||||
value: 'v1',
|
||||
},
|
||||
{
|
||||
name: 'TaskV2',
|
||||
value: 'v2',
|
||||
},
|
||||
{
|
||||
name: 'THIS FIELD IS DEPRECATED',
|
||||
value: '',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
displayName: 'Engine',
|
||||
name: 'runEngine',
|
||||
type: 'options',
|
||||
default: 'skyvern-2.0',
|
||||
options: [
|
||||
{
|
||||
name: 'Skyvern 1.0',
|
||||
value: 'skyvern-1.0',
|
||||
},
|
||||
{
|
||||
name: 'Skyvern 2.0',
|
||||
value: 'skyvern-2.0',
|
||||
},
|
||||
{
|
||||
name: 'OpenAI CUA',
|
||||
value: 'openai-cua',
|
||||
},
|
||||
{
|
||||
name: 'Anthropic CUA',
|
||||
value: 'anthropic-cua',
|
||||
}
|
||||
],
|
||||
routing: {
|
||||
request: {
|
||||
body: {
|
||||
engine: '={{$value}}',
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
],
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['task'],
|
||||
taskOperation: ['dispatchTask'],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
displayName: 'Workflow Name or ID',
|
||||
description: 'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>',
|
||||
name: 'workflowId',
|
||||
type: 'options',
|
||||
typeOptions: {
|
||||
loadOptionsMethod: 'getWorkflows',
|
||||
loadOptionsDependsOn: ['resource'],
|
||||
},
|
||||
required: true,
|
||||
default: '',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['workflow'],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
displayName: 'Workflow Run ID',
|
||||
description: 'The ID of the workflow run',
|
||||
name: 'workflowRunId',
|
||||
type: 'string',
|
||||
required: true,
|
||||
default: '',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['workflow'],
|
||||
workflowOperation: ['getWorkflow'],
|
||||
},
|
||||
},
|
||||
routing: {
|
||||
request: {
|
||||
url: '={{"/api/v1/workflows/" + $parameter["workflowId"] + "/runs/" + $value}}',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
displayName: 'Workflow Run Parameters',
|
||||
name: 'workflowRunParameters',
|
||||
type: 'resourceMapper',
|
||||
noDataExpression: true,
|
||||
description: 'The JSON-formatted parameters to pass the workflow run to execute',
|
||||
required: true,
|
||||
default: {
|
||||
mappingMode: 'defineBelow',
|
||||
value: null,
|
||||
},
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['workflow'],
|
||||
workflowOperation: ['dispatchWorkflow'],
|
||||
},
|
||||
},
|
||||
typeOptions: {
|
||||
loadOptionsDependsOn: ['workflowId'],
|
||||
resourceMapper: {
|
||||
resourceMapperMethod: 'getWorkflowRunParameters',
|
||||
mode: 'update',
|
||||
fieldWords: {
|
||||
singular: 'workflowRunParameter',
|
||||
plural: 'workflowRunParameters',
|
||||
},
|
||||
addAllFields: true,
|
||||
multiKeyMatch: true,
|
||||
},
|
||||
},
|
||||
routing: {
|
||||
request: {
|
||||
url: '={{"/api/v1/workflows/" + $parameter["workflowId"] + "/run"}}',
|
||||
body: {
|
||||
data: '={{$value["value"]}}',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
displayName: 'Webhook Callback URL',
|
||||
description: 'Optional URL that Skyvern will call when the workflow run finishes',
|
||||
name: 'webhookCallbackUrl',
|
||||
type: 'string',
|
||||
default: '',
|
||||
placeholder: 'https://example.com/webhook',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['workflow'],
|
||||
workflowOperation: ['dispatchWorkflow'],
|
||||
},
|
||||
},
|
||||
routing: {
|
||||
request: {
|
||||
body: {
|
||||
webhook_callback_url: '={{$value ? $value : null}}',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
version: 1,
|
||||
};
|
||||
|
||||
methods = {
|
||||
loadOptions: {
|
||||
async getWorkflows(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
|
||||
const resource = this.getCurrentNodeParameter('resource') as string;
|
||||
if (resource !== 'workflow') return [];
|
||||
|
||||
const response = await skyvernApiRequest.call(
|
||||
this,
|
||||
'GET',
|
||||
'/api/v1/workflows?page_size=100',
|
||||
);
|
||||
const data = response;
|
||||
return data.map((workflow: any) => ({
|
||||
name: workflow.title,
|
||||
value: workflow.workflow_permanent_id,
|
||||
}));
|
||||
},
|
||||
},
|
||||
resourceMapping: {
|
||||
async getWorkflowRunParameters(this: ILoadOptionsFunctions): Promise<ResourceMapperFields> {
|
||||
const resource = this.getCurrentNodeParameter('resource') as string;
|
||||
if (resource !== 'workflow') return { fields: [] };
|
||||
|
||||
const operation = this.getCurrentNodeParameter('workflowOperation') as string;
|
||||
if (operation !== 'dispatchWorkflow') return { fields: [] };
|
||||
|
||||
const workflowId = this.getCurrentNodeParameter('workflowId') as string;
|
||||
if (!workflowId) return { fields: [] };
|
||||
|
||||
const workflow = await skyvernApiRequest.call(
|
||||
this,
|
||||
'GET',
|
||||
`/api/v1/workflows/${workflowId}`,
|
||||
);
|
||||
const parameters: any[] = workflow.workflow_definition.parameters;
|
||||
|
||||
const fields: ResourceMapperField[] = await Promise.all(
|
||||
parameters
|
||||
.filter((parameter: any) => parameter.parameter_type === 'workflow' || parameter.parameter_type === 'credential')
|
||||
.map(async (parameter: any) => {
|
||||
let options: INodePropertyOptions[] | undefined = undefined;
|
||||
let parameterType: FieldType | undefined = undefined;
|
||||
if (parameter.parameter_type === 'credential') {
|
||||
const credData = await skyvernApiRequest.call(
|
||||
this,
|
||||
'GET',
|
||||
'/api/v1/credentials',
|
||||
);
|
||||
options = credData.map((credential: any) => ({
|
||||
name: credential.name,
|
||||
value: credential.credential_id,
|
||||
}));
|
||||
parameterType = 'options';
|
||||
} else {
|
||||
const parameter_type_map: Record<string, FieldType> = {
|
||||
string: 'string',
|
||||
integer: 'number',
|
||||
float: 'number',
|
||||
boolean: 'boolean',
|
||||
json: 'object',
|
||||
file_url: 'url',
|
||||
}
|
||||
parameterType = parameter_type_map[parameter.workflow_parameter_type];
|
||||
}
|
||||
|
||||
return {
|
||||
id: parameter.key,
|
||||
displayName: parameter.key,
|
||||
defaultMatch: true,
|
||||
canBeUsedToMatch: false,
|
||||
required: parameter.default_value === undefined || parameter.default_value === null,
|
||||
display: true,
|
||||
type: parameterType,
|
||||
options: options,
|
||||
};
|
||||
})
|
||||
);
|
||||
|
||||
|
||||
// HACK: If there are no parameters, add a empty field to avoid the resource mapper from crashing
|
||||
if (fields.length === 0) {
|
||||
fields.push({
|
||||
id: 'NO_PARAMETERS',
|
||||
displayName: 'No Parameters',
|
||||
defaultMatch: false,
|
||||
canBeUsedToMatch: false,
|
||||
required: false,
|
||||
display: true,
|
||||
type: 'string',
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
fields: fields,
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 27 KiB |
File diff suppressed because one or more lines are too long
|
Before Width: | Height: | Size: 132 KiB |
8405
integrations/n8n/package-lock.json
generated
8405
integrations/n8n/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -1,59 +0,0 @@
|
||||
{
|
||||
"name": "n8n-nodes-skyvern",
|
||||
"version": "0.0.8",
|
||||
"description": "Skyvern Node for n8n",
|
||||
"keywords": [
|
||||
"n8n-community-node-package"
|
||||
],
|
||||
"license": "MIT",
|
||||
"homepage": "",
|
||||
"author": {
|
||||
"name": "lawy",
|
||||
"email": "lawy@skyvern.com"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/Skyvern-AI/skyvern.git"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18.10",
|
||||
"pnpm": ">=9.1"
|
||||
},
|
||||
"packageManager": "pnpm@9.1.4",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"preinstall": "npx only-allow pnpm",
|
||||
"build": "rimraf dist && 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": "pnpm build && pnpm lint -c .eslintrc.prepublish.js nodes credentials package.json"
|
||||
},
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
"n8n": {
|
||||
"n8nNodesApiVersion": 1,
|
||||
"credentials": [
|
||||
"dist/credentials/SkyvernApi.credentials.js"
|
||||
],
|
||||
"nodes": [
|
||||
"dist/nodes/Skyvern/Skyvern.node.js"
|
||||
]
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^22.13.10",
|
||||
"@typescript-eslint/parser": "^7.15.0",
|
||||
"braces": "^3.0.3",
|
||||
"eslint": "^8.56.0",
|
||||
"eslint-plugin-n8n-nodes-base": "^1.16.1",
|
||||
"gulp": "^4.0.2",
|
||||
"prettier": "^3.3.2",
|
||||
"rimraf": "^6.0.1",
|
||||
"typescript": "^5.5.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"n8n-workflow": "^1.82.0"
|
||||
}
|
||||
}
|
||||
3482
integrations/n8n/pnpm-lock.yaml
generated
3482
integrations/n8n/pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -1,30 +0,0 @@
|
||||
{
|
||||
"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",
|
||||
],
|
||||
}
|
||||
Reference in New Issue
Block a user