@hemmilicious/n8n-nodes-ninjapipe 0.2.2
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/INSTALL.md +30 -0
- package/README.md +61 -0
- package/credentials/NinjaPipeApi.credentials.ts +32 -0
- package/dist/credentials/NinjaPipeApi.credentials.js +34 -0
- package/dist/credentials/NinjaPipeApi.credentials.js.map +1 -0
- package/dist/nodes/NinjaPipe/NinjaPipe.node.js +441 -0
- package/dist/nodes/NinjaPipe/NinjaPipe.node.js.map +1 -0
- package/dist/nodes/NinjaPipe/ninjapipe.svg +5 -0
- package/nodes/NinjaPipe/NinjaPipe.node.ts +484 -0
- package/nodes/NinjaPipe/ninjapipe.svg +5 -0
- package/package.json +58 -0
package/INSTALL.md
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# Install and publish
|
|
2
|
+
|
|
3
|
+
## Build locally
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
cd ~/Desktop/n8n-nodes-ninjapipe
|
|
7
|
+
npm install
|
|
8
|
+
npm run build
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Dry run
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npm pack --dry-run
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Publish to npm
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm login
|
|
21
|
+
npm whoami
|
|
22
|
+
npm publish --access public
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Publish update
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
npm version patch
|
|
29
|
+
npm publish --access public
|
|
30
|
+
```
|
package/README.md
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# @hemmilicious/n8n-nodes-ninjapipe
|
|
2
|
+
|
|
3
|
+
Community node for using the NinjaPipe API inside n8n.
|
|
4
|
+
|
|
5
|
+
## Included resources
|
|
6
|
+
|
|
7
|
+
- Contacts
|
|
8
|
+
- Companies
|
|
9
|
+
- Deals
|
|
10
|
+
- Products
|
|
11
|
+
- Budgets
|
|
12
|
+
- Lists
|
|
13
|
+
- Pipelines
|
|
14
|
+
- Pipeline Items
|
|
15
|
+
- Invoices
|
|
16
|
+
- Orders
|
|
17
|
+
- Projects
|
|
18
|
+
- Tasks
|
|
19
|
+
- Databins
|
|
20
|
+
- Custom API Request
|
|
21
|
+
|
|
22
|
+
## Included operations
|
|
23
|
+
|
|
24
|
+
For most resources
|
|
25
|
+
|
|
26
|
+
- Create
|
|
27
|
+
- Get
|
|
28
|
+
- Get Many
|
|
29
|
+
- Update
|
|
30
|
+
- Delete
|
|
31
|
+
|
|
32
|
+
Extra operations
|
|
33
|
+
|
|
34
|
+
- Contact: Enable Client Portal
|
|
35
|
+
- Contact: Disable Client Portal
|
|
36
|
+
- Budget: Create Expense
|
|
37
|
+
- Custom API Request: Execute any endpoint manually
|
|
38
|
+
|
|
39
|
+
## Why this node is broader now
|
|
40
|
+
|
|
41
|
+
NinjaPipe publicly documents API authentication with workspace specific API keys and lists API groups for Contacts, Deals, Products and Budgets. NinjaPipe product documentation also lists broader data areas such as Contacts, Companies, Products, Lists, Deals, Pipelines and Items, Invoices, Orders, Budgets, Projects and Tasks, and Databins. Pagination documentation states `page`, `limit` and a maximum page size of 100. Because not every broader endpoint was exposed in an equally detailed static view, this node includes a resource path override and a custom request mode so you can still map your workspace fully without waiting for a new release.
|
|
42
|
+
|
|
43
|
+
## Credentials
|
|
44
|
+
|
|
45
|
+
- Base URL, default `https://www.ninjapipe.app/api`
|
|
46
|
+
- API Key
|
|
47
|
+
|
|
48
|
+
## Notes
|
|
49
|
+
|
|
50
|
+
- `Get Many` supports `Return All`
|
|
51
|
+
- `Filters JSON` lets you pass extra query params
|
|
52
|
+
- `Resource Path Override` lets you correct or extend endpoint paths
|
|
53
|
+
- `Custom API Request` lets you hit any NinjaPipe path manually
|
|
54
|
+
|
|
55
|
+
## Local install in n8n
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
npm install @hemmilicious/n8n-nodes-ninjapipe
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Or for self hosted n8n community nodes, install it where your n8n instance loads community nodes.
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { ICredentialType, INodeProperties } from 'n8n-workflow';
|
|
2
|
+
|
|
3
|
+
export class NinjaPipeApi implements ICredentialType {
|
|
4
|
+
name = 'ninjaPipeApi';
|
|
5
|
+
|
|
6
|
+
displayName = 'NinjaPipe API';
|
|
7
|
+
|
|
8
|
+
documentationUrl = 'https://docs.ninjapipe.app/api-docs';
|
|
9
|
+
|
|
10
|
+
properties: INodeProperties[] = [
|
|
11
|
+
{
|
|
12
|
+
displayName: 'Base URL',
|
|
13
|
+
name: 'baseUrl',
|
|
14
|
+
type: 'string',
|
|
15
|
+
default: 'https://www.ninjapipe.app/api',
|
|
16
|
+
placeholder: 'https://www.ninjapipe.app/api',
|
|
17
|
+
required: true,
|
|
18
|
+
description: 'Base URL of the NinjaPipe API',
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
displayName: 'API Key',
|
|
22
|
+
name: 'apiKey',
|
|
23
|
+
type: 'string',
|
|
24
|
+
typeOptions: {
|
|
25
|
+
password: true,
|
|
26
|
+
},
|
|
27
|
+
default: '',
|
|
28
|
+
required: true,
|
|
29
|
+
description: 'NinjaPipe API key',
|
|
30
|
+
},
|
|
31
|
+
];
|
|
32
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.NinjaPipeApi = void 0;
|
|
4
|
+
class NinjaPipeApi {
|
|
5
|
+
constructor() {
|
|
6
|
+
this.name = 'ninjaPipeApi';
|
|
7
|
+
this.displayName = 'NinjaPipe API';
|
|
8
|
+
this.documentationUrl = 'https://docs.ninjapipe.app/api-docs';
|
|
9
|
+
this.properties = [
|
|
10
|
+
{
|
|
11
|
+
displayName: 'Base URL',
|
|
12
|
+
name: 'baseUrl',
|
|
13
|
+
type: 'string',
|
|
14
|
+
default: 'https://www.ninjapipe.app/api',
|
|
15
|
+
placeholder: 'https://www.ninjapipe.app/api',
|
|
16
|
+
required: true,
|
|
17
|
+
description: 'Base URL of the NinjaPipe API',
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
displayName: 'API Key',
|
|
21
|
+
name: 'apiKey',
|
|
22
|
+
type: 'string',
|
|
23
|
+
typeOptions: {
|
|
24
|
+
password: true,
|
|
25
|
+
},
|
|
26
|
+
default: '',
|
|
27
|
+
required: true,
|
|
28
|
+
description: 'NinjaPipe API key',
|
|
29
|
+
},
|
|
30
|
+
];
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
exports.NinjaPipeApi = NinjaPipeApi;
|
|
34
|
+
//# sourceMappingURL=NinjaPipeApi.credentials.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NinjaPipeApi.credentials.js","sourceRoot":"","sources":["../../credentials/NinjaPipeApi.credentials.ts"],"names":[],"mappings":";;;AAEA,MAAa,YAAY;IAAzB;QACC,SAAI,GAAG,cAAc,CAAC;QAEtB,gBAAW,GAAG,eAAe,CAAC;QAE9B,qBAAgB,GAAG,qCAAqC,CAAC;QAEzD,eAAU,GAAsB;YAC/B;gBACC,WAAW,EAAE,UAAU;gBACvB,IAAI,EAAE,SAAS;gBACf,IAAI,EAAE,QAAQ;gBACd,OAAO,EAAE,+BAA+B;gBACxC,WAAW,EAAE,+BAA+B;gBAC5C,QAAQ,EAAE,IAAI;gBACd,WAAW,EAAE,+BAA+B;aAC5C;YACD;gBACC,WAAW,EAAE,SAAS;gBACtB,IAAI,EAAE,QAAQ;gBACd,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE;oBACZ,QAAQ,EAAE,IAAI;iBACd;gBACD,OAAO,EAAE,EAAE;gBACX,QAAQ,EAAE,IAAI;gBACd,WAAW,EAAE,mBAAmB;aAChC;SACD,CAAC;IACH,CAAC;CAAA;AA7BD,oCA6BC"}
|
|
@@ -0,0 +1,441 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.NinjaPipe = void 0;
|
|
4
|
+
const n8n_workflow_1 = require("n8n-workflow");
|
|
5
|
+
const resourceConfig = {
|
|
6
|
+
contact: { path: 'contacts', supportsCrud: true },
|
|
7
|
+
company: { path: 'companies', supportsCrud: true },
|
|
8
|
+
deal: { path: 'deals', supportsCrud: true },
|
|
9
|
+
product: { path: 'products', supportsCrud: true },
|
|
10
|
+
budget: { path: 'budgets', supportsCrud: true },
|
|
11
|
+
list: { path: 'lists', supportsCrud: true },
|
|
12
|
+
pipeline: { path: 'pipelines', supportsCrud: true },
|
|
13
|
+
pipelineItem: { path: 'pipeline-items', supportsCrud: true },
|
|
14
|
+
invoice: { path: 'invoices', supportsCrud: true },
|
|
15
|
+
order: { path: 'orders', supportsCrud: true },
|
|
16
|
+
project: { path: 'projects', supportsCrud: true },
|
|
17
|
+
task: { path: 'tasks', supportsCrud: true },
|
|
18
|
+
databin: { path: 'databins', supportsCrud: true },
|
|
19
|
+
};
|
|
20
|
+
async function ninjaPipeApiRequest(context, method, endpoint, body, qs) {
|
|
21
|
+
const credentials = await context.getCredentials('ninjaPipeApi');
|
|
22
|
+
const baseUrl = String(credentials.baseUrl || '').replace(/\/+$/, '');
|
|
23
|
+
const apiKey = String(credentials.apiKey || '');
|
|
24
|
+
if (!baseUrl) {
|
|
25
|
+
throw new n8n_workflow_1.NodeOperationError(context.getNode(), 'Missing NinjaPipe base URL in credentials');
|
|
26
|
+
}
|
|
27
|
+
if (!apiKey) {
|
|
28
|
+
throw new n8n_workflow_1.NodeOperationError(context.getNode(), 'Missing NinjaPipe API key in credentials');
|
|
29
|
+
}
|
|
30
|
+
try {
|
|
31
|
+
return await context.helpers.httpRequest({
|
|
32
|
+
method,
|
|
33
|
+
url: `${baseUrl}${endpoint}`,
|
|
34
|
+
headers: {
|
|
35
|
+
Authorization: `Bearer ${apiKey}`,
|
|
36
|
+
Accept: 'application/json',
|
|
37
|
+
'Content-Type': 'application/json',
|
|
38
|
+
},
|
|
39
|
+
body,
|
|
40
|
+
qs,
|
|
41
|
+
json: true,
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
catch (error) {
|
|
45
|
+
throw new n8n_workflow_1.NodeApiError(context.getNode(), error);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
function parseJsonParameter(context, name, itemIndex) {
|
|
49
|
+
const rawValue = context.getNodeParameter(name, itemIndex);
|
|
50
|
+
if (typeof rawValue !== 'string')
|
|
51
|
+
return rawValue;
|
|
52
|
+
if (!rawValue || rawValue.trim() === '')
|
|
53
|
+
return {};
|
|
54
|
+
try {
|
|
55
|
+
return JSON.parse(rawValue);
|
|
56
|
+
}
|
|
57
|
+
catch (error) {
|
|
58
|
+
throw new n8n_workflow_1.NodeOperationError(context.getNode(), `Invalid JSON in field \"${name}\": ${error.message}`, {
|
|
59
|
+
itemIndex,
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
function normalizePath(path) {
|
|
64
|
+
const trimmed = path.trim();
|
|
65
|
+
if (!trimmed)
|
|
66
|
+
return '';
|
|
67
|
+
return trimmed.startsWith('/') ? trimmed : `/${trimmed}`;
|
|
68
|
+
}
|
|
69
|
+
function getResourcePath(resource, overridePath) {
|
|
70
|
+
if (overridePath && overridePath.trim()) {
|
|
71
|
+
return normalizePath(overridePath);
|
|
72
|
+
}
|
|
73
|
+
return `/${resourceConfig[resource].path}`;
|
|
74
|
+
}
|
|
75
|
+
function extractItems(response) {
|
|
76
|
+
if (Array.isArray(response))
|
|
77
|
+
return response;
|
|
78
|
+
if (response && typeof response === 'object') {
|
|
79
|
+
const obj = response;
|
|
80
|
+
for (const key of ['data', 'items', 'results', 'contacts', 'deals', 'products', 'budgets']) {
|
|
81
|
+
const value = obj[key];
|
|
82
|
+
if (Array.isArray(value))
|
|
83
|
+
return value;
|
|
84
|
+
}
|
|
85
|
+
return [obj];
|
|
86
|
+
}
|
|
87
|
+
return [{ value: response }];
|
|
88
|
+
}
|
|
89
|
+
async function getAllPages(context, endpoint, limit, search, filters) {
|
|
90
|
+
const aggregated = [];
|
|
91
|
+
let page = 1;
|
|
92
|
+
while (true) {
|
|
93
|
+
const qs = { page, limit, ...(filters || {}) };
|
|
94
|
+
if (search)
|
|
95
|
+
qs.search = search;
|
|
96
|
+
const response = await ninjaPipeApiRequest(context, 'GET', endpoint, undefined, qs);
|
|
97
|
+
const pageItems = extractItems(response);
|
|
98
|
+
aggregated.push(...pageItems);
|
|
99
|
+
if (pageItems.length < limit)
|
|
100
|
+
break;
|
|
101
|
+
page += 1;
|
|
102
|
+
if (page > 1000)
|
|
103
|
+
break;
|
|
104
|
+
}
|
|
105
|
+
return aggregated;
|
|
106
|
+
}
|
|
107
|
+
const genericResourceOptions = [
|
|
108
|
+
{ name: 'Budget', value: 'budget' },
|
|
109
|
+
{ name: 'Company', value: 'company' },
|
|
110
|
+
{ name: 'Contact', value: 'contact' },
|
|
111
|
+
{ name: 'Databin', value: 'databin' },
|
|
112
|
+
{ name: 'Deal', value: 'deal' },
|
|
113
|
+
{ name: 'Invoice', value: 'invoice' },
|
|
114
|
+
{ name: 'List', value: 'list' },
|
|
115
|
+
{ name: 'Order', value: 'order' },
|
|
116
|
+
{ name: 'Pipeline', value: 'pipeline' },
|
|
117
|
+
{ name: 'Pipeline Item', value: 'pipelineItem' },
|
|
118
|
+
{ name: 'Product', value: 'product' },
|
|
119
|
+
{ name: 'Project', value: 'project' },
|
|
120
|
+
{ name: 'Task', value: 'task' },
|
|
121
|
+
];
|
|
122
|
+
const commonCrudOperations = [
|
|
123
|
+
{ name: 'Create', value: 'create', action: 'Create the selected resource' },
|
|
124
|
+
{ name: 'Delete', value: 'delete', action: 'Delete the selected resource' },
|
|
125
|
+
{ name: 'Get', value: 'get', action: 'Get the selected resource' },
|
|
126
|
+
{ name: 'Get Many', value: 'getAll', action: 'Get many records for the selected resource' },
|
|
127
|
+
{ name: 'Update', value: 'update', action: 'Update the selected resource' },
|
|
128
|
+
];
|
|
129
|
+
class NinjaPipe {
|
|
130
|
+
constructor() {
|
|
131
|
+
this.description = {
|
|
132
|
+
displayName: 'NinjaPipe',
|
|
133
|
+
name: 'ninjaPipe',
|
|
134
|
+
icon: 'file:ninjapipe.svg',
|
|
135
|
+
group: ['transform'],
|
|
136
|
+
version: 1,
|
|
137
|
+
subtitle: '={{$parameter["resource"] + " " + $parameter["operation"]}}',
|
|
138
|
+
description: 'Consume the NinjaPipe API',
|
|
139
|
+
defaults: {
|
|
140
|
+
name: 'NinjaPipe',
|
|
141
|
+
},
|
|
142
|
+
inputs: ['main'],
|
|
143
|
+
outputs: ['main'],
|
|
144
|
+
credentials: [
|
|
145
|
+
{
|
|
146
|
+
name: 'ninjaPipeApi',
|
|
147
|
+
required: true,
|
|
148
|
+
},
|
|
149
|
+
],
|
|
150
|
+
properties: [
|
|
151
|
+
{
|
|
152
|
+
displayName: 'Resource',
|
|
153
|
+
name: 'resource',
|
|
154
|
+
type: 'options',
|
|
155
|
+
noDataExpression: true,
|
|
156
|
+
options: [
|
|
157
|
+
...genericResourceOptions,
|
|
158
|
+
{ name: 'Custom API Request', value: 'customRequest' },
|
|
159
|
+
],
|
|
160
|
+
default: 'contact',
|
|
161
|
+
description: 'Covers the publicly documented API areas and a flexible custom request mode',
|
|
162
|
+
},
|
|
163
|
+
{
|
|
164
|
+
displayName: 'Operation',
|
|
165
|
+
name: 'operation',
|
|
166
|
+
type: 'options',
|
|
167
|
+
displayOptions: {
|
|
168
|
+
show: {
|
|
169
|
+
resource: genericResourceOptions.map((option) => option.value),
|
|
170
|
+
},
|
|
171
|
+
},
|
|
172
|
+
options: [
|
|
173
|
+
...commonCrudOperations,
|
|
174
|
+
{ name: 'Create Expense', value: 'createExpense', action: 'Create a budget expense' },
|
|
175
|
+
{ name: 'Enable Client Portal', value: 'enableClientPortal', action: 'Enable the client portal for a contact' },
|
|
176
|
+
{ name: 'Disable Client Portal', value: 'disableClientPortal', action: 'Disable the client portal for a contact' },
|
|
177
|
+
],
|
|
178
|
+
default: 'getAll',
|
|
179
|
+
},
|
|
180
|
+
{
|
|
181
|
+
displayName: 'Operation',
|
|
182
|
+
name: 'operation',
|
|
183
|
+
type: 'options',
|
|
184
|
+
displayOptions: { show: { resource: ['customRequest'] } },
|
|
185
|
+
options: [{ name: 'Execute', value: 'execute', action: 'Execute a custom API request' }],
|
|
186
|
+
default: 'execute',
|
|
187
|
+
},
|
|
188
|
+
{
|
|
189
|
+
displayName: 'Resource Path Override',
|
|
190
|
+
name: 'resourcePathOverride',
|
|
191
|
+
type: 'string',
|
|
192
|
+
default: '',
|
|
193
|
+
displayOptions: {
|
|
194
|
+
show: {
|
|
195
|
+
resource: genericResourceOptions.map((option) => option.value),
|
|
196
|
+
},
|
|
197
|
+
},
|
|
198
|
+
placeholder: '/contacts',
|
|
199
|
+
description: 'Optional custom endpoint path. Leave empty to use the built-in path for the selected resource',
|
|
200
|
+
},
|
|
201
|
+
{
|
|
202
|
+
displayName: 'ID',
|
|
203
|
+
name: 'id',
|
|
204
|
+
type: 'string',
|
|
205
|
+
required: true,
|
|
206
|
+
default: '',
|
|
207
|
+
displayOptions: {
|
|
208
|
+
show: {
|
|
209
|
+
resource: genericResourceOptions.map((option) => option.value),
|
|
210
|
+
operation: ['get', 'update', 'delete', 'enableClientPortal', 'disableClientPortal'],
|
|
211
|
+
},
|
|
212
|
+
},
|
|
213
|
+
},
|
|
214
|
+
{
|
|
215
|
+
displayName: 'Return All',
|
|
216
|
+
name: 'returnAll',
|
|
217
|
+
type: 'boolean',
|
|
218
|
+
default: false,
|
|
219
|
+
displayOptions: {
|
|
220
|
+
show: {
|
|
221
|
+
resource: genericResourceOptions.map((option) => option.value),
|
|
222
|
+
operation: ['getAll'],
|
|
223
|
+
},
|
|
224
|
+
},
|
|
225
|
+
description: 'Whether to return all results by requesting all pages',
|
|
226
|
+
},
|
|
227
|
+
{
|
|
228
|
+
displayName: 'Page',
|
|
229
|
+
name: 'page',
|
|
230
|
+
type: 'number',
|
|
231
|
+
default: 1,
|
|
232
|
+
displayOptions: {
|
|
233
|
+
show: {
|
|
234
|
+
resource: genericResourceOptions.map((option) => option.value),
|
|
235
|
+
operation: ['getAll'],
|
|
236
|
+
returnAll: [false],
|
|
237
|
+
},
|
|
238
|
+
},
|
|
239
|
+
},
|
|
240
|
+
{
|
|
241
|
+
displayName: 'Limit',
|
|
242
|
+
name: 'limit',
|
|
243
|
+
type: 'number',
|
|
244
|
+
default: 20,
|
|
245
|
+
typeOptions: {
|
|
246
|
+
minValue: 1,
|
|
247
|
+
maxValue: 100,
|
|
248
|
+
},
|
|
249
|
+
displayOptions: {
|
|
250
|
+
show: {
|
|
251
|
+
resource: genericResourceOptions.map((option) => option.value),
|
|
252
|
+
operation: ['getAll'],
|
|
253
|
+
},
|
|
254
|
+
},
|
|
255
|
+
description: 'The public docs state a maximum page size of 100',
|
|
256
|
+
},
|
|
257
|
+
{
|
|
258
|
+
displayName: 'Search',
|
|
259
|
+
name: 'search',
|
|
260
|
+
type: 'string',
|
|
261
|
+
default: '',
|
|
262
|
+
displayOptions: {
|
|
263
|
+
show: {
|
|
264
|
+
resource: genericResourceOptions.map((option) => option.value),
|
|
265
|
+
operation: ['getAll'],
|
|
266
|
+
},
|
|
267
|
+
},
|
|
268
|
+
description: 'Optional free-text search string',
|
|
269
|
+
},
|
|
270
|
+
{
|
|
271
|
+
displayName: 'Filters JSON',
|
|
272
|
+
name: 'filters',
|
|
273
|
+
type: 'json',
|
|
274
|
+
default: '{}',
|
|
275
|
+
displayOptions: {
|
|
276
|
+
show: {
|
|
277
|
+
resource: genericResourceOptions.map((option) => option.value),
|
|
278
|
+
operation: ['getAll'],
|
|
279
|
+
},
|
|
280
|
+
},
|
|
281
|
+
description: 'Optional additional query parameters as JSON, for example status, owner, category or date filters',
|
|
282
|
+
},
|
|
283
|
+
{
|
|
284
|
+
displayName: 'Body',
|
|
285
|
+
name: 'body',
|
|
286
|
+
type: 'json',
|
|
287
|
+
default: '{}',
|
|
288
|
+
required: true,
|
|
289
|
+
displayOptions: {
|
|
290
|
+
show: {
|
|
291
|
+
resource: genericResourceOptions.map((option) => option.value),
|
|
292
|
+
operation: ['create', 'update', 'createExpense'],
|
|
293
|
+
},
|
|
294
|
+
},
|
|
295
|
+
description: 'JSON request body passed directly to NinjaPipe',
|
|
296
|
+
},
|
|
297
|
+
{
|
|
298
|
+
displayName: 'Portal Body',
|
|
299
|
+
name: 'portalBody',
|
|
300
|
+
type: 'json',
|
|
301
|
+
default: '{}',
|
|
302
|
+
required: false,
|
|
303
|
+
displayOptions: {
|
|
304
|
+
show: {
|
|
305
|
+
resource: ['contact'],
|
|
306
|
+
operation: ['enableClientPortal', 'disableClientPortal'],
|
|
307
|
+
},
|
|
308
|
+
},
|
|
309
|
+
description: 'Optional JSON body for the client portal action',
|
|
310
|
+
},
|
|
311
|
+
{
|
|
312
|
+
displayName: 'Method',
|
|
313
|
+
name: 'customMethod',
|
|
314
|
+
type: 'options',
|
|
315
|
+
displayOptions: { show: { resource: ['customRequest'], operation: ['execute'] } },
|
|
316
|
+
options: [
|
|
317
|
+
{ name: 'DELETE', value: 'DELETE' },
|
|
318
|
+
{ name: 'GET', value: 'GET' },
|
|
319
|
+
{ name: 'PATCH', value: 'PATCH' },
|
|
320
|
+
{ name: 'POST', value: 'POST' },
|
|
321
|
+
{ name: 'PUT', value: 'PUT' },
|
|
322
|
+
],
|
|
323
|
+
default: 'GET',
|
|
324
|
+
},
|
|
325
|
+
{
|
|
326
|
+
displayName: 'Path',
|
|
327
|
+
name: 'customPath',
|
|
328
|
+
type: 'string',
|
|
329
|
+
displayOptions: { show: { resource: ['customRequest'], operation: ['execute'] } },
|
|
330
|
+
default: '/contacts',
|
|
331
|
+
description: 'API path relative to the Base URL',
|
|
332
|
+
},
|
|
333
|
+
{
|
|
334
|
+
displayName: 'Query Parameters',
|
|
335
|
+
name: 'customQuery',
|
|
336
|
+
type: 'json',
|
|
337
|
+
displayOptions: { show: { resource: ['customRequest'], operation: ['execute'] } },
|
|
338
|
+
default: '{}',
|
|
339
|
+
},
|
|
340
|
+
{
|
|
341
|
+
displayName: 'Request Body',
|
|
342
|
+
name: 'customBody',
|
|
343
|
+
type: 'json',
|
|
344
|
+
displayOptions: { show: { resource: ['customRequest'], operation: ['execute'] } },
|
|
345
|
+
default: '{}',
|
|
346
|
+
},
|
|
347
|
+
],
|
|
348
|
+
};
|
|
349
|
+
}
|
|
350
|
+
async execute() {
|
|
351
|
+
const items = this.getInputData();
|
|
352
|
+
const returnData = [];
|
|
353
|
+
for (let i = 0; i < items.length; i++) {
|
|
354
|
+
try {
|
|
355
|
+
const resource = this.getNodeParameter('resource', i);
|
|
356
|
+
const operation = this.getNodeParameter('operation', i);
|
|
357
|
+
let responseData;
|
|
358
|
+
if (resource === 'customRequest') {
|
|
359
|
+
const method = this.getNodeParameter('customMethod', i);
|
|
360
|
+
const path = normalizePath(this.getNodeParameter('customPath', i));
|
|
361
|
+
const qs = parseJsonParameter(this, 'customQuery', i);
|
|
362
|
+
const body = ['GET', 'DELETE'].includes(method) ? undefined : parseJsonParameter(this, 'customBody', i);
|
|
363
|
+
responseData = await ninjaPipeApiRequest(this, method, path, body, qs);
|
|
364
|
+
}
|
|
365
|
+
else {
|
|
366
|
+
const resourcePathOverride = this.getNodeParameter('resourcePathOverride', i, '');
|
|
367
|
+
const basePath = getResourcePath(resource, resourcePathOverride);
|
|
368
|
+
if (operation === 'create') {
|
|
369
|
+
responseData = await ninjaPipeApiRequest(this, 'POST', basePath, parseJsonParameter(this, 'body', i));
|
|
370
|
+
}
|
|
371
|
+
else if (operation === 'get') {
|
|
372
|
+
const id = this.getNodeParameter('id', i);
|
|
373
|
+
responseData = await ninjaPipeApiRequest(this, 'GET', `${basePath}/${id}`);
|
|
374
|
+
}
|
|
375
|
+
else if (operation === 'getAll') {
|
|
376
|
+
const limit = this.getNodeParameter('limit', i);
|
|
377
|
+
const search = this.getNodeParameter('search', i, '');
|
|
378
|
+
const filters = parseJsonParameter(this, 'filters', i);
|
|
379
|
+
const returnAll = this.getNodeParameter('returnAll', i, false);
|
|
380
|
+
if (returnAll) {
|
|
381
|
+
responseData = await getAllPages(this, basePath, limit, search, filters);
|
|
382
|
+
}
|
|
383
|
+
else {
|
|
384
|
+
const page = this.getNodeParameter('page', i);
|
|
385
|
+
const qs = { page, limit, ...(filters || {}) };
|
|
386
|
+
if (search)
|
|
387
|
+
qs.search = search;
|
|
388
|
+
responseData = await ninjaPipeApiRequest(this, 'GET', basePath, undefined, qs);
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
else if (operation === 'update') {
|
|
392
|
+
const id = this.getNodeParameter('id', i);
|
|
393
|
+
responseData = await ninjaPipeApiRequest(this, 'PUT', `${basePath}/${id}`, parseJsonParameter(this, 'body', i));
|
|
394
|
+
}
|
|
395
|
+
else if (operation === 'delete') {
|
|
396
|
+
const id = this.getNodeParameter('id', i);
|
|
397
|
+
responseData = await ninjaPipeApiRequest(this, 'DELETE', `${basePath}/${id}`);
|
|
398
|
+
}
|
|
399
|
+
else if (operation === 'createExpense') {
|
|
400
|
+
if (resource !== 'budget') {
|
|
401
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Create Expense is only supported for the Budget resource', { itemIndex: i });
|
|
402
|
+
}
|
|
403
|
+
const id = this.getNodeParameter('id', i);
|
|
404
|
+
responseData = await ninjaPipeApiRequest(this, 'POST', `${basePath}/${id}/expenses`, parseJsonParameter(this, 'body', i));
|
|
405
|
+
}
|
|
406
|
+
else if (operation === 'enableClientPortal') {
|
|
407
|
+
if (resource !== 'contact') {
|
|
408
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Enable Client Portal is only supported for the Contact resource', { itemIndex: i });
|
|
409
|
+
}
|
|
410
|
+
const id = this.getNodeParameter('id', i);
|
|
411
|
+
responseData = await ninjaPipeApiRequest(this, 'PUT', `${basePath}/${id}/enable-client-portal`, parseJsonParameter(this, 'portalBody', i));
|
|
412
|
+
}
|
|
413
|
+
else if (operation === 'disableClientPortal') {
|
|
414
|
+
if (resource !== 'contact') {
|
|
415
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Disable Client Portal is only supported for the Contact resource', { itemIndex: i });
|
|
416
|
+
}
|
|
417
|
+
const id = this.getNodeParameter('id', i);
|
|
418
|
+
responseData = await ninjaPipeApiRequest(this, 'PUT', `${basePath}/${id}/disable-client-portal`, parseJsonParameter(this, 'portalBody', i));
|
|
419
|
+
}
|
|
420
|
+
else {
|
|
421
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Unsupported operation: ${operation}`, { itemIndex: i });
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
const responseItems = extractItems(responseData);
|
|
425
|
+
for (const entry of responseItems) {
|
|
426
|
+
returnData.push({ json: entry });
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
catch (error) {
|
|
430
|
+
if (this.continueOnFail()) {
|
|
431
|
+
returnData.push({ json: { error: error.message }, pairedItem: i });
|
|
432
|
+
continue;
|
|
433
|
+
}
|
|
434
|
+
throw error;
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
return [returnData];
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
exports.NinjaPipe = NinjaPipe;
|
|
441
|
+
//# sourceMappingURL=NinjaPipe.node.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NinjaPipe.node.js","sourceRoot":"","sources":["../../../nodes/NinjaPipe/NinjaPipe.node.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
<svg width="120" height="120" viewBox="0 0 120 120" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<rect width="120" height="120" rx="24" fill="#111111"/>
|
|
3
|
+
<path d="M27 88V32H37L64 69V32H75V88H65L38 51V88H27Z" fill="white"/>
|
|
4
|
+
<path d="M84 88V32H93C101.837 32 109 39.1634 109 48C109 56.8366 101.837 64 93 64H89V88H84ZM89 59H93C99.0751 59 104 54.0751 104 48C104 41.9249 99.0751 37 93 37H89V59Z" fill="white"/>
|
|
5
|
+
</svg>
|
|
@@ -0,0 +1,484 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
IDataObject,
|
|
3
|
+
IExecuteFunctions,
|
|
4
|
+
ILoadOptionsFunctions,
|
|
5
|
+
INodeExecutionData,
|
|
6
|
+
INodeProperties,
|
|
7
|
+
INodeType,
|
|
8
|
+
INodeTypeDescription,
|
|
9
|
+
JsonObject,
|
|
10
|
+
IHttpRequestMethods,
|
|
11
|
+
} from 'n8n-workflow';
|
|
12
|
+
import { NodeApiError, NodeOperationError } from 'n8n-workflow';
|
|
13
|
+
|
|
14
|
+
type Resource =
|
|
15
|
+
| 'contact'
|
|
16
|
+
| 'company'
|
|
17
|
+
| 'deal'
|
|
18
|
+
| 'product'
|
|
19
|
+
| 'budget'
|
|
20
|
+
| 'list'
|
|
21
|
+
| 'pipeline'
|
|
22
|
+
| 'pipelineItem'
|
|
23
|
+
| 'invoice'
|
|
24
|
+
| 'order'
|
|
25
|
+
| 'project'
|
|
26
|
+
| 'task'
|
|
27
|
+
| 'databin'
|
|
28
|
+
| 'customRequest';
|
|
29
|
+
|
|
30
|
+
type Operation =
|
|
31
|
+
| 'create'
|
|
32
|
+
| 'get'
|
|
33
|
+
| 'getAll'
|
|
34
|
+
| 'update'
|
|
35
|
+
| 'delete'
|
|
36
|
+
| 'createExpense'
|
|
37
|
+
| 'enableClientPortal'
|
|
38
|
+
| 'disableClientPortal'
|
|
39
|
+
| 'execute';
|
|
40
|
+
|
|
41
|
+
const resourceConfig: Record<Exclude<Resource, 'customRequest'>, { path: string; supportsCrud: boolean }> = {
|
|
42
|
+
contact: { path: 'contacts', supportsCrud: true },
|
|
43
|
+
company: { path: 'companies', supportsCrud: true },
|
|
44
|
+
deal: { path: 'deals', supportsCrud: true },
|
|
45
|
+
product: { path: 'products', supportsCrud: true },
|
|
46
|
+
budget: { path: 'budgets', supportsCrud: true },
|
|
47
|
+
list: { path: 'lists', supportsCrud: true },
|
|
48
|
+
pipeline: { path: 'pipelines', supportsCrud: true },
|
|
49
|
+
pipelineItem: { path: 'pipeline-items', supportsCrud: true },
|
|
50
|
+
invoice: { path: 'invoices', supportsCrud: true },
|
|
51
|
+
order: { path: 'orders', supportsCrud: true },
|
|
52
|
+
project: { path: 'projects', supportsCrud: true },
|
|
53
|
+
task: { path: 'tasks', supportsCrud: true },
|
|
54
|
+
databin: { path: 'databins', supportsCrud: true },
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
async function ninjaPipeApiRequest(
|
|
58
|
+
context: IExecuteFunctions | ILoadOptionsFunctions,
|
|
59
|
+
method: IHttpRequestMethods,
|
|
60
|
+
endpoint: string,
|
|
61
|
+
body?: IDataObject,
|
|
62
|
+
qs?: IDataObject,
|
|
63
|
+
) {
|
|
64
|
+
const credentials = await context.getCredentials('ninjaPipeApi');
|
|
65
|
+
const baseUrl = String(credentials.baseUrl || '').replace(/\/+$/, '');
|
|
66
|
+
const apiKey = String(credentials.apiKey || '');
|
|
67
|
+
|
|
68
|
+
if (!baseUrl) {
|
|
69
|
+
throw new NodeOperationError(context.getNode(), 'Missing NinjaPipe base URL in credentials');
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (!apiKey) {
|
|
73
|
+
throw new NodeOperationError(context.getNode(), 'Missing NinjaPipe API key in credentials');
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
try {
|
|
77
|
+
return await context.helpers.httpRequest({
|
|
78
|
+
method,
|
|
79
|
+
url: `${baseUrl}${endpoint}`,
|
|
80
|
+
headers: {
|
|
81
|
+
Authorization: `Bearer ${apiKey}`,
|
|
82
|
+
Accept: 'application/json',
|
|
83
|
+
'Content-Type': 'application/json',
|
|
84
|
+
},
|
|
85
|
+
body,
|
|
86
|
+
qs,
|
|
87
|
+
json: true,
|
|
88
|
+
});
|
|
89
|
+
} catch (error) {
|
|
90
|
+
throw new NodeApiError(context.getNode(), error as JsonObject);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function parseJsonParameter(context: IExecuteFunctions, name: string, itemIndex: number): IDataObject {
|
|
95
|
+
const rawValue = context.getNodeParameter(name, itemIndex) as string | IDataObject;
|
|
96
|
+
if (typeof rawValue !== 'string') return rawValue as IDataObject;
|
|
97
|
+
if (!rawValue || rawValue.trim() === '') return {};
|
|
98
|
+
try {
|
|
99
|
+
return JSON.parse(rawValue) as IDataObject;
|
|
100
|
+
} catch (error) {
|
|
101
|
+
throw new NodeOperationError(context.getNode(), `Invalid JSON in field \"${name}\": ${(error as Error).message}`, {
|
|
102
|
+
itemIndex,
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function normalizePath(path: string): string {
|
|
108
|
+
const trimmed = path.trim();
|
|
109
|
+
if (!trimmed) return '';
|
|
110
|
+
return trimmed.startsWith('/') ? trimmed : `/${trimmed}`;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function getResourcePath(resource: Exclude<Resource, 'customRequest'>, overridePath?: string): string {
|
|
114
|
+
if (overridePath && overridePath.trim()) {
|
|
115
|
+
return normalizePath(overridePath);
|
|
116
|
+
}
|
|
117
|
+
return `/${resourceConfig[resource].path}`;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function extractItems(response: unknown): IDataObject[] {
|
|
121
|
+
if (Array.isArray(response)) return response as IDataObject[];
|
|
122
|
+
if (response && typeof response === 'object') {
|
|
123
|
+
const obj = response as IDataObject;
|
|
124
|
+
for (const key of ['data', 'items', 'results', 'contacts', 'deals', 'products', 'budgets']) {
|
|
125
|
+
const value = obj[key];
|
|
126
|
+
if (Array.isArray(value)) return value as IDataObject[];
|
|
127
|
+
}
|
|
128
|
+
return [obj];
|
|
129
|
+
}
|
|
130
|
+
return [{ value: response } as IDataObject];
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
async function getAllPages(
|
|
134
|
+
context: IExecuteFunctions,
|
|
135
|
+
endpoint: string,
|
|
136
|
+
limit: number,
|
|
137
|
+
search: string,
|
|
138
|
+
filters: IDataObject,
|
|
139
|
+
): Promise<IDataObject[]> {
|
|
140
|
+
const aggregated: IDataObject[] = [];
|
|
141
|
+
let page = 1;
|
|
142
|
+
|
|
143
|
+
while (true) {
|
|
144
|
+
const qs: IDataObject = { page, limit, ...(filters || {}) };
|
|
145
|
+
if (search) qs.search = search;
|
|
146
|
+
const response = await ninjaPipeApiRequest(context, 'GET', endpoint, undefined, qs);
|
|
147
|
+
const pageItems = extractItems(response);
|
|
148
|
+
aggregated.push(...pageItems);
|
|
149
|
+
if (pageItems.length < limit) break;
|
|
150
|
+
page += 1;
|
|
151
|
+
if (page > 1000) break;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
return aggregated;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const genericResourceOptions = [
|
|
158
|
+
{ name: 'Budget', value: 'budget' },
|
|
159
|
+
{ name: 'Company', value: 'company' },
|
|
160
|
+
{ name: 'Contact', value: 'contact' },
|
|
161
|
+
{ name: 'Databin', value: 'databin' },
|
|
162
|
+
{ name: 'Deal', value: 'deal' },
|
|
163
|
+
{ name: 'Invoice', value: 'invoice' },
|
|
164
|
+
{ name: 'List', value: 'list' },
|
|
165
|
+
{ name: 'Order', value: 'order' },
|
|
166
|
+
{ name: 'Pipeline', value: 'pipeline' },
|
|
167
|
+
{ name: 'Pipeline Item', value: 'pipelineItem' },
|
|
168
|
+
{ name: 'Product', value: 'product' },
|
|
169
|
+
{ name: 'Project', value: 'project' },
|
|
170
|
+
{ name: 'Task', value: 'task' },
|
|
171
|
+
] as const;
|
|
172
|
+
|
|
173
|
+
const commonCrudOperations = [
|
|
174
|
+
{ name: 'Create', value: 'create', action: 'Create the selected resource' },
|
|
175
|
+
{ name: 'Delete', value: 'delete', action: 'Delete the selected resource' },
|
|
176
|
+
{ name: 'Get', value: 'get', action: 'Get the selected resource' },
|
|
177
|
+
{ name: 'Get Many', value: 'getAll', action: 'Get many records for the selected resource' },
|
|
178
|
+
{ name: 'Update', value: 'update', action: 'Update the selected resource' },
|
|
179
|
+
];
|
|
180
|
+
|
|
181
|
+
export class NinjaPipe implements INodeType {
|
|
182
|
+
description: INodeTypeDescription = {
|
|
183
|
+
displayName: 'NinjaPipe',
|
|
184
|
+
name: 'ninjaPipe',
|
|
185
|
+
icon: 'file:ninjapipe.svg',
|
|
186
|
+
group: ['transform'],
|
|
187
|
+
version: 1,
|
|
188
|
+
subtitle: '={{$parameter["resource"] + " " + $parameter["operation"]}}',
|
|
189
|
+
description: 'Consume the NinjaPipe API',
|
|
190
|
+
defaults: {
|
|
191
|
+
name: 'NinjaPipe',
|
|
192
|
+
},
|
|
193
|
+
inputs: ['main'],
|
|
194
|
+
outputs: ['main'],
|
|
195
|
+
credentials: [
|
|
196
|
+
{
|
|
197
|
+
name: 'ninjaPipeApi',
|
|
198
|
+
required: true,
|
|
199
|
+
},
|
|
200
|
+
],
|
|
201
|
+
properties: [
|
|
202
|
+
{
|
|
203
|
+
displayName: 'Resource',
|
|
204
|
+
name: 'resource',
|
|
205
|
+
type: 'options',
|
|
206
|
+
noDataExpression: true,
|
|
207
|
+
options: [
|
|
208
|
+
...genericResourceOptions,
|
|
209
|
+
{ name: 'Custom API Request', value: 'customRequest' },
|
|
210
|
+
],
|
|
211
|
+
default: 'contact',
|
|
212
|
+
description: 'Covers the publicly documented API areas and a flexible custom request mode',
|
|
213
|
+
},
|
|
214
|
+
{
|
|
215
|
+
displayName: 'Operation',
|
|
216
|
+
name: 'operation',
|
|
217
|
+
type: 'options',
|
|
218
|
+
displayOptions: {
|
|
219
|
+
show: {
|
|
220
|
+
resource: genericResourceOptions.map((option) => option.value),
|
|
221
|
+
},
|
|
222
|
+
},
|
|
223
|
+
options: [
|
|
224
|
+
...commonCrudOperations,
|
|
225
|
+
{ name: 'Create Expense', value: 'createExpense', action: 'Create a budget expense' },
|
|
226
|
+
{ name: 'Enable Client Portal', value: 'enableClientPortal', action: 'Enable the client portal for a contact' },
|
|
227
|
+
{ name: 'Disable Client Portal', value: 'disableClientPortal', action: 'Disable the client portal for a contact' },
|
|
228
|
+
],
|
|
229
|
+
default: 'getAll',
|
|
230
|
+
},
|
|
231
|
+
{
|
|
232
|
+
displayName: 'Operation',
|
|
233
|
+
name: 'operation',
|
|
234
|
+
type: 'options',
|
|
235
|
+
displayOptions: { show: { resource: ['customRequest'] } },
|
|
236
|
+
options: [{ name: 'Execute', value: 'execute', action: 'Execute a custom API request' }],
|
|
237
|
+
default: 'execute',
|
|
238
|
+
},
|
|
239
|
+
{
|
|
240
|
+
displayName: 'Resource Path Override',
|
|
241
|
+
name: 'resourcePathOverride',
|
|
242
|
+
type: 'string',
|
|
243
|
+
default: '',
|
|
244
|
+
displayOptions: {
|
|
245
|
+
show: {
|
|
246
|
+
resource: genericResourceOptions.map((option) => option.value),
|
|
247
|
+
},
|
|
248
|
+
},
|
|
249
|
+
placeholder: '/contacts',
|
|
250
|
+
description: 'Optional custom endpoint path. Leave empty to use the built-in path for the selected resource',
|
|
251
|
+
},
|
|
252
|
+
{
|
|
253
|
+
displayName: 'ID',
|
|
254
|
+
name: 'id',
|
|
255
|
+
type: 'string',
|
|
256
|
+
required: true,
|
|
257
|
+
default: '',
|
|
258
|
+
displayOptions: {
|
|
259
|
+
show: {
|
|
260
|
+
resource: genericResourceOptions.map((option) => option.value),
|
|
261
|
+
operation: ['get', 'update', 'delete', 'enableClientPortal', 'disableClientPortal'],
|
|
262
|
+
},
|
|
263
|
+
},
|
|
264
|
+
},
|
|
265
|
+
{
|
|
266
|
+
displayName: 'Return All',
|
|
267
|
+
name: 'returnAll',
|
|
268
|
+
type: 'boolean',
|
|
269
|
+
default: false,
|
|
270
|
+
displayOptions: {
|
|
271
|
+
show: {
|
|
272
|
+
resource: genericResourceOptions.map((option) => option.value),
|
|
273
|
+
operation: ['getAll'],
|
|
274
|
+
},
|
|
275
|
+
},
|
|
276
|
+
description: 'Whether to return all results by requesting all pages',
|
|
277
|
+
},
|
|
278
|
+
{
|
|
279
|
+
displayName: 'Page',
|
|
280
|
+
name: 'page',
|
|
281
|
+
type: 'number',
|
|
282
|
+
default: 1,
|
|
283
|
+
displayOptions: {
|
|
284
|
+
show: {
|
|
285
|
+
resource: genericResourceOptions.map((option) => option.value),
|
|
286
|
+
operation: ['getAll'],
|
|
287
|
+
returnAll: [false],
|
|
288
|
+
},
|
|
289
|
+
},
|
|
290
|
+
},
|
|
291
|
+
{
|
|
292
|
+
displayName: 'Limit',
|
|
293
|
+
name: 'limit',
|
|
294
|
+
type: 'number',
|
|
295
|
+
default: 20,
|
|
296
|
+
typeOptions: {
|
|
297
|
+
minValue: 1,
|
|
298
|
+
maxValue: 100,
|
|
299
|
+
},
|
|
300
|
+
displayOptions: {
|
|
301
|
+
show: {
|
|
302
|
+
resource: genericResourceOptions.map((option) => option.value),
|
|
303
|
+
operation: ['getAll'],
|
|
304
|
+
},
|
|
305
|
+
},
|
|
306
|
+
description: 'The public docs state a maximum page size of 100',
|
|
307
|
+
},
|
|
308
|
+
{
|
|
309
|
+
displayName: 'Search',
|
|
310
|
+
name: 'search',
|
|
311
|
+
type: 'string',
|
|
312
|
+
default: '',
|
|
313
|
+
displayOptions: {
|
|
314
|
+
show: {
|
|
315
|
+
resource: genericResourceOptions.map((option) => option.value),
|
|
316
|
+
operation: ['getAll'],
|
|
317
|
+
},
|
|
318
|
+
},
|
|
319
|
+
description: 'Optional free-text search string',
|
|
320
|
+
},
|
|
321
|
+
{
|
|
322
|
+
displayName: 'Filters JSON',
|
|
323
|
+
name: 'filters',
|
|
324
|
+
type: 'json',
|
|
325
|
+
default: '{}',
|
|
326
|
+
displayOptions: {
|
|
327
|
+
show: {
|
|
328
|
+
resource: genericResourceOptions.map((option) => option.value),
|
|
329
|
+
operation: ['getAll'],
|
|
330
|
+
},
|
|
331
|
+
},
|
|
332
|
+
description: 'Optional additional query parameters as JSON, for example status, owner, category or date filters',
|
|
333
|
+
},
|
|
334
|
+
{
|
|
335
|
+
displayName: 'Body',
|
|
336
|
+
name: 'body',
|
|
337
|
+
type: 'json',
|
|
338
|
+
default: '{}',
|
|
339
|
+
required: true,
|
|
340
|
+
displayOptions: {
|
|
341
|
+
show: {
|
|
342
|
+
resource: genericResourceOptions.map((option) => option.value),
|
|
343
|
+
operation: ['create', 'update', 'createExpense'],
|
|
344
|
+
},
|
|
345
|
+
},
|
|
346
|
+
description: 'JSON request body passed directly to NinjaPipe',
|
|
347
|
+
},
|
|
348
|
+
{
|
|
349
|
+
displayName: 'Portal Body',
|
|
350
|
+
name: 'portalBody',
|
|
351
|
+
type: 'json',
|
|
352
|
+
default: '{}',
|
|
353
|
+
required: false,
|
|
354
|
+
displayOptions: {
|
|
355
|
+
show: {
|
|
356
|
+
resource: ['contact'],
|
|
357
|
+
operation: ['enableClientPortal', 'disableClientPortal'],
|
|
358
|
+
},
|
|
359
|
+
},
|
|
360
|
+
description: 'Optional JSON body for the client portal action',
|
|
361
|
+
},
|
|
362
|
+
{
|
|
363
|
+
displayName: 'Method',
|
|
364
|
+
name: 'customMethod',
|
|
365
|
+
type: 'options',
|
|
366
|
+
displayOptions: { show: { resource: ['customRequest'], operation: ['execute'] } },
|
|
367
|
+
options: [
|
|
368
|
+
{ name: 'DELETE', value: 'DELETE' },
|
|
369
|
+
{ name: 'GET', value: 'GET' },
|
|
370
|
+
{ name: 'PATCH', value: 'PATCH' },
|
|
371
|
+
{ name: 'POST', value: 'POST' },
|
|
372
|
+
{ name: 'PUT', value: 'PUT' },
|
|
373
|
+
],
|
|
374
|
+
default: 'GET',
|
|
375
|
+
},
|
|
376
|
+
{
|
|
377
|
+
displayName: 'Path',
|
|
378
|
+
name: 'customPath',
|
|
379
|
+
type: 'string',
|
|
380
|
+
displayOptions: { show: { resource: ['customRequest'], operation: ['execute'] } },
|
|
381
|
+
default: '/contacts',
|
|
382
|
+
description: 'API path relative to the Base URL',
|
|
383
|
+
},
|
|
384
|
+
{
|
|
385
|
+
displayName: 'Query Parameters',
|
|
386
|
+
name: 'customQuery',
|
|
387
|
+
type: 'json',
|
|
388
|
+
displayOptions: { show: { resource: ['customRequest'], operation: ['execute'] } },
|
|
389
|
+
default: '{}',
|
|
390
|
+
},
|
|
391
|
+
{
|
|
392
|
+
displayName: 'Request Body',
|
|
393
|
+
name: 'customBody',
|
|
394
|
+
type: 'json',
|
|
395
|
+
displayOptions: { show: { resource: ['customRequest'], operation: ['execute'] } },
|
|
396
|
+
default: '{}',
|
|
397
|
+
},
|
|
398
|
+
] as INodeProperties[],
|
|
399
|
+
};
|
|
400
|
+
|
|
401
|
+
async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
|
|
402
|
+
const items = this.getInputData();
|
|
403
|
+
const returnData: INodeExecutionData[] = [];
|
|
404
|
+
|
|
405
|
+
for (let i = 0; i < items.length; i++) {
|
|
406
|
+
try {
|
|
407
|
+
const resource = this.getNodeParameter('resource', i) as Resource;
|
|
408
|
+
const operation = this.getNodeParameter('operation', i) as Operation;
|
|
409
|
+
let responseData: unknown;
|
|
410
|
+
|
|
411
|
+
if (resource === 'customRequest') {
|
|
412
|
+
const method = this.getNodeParameter('customMethod', i) as IHttpRequestMethods;
|
|
413
|
+
const path = normalizePath(this.getNodeParameter('customPath', i) as string);
|
|
414
|
+
const qs = parseJsonParameter(this, 'customQuery', i);
|
|
415
|
+
const body = ['GET', 'DELETE'].includes(method) ? undefined : parseJsonParameter(this, 'customBody', i);
|
|
416
|
+
responseData = await ninjaPipeApiRequest(this, method, path, body, qs);
|
|
417
|
+
} else {
|
|
418
|
+
const resourcePathOverride = this.getNodeParameter('resourcePathOverride', i, '') as string;
|
|
419
|
+
const basePath = getResourcePath(resource, resourcePathOverride);
|
|
420
|
+
|
|
421
|
+
if (operation === 'create') {
|
|
422
|
+
responseData = await ninjaPipeApiRequest(this, 'POST', basePath, parseJsonParameter(this, 'body', i));
|
|
423
|
+
} else if (operation === 'get') {
|
|
424
|
+
const id = this.getNodeParameter('id', i) as string;
|
|
425
|
+
responseData = await ninjaPipeApiRequest(this, 'GET', `${basePath}/${id}`);
|
|
426
|
+
} else if (operation === 'getAll') {
|
|
427
|
+
const limit = this.getNodeParameter('limit', i) as number;
|
|
428
|
+
const search = this.getNodeParameter('search', i, '') as string;
|
|
429
|
+
const filters = parseJsonParameter(this, 'filters', i);
|
|
430
|
+
const returnAll = this.getNodeParameter('returnAll', i, false) as boolean;
|
|
431
|
+
|
|
432
|
+
if (returnAll) {
|
|
433
|
+
responseData = await getAllPages(this, basePath, limit, search, filters);
|
|
434
|
+
} else {
|
|
435
|
+
const page = this.getNodeParameter('page', i) as number;
|
|
436
|
+
const qs: IDataObject = { page, limit, ...(filters || {}) };
|
|
437
|
+
if (search) qs.search = search;
|
|
438
|
+
responseData = await ninjaPipeApiRequest(this, 'GET', basePath, undefined, qs);
|
|
439
|
+
}
|
|
440
|
+
} else if (operation === 'update') {
|
|
441
|
+
const id = this.getNodeParameter('id', i) as string;
|
|
442
|
+
responseData = await ninjaPipeApiRequest(this, 'PUT', `${basePath}/${id}`, parseJsonParameter(this, 'body', i));
|
|
443
|
+
} else if (operation === 'delete') {
|
|
444
|
+
const id = this.getNodeParameter('id', i) as string;
|
|
445
|
+
responseData = await ninjaPipeApiRequest(this, 'DELETE', `${basePath}/${id}`);
|
|
446
|
+
} else if (operation === 'createExpense') {
|
|
447
|
+
if (resource !== 'budget') {
|
|
448
|
+
throw new NodeOperationError(this.getNode(), 'Create Expense is only supported for the Budget resource', { itemIndex: i });
|
|
449
|
+
}
|
|
450
|
+
const id = this.getNodeParameter('id', i) as string;
|
|
451
|
+
responseData = await ninjaPipeApiRequest(this, 'POST', `${basePath}/${id}/expenses`, parseJsonParameter(this, 'body', i));
|
|
452
|
+
} else if (operation === 'enableClientPortal') {
|
|
453
|
+
if (resource !== 'contact') {
|
|
454
|
+
throw new NodeOperationError(this.getNode(), 'Enable Client Portal is only supported for the Contact resource', { itemIndex: i });
|
|
455
|
+
}
|
|
456
|
+
const id = this.getNodeParameter('id', i) as string;
|
|
457
|
+
responseData = await ninjaPipeApiRequest(this, 'PUT', `${basePath}/${id}/enable-client-portal`, parseJsonParameter(this, 'portalBody', i));
|
|
458
|
+
} else if (operation === 'disableClientPortal') {
|
|
459
|
+
if (resource !== 'contact') {
|
|
460
|
+
throw new NodeOperationError(this.getNode(), 'Disable Client Portal is only supported for the Contact resource', { itemIndex: i });
|
|
461
|
+
}
|
|
462
|
+
const id = this.getNodeParameter('id', i) as string;
|
|
463
|
+
responseData = await ninjaPipeApiRequest(this, 'PUT', `${basePath}/${id}/disable-client-portal`, parseJsonParameter(this, 'portalBody', i));
|
|
464
|
+
} else {
|
|
465
|
+
throw new NodeOperationError(this.getNode(), `Unsupported operation: ${operation}`, { itemIndex: i });
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
const responseItems = extractItems(responseData);
|
|
470
|
+
for (const entry of responseItems) {
|
|
471
|
+
returnData.push({ json: entry });
|
|
472
|
+
}
|
|
473
|
+
} catch (error) {
|
|
474
|
+
if (this.continueOnFail()) {
|
|
475
|
+
returnData.push({ json: { error: (error as Error).message }, pairedItem: i });
|
|
476
|
+
continue;
|
|
477
|
+
}
|
|
478
|
+
throw error;
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
return [returnData];
|
|
483
|
+
}
|
|
484
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
<svg width="120" height="120" viewBox="0 0 120 120" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<rect width="120" height="120" rx="24" fill="#111111"/>
|
|
3
|
+
<path d="M27 88V32H37L64 69V32H75V88H65L38 51V88H27Z" fill="white"/>
|
|
4
|
+
<path d="M84 88V32H93C101.837 32 109 39.1634 109 48C109 56.8366 101.837 64 93 64H89V88H84ZM89 59H93C99.0751 59 104 54.0751 104 48C104 41.9249 99.0751 37 93 37H89V59Z" fill="white"/>
|
|
5
|
+
</svg>
|
package/package.json
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@hemmilicious/n8n-nodes-ninjapipe",
|
|
3
|
+
"version": "0.2.2",
|
|
4
|
+
"description": "NinjaPipe community node for n8n",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"n8n-community-node-package",
|
|
7
|
+
"n8n",
|
|
8
|
+
"ninjapipe",
|
|
9
|
+
"crm",
|
|
10
|
+
"automation"
|
|
11
|
+
],
|
|
12
|
+
"license": "MIT",
|
|
13
|
+
"homepage": "https://github.com/hemmilicious/n8n-nodes-ninjapipe",
|
|
14
|
+
"author": {
|
|
15
|
+
"name": "Michael Hemmersbach"
|
|
16
|
+
},
|
|
17
|
+
"repository": {
|
|
18
|
+
"type": "git",
|
|
19
|
+
"url": "https://github.com/hemmilicious/n8n-nodes-ninjapipe.git"
|
|
20
|
+
},
|
|
21
|
+
"publishConfig": {
|
|
22
|
+
"access": "public"
|
|
23
|
+
},
|
|
24
|
+
"main": "index.js",
|
|
25
|
+
"files": [
|
|
26
|
+
"credentials",
|
|
27
|
+
"dist",
|
|
28
|
+
"nodes",
|
|
29
|
+
"README.md",
|
|
30
|
+
"INSTALL.md"
|
|
31
|
+
],
|
|
32
|
+
"scripts": {
|
|
33
|
+
"build": "tsc && gulp build:icons",
|
|
34
|
+
"dev": "n8n-node dev",
|
|
35
|
+
"lint": "eslint nodes credentials package.json",
|
|
36
|
+
"prepublishOnly": "npm run build"
|
|
37
|
+
},
|
|
38
|
+
"n8n": {
|
|
39
|
+
"n8nNodesApiVersion": 1,
|
|
40
|
+
"credentials": [
|
|
41
|
+
"dist/credentials/NinjaPipeApi.credentials.js"
|
|
42
|
+
],
|
|
43
|
+
"nodes": [
|
|
44
|
+
"dist/nodes/NinjaPipe/NinjaPipe.node.js"
|
|
45
|
+
]
|
|
46
|
+
},
|
|
47
|
+
"devDependencies": {
|
|
48
|
+
"@n8n/node-cli": "^0.8.0",
|
|
49
|
+
"@types/node": "^20.17.0",
|
|
50
|
+
"eslint": "^9.0.0",
|
|
51
|
+
"gulp": "^5.0.0",
|
|
52
|
+
"n8n-workflow": "^1.82.0",
|
|
53
|
+
"typescript": "^5.6.3"
|
|
54
|
+
},
|
|
55
|
+
"peerDependencies": {
|
|
56
|
+
"n8n-workflow": "*"
|
|
57
|
+
}
|
|
58
|
+
}
|