@steprotech/n8n-nodes-composio 0.1.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +52 -11
- package/dist/credentials/ComposioApi.credentials.js +9 -1
- package/dist/credentials/ComposioApi.credentials.js.map +1 -1
- package/dist/nodes/Composio/Composio.node.d.ts +8 -1
- package/dist/nodes/Composio/Composio.node.js +244 -127
- package/dist/nodes/Composio/Composio.node.js.map +1 -1
- package/dist/nodes/Composio/ComposioTrigger.node.d.ts +12 -0
- package/dist/nodes/Composio/ComposioTrigger.node.js +172 -0
- package/dist/nodes/Composio/ComposioTrigger.node.js.map +1 -0
- package/dist/nodes/Composio/GenericFunctions.d.ts +5 -0
- package/dist/nodes/Composio/GenericFunctions.js +63 -5
- package/dist/nodes/Composio/GenericFunctions.js.map +1 -1
- package/dist/nodes/Composio/catalog.d.ts +25 -0
- package/dist/nodes/Composio/catalog.js +195 -0
- package/dist/nodes/Composio/catalog.js.map +1 -0
- package/dist/nodes/Composio/signature.d.ts +16 -0
- package/dist/nodes/Composio/signature.js +55 -0
- package/dist/nodes/Composio/signature.js.map +1 -0
- package/dist/nodes/ComposioTrigger/composio.dark.svg +266 -0
- package/dist/nodes/ComposioTrigger/composio.svg +266 -0
- package/dist/package.json +3 -2
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
An n8n node for [Composio](https://composio.dev). Connect your own apps through Composio, choose an
|
|
4
4
|
action, and run it in any workflow. No AI agent is required, and the node can also be used as a tool
|
|
5
|
-
inside an agent.
|
|
5
|
+
inside an agent. A trigger node starts workflows from app events too.
|
|
6
6
|
|
|
7
7
|
Composio is an integration and authentication layer: it holds the OAuth grants for around 1,600
|
|
8
8
|
apps, refreshes the tokens, and executes the action on your behalf. This node is the n8n front door
|
|
@@ -36,26 +36,67 @@ Never paste a key into a chat, an issue or a repository. Keys belong in n8n's cr
|
|
|
36
36
|
|
|
37
37
|
## Operations
|
|
38
38
|
|
|
39
|
+
Every app and every action is chosen from a **live search list**, so you never need to know a Composio
|
|
40
|
+
slug. The inputs of an action are read from the action's own schema, so you pick parameter names from a
|
|
41
|
+
list instead of writing JSON. Raw JSON is still there as an opt-in escape hatch.
|
|
42
|
+
|
|
39
43
|
**Connection**
|
|
40
44
|
|
|
41
45
|
- **Connect an App** returns the authorization link. Open it, approve in the browser, and the app is
|
|
42
46
|
connected to your Composio account. Managed auth means you never create an OAuth app yourself.
|
|
43
|
-
- **
|
|
44
|
-
|
|
45
|
-
- **
|
|
47
|
+
- **Check Connections** reports which of the apps you name are connected. Any app that is not connected
|
|
48
|
+
yet gets an authorization link in the output, so this doubles as "connect these three apps".
|
|
49
|
+
- **Reconnect an App** replaces an existing connection with a fresh authorization flow, which is what
|
|
50
|
+
you want when credentials go stale or when you need to re-consent after a permission change.
|
|
51
|
+
|
|
52
|
+
Disconnecting an app is not exposed on the consumer surface this node uses, so removal stays in the
|
|
53
|
+
Composio dashboard.
|
|
46
54
|
|
|
47
55
|
**Action**
|
|
48
56
|
|
|
49
|
-
- **Search Actions** takes what you want to do in plain words and returns matching actions
|
|
50
|
-
|
|
51
|
-
- **
|
|
52
|
-
|
|
57
|
+
- **Search Actions** takes what you want to do in plain words and returns matching actions, which app
|
|
58
|
+
each belongs to, and which of those apps are already connected.
|
|
59
|
+
- **Get Action Inputs** lists the inputs one or more actions expect, with types and required markers.
|
|
60
|
+
- **Execute an Action** runs the chosen action. Set **Set Inputs** to *Using Fields* and add one row per
|
|
61
|
+
input, picking the parameter name from the list, or switch to *Using JSON* to write the arguments
|
|
62
|
+
object yourself. The node can also be used as a tool by an AI Agent.
|
|
63
|
+
|
|
64
|
+
Values typed into the fields are converted sensibly: `true`, `false`, `null`, numbers and JSON objects
|
|
65
|
+
or arrays are sent as those types, while identifiers keep their form, so a phone number entered as
|
|
66
|
+
`0244123456` is not turned into a number.
|
|
53
67
|
|
|
54
68
|
**Advanced**
|
|
55
69
|
|
|
56
|
-
- **Call a Meta-Tool** sends any of Composio's
|
|
57
|
-
|
|
58
|
-
|
|
70
|
+
- **Call a Meta-Tool** sends any of Composio's meta-tools with arguments you supply. Composio has
|
|
71
|
+
thousands of actions with their own schemas, while n8n node parameters are fixed, so this is the
|
|
72
|
+
escape hatch for anything the operations above do not cover yet.
|
|
73
|
+
|
|
74
|
+
## Documentation
|
|
75
|
+
|
|
76
|
+
- `docs/INSTALL-OPTIONS.md` covers every way to install or update it, including troubleshooting.
|
|
77
|
+
- `docs/PUBLISHING.md` covers the release loop, CI, and the tokenless trusted-publishing path.
|
|
78
|
+
- `docs/PUBLISH-FROM-WINDOWS.md` is the PowerShell route for publishing from your own machine.
|
|
79
|
+
|
|
80
|
+
## Trigger
|
|
81
|
+
|
|
82
|
+
The **Composio Connect Trigger** starts a workflow when something happens in a connected app, such as
|
|
83
|
+
a new Gmail message or a new GitHub commit.
|
|
84
|
+
|
|
85
|
+
1. In Composio, note the single **webhook URL** your project delivers events to, and register the URL
|
|
86
|
+
n8n shows in the trigger node. Composio sends every project event to one URL, so this is a
|
|
87
|
+
per-project setting, not a per-workflow one.
|
|
88
|
+
2. Copy the webhook **signing secret** from that subscription into the credential's *Webhook Signing
|
|
89
|
+
Secret* field.
|
|
90
|
+
3. Choose the events you want. `Trigger Message` covers app events; `Connected Account Expired` tells
|
|
91
|
+
you when a connection needs re-authorizing. Use `Only These Triggers` to accept a single trigger
|
|
92
|
+
slug such as `GITHUB_COMMIT_EVENT`.
|
|
93
|
+
|
|
94
|
+
Signature verification is **on by default**. Every request carries `webhook-id`, `webhook-timestamp`
|
|
95
|
+
and `webhook-signature`, and the trigger recomputes an HMAC-SHA256 over
|
|
96
|
+
`{webhook-id}.{webhook-timestamp}.{body}`, compares it in constant time, and refuses anything older
|
|
97
|
+
than the tolerance (300 seconds by default) so a captured payload cannot be replayed. Note this while
|
|
98
|
+
writing it down: with verification on and no secret in the credential, the trigger refuses to run
|
|
99
|
+
rather than trusting the request, which is deliberate.
|
|
59
100
|
|
|
60
101
|
## Composio's meta-tools
|
|
61
102
|
|
|
@@ -31,6 +31,14 @@ class ComposioApi {
|
|
|
31
31
|
default: '',
|
|
32
32
|
description: 'Optional. The Composio user ID whose connections this credential uses by default. Composio derives one from the key when this is left empty. Use separate credentials if you keep several users apart.',
|
|
33
33
|
},
|
|
34
|
+
{
|
|
35
|
+
displayName: 'Webhook Signing Secret',
|
|
36
|
+
name: 'webhookSecret',
|
|
37
|
+
type: 'string',
|
|
38
|
+
typeOptions: { password: true },
|
|
39
|
+
default: '',
|
|
40
|
+
description: 'Optional. The signing secret of your Composio webhook subscription, used by the Composio Trigger to verify that events really came from Composio. Copy it from your Composio webhook subscription settings.',
|
|
41
|
+
},
|
|
34
42
|
];
|
|
35
43
|
this.authenticate = {
|
|
36
44
|
type: 'generic',
|
|
@@ -58,7 +66,7 @@ class ComposioApi {
|
|
|
58
66
|
capabilities: {},
|
|
59
67
|
clientInfo: {
|
|
60
68
|
name: 'n8n-nodes-composio',
|
|
61
|
-
version: '0.1.
|
|
69
|
+
version: '0.1.1',
|
|
62
70
|
},
|
|
63
71
|
},
|
|
64
72
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ComposioApi.credentials.js","sourceRoot":"","sources":["../../credentials/ComposioApi.credentials.ts"],"names":[],"mappings":";;;AAEA,MAAa,WAAW;IAAxB;QACC,SAAI,GAAG,aAAa,CAAC;QAErB,gBAAW,GAAG,cAAc,CAAC;QAE7B,qBAAgB,GAAG,mFAAmF,CAAC;QAEvG,SAAI,GAAG,EAAE,KAAK,EAAE,mBAAmB,EAAE,IAAI,EAAE,wBAAwB,EAAW,CAAC;QAE/E,eAAU,GAAsB;YAC/B;gBACC,WAAW,EAAE,cAAc;gBAC3B,IAAI,EAAE,QAAQ;gBACd,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE;gBAC/B,OAAO,EAAE,EAAE;gBACX,QAAQ,EAAE,IAAI;gBACd,WAAW,EACV,2KAA2K;aAC5K;YACD;gBACC,WAAW,EAAE,UAAU;gBACvB,IAAI,EAAE,SAAS;gBACf,IAAI,EAAE,QAAQ;gBACd,OAAO,EAAE,8BAA8B;gBACvC,WAAW,EAAE,2EAA2E;aACxF;YACD;gBACC,WAAW,EAAE,iBAAiB;gBAC9B,IAAI,EAAE,QAAQ;gBACd,IAAI,EAAE,QAAQ;gBACd,OAAO,EAAE,EAAE;gBACX,WAAW,EACV,wMAAwM;aACzM;SACD,CAAC;QAEF,iBAAY,GAAG;YACd,IAAI,EAAE,SAAkB;YACxB,UAAU,EAAE;gBACX,OAAO,EAAE;oBACR,oBAAoB,EAAE,0BAA0B;iBAChD;aACD;SACD,CAAC;QAEF,SAAI,GAAG;YACN,OAAO,EAAE;gBACR,OAAO,EAAE,2BAA2B;gBACpC,GAAG,EAAE,MAAM;gBACX,MAAM,EAAE,MAAe;gBACvB,OAAO,EAAE;oBACR,MAAM,EAAE,qCAAqC;oBAC7C,cAAc,EAAE,kBAAkB;iBAClC;gBACD,IAAI,EAAE;oBACL,OAAO,EAAE,KAAK;oBACd,EAAE,EAAE,CAAC;oBACL,MAAM,EAAE,YAAY;oBACpB,MAAM,EAAE;wBACP,eAAe,EAAE,YAAY;wBAC7B,YAAY,EAAE,EAAE;wBAChB,UAAU,EAAE;4BACX,IAAI,EAAE,oBAAoB;4BAC1B,OAAO,EAAE,OAAO;yBAChB;qBACD;iBACD;aACD;SACD,CAAC;IACH,CAAC;CAAA;
|
|
1
|
+
{"version":3,"file":"ComposioApi.credentials.js","sourceRoot":"","sources":["../../credentials/ComposioApi.credentials.ts"],"names":[],"mappings":";;;AAEA,MAAa,WAAW;IAAxB;QACC,SAAI,GAAG,aAAa,CAAC;QAErB,gBAAW,GAAG,cAAc,CAAC;QAE7B,qBAAgB,GAAG,mFAAmF,CAAC;QAEvG,SAAI,GAAG,EAAE,KAAK,EAAE,mBAAmB,EAAE,IAAI,EAAE,wBAAwB,EAAW,CAAC;QAE/E,eAAU,GAAsB;YAC/B;gBACC,WAAW,EAAE,cAAc;gBAC3B,IAAI,EAAE,QAAQ;gBACd,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE;gBAC/B,OAAO,EAAE,EAAE;gBACX,QAAQ,EAAE,IAAI;gBACd,WAAW,EACV,2KAA2K;aAC5K;YACD;gBACC,WAAW,EAAE,UAAU;gBACvB,IAAI,EAAE,SAAS;gBACf,IAAI,EAAE,QAAQ;gBACd,OAAO,EAAE,8BAA8B;gBACvC,WAAW,EAAE,2EAA2E;aACxF;YACD;gBACC,WAAW,EAAE,iBAAiB;gBAC9B,IAAI,EAAE,QAAQ;gBACd,IAAI,EAAE,QAAQ;gBACd,OAAO,EAAE,EAAE;gBACX,WAAW,EACV,wMAAwM;aACzM;YACD;gBACC,WAAW,EAAE,wBAAwB;gBACrC,IAAI,EAAE,eAAe;gBACrB,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE;gBAC/B,OAAO,EAAE,EAAE;gBACX,WAAW,EACV,6MAA6M;aAC9M;SACD,CAAC;QAEF,iBAAY,GAAG;YACd,IAAI,EAAE,SAAkB;YACxB,UAAU,EAAE;gBACX,OAAO,EAAE;oBACR,oBAAoB,EAAE,0BAA0B;iBAChD;aACD;SACD,CAAC;QAEF,SAAI,GAAG;YACN,OAAO,EAAE;gBACR,OAAO,EAAE,2BAA2B;gBACpC,GAAG,EAAE,MAAM;gBACX,MAAM,EAAE,MAAe;gBACvB,OAAO,EAAE;oBACR,MAAM,EAAE,qCAAqC;oBAC7C,cAAc,EAAE,kBAAkB;iBAClC;gBACD,IAAI,EAAE;oBACL,OAAO,EAAE,KAAK;oBACd,EAAE,EAAE,CAAC;oBACL,MAAM,EAAE,YAAY;oBACpB,MAAM,EAAE;wBACP,eAAe,EAAE,YAAY;wBAC7B,YAAY,EAAE,EAAE;wBAChB,UAAU,EAAE;4BACX,IAAI,EAAE,oBAAoB;4BAC1B,OAAO,EAAE,OAAO;yBAChB;qBACD;iBACD;aACD;SACD,CAAC;IACH,CAAC;CAAA;AA/ED,kCA+EC"}
|
|
@@ -1,5 +1,12 @@
|
|
|
1
|
-
import type { IExecuteFunctions, INodeExecutionData, INodeType, INodeTypeDescription } from 'n8n-workflow';
|
|
1
|
+
import type { IExecuteFunctions, ILoadOptionsFunctions, INodeExecutionData, INodePropertyOptions, INodeType, INodeTypeDescription } from 'n8n-workflow';
|
|
2
2
|
export declare class Composio implements INodeType {
|
|
3
3
|
description: INodeTypeDescription;
|
|
4
|
+
methods: {
|
|
5
|
+
loadOptions: {
|
|
6
|
+
searchToolkits(this: ILoadOptionsFunctions, filter?: string): Promise<INodePropertyOptions[]>;
|
|
7
|
+
searchActions(this: ILoadOptionsFunctions, filter?: string): Promise<INodePropertyOptions[]>;
|
|
8
|
+
getToolParameters(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]>;
|
|
9
|
+
};
|
|
10
|
+
};
|
|
4
11
|
execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]>;
|
|
5
12
|
}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.Composio = void 0;
|
|
4
4
|
const n8n_workflow_1 = require("n8n-workflow");
|
|
5
|
+
const catalog_1 = require("./catalog");
|
|
5
6
|
const GenericFunctions_1 = require("./GenericFunctions");
|
|
6
7
|
const metatools_1 = require("./metatools");
|
|
7
8
|
const resourceOptions = {
|
|
@@ -18,7 +19,7 @@ const resourceOptions = {
|
|
|
18
19
|
{
|
|
19
20
|
name: 'Connection',
|
|
20
21
|
value: 'connection',
|
|
21
|
-
description: 'Connect an app,
|
|
22
|
+
description: 'Connect an app, check which apps are connected, or reconnect one',
|
|
22
23
|
},
|
|
23
24
|
{
|
|
24
25
|
name: 'Advanced',
|
|
@@ -39,19 +40,19 @@ const operationOptions = [
|
|
|
39
40
|
{
|
|
40
41
|
name: 'Execute an Action',
|
|
41
42
|
value: 'execute',
|
|
42
|
-
description: 'Run
|
|
43
|
+
description: 'Run the chosen action with the inputs you fill in',
|
|
43
44
|
action: 'Execute an action',
|
|
44
45
|
},
|
|
45
46
|
{
|
|
46
|
-
name: 'Get Action
|
|
47
|
+
name: 'Get Action Inputs',
|
|
47
48
|
value: 'schemas',
|
|
48
|
-
description: '
|
|
49
|
-
action: 'Get action
|
|
49
|
+
description: 'List the inputs one or more actions expect',
|
|
50
|
+
action: 'Get action inputs',
|
|
50
51
|
},
|
|
51
52
|
{
|
|
52
53
|
name: 'Search Actions',
|
|
53
54
|
value: 'search',
|
|
54
|
-
description: 'Search the Composio catalog for actions matching
|
|
55
|
+
description: 'Search the Composio catalog for actions matching what you want to do',
|
|
55
56
|
action: 'Search actions',
|
|
56
57
|
},
|
|
57
58
|
],
|
|
@@ -64,6 +65,12 @@ const operationOptions = [
|
|
|
64
65
|
noDataExpression: true,
|
|
65
66
|
displayOptions: { show: { resource: ['connection'] } },
|
|
66
67
|
options: [
|
|
68
|
+
{
|
|
69
|
+
name: 'Check Connections',
|
|
70
|
+
value: 'check',
|
|
71
|
+
description: 'Report which of the chosen apps are connected',
|
|
72
|
+
action: 'Check connections',
|
|
73
|
+
},
|
|
67
74
|
{
|
|
68
75
|
name: 'Connect an App',
|
|
69
76
|
value: 'connect',
|
|
@@ -71,22 +78,10 @@ const operationOptions = [
|
|
|
71
78
|
action: 'Connect an app',
|
|
72
79
|
},
|
|
73
80
|
{
|
|
74
|
-
name: '
|
|
75
|
-
value: '
|
|
76
|
-
description: '
|
|
77
|
-
action: '
|
|
78
|
-
},
|
|
79
|
-
{
|
|
80
|
-
name: 'List Connections',
|
|
81
|
-
value: 'list',
|
|
82
|
-
description: 'List the apps already connected to this Composio account',
|
|
83
|
-
action: 'List connections',
|
|
84
|
-
},
|
|
85
|
-
{
|
|
86
|
-
name: 'Remove Connection',
|
|
87
|
-
value: 'remove',
|
|
88
|
-
description: 'Disconnect an app and delete its stored credentials',
|
|
89
|
-
action: 'Remove a connection',
|
|
81
|
+
name: 'Reconnect an App',
|
|
82
|
+
value: 'reconnect',
|
|
83
|
+
description: 'Replace a connection with a fresh authorization flow',
|
|
84
|
+
action: 'Reconnect an app',
|
|
90
85
|
},
|
|
91
86
|
],
|
|
92
87
|
default: 'connect',
|
|
@@ -108,72 +103,124 @@ const operationOptions = [
|
|
|
108
103
|
default: 'call',
|
|
109
104
|
},
|
|
110
105
|
];
|
|
111
|
-
const toolkitField = (displayName, description) => ({
|
|
112
|
-
displayName,
|
|
113
|
-
name: 'toolkit',
|
|
114
|
-
type: 'string',
|
|
115
|
-
default: '',
|
|
116
|
-
required: true,
|
|
117
|
-
description,
|
|
118
|
-
placeholder: 'gmail',
|
|
119
|
-
});
|
|
120
106
|
const fields = [
|
|
121
107
|
{
|
|
122
|
-
|
|
123
|
-
|
|
108
|
+
displayName: 'App Name or ID',
|
|
109
|
+
name: 'toolkit',
|
|
110
|
+
type: 'options',
|
|
111
|
+
typeOptions: { loadOptionsMethod: 'searchToolkits' },
|
|
112
|
+
default: '',
|
|
113
|
+
required: true,
|
|
114
|
+
description: 'The app to work with. Type part of a name such as gmail or sheets and pick from the list. Apps you have already connected are marked. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>.',
|
|
115
|
+
displayOptions: { show: { resource: ['connection'], operation: ['connect', 'reconnect'] } },
|
|
124
116
|
},
|
|
125
117
|
{
|
|
126
|
-
displayName: '
|
|
127
|
-
name: '
|
|
128
|
-
type: '
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
118
|
+
displayName: 'App Names or IDs',
|
|
119
|
+
name: 'toolkits',
|
|
120
|
+
type: 'multiOptions',
|
|
121
|
+
typeOptions: { loadOptionsMethod: 'searchToolkits' },
|
|
122
|
+
default: [],
|
|
123
|
+
required: true,
|
|
124
|
+
description: 'The apps to check. Search and add each one. Any app that is not connected yet gets an authorization link in the output. Choose from the list, or specify IDs using an <a href="https://docs.n8n.io/code/expressions/">expression</a>.',
|
|
125
|
+
displayOptions: { show: { resource: ['connection'], operation: ['check'] } },
|
|
132
126
|
},
|
|
133
127
|
{
|
|
134
|
-
displayName: 'Search
|
|
135
|
-
name: '
|
|
128
|
+
displayName: 'Search For',
|
|
129
|
+
name: 'useCase',
|
|
136
130
|
type: 'string',
|
|
137
131
|
default: '',
|
|
138
132
|
required: true,
|
|
139
|
-
placeholder: 'send an email
|
|
140
|
-
description: 'What you want to do, in plain words. Composio returns matching actions and
|
|
133
|
+
placeholder: 'send an email with an attachment',
|
|
134
|
+
description: 'What you want to do, in plain words. Composio returns matching actions, which app each belongs to, and which of those apps are already connected.',
|
|
141
135
|
displayOptions: { show: { resource: ['action'], operation: ['search'] } },
|
|
142
136
|
},
|
|
143
137
|
{
|
|
144
|
-
displayName: '
|
|
145
|
-
name: '
|
|
146
|
-
type: '
|
|
138
|
+
displayName: 'Action Name or ID',
|
|
139
|
+
name: 'toolSlug',
|
|
140
|
+
type: 'options',
|
|
141
|
+
typeOptions: { loadOptionsMethod: 'searchActions' },
|
|
147
142
|
default: '',
|
|
148
143
|
required: true,
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
displayOptions: { show: { resource: ['action'], operation: ['schemas'] } },
|
|
144
|
+
description: 'The action to run. Type part of what it does, or of its name, and pick from the list. Use Search Actions first if you are unsure. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>.',
|
|
145
|
+
displayOptions: { show: { resource: ['action'], operation: ['execute'] } },
|
|
152
146
|
},
|
|
153
147
|
{
|
|
154
|
-
displayName: 'Action
|
|
155
|
-
name: '
|
|
156
|
-
type: '
|
|
157
|
-
|
|
148
|
+
displayName: 'Action Names or IDs',
|
|
149
|
+
name: 'toolSlugs',
|
|
150
|
+
type: 'multiOptions',
|
|
151
|
+
typeOptions: { loadOptionsMethod: 'searchActions' },
|
|
152
|
+
default: [],
|
|
158
153
|
required: true,
|
|
159
|
-
|
|
160
|
-
|
|
154
|
+
description: 'The actions whose inputs you want to see. Choose from the list, or specify IDs using an <a href="https://docs.n8n.io/code/expressions/">expression</a>.',
|
|
155
|
+
displayOptions: { show: { resource: ['action'], operation: ['schemas'] } },
|
|
156
|
+
},
|
|
157
|
+
{
|
|
158
|
+
displayName: 'Set Inputs',
|
|
159
|
+
name: 'inputMode',
|
|
160
|
+
type: 'options',
|
|
161
|
+
options: [
|
|
162
|
+
{
|
|
163
|
+
name: 'Using Fields',
|
|
164
|
+
value: 'fields',
|
|
165
|
+
description: 'Pick each input by name and type its value, with no JSON to write',
|
|
166
|
+
},
|
|
167
|
+
{
|
|
168
|
+
name: 'Using JSON',
|
|
169
|
+
value: 'json',
|
|
170
|
+
description: 'Write the whole arguments object yourself',
|
|
171
|
+
},
|
|
172
|
+
],
|
|
173
|
+
default: 'fields',
|
|
174
|
+
description: 'How to provide the action inputs',
|
|
161
175
|
displayOptions: { show: { resource: ['action'], operation: ['execute'] } },
|
|
162
176
|
},
|
|
177
|
+
{
|
|
178
|
+
displayName: 'Input Parameters',
|
|
179
|
+
name: 'parameterRows',
|
|
180
|
+
type: 'fixedCollection',
|
|
181
|
+
typeOptions: { multipleValues: true },
|
|
182
|
+
default: {},
|
|
183
|
+
placeholder: 'Add Input',
|
|
184
|
+
description: 'The inputs this action needs. Add one row per input and pick its name from the list, which is read from the action itself. Values that look like JSON, such as true, 42 or {"a":1}, are sent as JSON.',
|
|
185
|
+
displayOptions: { show: { resource: ['action'], operation: ['execute'], inputMode: ['fields'] } },
|
|
186
|
+
options: [
|
|
187
|
+
{
|
|
188
|
+
displayName: 'Input',
|
|
189
|
+
name: 'parameters',
|
|
190
|
+
values: [
|
|
191
|
+
{
|
|
192
|
+
displayName: 'Parameter Name or ID',
|
|
193
|
+
name: 'name',
|
|
194
|
+
type: 'options',
|
|
195
|
+
typeOptions: { loadOptionsMethod: 'getToolParameters' },
|
|
196
|
+
default: '',
|
|
197
|
+
description: 'Which input of the action to set. The list is read from the action chosen above, and marks the required ones. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>.',
|
|
198
|
+
},
|
|
199
|
+
{
|
|
200
|
+
displayName: 'Value',
|
|
201
|
+
name: 'value',
|
|
202
|
+
type: 'string',
|
|
203
|
+
default: '',
|
|
204
|
+
description: 'The value to send. Numbers, true, false, null, and JSON objects or arrays are recognised automatically. Everything else is sent as text.',
|
|
205
|
+
},
|
|
206
|
+
],
|
|
207
|
+
},
|
|
208
|
+
],
|
|
209
|
+
},
|
|
163
210
|
{
|
|
164
211
|
displayName: 'Arguments (JSON)',
|
|
165
212
|
name: 'arguments',
|
|
166
213
|
type: 'json',
|
|
167
214
|
default: '{}',
|
|
168
|
-
description: 'The
|
|
169
|
-
displayOptions: { show: { resource: ['action'], operation: ['execute'] } },
|
|
215
|
+
description: 'The full arguments object, exactly as the action expects it',
|
|
216
|
+
displayOptions: { show: { resource: ['action'], operation: ['execute'], inputMode: ['json'] } },
|
|
170
217
|
},
|
|
171
218
|
{
|
|
172
|
-
displayName: '
|
|
173
|
-
name: '
|
|
174
|
-
type: '
|
|
175
|
-
default:
|
|
176
|
-
description: '
|
|
219
|
+
displayName: 'Save Large Responses in the Workbench',
|
|
220
|
+
name: 'syncToWorkbench',
|
|
221
|
+
type: 'boolean',
|
|
222
|
+
default: false,
|
|
223
|
+
description: 'Whether Composio should keep the full response in its workbench and return only a preview, which helps when an action returns something big',
|
|
177
224
|
displayOptions: { show: { resource: ['action'], operation: ['execute'] } },
|
|
178
225
|
},
|
|
179
226
|
{
|
|
@@ -204,20 +251,90 @@ const fields = [
|
|
|
204
251
|
class Composio {
|
|
205
252
|
constructor() {
|
|
206
253
|
this.description = {
|
|
207
|
-
displayName: 'Composio',
|
|
254
|
+
displayName: 'Composio Connect',
|
|
208
255
|
name: 'composio',
|
|
209
256
|
icon: { light: 'file:composio.svg', dark: 'file:composio.dark.svg' },
|
|
210
257
|
group: ['transform'],
|
|
211
258
|
version: [1],
|
|
212
259
|
subtitle: '={{$parameter["resource"] + ": " + $parameter["operation"]}}',
|
|
213
260
|
description: 'Connect your own apps through Composio and run their actions in any workflow',
|
|
214
|
-
defaults: { name: 'Composio' },
|
|
261
|
+
defaults: { name: 'Composio Connect' },
|
|
215
262
|
usableAsTool: true,
|
|
216
263
|
inputs: [n8n_workflow_1.NodeConnectionTypes.Main],
|
|
217
264
|
outputs: [n8n_workflow_1.NodeConnectionTypes.Main],
|
|
218
265
|
credentials: [{ name: 'composioApi', required: true }],
|
|
219
266
|
properties: [resourceOptions, ...operationOptions, ...fields],
|
|
220
267
|
};
|
|
268
|
+
this.methods = {
|
|
269
|
+
loadOptions: {
|
|
270
|
+
async searchToolkits(filter) {
|
|
271
|
+
const search = (filter !== null && filter !== void 0 ? filter : '').trim();
|
|
272
|
+
const data = await (0, GenericFunctions_1.searchCatalog)(this, search === '' ? 'popular apps and their actions' : search);
|
|
273
|
+
const toolkits = (0, catalog_1.extractToolkits)(data);
|
|
274
|
+
if (toolkits.length === 0) {
|
|
275
|
+
return [
|
|
276
|
+
{
|
|
277
|
+
name: 'No App Matched. Keep Typing, for Example Gmail, Slack or Sheets.',
|
|
278
|
+
value: '',
|
|
279
|
+
description: 'No match',
|
|
280
|
+
},
|
|
281
|
+
];
|
|
282
|
+
}
|
|
283
|
+
return toolkits.map((entry) => ({
|
|
284
|
+
name: `${entry.toolkit}${entry.connected ? ' (connected)' : ''}`,
|
|
285
|
+
value: entry.toolkit,
|
|
286
|
+
description: entry.description === '' ? 'Composio app' : entry.description.slice(0, 120),
|
|
287
|
+
}));
|
|
288
|
+
},
|
|
289
|
+
async searchActions(filter) {
|
|
290
|
+
const search = (filter !== null && filter !== void 0 ? filter : '').trim();
|
|
291
|
+
const data = await (0, GenericFunctions_1.searchCatalog)(this, search === '' ? 'common actions' : search);
|
|
292
|
+
const tools = (0, catalog_1.extractTools)(data);
|
|
293
|
+
if (tools.length === 0) {
|
|
294
|
+
return [
|
|
295
|
+
{
|
|
296
|
+
name: 'No Action Matched. Describe What You Want to Do, for Example Send an Email.',
|
|
297
|
+
value: '',
|
|
298
|
+
description: 'No match',
|
|
299
|
+
},
|
|
300
|
+
];
|
|
301
|
+
}
|
|
302
|
+
return tools.map((tool) => ({
|
|
303
|
+
name: tool.slug,
|
|
304
|
+
value: tool.slug,
|
|
305
|
+
description: `${tool.toolkit}${tool.description === '' ? '' : ' — ' + tool.description.slice(0, 110)}`,
|
|
306
|
+
}));
|
|
307
|
+
},
|
|
308
|
+
async getToolParameters() {
|
|
309
|
+
const toolSlug = this.getCurrentNodeParameter('toolSlug') || '';
|
|
310
|
+
if (toolSlug === '') {
|
|
311
|
+
return [
|
|
312
|
+
{
|
|
313
|
+
name: 'Choose an Action Above First',
|
|
314
|
+
value: '',
|
|
315
|
+
description: 'An action is needed before its inputs can be listed',
|
|
316
|
+
},
|
|
317
|
+
];
|
|
318
|
+
}
|
|
319
|
+
const data = await (0, GenericFunctions_1.fetchToolSchemas)(this, [toolSlug]);
|
|
320
|
+
const parameters = (0, catalog_1.extractParameters)(data, toolSlug);
|
|
321
|
+
if (parameters.length === 0) {
|
|
322
|
+
return [
|
|
323
|
+
{
|
|
324
|
+
name: 'This Action Reports No Inputs, or Its Schema Could Not Be Read. Use Using JSON if You Know the Fields.',
|
|
325
|
+
value: '',
|
|
326
|
+
description: 'No inputs found',
|
|
327
|
+
},
|
|
328
|
+
];
|
|
329
|
+
}
|
|
330
|
+
return parameters.map((parameter) => ({
|
|
331
|
+
name: `${parameter.name}${parameter.required ? ' (required)' : ''}`,
|
|
332
|
+
value: parameter.name,
|
|
333
|
+
description: `${parameter.type}${parameter.description === '' ? '' : ' — ' + parameter.description.slice(0, 110)}`,
|
|
334
|
+
}));
|
|
335
|
+
},
|
|
336
|
+
},
|
|
337
|
+
};
|
|
221
338
|
}
|
|
222
339
|
async execute() {
|
|
223
340
|
const items = this.getInputData();
|
|
@@ -229,90 +346,90 @@ class Composio {
|
|
|
229
346
|
const operation = this.getNodeParameter('operation', i);
|
|
230
347
|
const nodeUserId = this.getNodeParameter('userId', i, '') || undefined;
|
|
231
348
|
const userId = nodeUserId || (credentials.userId || undefined);
|
|
232
|
-
const
|
|
233
|
-
|
|
234
|
-
|
|
349
|
+
const push = (payload) => {
|
|
350
|
+
returnData.push({ json: payload, pairedItem: { item: i } });
|
|
351
|
+
};
|
|
235
352
|
if (resource === 'connection') {
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
}
|
|
245
|
-
else if (operation === 'wait') {
|
|
246
|
-
const timeout = this.getNodeParameter('timeout', i, 120);
|
|
247
|
-
tool = metatools_1.META_TOOLS.waitForConnections;
|
|
248
|
-
args = (0, GenericFunctions_1.buildToolArguments)({
|
|
249
|
-
timeout,
|
|
250
|
-
user_id: resolvedUserId,
|
|
251
|
-
});
|
|
252
|
-
}
|
|
253
|
-
else if (operation === 'remove') {
|
|
254
|
-
tool = metatools_1.META_TOOLS.manageConnections;
|
|
255
|
-
args = (0, GenericFunctions_1.buildToolArguments)({
|
|
256
|
-
action: metatools_1.CONNECTION_ACTIONS.remove,
|
|
257
|
-
toolkit,
|
|
258
|
-
user_id: resolvedUserId,
|
|
259
|
-
});
|
|
260
|
-
}
|
|
261
|
-
else {
|
|
262
|
-
tool = metatools_1.META_TOOLS.manageConnections;
|
|
263
|
-
args = (0, GenericFunctions_1.buildToolArguments)({
|
|
264
|
-
action: metatools_1.CONNECTION_ACTIONS.list,
|
|
265
|
-
user_id: resolvedUserId,
|
|
353
|
+
if (operation === 'check') {
|
|
354
|
+
const toolkits = this.getNodeParameter('toolkits', i, []).filter((toolkit) => toolkit !== '');
|
|
355
|
+
const outcome = await (0, GenericFunctions_1.manageConnections)(this, toolkits);
|
|
356
|
+
push({
|
|
357
|
+
tool: outcome.tool,
|
|
358
|
+
data: outcome.data,
|
|
359
|
+
raw: outcome.text,
|
|
360
|
+
isError: outcome.isError,
|
|
266
361
|
});
|
|
362
|
+
continue;
|
|
267
363
|
}
|
|
364
|
+
const toolkit = this.getNodeParameter('toolkit', i);
|
|
365
|
+
const outcome = await (0, GenericFunctions_1.manageConnections)(this, [toolkit], operation === 'reconnect');
|
|
366
|
+
push({
|
|
367
|
+
tool: outcome.tool,
|
|
368
|
+
data: outcome.data,
|
|
369
|
+
raw: outcome.text,
|
|
370
|
+
isError: outcome.isError,
|
|
371
|
+
});
|
|
372
|
+
continue;
|
|
268
373
|
}
|
|
269
|
-
|
|
374
|
+
let tool;
|
|
375
|
+
let args;
|
|
376
|
+
if (resource === 'action') {
|
|
270
377
|
if (operation === 'search') {
|
|
271
|
-
const query = this.getNodeParameter('query', i);
|
|
272
378
|
tool = metatools_1.META_TOOLS.searchTools;
|
|
273
|
-
args =
|
|
379
|
+
args = {
|
|
380
|
+
queries: [{ use_case: this.getNodeParameter('useCase', i) }],
|
|
381
|
+
session: { generate_id: true },
|
|
382
|
+
};
|
|
274
383
|
}
|
|
275
384
|
else if (operation === 'schemas') {
|
|
276
|
-
const raw = this.getNodeParameter('toolSlugs', i);
|
|
277
|
-
const toolSlugs = raw
|
|
278
|
-
.split(',')
|
|
279
|
-
.map((slug) => slug.trim())
|
|
280
|
-
.filter((slug) => slug !== '');
|
|
281
385
|
tool = metatools_1.META_TOOLS.getToolSchemas;
|
|
282
|
-
args =
|
|
386
|
+
args = {
|
|
387
|
+
tool_slugs: this.getNodeParameter('toolSlugs', i, []).filter((slug) => slug !== ''),
|
|
388
|
+
include: ['input_schema'],
|
|
389
|
+
};
|
|
283
390
|
}
|
|
284
391
|
else {
|
|
285
|
-
const
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
392
|
+
const inputMode = this.getNodeParameter('inputMode', i, 'fields');
|
|
393
|
+
let toolArguments;
|
|
394
|
+
if (inputMode === 'json') {
|
|
395
|
+
const raw = this.getNodeParameter('arguments', i, '{}');
|
|
396
|
+
toolArguments =
|
|
397
|
+
typeof raw === 'string'
|
|
398
|
+
? JSON.parse(raw === '' ? '{}' : raw)
|
|
399
|
+
: raw;
|
|
400
|
+
}
|
|
401
|
+
else {
|
|
402
|
+
const rows = this.getNodeParameter('parameterRows.parameters', i, []);
|
|
403
|
+
toolArguments = (0, catalog_1.buildArgumentsFromRows)(rows);
|
|
404
|
+
}
|
|
291
405
|
tool = metatools_1.META_TOOLS.multiExecuteTool;
|
|
292
|
-
args =
|
|
293
|
-
tools: [
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
406
|
+
args = {
|
|
407
|
+
tools: [
|
|
408
|
+
{
|
|
409
|
+
tool_slug: this.getNodeParameter('toolSlug', i),
|
|
410
|
+
arguments: toolArguments,
|
|
411
|
+
},
|
|
412
|
+
],
|
|
413
|
+
sync_response_to_workbench: this.getNodeParameter('syncToWorkbench', i, false),
|
|
414
|
+
};
|
|
297
415
|
}
|
|
298
416
|
}
|
|
299
417
|
else {
|
|
300
418
|
tool = this.getNodeParameter('metaTool', i);
|
|
301
419
|
const rawMetaArguments = this.getNodeParameter('metaArguments', i, '{}');
|
|
302
|
-
const
|
|
420
|
+
const parsed = typeof rawMetaArguments === 'string'
|
|
303
421
|
? JSON.parse(rawMetaArguments === '' ? '{}' : rawMetaArguments)
|
|
304
422
|
: rawMetaArguments;
|
|
305
|
-
args =
|
|
423
|
+
args = { ...parsed };
|
|
306
424
|
}
|
|
425
|
+
if (userId !== undefined)
|
|
426
|
+
args.user_id = userId;
|
|
307
427
|
const outcome = await (0, GenericFunctions_1.callMetaTool)(this, tool, args);
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
isError: outcome.isError,
|
|
314
|
-
},
|
|
315
|
-
pairedItem: { item: i },
|
|
428
|
+
push({
|
|
429
|
+
tool: outcome.tool,
|
|
430
|
+
data: outcome.data,
|
|
431
|
+
raw: outcome.text,
|
|
432
|
+
isError: outcome.isError,
|
|
316
433
|
});
|
|
317
434
|
}
|
|
318
435
|
catch (error) {
|