n8n-nodes-linkedin-toolkit 2.0.0

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 ADDED
@@ -0,0 +1,108 @@
1
+ # n8n-nodes-linkedin-toolkit
2
+
3
+ The n8n community node for [LinkedIn Toolkit](https://github.com/FormatixAI/linkedin-toolkit).
4
+ Two nodes and one credential: every action of the local HTTP API, and a trigger fed by the
5
+ server's webhooks.
6
+
7
+ ## Install
8
+
9
+ **Settings → Community Nodes → Install** `n8n-nodes-linkedin-toolkit`.
10
+
11
+ ## Prerequisites
12
+
13
+ ```bash
14
+ npx linkedin-toolkit-mcp # pair the extension once
15
+ lit serve --http # 127.0.0.1:47830
16
+ ```
17
+
18
+ Add `--fake` to `lit serve` to build and test a workflow without a LinkedIn account: real
19
+ envelopes, real error codes, invented data.
20
+
21
+ ## Credential
22
+
23
+ **LinkedIn Toolkit API**
24
+
25
+ | Field | Value |
26
+ |---|---|
27
+ | Base URL | `http://127.0.0.1:47830` |
28
+ | Token | the `token` field in `~/.linkedin-toolkit/config.json`, or `lit config get token --reveal` |
29
+
30
+ The token is sent as `Authorization: Bearer …`. The credential test hits `/health`, which needs no
31
+ token, so a passing test proves the URL is reachable — which is the failure worth catching first.
32
+
33
+ **Docker:** `127.0.0.1` inside a container is the container. Use `http://host.docker.internal:47830`
34
+ on Docker Desktop, or run n8n with `--network host` on Linux.
35
+
36
+ ## LinkedIn Toolkit node
37
+
38
+ Pick a **Resource** (the action namespace — Search, Profile, Outreach, Inbox, List, Campaign,
39
+ Queue, Research, …) and an **Operation** (the action). Required fields appear directly; everything
40
+ else, including **Dry Run** on write operations, lives in **Additional Fields**.
41
+
42
+ Field conventions:
43
+
44
+ - a list of ids is a comma-separated string — `ada-lovelace, grace-hopper`
45
+ - a structured parameter (campaign `Steps`, `Profiles`, research `Rows`, queue `Edits`) is a JSON
46
+ field
47
+ - an empty optional is not sent, so leaving a field blank is the same as not setting it
48
+
49
+ The node outputs the envelope's `data` by default; switch on **Return the Full Envelope** for
50
+ `{id, ok, data}`. An engine failure throws with the code and `howToFix`; turn on n8n's *Continue On
51
+ Fail* to get `{error, message, howToFix}` as an item instead.
52
+
53
+ Writes return `{"status": "queued", "queueId": …}` while Copilot mode is on. **That is success** —
54
+ a human approves them in the extension popup.
55
+
56
+ ## LinkedIn Toolkit Trigger node
57
+
58
+ A webhook trigger. Copy the node's Production URL and point the server at it:
59
+
60
+ ```bash
61
+ lit config set webhookUrl https://your-n8n/webhook/linkedin-events
62
+ ```
63
+
64
+ The server POSTs `{ event, payload, at }` and retries at 1 s, 5 s and 25 s. Select the events you
65
+ care about, or leave the list empty for all eleven:
66
+
67
+ | Event | Worth automating |
68
+ |---|---|
69
+ | `invite_accepted` | Draft a first message |
70
+ | `reply_received`, `positive_reply` | Route to triage, create a CRM task |
71
+ | `campaign_step_done`, `campaign_completed` | Progress and reporting |
72
+ | `quota_hit` | Log it — the engine is working as intended |
73
+ | `challenge_detected` | **Page someone.** All writes are paused until a human clears it in Chrome |
74
+ | `queue_item_added`, `queue_item_sent` | Approval dashboards |
75
+ | `research_progress`, `research_completed` | Research Pack progress |
76
+
77
+ A delivery whose event is filtered out is answered — so the server does not retry — but does not
78
+ start the workflow.
79
+
80
+ **The webhook is unauthenticated.** Like every n8n webhook it accepts any POST that reaches its
81
+ URL, and the toolkit server sends no signature to check. On a laptop that is fine: the URL is
82
+ localhost or a private n8n. If you expose it, anything that learns the URL can inject an event, so
83
+ put your own gate in front of it — n8n's Header Auth on the node, or a reverse proxy — and treat
84
+ the payload as untrusted input rather than as a fact about your LinkedIn account.
85
+
86
+ ## What you cannot change from here
87
+
88
+ - **Hard caps** live in the extension: 100 invites, 150 messages, 500 profile visits and 1,000
89
+ search results per day. No field in this node raises them.
90
+ - **Copilot mode** is on by default and the approval queue cannot be bypassed by a workflow.
91
+
92
+ You could delete the approval step from a workflow. The hard caps will stop it becoming a disaster;
93
+ they will not stop it being embarrassing. Watch a few hundred drafts first.
94
+
95
+ ## Development
96
+
97
+ ```bash
98
+ npm run gen # rebuild the action table from mcp-server/openapi.json
99
+ npm run build # tsc + copy the icons into dist
100
+ npm test # vitest
101
+ ```
102
+
103
+ `nodes/LinkedInToolkit/actions.generated.ts` is generated and committed; a test fails if it is
104
+ stale, so the node cannot quietly fall behind the action contract.
105
+
106
+ ## Licence
107
+
108
+ MIT.
@@ -0,0 +1,22 @@
1
+ import type { IAuthenticateGeneric, ICredentialTestRequest, ICredentialType, INodeProperties } from 'n8n-workflow';
2
+ /**
3
+ * The pairing token from `~/.linkedin-toolkit/config.json`, plus the URL the
4
+ * server is listening on.
5
+ *
6
+ * The same credential works with the plain HTTP Request node, so a workflow can
7
+ * reach an action this package's node has not caught up with yet.
8
+ */
9
+ export declare class LinkedInToolkitApi implements ICredentialType {
10
+ name: string;
11
+ displayName: string;
12
+ documentationUrl: string;
13
+ properties: INodeProperties[];
14
+ authenticate: IAuthenticateGeneric;
15
+ /**
16
+ * `/health` needs no token, so a passing test proves the URL is reachable
17
+ * rather than that the token is right. That is still the failure worth
18
+ * catching first: almost every setup problem here is the port or Docker
19
+ * networking, not the token.
20
+ */
21
+ test: ICredentialTestRequest;
22
+ }
@@ -0,0 +1,57 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.LinkedInToolkitApi = void 0;
4
+ /**
5
+ * The pairing token from `~/.linkedin-toolkit/config.json`, plus the URL the
6
+ * server is listening on.
7
+ *
8
+ * The same credential works with the plain HTTP Request node, so a workflow can
9
+ * reach an action this package's node has not caught up with yet.
10
+ */
11
+ class LinkedInToolkitApi {
12
+ name = 'linkedInToolkitApi';
13
+ displayName = 'LinkedIn Toolkit API';
14
+ documentationUrl = 'https://github.com/FormatixAI/linkedin-toolkit/blob/main/docs/agents/n8n.md';
15
+ properties = [
16
+ {
17
+ displayName: 'Base URL',
18
+ name: 'baseUrl',
19
+ type: 'string',
20
+ default: 'http://127.0.0.1:47830',
21
+ required: true,
22
+ description: 'Where `lit serve --http` is listening. Inside Docker, 127.0.0.1 is the container: use http://host.docker.internal:47830 on Docker Desktop, or run n8n with --network host on Linux.',
23
+ },
24
+ {
25
+ displayName: 'Token',
26
+ name: 'token',
27
+ type: 'string',
28
+ typeOptions: { password: true },
29
+ default: '',
30
+ required: true,
31
+ description: 'The pairing token — the `token` field in ~/.linkedin-toolkit/config.json, or the value `lit config get token --reveal` prints.',
32
+ },
33
+ ];
34
+ authenticate = {
35
+ type: 'generic',
36
+ properties: {
37
+ headers: {
38
+ Authorization: '=Bearer {{$credentials.token}}',
39
+ },
40
+ },
41
+ };
42
+ /**
43
+ * `/health` needs no token, so a passing test proves the URL is reachable
44
+ * rather than that the token is right. That is still the failure worth
45
+ * catching first: almost every setup problem here is the port or Docker
46
+ * networking, not the token.
47
+ */
48
+ test = {
49
+ request: {
50
+ baseURL: '={{$credentials.baseUrl}}',
51
+ url: '/health',
52
+ method: 'GET',
53
+ },
54
+ };
55
+ }
56
+ exports.LinkedInToolkitApi = LinkedInToolkitApi;
57
+ //# sourceMappingURL=LinkedInToolkitApi.credentials.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LinkedInToolkitApi.credentials.js","sourceRoot":"","sources":["../../credentials/LinkedInToolkitApi.credentials.ts"],"names":[],"mappings":";;;AAOA;;;;;;GAMG;AACH,MAAa,kBAAkB;IAC9B,IAAI,GAAG,oBAAoB,CAAC;IAE5B,WAAW,GAAG,sBAAsB,CAAC;IAErC,gBAAgB,GAAG,6EAA6E,CAAC;IAEjG,UAAU,GAAsB;QAC/B;YACC,WAAW,EAAE,UAAU;YACvB,IAAI,EAAE,SAAS;YACf,IAAI,EAAE,QAAQ;YACd,OAAO,EAAE,wBAAwB;YACjC,QAAQ,EAAE,IAAI;YACd,WAAW,EACV,qLAAqL;SACtL;QACD;YACC,WAAW,EAAE,OAAO;YACpB,IAAI,EAAE,OAAO;YACb,IAAI,EAAE,QAAQ;YACd,WAAW,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE;YAC/B,OAAO,EAAE,EAAE;YACX,QAAQ,EAAE,IAAI;YACd,WAAW,EACV,gIAAgI;SACjI;KACD,CAAC;IAEF,YAAY,GAAyB;QACpC,IAAI,EAAE,SAAS;QACf,UAAU,EAAE;YACX,OAAO,EAAE;gBACR,aAAa,EAAE,gCAAgC;aAC/C;SACD;KACD,CAAC;IAEF;;;;;OAKG;IACH,IAAI,GAA2B;QAC9B,OAAO,EAAE;YACR,OAAO,EAAE,2BAA2B;YACpC,GAAG,EAAE,SAAS;YACd,MAAM,EAAE,KAAK;SACb;KACD,CAAC;CACF;AAnDD,gDAmDC"}
@@ -0,0 +1,18 @@
1
+ import { type IDataObject, type IExecuteFunctions, type INodeExecutionData, type INodeType, type INodeTypeDescription } from 'n8n-workflow';
2
+ import type { ActionSpec, FieldSpec } from './actions.generated';
3
+ /**
4
+ * Turn one n8n field value into the JSON the contract expects.
5
+ *
6
+ * Only three shapes need work: a comma-separated string becomes an array, a
7
+ * JSON field is parsed, and an empty optional is dropped rather than sent as
8
+ * `""`, which the server would reject as an invalid param.
9
+ */
10
+ export declare function coerce(field: FieldSpec, value: unknown, context: {
11
+ nodeName: string;
12
+ }): unknown | undefined;
13
+ /** Build the request body for one action from the node's parameters. */
14
+ export declare function buildParams(action: ActionSpec, read: (name: string) => unknown, nodeName?: string): IDataObject;
15
+ export declare class LinkedInToolkit implements INodeType {
16
+ description: INodeTypeDescription;
17
+ execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]>;
18
+ }
@@ -0,0 +1,141 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.LinkedInToolkit = void 0;
4
+ exports.coerce = coerce;
5
+ exports.buildParams = buildParams;
6
+ const n8n_workflow_1 = require("n8n-workflow");
7
+ const properties_1 = require("./properties");
8
+ /**
9
+ * Turn one n8n field value into the JSON the contract expects.
10
+ *
11
+ * Only three shapes need work: a comma-separated string becomes an array, a
12
+ * JSON field is parsed, and an empty optional is dropped rather than sent as
13
+ * `""`, which the server would reject as an invalid param.
14
+ */
15
+ function coerce(field, value, context) {
16
+ if (value === undefined || value === null)
17
+ return undefined;
18
+ if (field.type === 'stringList') {
19
+ if (typeof value !== 'string')
20
+ return Array.isArray(value) ? value : undefined;
21
+ const items = value
22
+ .split(',')
23
+ .map((item) => item.trim())
24
+ .filter((item) => item.length > 0);
25
+ return items.length > 0 ? items : undefined;
26
+ }
27
+ if (field.type === 'json') {
28
+ if (typeof value !== 'string')
29
+ return value;
30
+ const trimmed = value.trim();
31
+ if (trimmed === '' || trimmed === '{}' || trimmed === '[]')
32
+ return undefined;
33
+ try {
34
+ return JSON.parse(trimmed);
35
+ }
36
+ catch {
37
+ throw new Error(`${context.nodeName}: "${field.displayName}" is not valid JSON. Expected ${field.default === '[]' ? 'an array' : 'an object'}.`);
38
+ }
39
+ }
40
+ if (field.type === 'string' && value === '')
41
+ return undefined;
42
+ return value;
43
+ }
44
+ /** Build the request body for one action from the node's parameters. */
45
+ function buildParams(action, read, nodeName = 'LinkedIn Toolkit') {
46
+ const params = {};
47
+ for (const field of action.required) {
48
+ const value = coerce(field, read(field.name), { nodeName });
49
+ if (value !== undefined)
50
+ params[field.key] = value;
51
+ }
52
+ const extra = (read(`${action.key}_extra`) ?? {});
53
+ for (const field of action.optional) {
54
+ const value = coerce(field, extra[field.name], { nodeName });
55
+ if (value !== undefined)
56
+ params[field.key] = value;
57
+ }
58
+ return params;
59
+ }
60
+ class LinkedInToolkit {
61
+ description = {
62
+ displayName: 'LinkedIn Toolkit',
63
+ name: 'linkedInToolkit',
64
+ icon: 'file:linkedInToolkit.svg',
65
+ group: ['transform'],
66
+ version: 1,
67
+ subtitle: '={{$parameter["operation"]}}',
68
+ description: 'Search, read and act on LinkedIn through your own logged-in Chrome session. Hard caps and the approval queue live in the extension and cannot be raised from here.',
69
+ defaults: { name: 'LinkedIn Toolkit' },
70
+ inputs: [n8n_workflow_1.NodeConnectionTypes.Main],
71
+ outputs: [n8n_workflow_1.NodeConnectionTypes.Main],
72
+ credentials: [{ name: 'linkedInToolkitApi', required: true }],
73
+ requestDefaults: {
74
+ headers: { 'content-type': 'application/json' },
75
+ },
76
+ properties: properties_1.NODE_PROPERTIES,
77
+ };
78
+ async execute() {
79
+ const items = this.getInputData();
80
+ const output = [];
81
+ const credentials = await this.getCredentials('linkedInToolkitApi');
82
+ const baseUrl = String(credentials.baseUrl ?? 'http://127.0.0.1:47830').replace(/\/+$/, '');
83
+ for (let index = 0; index < items.length; index++) {
84
+ const operation = this.getNodeParameter('operation', index);
85
+ const action = properties_1.ACTION_BY_NAME.get(operation);
86
+ if (!action) {
87
+ throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Unknown operation "${operation}". Reinstall n8n-nodes-linkedin-toolkit if this node is older than your server.`, { itemIndex: index });
88
+ }
89
+ let params;
90
+ try {
91
+ params = buildParams(action, (name) => this.getNodeParameter(name, index, undefined));
92
+ }
93
+ catch (error) {
94
+ throw new n8n_workflow_1.NodeOperationError(this.getNode(), error.message, {
95
+ itemIndex: index,
96
+ });
97
+ }
98
+ const response = (await this.helpers.httpRequestWithAuthentication.call(this, 'linkedInToolkitApi', {
99
+ method: 'POST',
100
+ url: `${baseUrl}/actions/${action.action}`,
101
+ body: params,
102
+ json: true,
103
+ // The server answers an engine failure with HTTP 200 and
104
+ // `ok: false`, so a non-2xx here is a transport or auth problem
105
+ // and we want to read the body either way.
106
+ returnFullResponse: false,
107
+ ignoreHttpStatusErrors: true,
108
+ }));
109
+ if (response?.ok === true) {
110
+ const full = this.getNodeParameter('fullEnvelope', index, false);
111
+ const data = response.data;
112
+ const json = full
113
+ ? response
114
+ : data && typeof data === 'object' && !Array.isArray(data)
115
+ ? data
116
+ : { data };
117
+ output.push({ json, pairedItem: { item: index } });
118
+ continue;
119
+ }
120
+ const failure = (response?.error ?? {
121
+ code: 'INTERNAL',
122
+ message: 'The server returned an unrecognised body.',
123
+ });
124
+ if (this.continueOnFail()) {
125
+ output.push({
126
+ json: { error: failure.code, message: failure.message, howToFix: failure.howToFix },
127
+ pairedItem: { item: index },
128
+ });
129
+ continue;
130
+ }
131
+ throw new n8n_workflow_1.NodeApiError(this.getNode(), failure, {
132
+ message: `${failure.code}: ${failure.message}`,
133
+ description: failure.howToFix ?? undefined,
134
+ itemIndex: index,
135
+ });
136
+ }
137
+ return [output];
138
+ }
139
+ }
140
+ exports.LinkedInToolkit = LinkedInToolkit;
141
+ //# sourceMappingURL=LinkedInToolkit.node.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LinkedInToolkit.node.js","sourceRoot":"","sources":["../../../nodes/LinkedInToolkit/LinkedInToolkit.node.ts"],"names":[],"mappings":";;;AAsBA,wBAkCC;AAGD,kCAmBC;AA9ED,+CAUsB;AAGtB,6CAA+D;AAE/D;;;;;;GAMG;AACH,SAAgB,MAAM,CACrB,KAAgB,EAChB,KAAc,EACd,OAA6B;IAE7B,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,SAAS,CAAC;IAE5D,IAAI,KAAK,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;QACjC,IAAI,OAAO,KAAK,KAAK,QAAQ;YAAE,OAAO,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;QAC/E,MAAM,KAAK,GAAG,KAAK;aACjB,KAAK,CAAC,GAAG,CAAC;aACV,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;aAC1B,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QACpC,OAAO,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;IAC7C,CAAC;IAED,IAAI,KAAK,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;QAC3B,IAAI,OAAO,KAAK,KAAK,QAAQ;YAAE,OAAO,KAAK,CAAC;QAC5C,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;QAC7B,IAAI,OAAO,KAAK,EAAE,IAAI,OAAO,KAAK,IAAI,IAAI,OAAO,KAAK,IAAI;YAAE,OAAO,SAAS,CAAC;QAC7E,IAAI,CAAC;YACJ,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QAC5B,CAAC;QAAC,MAAM,CAAC;YACR,MAAM,IAAI,KAAK,CACd,GAAG,OAAO,CAAC,QAAQ,MAAM,KAAK,CAAC,WAAW,iCACzC,KAAK,CAAC,OAAO,KAAK,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,WACvC,GAAG,CACH,CAAC;QACH,CAAC;IACF,CAAC;IAED,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ,IAAI,KAAK,KAAK,EAAE;QAAE,OAAO,SAAS,CAAC;IAE9D,OAAO,KAAK,CAAC;AACd,CAAC;AAED,wEAAwE;AACxE,SAAgB,WAAW,CAC1B,MAAkB,EAClB,IAA+B,EAC/B,QAAQ,GAAG,kBAAkB;IAE7B,MAAM,MAAM,GAAgB,EAAE,CAAC;IAE/B,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;QACrC,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC;QAC5D,IAAI,KAAK,KAAK,SAAS;YAAE,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;IACpD,CAAC;IAED,MAAM,KAAK,GAAG,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,GAAG,QAAQ,CAAC,IAAI,EAAE,CAAgB,CAAC;IACjE,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;QACrC,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC;QAC7D,IAAI,KAAK,KAAK,SAAS;YAAE,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;IACpD,CAAC;IAED,OAAO,MAAM,CAAC;AACf,CAAC;AAED,MAAa,eAAe;IAC3B,WAAW,GAAyB;QACnC,WAAW,EAAE,kBAAkB;QAC/B,IAAI,EAAE,iBAAiB;QACvB,IAAI,EAAE,0BAA0B;QAChC,KAAK,EAAE,CAAC,WAAW,CAAC;QACpB,OAAO,EAAE,CAAC;QACV,QAAQ,EAAE,8BAA8B;QACxC,WAAW,EACV,oKAAoK;QACrK,QAAQ,EAAE,EAAE,IAAI,EAAE,kBAAkB,EAAE;QACtC,MAAM,EAAE,CAAC,kCAAmB,CAAC,IAAI,CAAC;QAClC,OAAO,EAAE,CAAC,kCAAmB,CAAC,IAAI,CAAC;QACnC,WAAW,EAAE,CAAC,EAAE,IAAI,EAAE,oBAAoB,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;QAC7D,eAAe,EAAE;YAChB,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;SAC/C;QACD,UAAU,EAAE,4BAAe;KAC3B,CAAC;IAEF,KAAK,CAAC,OAAO;QACZ,MAAM,KAAK,GAAG,IAAI,CAAC,YAAY,EAAE,CAAC;QAClC,MAAM,MAAM,GAAyB,EAAE,CAAC;QACxC,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,oBAAoB,CAAC,CAAC;QACpE,MAAM,OAAO,GAAG,MAAM,CAAC,WAAW,CAAC,OAAO,IAAI,wBAAwB,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;QAE5F,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,KAAK,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,CAAC;YACnD,MAAM,SAAS,GAAG,IAAI,CAAC,gBAAgB,CAAC,WAAW,EAAE,KAAK,CAAW,CAAC;YACtE,MAAM,MAAM,GAAG,2BAAc,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;YAE7C,IAAI,CAAC,MAAM,EAAE,CAAC;gBACb,MAAM,IAAI,iCAAkB,CAC3B,IAAI,CAAC,OAAO,EAAE,EACd,sBAAsB,SAAS,iFAAiF,EAChH,EAAE,SAAS,EAAE,KAAK,EAAE,CACpB,CAAC;YACH,CAAC;YAED,IAAI,MAAmB,CAAC;YACxB,IAAI,CAAC;gBACJ,MAAM,GAAG,WAAW,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,gBAAgB,CAAC,IAAI,EAAE,KAAK,EAAE,SAAS,CAAC,CAAC,CAAC;YACvF,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBAChB,MAAM,IAAI,iCAAkB,CAAC,IAAI,CAAC,OAAO,EAAE,EAAG,KAAe,CAAC,OAAO,EAAE;oBACtE,SAAS,EAAE,KAAK;iBAChB,CAAC,CAAC;YACJ,CAAC;YAED,MAAM,QAAQ,GAAG,CAAC,MAAM,IAAI,CAAC,OAAO,CAAC,6BAA6B,CAAC,IAAI,CACtE,IAAI,EACJ,oBAAoB,EACpB;gBACC,MAAM,EAAE,MAAM;gBACd,GAAG,EAAE,GAAG,OAAO,YAAY,MAAM,CAAC,MAAM,EAAE;gBAC1C,IAAI,EAAE,MAAM;gBACZ,IAAI,EAAE,IAAI;gBACV,yDAAyD;gBACzD,gEAAgE;gBAChE,2CAA2C;gBAC3C,kBAAkB,EAAE,KAAK;gBACzB,sBAAsB,EAAE,IAAI;aAC5B,CACD,CAAgB,CAAC;YAElB,IAAI,QAAQ,EAAE,EAAE,KAAK,IAAI,EAAE,CAAC;gBAC3B,MAAM,IAAI,GAAG,IAAI,CAAC,gBAAgB,CAAC,cAAc,EAAE,KAAK,EAAE,KAAK,CAAY,CAAC;gBAC5E,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAC;gBAC3B,MAAM,IAAI,GAAgB,IAAI;oBAC7B,CAAC,CAAC,QAAQ;oBACV,CAAC,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC;wBACzD,CAAC,CAAE,IAAoB;wBACvB,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC;gBACb,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC;gBACnD,SAAS;YACV,CAAC;YAED,MAAM,OAAO,GAAG,CAAC,QAAQ,EAAE,KAAK,IAAI;gBACnC,IAAI,EAAE,UAAU;gBAChB,OAAO,EAAE,2CAA2C;aACpD,CAAgB,CAAC;YAElB,IAAI,IAAI,CAAC,cAAc,EAAE,EAAE,CAAC;gBAC3B,MAAM,CAAC,IAAI,CAAC;oBACX,IAAI,EAAE,EAAE,KAAK,EAAE,OAAO,CAAC,IAAI,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE;oBACnF,UAAU,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE;iBAC3B,CAAC,CAAC;gBACH,SAAS;YACV,CAAC;YAED,MAAM,IAAI,2BAAY,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,OAAgC,EAAE;gBACxE,OAAO,EAAE,GAAG,OAAO,CAAC,IAAI,KAAK,OAAO,CAAC,OAAO,EAAE;gBAC9C,WAAW,EAAG,OAAO,CAAC,QAAmB,IAAI,SAAS;gBACtD,SAAS,EAAE,KAAK;aAChB,CAAC,CAAC;QACJ,CAAC;QAED,OAAO,CAAC,MAAM,CAAC,CAAC;IACjB,CAAC;CACD;AAjGD,0CAiGC"}
@@ -0,0 +1,38 @@
1
+ /**
2
+ * AUTO-GENERATED — do not edit by hand.
3
+ *
4
+ * Written by `npm run gen` in `clients/n8n` from `mcp-server/openapi.json`
5
+ * and `mcp-server/tools.json`. Every resource, operation and field in the
6
+ * node comes from here, so the node cannot fall behind the action contract
7
+ * without `tests/gen.test.ts` failing.
8
+ */
9
+ export type FieldSpec = {
10
+ name: string;
11
+ key: string;
12
+ displayName: string;
13
+ type: 'string' | 'number' | 'boolean' | 'options' | 'json' | 'stringList';
14
+ required: boolean;
15
+ default: string | number | boolean;
16
+ description: string;
17
+ options?: Array<{
18
+ name: string;
19
+ value: string;
20
+ }>;
21
+ };
22
+ export type ActionSpec = {
23
+ action: string;
24
+ key: string;
25
+ resource: string;
26
+ operation: string;
27
+ displayName: string;
28
+ description: string;
29
+ write: boolean;
30
+ required: FieldSpec[];
31
+ optional: FieldSpec[];
32
+ };
33
+ export declare const RESOURCES: Array<{
34
+ name: string;
35
+ value: string;
36
+ description: string;
37
+ }>;
38
+ export declare const ACTIONS: ActionSpec[];