n8n-nodes-ninjapipe 0.1.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,48 @@
1
+ # n8n-nodes-ninjapipe
2
+
3
+ Community node for NinjaPipe.
4
+
5
+ ## Included
6
+
7
+ - NinjaPipe API credentials
8
+ - Resources:
9
+ - Contacts
10
+ - Deals
11
+ - Products
12
+ - Budgets
13
+ - Custom API Request
14
+
15
+ ## Current scope
16
+
17
+ This package is built from the public NinjaPipe API documentation that clearly exposes authentication with Bearer API keys, a `/api/...` base path, contacts, deals, products, budgets, pagination, and client-portal actions. Anything beyond that should be added once the endpoint contract is verified in the docs.
18
+
19
+ ## Install locally
20
+
21
+ ```bash
22
+ npm install
23
+ npm run build
24
+ npm link
25
+ ```
26
+
27
+ In your n8n custom extensions folder, link or install the package and restart n8n.
28
+
29
+ ## Credentials
30
+
31
+ - API Key
32
+ - Base URL, default: `https://www.ninjapipe.app/api`
33
+
34
+ ## Notes
35
+
36
+ - Pagination defaults to page 1 and limit 20.
37
+ - NinjaPipe documentation mentions a maximum limit of 100 for paginated list endpoints.
38
+ - Contacts support client portal enable and disable as documented.
39
+
40
+ ## Next expansion ideas
41
+
42
+ - Companies
43
+ - Tasks
44
+ - Projects
45
+ - Forms
46
+ - Files
47
+ - Webhook trigger node
48
+ - Load options from live endpoints
@@ -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,451 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.NinjaPipe = void 0;
4
+ const n8n_workflow_1 = require("n8n-workflow");
5
+ async function ninjaPipeApiRequest(context, method, endpoint, body, qs) {
6
+ const credentials = await context.getCredentials('ninjaPipeApi');
7
+ const baseUrl = String(credentials.baseUrl || '').replace(/\/+$/, '');
8
+ const apiKey = String(credentials.apiKey || '');
9
+ if (!baseUrl) {
10
+ throw new n8n_workflow_1.NodeOperationError(context.getNode(), 'Missing NinjaPipe base URL in credentials');
11
+ }
12
+ if (!apiKey) {
13
+ throw new n8n_workflow_1.NodeOperationError(context.getNode(), 'Missing NinjaPipe API key in credentials');
14
+ }
15
+ try {
16
+ return await context.helpers.httpRequest({
17
+ method,
18
+ url: `${baseUrl}${endpoint}`,
19
+ headers: {
20
+ Authorization: `Bearer ${apiKey}`,
21
+ Accept: 'application/json',
22
+ 'Content-Type': 'application/json',
23
+ },
24
+ body,
25
+ qs,
26
+ json: true,
27
+ });
28
+ }
29
+ catch (error) {
30
+ throw new n8n_workflow_1.NodeApiError(context.getNode(), error);
31
+ }
32
+ }
33
+ function buildListQuery(page, limit, search, extra) {
34
+ const qs = {
35
+ page,
36
+ limit,
37
+ };
38
+ if (search) {
39
+ qs.search = search;
40
+ }
41
+ return {
42
+ ...qs,
43
+ ...(extra || {}),
44
+ };
45
+ }
46
+ class NinjaPipe {
47
+ constructor() {
48
+ this.description = {
49
+ displayName: 'NinjaPipe',
50
+ name: 'ninjaPipe',
51
+ icon: 'file:ninjapipe.svg',
52
+ group: ['transform'],
53
+ version: 1,
54
+ subtitle: '={{$parameter["resource"] + " " + $parameter["operation"]}}',
55
+ description: 'Consume the NinjaPipe API',
56
+ defaults: {
57
+ name: 'NinjaPipe',
58
+ },
59
+ inputs: ['main'],
60
+ outputs: ['main'],
61
+ credentials: [
62
+ {
63
+ name: 'ninjaPipeApi',
64
+ required: true,
65
+ },
66
+ ],
67
+ properties: [
68
+ {
69
+ displayName: 'Resource',
70
+ name: 'resource',
71
+ type: 'options',
72
+ noDataExpression: true,
73
+ options: [
74
+ { name: 'Budget', value: 'budget' },
75
+ { name: 'Contact', value: 'contact' },
76
+ { name: 'Custom API Request', value: 'customRequest' },
77
+ { name: 'Deal', value: 'deal' },
78
+ { name: 'Product', value: 'product' },
79
+ ],
80
+ default: 'contact',
81
+ },
82
+ {
83
+ displayName: 'Operation',
84
+ name: 'operation',
85
+ type: 'options',
86
+ displayOptions: { show: { resource: ['contact'] } },
87
+ options: [
88
+ { name: 'Create', value: 'create', action: 'Create a contact' },
89
+ { name: 'Delete', value: 'delete', action: 'Delete a contact' },
90
+ { name: 'Disable Client Portal', value: 'disableClientPortal', action: 'Disable client portal for a contact' },
91
+ { name: 'Enable Client Portal', value: 'enableClientPortal', action: 'Enable client portal for a contact' },
92
+ { name: 'Get', value: 'get', action: 'Get a contact' },
93
+ { name: 'Get Many', value: 'getAll', action: 'Get many contacts' },
94
+ { name: 'Update', value: 'update', action: 'Update a contact' },
95
+ ],
96
+ default: 'getAll',
97
+ },
98
+ {
99
+ displayName: 'Operation',
100
+ name: 'operation',
101
+ type: 'options',
102
+ displayOptions: { show: { resource: ['deal'] } },
103
+ options: [
104
+ { name: 'Create', value: 'create', action: 'Create a deal' },
105
+ { name: 'Delete', value: 'delete', action: 'Delete a deal' },
106
+ { name: 'Get', value: 'get', action: 'Get a deal' },
107
+ { name: 'Get Many', value: 'getAll', action: 'Get many deals' },
108
+ { name: 'Update', value: 'update', action: 'Update a deal' },
109
+ ],
110
+ default: 'getAll',
111
+ },
112
+ {
113
+ displayName: 'Operation',
114
+ name: 'operation',
115
+ type: 'options',
116
+ displayOptions: { show: { resource: ['product'] } },
117
+ options: [
118
+ { name: 'Create', value: 'create', action: 'Create a product' },
119
+ { name: 'Delete', value: 'delete', action: 'Delete a product' },
120
+ { name: 'Get', value: 'get', action: 'Get a product' },
121
+ { name: 'Get Many', value: 'getAll', action: 'Get many products' },
122
+ { name: 'Update', value: 'update', action: 'Update a product' },
123
+ ],
124
+ default: 'getAll',
125
+ },
126
+ {
127
+ displayName: 'Operation',
128
+ name: 'operation',
129
+ type: 'options',
130
+ displayOptions: { show: { resource: ['budget'] } },
131
+ options: [
132
+ { name: 'Create', value: 'create', action: 'Create a budget' },
133
+ { name: 'Create Expense', value: 'createExpense', action: 'Create a budget expense' },
134
+ { name: 'Delete', value: 'delete', action: 'Delete a budget' },
135
+ { name: 'Get', value: 'get', action: 'Get a budget' },
136
+ { name: 'Get Many', value: 'getAll', action: 'Get many budgets' },
137
+ { name: 'Update', value: 'update', action: 'Update a budget' },
138
+ ],
139
+ default: 'getAll',
140
+ },
141
+ {
142
+ displayName: 'Operation',
143
+ name: 'operation',
144
+ type: 'options',
145
+ displayOptions: { show: { resource: ['customRequest'] } },
146
+ options: [
147
+ { name: 'Execute', value: 'execute', action: 'Execute a custom API request' },
148
+ ],
149
+ default: 'execute',
150
+ },
151
+ {
152
+ displayName: 'ID',
153
+ name: 'id',
154
+ type: 'string',
155
+ required: true,
156
+ default: '',
157
+ displayOptions: {
158
+ show: {
159
+ resource: ['contact', 'deal', 'product', 'budget'],
160
+ operation: ['get', 'update', 'delete', 'enableClientPortal', 'disableClientPortal'],
161
+ },
162
+ },
163
+ },
164
+ {
165
+ displayName: 'Page',
166
+ name: 'page',
167
+ type: 'number',
168
+ default: 1,
169
+ displayOptions: {
170
+ show: {
171
+ resource: ['contact', 'deal', 'product', 'budget'],
172
+ operation: ['getAll'],
173
+ },
174
+ },
175
+ },
176
+ {
177
+ displayName: 'Limit',
178
+ name: 'limit',
179
+ type: 'number',
180
+ default: 20,
181
+ typeOptions: {
182
+ minValue: 1,
183
+ maxValue: 100,
184
+ },
185
+ displayOptions: {
186
+ show: {
187
+ resource: ['contact', 'deal', 'product', 'budget'],
188
+ operation: ['getAll'],
189
+ },
190
+ },
191
+ description: 'Maximum according to the public docs is 100',
192
+ },
193
+ {
194
+ displayName: 'Search',
195
+ name: 'search',
196
+ type: 'string',
197
+ default: '',
198
+ displayOptions: {
199
+ show: {
200
+ resource: ['contact', 'deal', 'product', 'budget'],
201
+ operation: ['getAll'],
202
+ },
203
+ },
204
+ },
205
+ {
206
+ displayName: 'Body',
207
+ name: 'body',
208
+ type: 'json',
209
+ default: '{}',
210
+ required: true,
211
+ displayOptions: {
212
+ show: {
213
+ resource: ['contact', 'deal', 'product', 'budget'],
214
+ operation: ['create', 'update', 'createExpense'],
215
+ },
216
+ },
217
+ description: 'JSON request body passed directly to NinjaPipe',
218
+ },
219
+ {
220
+ displayName: 'Portal Body',
221
+ name: 'portalBody',
222
+ type: 'json',
223
+ default: '{}',
224
+ required: false,
225
+ displayOptions: {
226
+ show: {
227
+ resource: ['contact'],
228
+ operation: ['enableClientPortal', 'disableClientPortal'],
229
+ },
230
+ },
231
+ description: 'Optional JSON body for client portal actions',
232
+ },
233
+ {
234
+ displayName: 'Method',
235
+ name: 'customMethod',
236
+ type: 'options',
237
+ displayOptions: {
238
+ show: {
239
+ resource: ['customRequest'],
240
+ operation: ['execute'],
241
+ },
242
+ },
243
+ options: [
244
+ { name: 'DELETE', value: 'DELETE' },
245
+ { name: 'GET', value: 'GET' },
246
+ { name: 'PATCH', value: 'PATCH' },
247
+ { name: 'POST', value: 'POST' },
248
+ { name: 'PUT', value: 'PUT' },
249
+ ],
250
+ default: 'GET',
251
+ },
252
+ {
253
+ displayName: 'Path',
254
+ name: 'customPath',
255
+ type: 'string',
256
+ displayOptions: {
257
+ show: {
258
+ resource: ['customRequest'],
259
+ operation: ['execute'],
260
+ },
261
+ },
262
+ default: '/contacts',
263
+ placeholder: '/contacts',
264
+ description: 'Path relative to the base URL',
265
+ },
266
+ {
267
+ displayName: 'Query Parameters',
268
+ name: 'customQuery',
269
+ type: 'json',
270
+ displayOptions: {
271
+ show: {
272
+ resource: ['customRequest'],
273
+ operation: ['execute'],
274
+ },
275
+ },
276
+ default: '{}',
277
+ },
278
+ {
279
+ displayName: 'Request Body',
280
+ name: 'customBody',
281
+ type: 'json',
282
+ displayOptions: {
283
+ show: {
284
+ resource: ['customRequest'],
285
+ operation: ['execute'],
286
+ },
287
+ },
288
+ default: '{}',
289
+ },
290
+ ],
291
+ };
292
+ }
293
+ async execute() {
294
+ const items = this.getInputData();
295
+ const returnData = [];
296
+ for (let i = 0; i < items.length; i++) {
297
+ try {
298
+ const resource = this.getNodeParameter('resource', i);
299
+ const operation = this.getNodeParameter('operation', i);
300
+ let responseData;
301
+ if (resource === 'contact') {
302
+ if (operation === 'create') {
303
+ const body = this.getNodeParameter('body', i);
304
+ responseData = await ninjaPipeApiRequest(this, 'POST', '/contacts', body);
305
+ }
306
+ else if (operation === 'get') {
307
+ const id = this.getNodeParameter('id', i);
308
+ responseData = await ninjaPipeApiRequest(this, 'GET', `/contacts/${id}`);
309
+ }
310
+ else if (operation === 'getAll') {
311
+ const page = this.getNodeParameter('page', i);
312
+ const limit = this.getNodeParameter('limit', i);
313
+ const search = this.getNodeParameter('search', i);
314
+ responseData = await ninjaPipeApiRequest(this, 'GET', '/contacts', undefined, buildListQuery(page, limit, search));
315
+ }
316
+ else if (operation === 'update') {
317
+ const id = this.getNodeParameter('id', i);
318
+ const body = this.getNodeParameter('body', i);
319
+ responseData = await ninjaPipeApiRequest(this, 'PUT', `/contacts/${id}`, body);
320
+ }
321
+ else if (operation === 'delete') {
322
+ const id = this.getNodeParameter('id', i);
323
+ responseData = await ninjaPipeApiRequest(this, 'DELETE', `/contacts/${id}`);
324
+ }
325
+ else if (operation === 'enableClientPortal') {
326
+ const id = this.getNodeParameter('id', i);
327
+ const portalBody = this.getNodeParameter('portalBody', i);
328
+ responseData = await ninjaPipeApiRequest(this, 'PUT', `/contacts/${id}/enable-client-portal`, portalBody);
329
+ }
330
+ else if (operation === 'disableClientPortal') {
331
+ const id = this.getNodeParameter('id', i);
332
+ const portalBody = this.getNodeParameter('portalBody', i);
333
+ responseData = await ninjaPipeApiRequest(this, 'PUT', `/contacts/${id}/disable-client-portal`, portalBody);
334
+ }
335
+ }
336
+ if (resource === 'deal') {
337
+ if (operation === 'create') {
338
+ const body = this.getNodeParameter('body', i);
339
+ responseData = await ninjaPipeApiRequest(this, 'POST', '/deals', body);
340
+ }
341
+ else if (operation === 'get') {
342
+ const id = this.getNodeParameter('id', i);
343
+ responseData = await ninjaPipeApiRequest(this, 'GET', `/deals/${id}`);
344
+ }
345
+ else if (operation === 'getAll') {
346
+ const page = this.getNodeParameter('page', i);
347
+ const limit = this.getNodeParameter('limit', i);
348
+ const search = this.getNodeParameter('search', i);
349
+ responseData = await ninjaPipeApiRequest(this, 'GET', '/deals', undefined, buildListQuery(page, limit, search));
350
+ }
351
+ else if (operation === 'update') {
352
+ const id = this.getNodeParameter('id', i);
353
+ const body = this.getNodeParameter('body', i);
354
+ responseData = await ninjaPipeApiRequest(this, 'PUT', `/deals/${id}`, body);
355
+ }
356
+ else if (operation === 'delete') {
357
+ const id = this.getNodeParameter('id', i);
358
+ responseData = await ninjaPipeApiRequest(this, 'DELETE', `/deals/${id}`);
359
+ }
360
+ }
361
+ if (resource === 'product') {
362
+ if (operation === 'create') {
363
+ const body = this.getNodeParameter('body', i);
364
+ responseData = await ninjaPipeApiRequest(this, 'POST', '/products', body);
365
+ }
366
+ else if (operation === 'get') {
367
+ const id = this.getNodeParameter('id', i);
368
+ responseData = await ninjaPipeApiRequest(this, 'GET', `/products/${id}`);
369
+ }
370
+ else if (operation === 'getAll') {
371
+ const page = this.getNodeParameter('page', i);
372
+ const limit = this.getNodeParameter('limit', i);
373
+ const search = this.getNodeParameter('search', i);
374
+ responseData = await ninjaPipeApiRequest(this, 'GET', '/products', undefined, buildListQuery(page, limit, search));
375
+ }
376
+ else if (operation === 'update') {
377
+ const id = this.getNodeParameter('id', i);
378
+ const body = this.getNodeParameter('body', i);
379
+ responseData = await ninjaPipeApiRequest(this, 'PUT', `/products/${id}`, body);
380
+ }
381
+ else if (operation === 'delete') {
382
+ const id = this.getNodeParameter('id', i);
383
+ responseData = await ninjaPipeApiRequest(this, 'DELETE', `/products/${id}`);
384
+ }
385
+ }
386
+ if (resource === 'budget') {
387
+ if (operation === 'create') {
388
+ const body = this.getNodeParameter('body', i);
389
+ responseData = await ninjaPipeApiRequest(this, 'POST', '/budgets', body);
390
+ }
391
+ else if (operation === 'createExpense') {
392
+ const body = this.getNodeParameter('body', i);
393
+ responseData = await ninjaPipeApiRequest(this, 'POST', '/budgets/expenses', body);
394
+ }
395
+ else if (operation === 'get') {
396
+ const id = this.getNodeParameter('id', i);
397
+ responseData = await ninjaPipeApiRequest(this, 'GET', `/budgets/${id}`);
398
+ }
399
+ else if (operation === 'getAll') {
400
+ const page = this.getNodeParameter('page', i);
401
+ const limit = this.getNodeParameter('limit', i);
402
+ const search = this.getNodeParameter('search', i);
403
+ responseData = await ninjaPipeApiRequest(this, 'GET', '/budgets', undefined, buildListQuery(page, limit, search));
404
+ }
405
+ else if (operation === 'update') {
406
+ const id = this.getNodeParameter('id', i);
407
+ const body = this.getNodeParameter('body', i);
408
+ responseData = await ninjaPipeApiRequest(this, 'PUT', `/budgets/${id}`, body);
409
+ }
410
+ else if (operation === 'delete') {
411
+ const id = this.getNodeParameter('id', i);
412
+ responseData = await ninjaPipeApiRequest(this, 'DELETE', `/budgets/${id}`);
413
+ }
414
+ }
415
+ if (resource === 'customRequest') {
416
+ const method = this.getNodeParameter('customMethod', i);
417
+ const customPath = this.getNodeParameter('customPath', i);
418
+ const customQuery = this.getNodeParameter('customQuery', i);
419
+ const customBody = this.getNodeParameter('customBody', i);
420
+ responseData = await ninjaPipeApiRequest(this, method, customPath, customBody, customQuery);
421
+ }
422
+ if (responseData === undefined) {
423
+ throw new n8n_workflow_1.NodeOperationError(this.getNode(), `The selected operation "${operation}" for resource "${resource}" is not implemented`);
424
+ }
425
+ if (Array.isArray(responseData)) {
426
+ for (const entry of responseData) {
427
+ returnData.push({ json: entry });
428
+ }
429
+ }
430
+ else {
431
+ returnData.push({ json: responseData });
432
+ }
433
+ }
434
+ catch (error) {
435
+ if (this.continueOnFail()) {
436
+ returnData.push({
437
+ json: {
438
+ error: error.message,
439
+ },
440
+ pairedItem: i,
441
+ });
442
+ continue;
443
+ }
444
+ throw error;
445
+ }
446
+ }
447
+ return [returnData];
448
+ }
449
+ }
450
+ exports.NinjaPipe = NinjaPipe;
451
+ //# 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,466 @@
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 = 'contact' | 'deal' | 'product' | 'budget' | 'customRequest';
15
+
16
+ async function ninjaPipeApiRequest(
17
+ context: IExecuteFunctions | ILoadOptionsFunctions,
18
+ method: IHttpRequestMethods,
19
+ endpoint: string,
20
+ body?: IDataObject,
21
+ qs?: IDataObject,
22
+ ) {
23
+ const credentials = await context.getCredentials('ninjaPipeApi');
24
+ const baseUrl = String(credentials.baseUrl || '').replace(/\/+$/, '');
25
+ const apiKey = String(credentials.apiKey || '');
26
+
27
+ if (!baseUrl) {
28
+ throw new NodeOperationError(context.getNode(), 'Missing NinjaPipe base URL in credentials');
29
+ }
30
+
31
+ if (!apiKey) {
32
+ throw new NodeOperationError(context.getNode(), 'Missing NinjaPipe API key in credentials');
33
+ }
34
+
35
+ try {
36
+ return await context.helpers.httpRequest({
37
+ method,
38
+ url: `${baseUrl}${endpoint}`,
39
+ headers: {
40
+ Authorization: `Bearer ${apiKey}`,
41
+ Accept: 'application/json',
42
+ 'Content-Type': 'application/json',
43
+ },
44
+ body,
45
+ qs,
46
+ json: true,
47
+ });
48
+ } catch (error) {
49
+ throw new NodeApiError(context.getNode(), error as JsonObject);
50
+ }
51
+ }
52
+
53
+ function buildListQuery(page: number, limit: number, search?: string, extra?: IDataObject) {
54
+ const qs: IDataObject = {
55
+ page,
56
+ limit,
57
+ };
58
+
59
+ if (search) {
60
+ qs.search = search;
61
+ }
62
+
63
+ return {
64
+ ...qs,
65
+ ...(extra || {}),
66
+ };
67
+ }
68
+
69
+ export class NinjaPipe implements INodeType {
70
+ description: INodeTypeDescription = {
71
+ displayName: 'NinjaPipe',
72
+ name: 'ninjaPipe',
73
+ icon: 'file:ninjapipe.svg',
74
+ group: ['transform'],
75
+ version: 1,
76
+ subtitle: '={{$parameter["resource"] + " " + $parameter["operation"]}}',
77
+ description: 'Consume the NinjaPipe API',
78
+ defaults: {
79
+ name: 'NinjaPipe',
80
+ },
81
+ inputs: ['main'],
82
+ outputs: ['main'],
83
+ credentials: [
84
+ {
85
+ name: 'ninjaPipeApi',
86
+ required: true,
87
+ },
88
+ ],
89
+ properties: [
90
+ {
91
+ displayName: 'Resource',
92
+ name: 'resource',
93
+ type: 'options',
94
+ noDataExpression: true,
95
+ options: [
96
+ { name: 'Budget', value: 'budget' },
97
+ { name: 'Contact', value: 'contact' },
98
+ { name: 'Custom API Request', value: 'customRequest' },
99
+ { name: 'Deal', value: 'deal' },
100
+ { name: 'Product', value: 'product' },
101
+ ],
102
+ default: 'contact',
103
+ },
104
+
105
+ {
106
+ displayName: 'Operation',
107
+ name: 'operation',
108
+ type: 'options',
109
+ displayOptions: { show: { resource: ['contact'] } },
110
+ options: [
111
+ { name: 'Create', value: 'create', action: 'Create a contact' },
112
+ { name: 'Delete', value: 'delete', action: 'Delete a contact' },
113
+ { name: 'Disable Client Portal', value: 'disableClientPortal', action: 'Disable client portal for a contact' },
114
+ { name: 'Enable Client Portal', value: 'enableClientPortal', action: 'Enable client portal for a contact' },
115
+ { name: 'Get', value: 'get', action: 'Get a contact' },
116
+ { name: 'Get Many', value: 'getAll', action: 'Get many contacts' },
117
+ { name: 'Update', value: 'update', action: 'Update a contact' },
118
+ ],
119
+ default: 'getAll',
120
+ },
121
+ {
122
+ displayName: 'Operation',
123
+ name: 'operation',
124
+ type: 'options',
125
+ displayOptions: { show: { resource: ['deal'] } },
126
+ options: [
127
+ { name: 'Create', value: 'create', action: 'Create a deal' },
128
+ { name: 'Delete', value: 'delete', action: 'Delete a deal' },
129
+ { name: 'Get', value: 'get', action: 'Get a deal' },
130
+ { name: 'Get Many', value: 'getAll', action: 'Get many deals' },
131
+ { name: 'Update', value: 'update', action: 'Update a deal' },
132
+ ],
133
+ default: 'getAll',
134
+ },
135
+ {
136
+ displayName: 'Operation',
137
+ name: 'operation',
138
+ type: 'options',
139
+ displayOptions: { show: { resource: ['product'] } },
140
+ options: [
141
+ { name: 'Create', value: 'create', action: 'Create a product' },
142
+ { name: 'Delete', value: 'delete', action: 'Delete a product' },
143
+ { name: 'Get', value: 'get', action: 'Get a product' },
144
+ { name: 'Get Many', value: 'getAll', action: 'Get many products' },
145
+ { name: 'Update', value: 'update', action: 'Update a product' },
146
+ ],
147
+ default: 'getAll',
148
+ },
149
+ {
150
+ displayName: 'Operation',
151
+ name: 'operation',
152
+ type: 'options',
153
+ displayOptions: { show: { resource: ['budget'] } },
154
+ options: [
155
+ { name: 'Create', value: 'create', action: 'Create a budget' },
156
+ { name: 'Create Expense', value: 'createExpense', action: 'Create a budget expense' },
157
+ { name: 'Delete', value: 'delete', action: 'Delete a budget' },
158
+ { name: 'Get', value: 'get', action: 'Get a budget' },
159
+ { name: 'Get Many', value: 'getAll', action: 'Get many budgets' },
160
+ { name: 'Update', value: 'update', action: 'Update a budget' },
161
+ ],
162
+ default: 'getAll',
163
+ },
164
+ {
165
+ displayName: 'Operation',
166
+ name: 'operation',
167
+ type: 'options',
168
+ displayOptions: { show: { resource: ['customRequest'] } },
169
+ options: [
170
+ { name: 'Execute', value: 'execute', action: 'Execute a custom API request' },
171
+ ],
172
+ default: 'execute',
173
+ },
174
+
175
+ {
176
+ displayName: 'ID',
177
+ name: 'id',
178
+ type: 'string',
179
+ required: true,
180
+ default: '',
181
+ displayOptions: {
182
+ show: {
183
+ resource: ['contact', 'deal', 'product', 'budget'],
184
+ operation: ['get', 'update', 'delete', 'enableClientPortal', 'disableClientPortal'],
185
+ },
186
+ },
187
+ },
188
+
189
+ {
190
+ displayName: 'Page',
191
+ name: 'page',
192
+ type: 'number',
193
+ default: 1,
194
+ displayOptions: {
195
+ show: {
196
+ resource: ['contact', 'deal', 'product', 'budget'],
197
+ operation: ['getAll'],
198
+ },
199
+ },
200
+ },
201
+ {
202
+ displayName: 'Limit',
203
+ name: 'limit',
204
+ type: 'number',
205
+ default: 20,
206
+ typeOptions: {
207
+ minValue: 1,
208
+ maxValue: 100,
209
+ },
210
+ displayOptions: {
211
+ show: {
212
+ resource: ['contact', 'deal', 'product', 'budget'],
213
+ operation: ['getAll'],
214
+ },
215
+ },
216
+ description: 'Maximum according to the public docs is 100',
217
+ },
218
+ {
219
+ displayName: 'Search',
220
+ name: 'search',
221
+ type: 'string',
222
+ default: '',
223
+ displayOptions: {
224
+ show: {
225
+ resource: ['contact', 'deal', 'product', 'budget'],
226
+ operation: ['getAll'],
227
+ },
228
+ },
229
+ },
230
+
231
+ {
232
+ displayName: 'Body',
233
+ name: 'body',
234
+ type: 'json',
235
+ default: '{}',
236
+ required: true,
237
+ displayOptions: {
238
+ show: {
239
+ resource: ['contact', 'deal', 'product', 'budget'],
240
+ operation: ['create', 'update', 'createExpense'],
241
+ },
242
+ },
243
+ description: 'JSON request body passed directly to NinjaPipe',
244
+ },
245
+
246
+ {
247
+ displayName: 'Portal Body',
248
+ name: 'portalBody',
249
+ type: 'json',
250
+ default: '{}',
251
+ required: false,
252
+ displayOptions: {
253
+ show: {
254
+ resource: ['contact'],
255
+ operation: ['enableClientPortal', 'disableClientPortal'],
256
+ },
257
+ },
258
+ description: 'Optional JSON body for client portal actions',
259
+ },
260
+
261
+ {
262
+ displayName: 'Method',
263
+ name: 'customMethod',
264
+ type: 'options',
265
+ displayOptions: {
266
+ show: {
267
+ resource: ['customRequest'],
268
+ operation: ['execute'],
269
+ },
270
+ },
271
+ options: [
272
+ { name: 'DELETE', value: 'DELETE' },
273
+ { name: 'GET', value: 'GET' },
274
+ { name: 'PATCH', value: 'PATCH' },
275
+ { name: 'POST', value: 'POST' },
276
+ { name: 'PUT', value: 'PUT' },
277
+ ],
278
+ default: 'GET',
279
+ },
280
+ {
281
+ displayName: 'Path',
282
+ name: 'customPath',
283
+ type: 'string',
284
+ displayOptions: {
285
+ show: {
286
+ resource: ['customRequest'],
287
+ operation: ['execute'],
288
+ },
289
+ },
290
+ default: '/contacts',
291
+ placeholder: '/contacts',
292
+ description: 'Path relative to the base URL',
293
+ },
294
+ {
295
+ displayName: 'Query Parameters',
296
+ name: 'customQuery',
297
+ type: 'json',
298
+ displayOptions: {
299
+ show: {
300
+ resource: ['customRequest'],
301
+ operation: ['execute'],
302
+ },
303
+ },
304
+ default: '{}',
305
+ },
306
+ {
307
+ displayName: 'Request Body',
308
+ name: 'customBody',
309
+ type: 'json',
310
+ displayOptions: {
311
+ show: {
312
+ resource: ['customRequest'],
313
+ operation: ['execute'],
314
+ },
315
+ },
316
+ default: '{}',
317
+ },
318
+ ],
319
+ };
320
+
321
+ async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
322
+ const items = this.getInputData();
323
+ const returnData: INodeExecutionData[] = [];
324
+
325
+ for (let i = 0; i < items.length; i++) {
326
+ try {
327
+ const resource = this.getNodeParameter('resource', i) as Resource;
328
+ const operation = this.getNodeParameter('operation', i) as string;
329
+
330
+ let responseData: IDataObject | IDataObject[] | undefined;
331
+
332
+ if (resource === 'contact') {
333
+ if (operation === 'create') {
334
+ const body = this.getNodeParameter('body', i) as IDataObject;
335
+ responseData = await ninjaPipeApiRequest(this, 'POST', '/contacts', body);
336
+ } else if (operation === 'get') {
337
+ const id = this.getNodeParameter('id', i) as string;
338
+ responseData = await ninjaPipeApiRequest(this, 'GET', `/contacts/${id}`);
339
+ } else if (operation === 'getAll') {
340
+ const page = this.getNodeParameter('page', i) as number;
341
+ const limit = this.getNodeParameter('limit', i) as number;
342
+ const search = this.getNodeParameter('search', i) as string;
343
+ responseData = await ninjaPipeApiRequest(this, 'GET', '/contacts', undefined, buildListQuery(page, limit, search));
344
+ } else if (operation === 'update') {
345
+ const id = this.getNodeParameter('id', i) as string;
346
+ const body = this.getNodeParameter('body', i) as IDataObject;
347
+ responseData = await ninjaPipeApiRequest(this, 'PUT', `/contacts/${id}`, body);
348
+ } else if (operation === 'delete') {
349
+ const id = this.getNodeParameter('id', i) as string;
350
+ responseData = await ninjaPipeApiRequest(this, 'DELETE', `/contacts/${id}`);
351
+ } else if (operation === 'enableClientPortal') {
352
+ const id = this.getNodeParameter('id', i) as string;
353
+ const portalBody = this.getNodeParameter('portalBody', i) as IDataObject;
354
+ responseData = await ninjaPipeApiRequest(this, 'PUT', `/contacts/${id}/enable-client-portal`, portalBody);
355
+ } else if (operation === 'disableClientPortal') {
356
+ const id = this.getNodeParameter('id', i) as string;
357
+ const portalBody = this.getNodeParameter('portalBody', i) as IDataObject;
358
+ responseData = await ninjaPipeApiRequest(this, 'PUT', `/contacts/${id}/disable-client-portal`, portalBody);
359
+ }
360
+ }
361
+
362
+ if (resource === 'deal') {
363
+ if (operation === 'create') {
364
+ const body = this.getNodeParameter('body', i) as IDataObject;
365
+ responseData = await ninjaPipeApiRequest(this, 'POST', '/deals', body);
366
+ } else if (operation === 'get') {
367
+ const id = this.getNodeParameter('id', i) as string;
368
+ responseData = await ninjaPipeApiRequest(this, 'GET', `/deals/${id}`);
369
+ } else if (operation === 'getAll') {
370
+ const page = this.getNodeParameter('page', i) as number;
371
+ const limit = this.getNodeParameter('limit', i) as number;
372
+ const search = this.getNodeParameter('search', i) as string;
373
+ responseData = await ninjaPipeApiRequest(this, 'GET', '/deals', undefined, buildListQuery(page, limit, search));
374
+ } else if (operation === 'update') {
375
+ const id = this.getNodeParameter('id', i) as string;
376
+ const body = this.getNodeParameter('body', i) as IDataObject;
377
+ responseData = await ninjaPipeApiRequest(this, 'PUT', `/deals/${id}`, body);
378
+ } else if (operation === 'delete') {
379
+ const id = this.getNodeParameter('id', i) as string;
380
+ responseData = await ninjaPipeApiRequest(this, 'DELETE', `/deals/${id}`);
381
+ }
382
+ }
383
+
384
+ if (resource === 'product') {
385
+ if (operation === 'create') {
386
+ const body = this.getNodeParameter('body', i) as IDataObject;
387
+ responseData = await ninjaPipeApiRequest(this, 'POST', '/products', body);
388
+ } else if (operation === 'get') {
389
+ const id = this.getNodeParameter('id', i) as string;
390
+ responseData = await ninjaPipeApiRequest(this, 'GET', `/products/${id}`);
391
+ } else if (operation === 'getAll') {
392
+ const page = this.getNodeParameter('page', i) as number;
393
+ const limit = this.getNodeParameter('limit', i) as number;
394
+ const search = this.getNodeParameter('search', i) as string;
395
+ responseData = await ninjaPipeApiRequest(this, 'GET', '/products', undefined, buildListQuery(page, limit, search));
396
+ } else if (operation === 'update') {
397
+ const id = this.getNodeParameter('id', i) as string;
398
+ const body = this.getNodeParameter('body', i) as IDataObject;
399
+ responseData = await ninjaPipeApiRequest(this, 'PUT', `/products/${id}`, body);
400
+ } else if (operation === 'delete') {
401
+ const id = this.getNodeParameter('id', i) as string;
402
+ responseData = await ninjaPipeApiRequest(this, 'DELETE', `/products/${id}`);
403
+ }
404
+ }
405
+
406
+ if (resource === 'budget') {
407
+ if (operation === 'create') {
408
+ const body = this.getNodeParameter('body', i) as IDataObject;
409
+ responseData = await ninjaPipeApiRequest(this, 'POST', '/budgets', body);
410
+ } else if (operation === 'createExpense') {
411
+ const body = this.getNodeParameter('body', i) as IDataObject;
412
+ responseData = await ninjaPipeApiRequest(this, 'POST', '/budgets/expenses', body);
413
+ } else if (operation === 'get') {
414
+ const id = this.getNodeParameter('id', i) as string;
415
+ responseData = await ninjaPipeApiRequest(this, 'GET', `/budgets/${id}`);
416
+ } else if (operation === 'getAll') {
417
+ const page = this.getNodeParameter('page', i) as number;
418
+ const limit = this.getNodeParameter('limit', i) as number;
419
+ const search = this.getNodeParameter('search', i) as string;
420
+ responseData = await ninjaPipeApiRequest(this, 'GET', '/budgets', undefined, buildListQuery(page, limit, search));
421
+ } else if (operation === 'update') {
422
+ const id = this.getNodeParameter('id', i) as string;
423
+ const body = this.getNodeParameter('body', i) as IDataObject;
424
+ responseData = await ninjaPipeApiRequest(this, 'PUT', `/budgets/${id}`, body);
425
+ } else if (operation === 'delete') {
426
+ const id = this.getNodeParameter('id', i) as string;
427
+ responseData = await ninjaPipeApiRequest(this, 'DELETE', `/budgets/${id}`);
428
+ }
429
+ }
430
+
431
+ if (resource === 'customRequest') {
432
+ const method = this.getNodeParameter('customMethod', i) as IHttpRequestMethods;
433
+ const customPath = this.getNodeParameter('customPath', i) as string;
434
+ const customQuery = this.getNodeParameter('customQuery', i) as IDataObject;
435
+ const customBody = this.getNodeParameter('customBody', i) as IDataObject;
436
+ responseData = await ninjaPipeApiRequest(this, method, customPath, customBody, customQuery);
437
+ }
438
+
439
+ if (responseData === undefined) {
440
+ throw new NodeOperationError(this.getNode(), `The selected operation "${operation}" for resource "${resource}" is not implemented`);
441
+ }
442
+
443
+ if (Array.isArray(responseData)) {
444
+ for (const entry of responseData) {
445
+ returnData.push({ json: entry });
446
+ }
447
+ } else {
448
+ returnData.push({ json: responseData });
449
+ }
450
+ } catch (error) {
451
+ if (this.continueOnFail()) {
452
+ returnData.push({
453
+ json: {
454
+ error: (error as Error).message,
455
+ },
456
+ pairedItem: i,
457
+ });
458
+ continue;
459
+ }
460
+ throw error;
461
+ }
462
+ }
463
+
464
+ return [returnData];
465
+ }
466
+ }
@@ -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,53 @@
1
+ {
2
+ "name": "n8n-nodes-ninjapipe",
3
+ "version": "0.1.0",
4
+ "description": "NinjaPipe community node for n8n",
5
+ "keywords": [
6
+ "n8n-community-node-package",
7
+ "n8n",
8
+ "ninjapipe",
9
+ "crm"
10
+ ],
11
+ "license": "MIT",
12
+ "homepage": "https://github.com/your-org/n8n-nodes-ninjapipe",
13
+ "author": {
14
+ "name": "OpenAI for Mike"
15
+ },
16
+ "repository": {
17
+ "type": "git",
18
+ "url": "https://github.com/your-org/n8n-nodes-ninjapipe.git"
19
+ },
20
+ "main": "index.js",
21
+ "files": [
22
+ "credentials",
23
+ "dist",
24
+ "nodes",
25
+ "README.md"
26
+ ],
27
+ "scripts": {
28
+ "build": "tsc && gulp build:icons",
29
+ "dev": "n8n-node dev",
30
+ "lint": "eslint nodes credentials package.json",
31
+ "prepublishOnly": "npm run build"
32
+ },
33
+ "n8n": {
34
+ "n8nNodesApiVersion": 1,
35
+ "credentials": [
36
+ "dist/credentials/NinjaPipeApi.credentials.js"
37
+ ],
38
+ "nodes": [
39
+ "dist/nodes/NinjaPipe/NinjaPipe.node.js"
40
+ ]
41
+ },
42
+ "devDependencies": {
43
+ "@n8n/node-cli": "^0.8.0",
44
+ "@types/node": "^20.17.0",
45
+ "eslint": "^9.0.0",
46
+ "gulp": "^5.0.0",
47
+ "n8n-workflow": "^1.82.0",
48
+ "typescript": "^5.6.3"
49
+ },
50
+ "peerDependencies": {
51
+ "n8n-workflow": "*"
52
+ }
53
+ }