n8n-nodes-cribops 0.1.17 → 0.1.20
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/dist/credentials/CribopsApi.credentials.js +7 -0
- package/dist/nodes/CribopsTrigger/CribopsTrigger.node.d.ts +2 -3
- package/dist/nodes/CribopsTrigger/CribopsTrigger.node.js +95 -232
- package/dist/package.json +1 -1
- package/dist/utils/CribopsHttp.d.ts +22 -1
- package/dist/utils/CribopsHttp.js +47 -2
- package/package.json +1 -1
|
@@ -25,6 +25,13 @@ class CribopsApi {
|
|
|
25
25
|
required: true,
|
|
26
26
|
description: 'Base URL of the Cribops API',
|
|
27
27
|
},
|
|
28
|
+
{
|
|
29
|
+
displayName: 'Organization ID',
|
|
30
|
+
name: 'organizationId',
|
|
31
|
+
type: 'string',
|
|
32
|
+
default: '',
|
|
33
|
+
description: 'Organization ID (optional - if not provided, will use the default organization for the API token)',
|
|
34
|
+
},
|
|
28
35
|
];
|
|
29
36
|
authenticate = {
|
|
30
37
|
type: 'generic',
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { INodeType, INodeTypeDescription,
|
|
1
|
+
import { INodeType, INodeTypeDescription, IWebhookFunctions, IWebhookResponseData, IHookFunctions, ILoadOptionsFunctions, INodePropertyOptions } from 'n8n-workflow';
|
|
2
2
|
export declare class CribopsTrigger implements INodeType {
|
|
3
3
|
description: INodeTypeDescription;
|
|
4
4
|
methods: {
|
|
5
5
|
loadOptions: {
|
|
6
|
-
|
|
6
|
+
getWebhooks(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]>;
|
|
7
7
|
};
|
|
8
8
|
};
|
|
9
9
|
webhookMethods: {
|
|
@@ -13,6 +13,5 @@ export declare class CribopsTrigger implements INodeType {
|
|
|
13
13
|
delete(this: IHookFunctions): Promise<boolean>;
|
|
14
14
|
};
|
|
15
15
|
};
|
|
16
|
-
trigger(this: ITriggerFunctions): Promise<ITriggerResponse>;
|
|
17
16
|
webhook(this: IWebhookFunctions): Promise<IWebhookResponseData>;
|
|
18
17
|
}
|
|
@@ -10,7 +10,7 @@ class CribopsTrigger {
|
|
|
10
10
|
icon: 'file:cribopstrigger.svg',
|
|
11
11
|
group: ['trigger'],
|
|
12
12
|
version: 1,
|
|
13
|
-
description: 'Triggers when receiving messages
|
|
13
|
+
description: 'Triggers when receiving messages via Cribops webhook',
|
|
14
14
|
defaults: {
|
|
15
15
|
name: 'Cribops Trigger',
|
|
16
16
|
},
|
|
@@ -27,92 +27,21 @@ class CribopsTrigger {
|
|
|
27
27
|
name: 'default',
|
|
28
28
|
httpMethod: 'POST',
|
|
29
29
|
responseMode: 'onReceived',
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
isFullPath: true,
|
|
30
|
+
path: '={{$parameter["webhookId"]}}',
|
|
31
|
+
isFullPath: false,
|
|
33
32
|
},
|
|
34
33
|
],
|
|
35
|
-
polling: true,
|
|
36
34
|
properties: [
|
|
37
35
|
{
|
|
38
|
-
displayName: '
|
|
39
|
-
name: '
|
|
36
|
+
displayName: 'Webhook Name or ID',
|
|
37
|
+
name: 'webhookId',
|
|
40
38
|
type: 'options',
|
|
41
|
-
options: [
|
|
42
|
-
{
|
|
43
|
-
name: 'Polling',
|
|
44
|
-
value: 'polling',
|
|
45
|
-
description: 'Poll the queue for messages at regular intervals',
|
|
46
|
-
},
|
|
47
|
-
{
|
|
48
|
-
name: 'Webhook',
|
|
49
|
-
value: 'webhook',
|
|
50
|
-
description: 'Receive messages via webhook',
|
|
51
|
-
},
|
|
52
|
-
],
|
|
53
|
-
default: 'polling',
|
|
54
|
-
description: 'How to receive messages from Cribops',
|
|
55
|
-
},
|
|
56
|
-
{
|
|
57
|
-
displayName: 'Tenant ID',
|
|
58
|
-
name: 'tenantId',
|
|
59
|
-
type: 'string',
|
|
60
39
|
required: true,
|
|
61
|
-
default: '',
|
|
62
|
-
description: 'The tenant ID for your Cribops organization',
|
|
63
|
-
},
|
|
64
|
-
{
|
|
65
|
-
displayName: 'Agent Name or ID',
|
|
66
|
-
name: 'agentId',
|
|
67
|
-
type: 'options',
|
|
68
|
-
required: true,
|
|
69
|
-
displayOptions: {
|
|
70
|
-
show: {
|
|
71
|
-
triggerMode: ['webhook'],
|
|
72
|
-
},
|
|
73
|
-
},
|
|
74
40
|
typeOptions: {
|
|
75
|
-
loadOptionsMethod: '
|
|
41
|
+
loadOptionsMethod: 'getWebhooks',
|
|
76
42
|
},
|
|
77
43
|
default: '',
|
|
78
|
-
description: '
|
|
79
|
-
},
|
|
80
|
-
{
|
|
81
|
-
displayName: 'Queue Name',
|
|
82
|
-
name: 'queueName',
|
|
83
|
-
type: 'string',
|
|
84
|
-
displayOptions: {
|
|
85
|
-
show: {
|
|
86
|
-
triggerMode: ['polling'],
|
|
87
|
-
},
|
|
88
|
-
},
|
|
89
|
-
default: '',
|
|
90
|
-
placeholder: 'e.g., stripe_events',
|
|
91
|
-
description: 'Specific queue to poll (optional). Leave empty to poll all queues.',
|
|
92
|
-
},
|
|
93
|
-
{
|
|
94
|
-
displayName: 'Poll Interval',
|
|
95
|
-
name: 'pollInterval',
|
|
96
|
-
type: 'number',
|
|
97
|
-
displayOptions: {
|
|
98
|
-
show: {
|
|
99
|
-
triggerMode: ['polling'],
|
|
100
|
-
},
|
|
101
|
-
},
|
|
102
|
-
default: 30,
|
|
103
|
-
description: 'How often to poll for messages in seconds',
|
|
104
|
-
},
|
|
105
|
-
{
|
|
106
|
-
displayName: 'Batch Size',
|
|
107
|
-
name: 'batchSize',
|
|
108
|
-
type: 'number',
|
|
109
|
-
displayOptions: {
|
|
110
|
-
show: {
|
|
111
|
-
triggerMode: ['polling'],
|
|
112
|
-
},
|
|
113
|
-
},
|
|
114
|
-
default: 10,
|
|
115
|
-
description: 'Number of messages to retrieve per poll (max 100)',
|
|
44
|
+
description: 'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>',
|
|
116
45
|
},
|
|
117
46
|
{
|
|
118
47
|
displayName: 'Event Types',
|
|
@@ -134,8 +63,13 @@ class CribopsTrigger {
|
|
|
134
63
|
value: 'file_attachment',
|
|
135
64
|
description: 'File attachments',
|
|
136
65
|
},
|
|
66
|
+
{
|
|
67
|
+
name: 'System Event',
|
|
68
|
+
value: 'system_event',
|
|
69
|
+
description: 'System events and notifications',
|
|
70
|
+
},
|
|
137
71
|
],
|
|
138
|
-
default: ['user_message'],
|
|
72
|
+
default: ['user_message', 'agent_response'],
|
|
139
73
|
description: 'Types of events to trigger on',
|
|
140
74
|
},
|
|
141
75
|
{
|
|
@@ -153,7 +87,14 @@ class CribopsTrigger {
|
|
|
153
87
|
password: true,
|
|
154
88
|
},
|
|
155
89
|
default: '',
|
|
156
|
-
description: 'Secret token for webhook
|
|
90
|
+
description: 'Secret token for webhook signature validation',
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
displayName: 'Include Headers',
|
|
94
|
+
name: 'includeHeaders',
|
|
95
|
+
type: 'boolean',
|
|
96
|
+
default: false,
|
|
97
|
+
description: 'Whether to include the webhook headers in the output',
|
|
157
98
|
},
|
|
158
99
|
],
|
|
159
100
|
},
|
|
@@ -161,22 +102,28 @@ class CribopsTrigger {
|
|
|
161
102
|
};
|
|
162
103
|
methods = {
|
|
163
104
|
loadOptions: {
|
|
164
|
-
async
|
|
105
|
+
async getWebhooks() {
|
|
165
106
|
const credentials = await this.getCredentials('cribopsApi');
|
|
166
107
|
const cribopsHttp = new CribopsHttp_1.CribopsHttp({
|
|
167
108
|
baseUrl: credentials.baseUrl,
|
|
168
109
|
apiToken: credentials.apiToken,
|
|
169
110
|
});
|
|
170
111
|
try {
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
112
|
+
// Get organization ID from credentials if provided
|
|
113
|
+
const organizationId = credentials.organizationId;
|
|
114
|
+
const webhooks = await cribopsHttp.getWebhooks(organizationId);
|
|
115
|
+
// Filter for N8N type webhooks that are active and not linked
|
|
116
|
+
const availableWebhooks = webhooks.filter((webhook) => webhook.type === 'N8N' &&
|
|
117
|
+
webhook.status === 'active' &&
|
|
118
|
+
!webhook.linked_workflow_id);
|
|
119
|
+
return availableWebhooks.map((webhook) => ({
|
|
120
|
+
name: webhook.name,
|
|
121
|
+
value: webhook.id,
|
|
122
|
+
description: webhook.description || `Type: ${webhook.type}`,
|
|
176
123
|
}));
|
|
177
124
|
}
|
|
178
125
|
catch (error) {
|
|
179
|
-
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Failed to load
|
|
126
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Failed to load webhooks: ${error instanceof Error ? error.message : String(error)}`);
|
|
180
127
|
}
|
|
181
128
|
},
|
|
182
129
|
},
|
|
@@ -184,52 +131,38 @@ class CribopsTrigger {
|
|
|
184
131
|
webhookMethods = {
|
|
185
132
|
default: {
|
|
186
133
|
async checkExists() {
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
const cribopsHttp = new CribopsHttp_1.CribopsHttp({
|
|
191
|
-
baseUrl: credentials.baseUrl,
|
|
192
|
-
apiToken: credentials.apiToken,
|
|
193
|
-
});
|
|
194
|
-
try {
|
|
195
|
-
// Check if webhook exists for this agent
|
|
196
|
-
// This would need to be implemented in your Cribops API
|
|
197
|
-
// For now, return false to always create
|
|
198
|
-
return false;
|
|
199
|
-
}
|
|
200
|
-
catch (error) {
|
|
201
|
-
return false;
|
|
202
|
-
}
|
|
134
|
+
// Always return false to create webhook registration
|
|
135
|
+
// The actual webhook already exists in Cribops backend
|
|
136
|
+
return false;
|
|
203
137
|
},
|
|
204
138
|
async create() {
|
|
205
139
|
const webhookUrl = this.getNodeWebhookUrl('default');
|
|
206
|
-
const
|
|
207
|
-
const eventTypes = this.getNodeParameter('eventTypes', []);
|
|
208
|
-
const additionalFields = this.getNodeParameter('additionalFields', {});
|
|
140
|
+
const webhookId = this.getNodeParameter('webhookId');
|
|
209
141
|
const credentials = await this.getCredentials('cribopsApi');
|
|
142
|
+
const workflowId = this.getWorkflow().id;
|
|
143
|
+
const workflowName = this.getWorkflow().name;
|
|
210
144
|
const cribopsHttp = new CribopsHttp_1.CribopsHttp({
|
|
211
145
|
baseUrl: credentials.baseUrl,
|
|
212
146
|
apiToken: credentials.apiToken,
|
|
213
147
|
});
|
|
214
148
|
try {
|
|
215
|
-
//
|
|
216
|
-
// This is a placeholder - implement actual API call
|
|
149
|
+
// Link this workflow to the webhook entity
|
|
217
150
|
const body = {
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
151
|
+
workflow_id: workflowId,
|
|
152
|
+
webhook_url: webhookUrl,
|
|
153
|
+
test_webhook_url: webhookUrl.replace('/webhook/', '/webhook-test/'),
|
|
154
|
+
workflow_name: workflowName || 'Unnamed Workflow',
|
|
222
155
|
};
|
|
223
|
-
//
|
|
224
|
-
|
|
156
|
+
// Link the n8n workflow to the webhook entity
|
|
157
|
+
await cribopsHttp.request('POST', `/api/v1/webhooks/${webhookId}/link`, body);
|
|
225
158
|
// Store webhook data for later use
|
|
226
159
|
const webhookData = this.getWorkflowStaticData('node');
|
|
227
|
-
webhookData.webhookId =
|
|
228
|
-
webhookData.
|
|
160
|
+
webhookData.webhookId = webhookId;
|
|
161
|
+
webhookData.webhookUrl = webhookUrl;
|
|
229
162
|
return true;
|
|
230
163
|
}
|
|
231
164
|
catch (error) {
|
|
232
|
-
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Failed to
|
|
165
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Failed to link webhook: ${error instanceof Error ? error.message : String(error)}`);
|
|
233
166
|
}
|
|
234
167
|
},
|
|
235
168
|
async delete() {
|
|
@@ -243,118 +176,34 @@ class CribopsTrigger {
|
|
|
243
176
|
apiToken: credentials.apiToken,
|
|
244
177
|
});
|
|
245
178
|
try {
|
|
246
|
-
//
|
|
247
|
-
|
|
248
|
-
// await cribopsHttp.deleteWebhook(webhookData.agentId, webhookData.webhookId);
|
|
179
|
+
// Unlink the workflow from the webhook entity
|
|
180
|
+
await cribopsHttp.request('DELETE', `/api/v1/webhooks/${webhookData.webhookId}/link`);
|
|
249
181
|
delete webhookData.webhookId;
|
|
250
|
-
delete webhookData.
|
|
182
|
+
delete webhookData.webhookUrl;
|
|
251
183
|
return true;
|
|
252
184
|
}
|
|
253
185
|
catch (error) {
|
|
254
|
-
|
|
186
|
+
// Log error but don't fail
|
|
187
|
+
console.error('Failed to unlink webhook:', error);
|
|
188
|
+
return true;
|
|
255
189
|
}
|
|
256
190
|
},
|
|
257
191
|
},
|
|
258
192
|
};
|
|
259
|
-
async trigger() {
|
|
260
|
-
const triggerMode = this.getNodeParameter('triggerMode');
|
|
261
|
-
if (triggerMode === 'webhook') {
|
|
262
|
-
// Webhook mode - minimal implementation as webhooks are handled by webhook() method
|
|
263
|
-
return {
|
|
264
|
-
closeFunction: async () => { },
|
|
265
|
-
manualTriggerFunction: async () => {
|
|
266
|
-
throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'This node only works with webhooks in webhook mode. Please activate the workflow.');
|
|
267
|
-
},
|
|
268
|
-
};
|
|
269
|
-
}
|
|
270
|
-
// Polling mode
|
|
271
|
-
const credentials = await this.getCredentials('cribopsApi');
|
|
272
|
-
const tenantId = this.getNodeParameter('tenantId');
|
|
273
|
-
const pollInterval = this.getNodeParameter('pollInterval', 30);
|
|
274
|
-
const batchSize = this.getNodeParameter('batchSize', 10);
|
|
275
|
-
const queueName = this.getNodeParameter('queueName', '') || undefined;
|
|
276
|
-
const cribopsHttp = new CribopsHttp_1.CribopsHttp({
|
|
277
|
-
baseUrl: credentials.baseUrl,
|
|
278
|
-
apiToken: credentials.apiToken,
|
|
279
|
-
});
|
|
280
|
-
let intervalId;
|
|
281
|
-
const poll = async () => {
|
|
282
|
-
try {
|
|
283
|
-
const messages = await cribopsHttp.pollQueue(tenantId, batchSize, queueName);
|
|
284
|
-
if (messages.length > 0) {
|
|
285
|
-
const messageIds = messages.map(msg => msg.id);
|
|
286
|
-
// Process each message
|
|
287
|
-
for (const message of messages) {
|
|
288
|
-
// Parse the webhook data if it's JSON
|
|
289
|
-
let parsedData = message.data.data;
|
|
290
|
-
try {
|
|
291
|
-
parsedData = JSON.parse(message.data.data);
|
|
292
|
-
}
|
|
293
|
-
catch (e) {
|
|
294
|
-
// Keep as string if not valid JSON
|
|
295
|
-
}
|
|
296
|
-
// Emit the message
|
|
297
|
-
this.emit([
|
|
298
|
-
[
|
|
299
|
-
{
|
|
300
|
-
json: {
|
|
301
|
-
id: message.id,
|
|
302
|
-
correlation_id: message.correlation_id,
|
|
303
|
-
queue_name: message.queue_name,
|
|
304
|
-
data: parsedData,
|
|
305
|
-
headers: message.data.headers,
|
|
306
|
-
params: message.data.params,
|
|
307
|
-
inserted_at: message.inserted_at,
|
|
308
|
-
// Extract useful fields from headers
|
|
309
|
-
tenant_id: message.data.headers['x-cribops-tenant-id'] || tenantId,
|
|
310
|
-
path: message.data.headers['x-cribops-path'],
|
|
311
|
-
},
|
|
312
|
-
},
|
|
313
|
-
],
|
|
314
|
-
]);
|
|
315
|
-
}
|
|
316
|
-
// Acknowledge messages after processing
|
|
317
|
-
try {
|
|
318
|
-
await cribopsHttp.acknowledgeMessages(tenantId, messageIds);
|
|
319
|
-
}
|
|
320
|
-
catch (ackError) {
|
|
321
|
-
console.error('Failed to acknowledge messages:', ackError);
|
|
322
|
-
}
|
|
323
|
-
}
|
|
324
|
-
}
|
|
325
|
-
catch (error) {
|
|
326
|
-
console.error('Polling error:', error);
|
|
327
|
-
// Don't throw - continue polling
|
|
328
|
-
}
|
|
329
|
-
};
|
|
330
|
-
// Start polling
|
|
331
|
-
poll(); // Initial poll
|
|
332
|
-
intervalId = setInterval(poll, pollInterval * 1000);
|
|
333
|
-
// Manual trigger function for testing
|
|
334
|
-
const manualTriggerFunction = async () => {
|
|
335
|
-
await poll();
|
|
336
|
-
};
|
|
337
|
-
// Cleanup function
|
|
338
|
-
const closeFunction = async () => {
|
|
339
|
-
if (intervalId) {
|
|
340
|
-
clearInterval(intervalId);
|
|
341
|
-
}
|
|
342
|
-
};
|
|
343
|
-
return {
|
|
344
|
-
closeFunction,
|
|
345
|
-
manualTriggerFunction,
|
|
346
|
-
};
|
|
347
|
-
}
|
|
348
193
|
async webhook() {
|
|
349
194
|
const body = this.getBodyData();
|
|
350
195
|
const headers = this.getHeaderData();
|
|
351
196
|
const eventTypes = this.getNodeParameter('eventTypes', []);
|
|
352
197
|
const additionalFields = this.getNodeParameter('additionalFields', {});
|
|
353
|
-
const
|
|
198
|
+
const webhookId = this.getNodeParameter('webhookId');
|
|
354
199
|
// Validate secret token if provided
|
|
355
200
|
if (additionalFields.secretToken) {
|
|
356
|
-
|
|
357
|
-
|
|
201
|
+
// Check for signature in headers (could be HMAC signature or bearer token)
|
|
202
|
+
const signature = headers['x-cribops-signature'] || headers['x-webhook-signature'];
|
|
203
|
+
const authHeader = headers['authorization'];
|
|
204
|
+
// You can implement HMAC signature validation here if needed
|
|
205
|
+
// For now, simple token comparison
|
|
206
|
+
if (additionalFields.secretToken !== signature && `Bearer ${additionalFields.secretToken}` !== authHeader) {
|
|
358
207
|
return {
|
|
359
208
|
webhookResponse: {
|
|
360
209
|
status: 401,
|
|
@@ -363,8 +212,9 @@ class CribopsTrigger {
|
|
|
363
212
|
};
|
|
364
213
|
}
|
|
365
214
|
}
|
|
366
|
-
// Filter by event type
|
|
367
|
-
|
|
215
|
+
// Filter by event type if specified
|
|
216
|
+
const eventType = body.event_type || body.type || body.eventType;
|
|
217
|
+
if (eventTypes.length > 0 && eventType && !eventTypes.includes(eventType)) {
|
|
368
218
|
return {
|
|
369
219
|
webhookResponse: {
|
|
370
220
|
status: 200,
|
|
@@ -372,27 +222,40 @@ class CribopsTrigger {
|
|
|
372
222
|
},
|
|
373
223
|
};
|
|
374
224
|
}
|
|
375
|
-
//
|
|
225
|
+
// Prepare output data with all relevant fields
|
|
376
226
|
const outputData = {
|
|
227
|
+
// Core webhook data
|
|
228
|
+
webhook_id: webhookId,
|
|
229
|
+
event_type: eventType,
|
|
230
|
+
// Message content
|
|
231
|
+
message: body.message || body.content || body.text,
|
|
232
|
+
// Conversation/thread tracking
|
|
233
|
+
conversation_id: body.conversation_id || body.conversationId || body.thread_id || body.threadId,
|
|
234
|
+
// User/agent identification
|
|
235
|
+
user_id: body.user_id || body.userId || body.from_user || body.fromUser,
|
|
236
|
+
agent_id: body.agent_id || body.agentId || body.to_agent || body.toAgent,
|
|
237
|
+
// Response handling
|
|
238
|
+
response_webhook: body.response_webhook || body.responseWebhook || body.callback_url || body.callbackUrl,
|
|
239
|
+
// Metadata
|
|
240
|
+
metadata: body.metadata || {},
|
|
241
|
+
// File attachments if any
|
|
242
|
+
attachments: body.attachments || body.files || [],
|
|
243
|
+
// Timestamp
|
|
244
|
+
timestamp: body.timestamp || body.created_at || body.createdAt || new Date().toISOString(),
|
|
245
|
+
// Include any other fields from the webhook
|
|
377
246
|
...body,
|
|
378
|
-
agent_id: agentId,
|
|
379
|
-
// Ensure conversation_id is available (handle different field names)
|
|
380
|
-
conversation_id: body.conversation_id || body.conversationId || body.thread_id,
|
|
381
|
-
// Ensure response_webhook is available if it exists
|
|
382
|
-
response_webhook: body.response_webhook || body.responseWebhook || body.callback_url,
|
|
383
247
|
};
|
|
384
|
-
//
|
|
385
|
-
|
|
248
|
+
// Include headers if requested
|
|
249
|
+
const workflowData = additionalFields.includeHeaders
|
|
250
|
+
? { json: outputData, headers }
|
|
251
|
+
: { json: outputData };
|
|
386
252
|
// Return the data to the workflow
|
|
387
253
|
return {
|
|
388
|
-
workflowData: [
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
},
|
|
394
|
-
],
|
|
395
|
-
],
|
|
254
|
+
workflowData: [[workflowData]],
|
|
255
|
+
webhookResponse: {
|
|
256
|
+
status: 200,
|
|
257
|
+
body: { received: true },
|
|
258
|
+
},
|
|
396
259
|
};
|
|
397
260
|
}
|
|
398
261
|
}
|
package/dist/package.json
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { IDataObject } from 'n8n-workflow';
|
|
1
|
+
import { IDataObject, IHttpRequestMethods, IHttpRequestOptions } from 'n8n-workflow';
|
|
2
2
|
export interface CribopsHttpConfig {
|
|
3
3
|
baseUrl: string;
|
|
4
4
|
apiToken: string;
|
|
@@ -37,6 +37,18 @@ export interface CribopsQueueMessage {
|
|
|
37
37
|
};
|
|
38
38
|
inserted_at: string;
|
|
39
39
|
}
|
|
40
|
+
export interface CribopsWebhookEntity {
|
|
41
|
+
id: string;
|
|
42
|
+
name: string;
|
|
43
|
+
description?: string;
|
|
44
|
+
type: 'N8N' | 'GHL_API' | 'GENERIC';
|
|
45
|
+
status: 'active' | 'inactive';
|
|
46
|
+
linked_workflow_id?: string;
|
|
47
|
+
linked_workflow_name?: string;
|
|
48
|
+
organization_id: string;
|
|
49
|
+
created_at: string;
|
|
50
|
+
updated_at: string;
|
|
51
|
+
}
|
|
40
52
|
export declare class CribopsHttp {
|
|
41
53
|
private config;
|
|
42
54
|
constructor(config: CribopsHttpConfig);
|
|
@@ -57,4 +69,13 @@ export declare class CribopsHttp {
|
|
|
57
69
|
status: string;
|
|
58
70
|
updated_count: number;
|
|
59
71
|
}>;
|
|
72
|
+
getWebhooks(organizationId?: string): Promise<CribopsWebhookEntity[]>;
|
|
73
|
+
linkWebhook(webhookId: string, linkData: {
|
|
74
|
+
workflow_id: string;
|
|
75
|
+
webhook_url: string;
|
|
76
|
+
test_webhook_url: string;
|
|
77
|
+
workflow_name: string;
|
|
78
|
+
}): Promise<any>;
|
|
79
|
+
unlinkWebhook(webhookId: string): Promise<any>;
|
|
80
|
+
request<T = any>(method: IHttpRequestMethods, endpoint: string, data?: IDataObject, options?: Partial<IHttpRequestOptions>): Promise<T>;
|
|
60
81
|
}
|
|
@@ -10,7 +10,21 @@ class CribopsHttp {
|
|
|
10
10
|
};
|
|
11
11
|
}
|
|
12
12
|
async makeRequest(method, endpoint, data, options) {
|
|
13
|
-
|
|
13
|
+
let url = `${this.config.baseUrl}${endpoint}`;
|
|
14
|
+
// Handle query parameters
|
|
15
|
+
if (method === 'GET' && data?.params) {
|
|
16
|
+
const params = new URLSearchParams();
|
|
17
|
+
Object.entries(data.params).forEach(([key, value]) => {
|
|
18
|
+
if (value !== undefined && value !== null) {
|
|
19
|
+
params.append(key, String(value));
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
const queryString = params.toString();
|
|
23
|
+
if (queryString) {
|
|
24
|
+
url += `?${queryString}`;
|
|
25
|
+
}
|
|
26
|
+
delete data.params;
|
|
27
|
+
}
|
|
14
28
|
const requestHeaders = {
|
|
15
29
|
'Authorization': `Bearer ${this.config.apiToken}`,
|
|
16
30
|
'Content-Type': 'application/json',
|
|
@@ -25,7 +39,7 @@ class CribopsHttp {
|
|
|
25
39
|
const response = await fetch(url, {
|
|
26
40
|
method,
|
|
27
41
|
headers: requestHeaders,
|
|
28
|
-
body: data ? JSON.stringify(data) : undefined,
|
|
42
|
+
body: (method !== 'GET' && data) ? JSON.stringify(data) : undefined,
|
|
29
43
|
});
|
|
30
44
|
if (!response.ok) {
|
|
31
45
|
const errorText = await response.text();
|
|
@@ -144,5 +158,36 @@ class CribopsHttp {
|
|
|
144
158
|
throw new Error(`Failed to mark messages as failed for tenant ${tenantId}: ${error}`);
|
|
145
159
|
}
|
|
146
160
|
}
|
|
161
|
+
// Webhook-specific methods
|
|
162
|
+
async getWebhooks(organizationId) {
|
|
163
|
+
try {
|
|
164
|
+
const params = organizationId ? { params: { organization_id: organizationId } } : undefined;
|
|
165
|
+
const response = await this.makeRequest('GET', '/api/v1/webhooks', params);
|
|
166
|
+
return response.data || [];
|
|
167
|
+
}
|
|
168
|
+
catch (error) {
|
|
169
|
+
throw new Error(`Failed to fetch webhooks: ${error}`);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
async linkWebhook(webhookId, linkData) {
|
|
173
|
+
try {
|
|
174
|
+
return await this.makeRequest('POST', `/api/v1/webhooks/${webhookId}/link`, linkData);
|
|
175
|
+
}
|
|
176
|
+
catch (error) {
|
|
177
|
+
throw new Error(`Failed to link webhook: ${error}`);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
async unlinkWebhook(webhookId) {
|
|
181
|
+
try {
|
|
182
|
+
return await this.makeRequest('DELETE', `/api/v1/webhooks/${webhookId}/link`);
|
|
183
|
+
}
|
|
184
|
+
catch (error) {
|
|
185
|
+
throw new Error(`Failed to unlink webhook: ${error}`);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
// Generic request method for custom API calls
|
|
189
|
+
async request(method, endpoint, data, options) {
|
|
190
|
+
return this.makeRequest(method, endpoint, data, options);
|
|
191
|
+
}
|
|
147
192
|
}
|
|
148
193
|
exports.CribopsHttp = CribopsHttp;
|