n8n-nodes-cribops 0.1.24 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +149 -245
- package/dist/credentials/CribopsApi.credentials.js +3 -3
- package/dist/credentials/HiveApi.credentials.d.ts +7 -0
- package/dist/credentials/HiveApi.credentials.js +44 -0
- package/dist/nodes/Cribops/Cribops.node.d.ts +1 -6
- package/dist/nodes/Cribops/Cribops.node.js +343 -494
- package/dist/nodes/CribopsTrigger/CribopsTrigger.node.d.ts +1 -6
- package/dist/nodes/CribopsTrigger/CribopsTrigger.node.js +122 -159
- package/dist/nodes/HiveAccelerator/HiveAccelerator.node.d.ts +5 -0
- package/dist/nodes/HiveAccelerator/HiveAccelerator.node.js +461 -0
- package/dist/nodes/HiveAccelerator/hive.svg +7 -0
- package/dist/package.json +11 -5
- package/dist/utils/CribopsHttp.d.ts +190 -56
- package/dist/utils/CribopsHttp.js +84 -92
- package/dist/utils/HiveClient.d.ts +138 -0
- package/dist/utils/HiveClient.js +113 -0
- package/package.json +11 -5
|
@@ -1,11 +1,6 @@
|
|
|
1
|
-
import { INodeType, INodeTypeDescription, IWebhookFunctions, IWebhookResponseData, IHookFunctions
|
|
1
|
+
import { INodeType, INodeTypeDescription, IWebhookFunctions, IWebhookResponseData, IHookFunctions } from 'n8n-workflow';
|
|
2
2
|
export declare class CribopsTrigger implements INodeType {
|
|
3
3
|
description: INodeTypeDescription;
|
|
4
|
-
methods: {
|
|
5
|
-
loadOptions: {
|
|
6
|
-
getWebhooks(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]>;
|
|
7
|
-
};
|
|
8
|
-
};
|
|
9
4
|
webhookMethods: {
|
|
10
5
|
default: {
|
|
11
6
|
checkExists(this: IHookFunctions): Promise<boolean>;
|
|
@@ -5,14 +5,14 @@ const n8n_workflow_1 = require("n8n-workflow");
|
|
|
5
5
|
const CribopsHttp_1 = require("../../utils/CribopsHttp");
|
|
6
6
|
class CribopsTrigger {
|
|
7
7
|
description = {
|
|
8
|
-
displayName: 'Cribops Trigger',
|
|
8
|
+
displayName: 'Cribops Webhook Trigger',
|
|
9
9
|
name: 'cribopsTrigger',
|
|
10
10
|
icon: 'file:cribopstrigger.svg',
|
|
11
11
|
group: ['trigger'],
|
|
12
12
|
version: 1,
|
|
13
|
-
description: '
|
|
13
|
+
description: 'Receive webhooks from Cribops queue at a controlled rate',
|
|
14
14
|
defaults: {
|
|
15
|
-
name: 'Cribops Trigger',
|
|
15
|
+
name: 'Cribops Webhook Trigger',
|
|
16
16
|
},
|
|
17
17
|
inputs: [],
|
|
18
18
|
outputs: ["main" /* NodeConnectionType.Main */],
|
|
@@ -27,167 +27,128 @@ class CribopsTrigger {
|
|
|
27
27
|
name: 'default',
|
|
28
28
|
httpMethod: 'POST',
|
|
29
29
|
responseMode: 'onReceived',
|
|
30
|
-
path: '={{$parameter["
|
|
30
|
+
path: '={{$parameter["webhookPath"]}}',
|
|
31
31
|
isFullPath: false,
|
|
32
32
|
},
|
|
33
33
|
],
|
|
34
34
|
properties: [
|
|
35
35
|
{
|
|
36
|
-
displayName: 'Webhook
|
|
37
|
-
name: '
|
|
38
|
-
type: '
|
|
36
|
+
displayName: 'Webhook Path',
|
|
37
|
+
name: 'webhookPath',
|
|
38
|
+
type: 'string',
|
|
39
39
|
required: true,
|
|
40
|
-
typeOptions: {
|
|
41
|
-
loadOptionsMethod: 'getWebhooks',
|
|
42
|
-
},
|
|
43
40
|
default: '',
|
|
44
|
-
|
|
41
|
+
placeholder: 'my-webhook-endpoint',
|
|
42
|
+
description: 'The path for this webhook endpoint (will be appended to your n8n webhook URL)',
|
|
45
43
|
},
|
|
46
44
|
{
|
|
47
|
-
displayName: '
|
|
48
|
-
name: '
|
|
49
|
-
type: '
|
|
45
|
+
displayName: 'Options',
|
|
46
|
+
name: 'options',
|
|
47
|
+
type: 'collection',
|
|
48
|
+
placeholder: 'Add Option',
|
|
49
|
+
default: {},
|
|
50
50
|
options: [
|
|
51
51
|
{
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
52
|
+
displayName: 'Include Cribops Metadata',
|
|
53
|
+
name: 'includeCribopsMetadata',
|
|
54
|
+
type: 'boolean',
|
|
55
|
+
default: true,
|
|
56
|
+
description: 'Include Cribops tracking ID, queue info, and processing metadata',
|
|
55
57
|
},
|
|
56
58
|
{
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
59
|
+
displayName: 'Include Original Headers',
|
|
60
|
+
name: 'includeHeaders',
|
|
61
|
+
type: 'boolean',
|
|
62
|
+
default: false,
|
|
63
|
+
description: 'Include the original webhook headers',
|
|
60
64
|
},
|
|
61
65
|
{
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
66
|
+
displayName: 'Report Performance',
|
|
67
|
+
name: 'reportPerformance',
|
|
68
|
+
type: 'boolean',
|
|
69
|
+
default: true,
|
|
70
|
+
description: 'Automatically report processing time back to Cribops',
|
|
65
71
|
},
|
|
66
72
|
{
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
73
|
+
displayName: 'Report Errors',
|
|
74
|
+
name: 'reportErrors',
|
|
75
|
+
type: 'boolean',
|
|
76
|
+
default: true,
|
|
77
|
+
description: 'Automatically report errors back to Cribops for monitoring',
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
displayName: 'Validate Signature',
|
|
81
|
+
name: 'validateSignature',
|
|
82
|
+
type: 'boolean',
|
|
83
|
+
default: true,
|
|
84
|
+
description: 'Validate webhook signature from Cribops',
|
|
70
85
|
},
|
|
71
|
-
],
|
|
72
|
-
default: ['user_message', 'agent_response'],
|
|
73
|
-
description: 'Types of events to trigger on',
|
|
74
|
-
},
|
|
75
|
-
{
|
|
76
|
-
displayName: 'Additional Fields',
|
|
77
|
-
name: 'additionalFields',
|
|
78
|
-
type: 'collection',
|
|
79
|
-
placeholder: 'Add Field',
|
|
80
|
-
default: {},
|
|
81
|
-
options: [
|
|
82
86
|
{
|
|
83
|
-
displayName: 'Secret
|
|
84
|
-
name: '
|
|
87
|
+
displayName: 'Signature Secret',
|
|
88
|
+
name: 'signatureSecret',
|
|
85
89
|
type: 'string',
|
|
86
90
|
typeOptions: {
|
|
87
91
|
password: true,
|
|
88
92
|
},
|
|
93
|
+
displayOptions: {
|
|
94
|
+
show: {
|
|
95
|
+
validateSignature: [true],
|
|
96
|
+
},
|
|
97
|
+
},
|
|
89
98
|
default: '',
|
|
90
|
-
description: 'Secret
|
|
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',
|
|
99
|
+
description: 'Secret key shared with Cribops for signature validation',
|
|
98
100
|
},
|
|
99
101
|
],
|
|
100
102
|
},
|
|
101
103
|
],
|
|
102
104
|
};
|
|
103
|
-
methods = {
|
|
104
|
-
loadOptions: {
|
|
105
|
-
async getWebhooks() {
|
|
106
|
-
const credentials = await this.getCredentials('cribopsApi');
|
|
107
|
-
const cribopsHttp = new CribopsHttp_1.CribopsHttp({
|
|
108
|
-
baseUrl: credentials.baseUrl,
|
|
109
|
-
apiToken: credentials.apiToken,
|
|
110
|
-
});
|
|
111
|
-
try {
|
|
112
|
-
// Organization is automatically determined from API key
|
|
113
|
-
const webhooks = await cribopsHttp.getWebhooks();
|
|
114
|
-
// Filter for N8N type webhooks that are active and not linked
|
|
115
|
-
const availableWebhooks = webhooks.filter((webhook) => webhook.type === 'N8N' &&
|
|
116
|
-
webhook.status === 'active' &&
|
|
117
|
-
!webhook.linked_workflow_id);
|
|
118
|
-
return availableWebhooks.map((webhook) => ({
|
|
119
|
-
name: webhook.name,
|
|
120
|
-
value: webhook.id,
|
|
121
|
-
description: webhook.description || `Type: ${webhook.type}`,
|
|
122
|
-
}));
|
|
123
|
-
}
|
|
124
|
-
catch (error) {
|
|
125
|
-
let errorMessage = 'Failed to load webhooks';
|
|
126
|
-
if (error instanceof Error) {
|
|
127
|
-
errorMessage += `: ${error.message}`;
|
|
128
|
-
// Check for common issues
|
|
129
|
-
if (error.message.includes('HTTP 401') || error.message.includes('Unauthorized')) {
|
|
130
|
-
errorMessage = 'Authentication failed. Please check your API token in the credentials.';
|
|
131
|
-
}
|
|
132
|
-
else if (error.message.includes('HTTP 404')) {
|
|
133
|
-
errorMessage = 'Webhook endpoint not found. Please check the API base URL in credentials.';
|
|
134
|
-
}
|
|
135
|
-
else if (error.message.includes('HTTP 403')) {
|
|
136
|
-
errorMessage = 'Access forbidden. Your API token may not have permission to access webhooks.';
|
|
137
|
-
}
|
|
138
|
-
else if (error.message.includes('Failed to fetch') || error.message.includes('network')) {
|
|
139
|
-
errorMessage = 'Network error. Please check the API base URL and ensure the Cribops API is accessible.';
|
|
140
|
-
}
|
|
141
|
-
else if (error.message.includes('HTTP 400')) {
|
|
142
|
-
errorMessage = 'Bad request. Please check that the API endpoint is correct and your API token has the necessary permissions.';
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
throw new n8n_workflow_1.NodeOperationError(this.getNode(), errorMessage);
|
|
146
|
-
}
|
|
147
|
-
},
|
|
148
|
-
},
|
|
149
|
-
};
|
|
150
105
|
webhookMethods = {
|
|
151
106
|
default: {
|
|
152
107
|
async checkExists() {
|
|
153
|
-
// Always return false to
|
|
154
|
-
// The actual webhook already exists in Cribops backend
|
|
108
|
+
// Always return false to ensure webhook is registered
|
|
155
109
|
return false;
|
|
156
110
|
},
|
|
157
111
|
async create() {
|
|
158
112
|
const webhookUrl = this.getNodeWebhookUrl('default');
|
|
159
|
-
const
|
|
113
|
+
const webhookPath = this.getNodeParameter('webhookPath');
|
|
114
|
+
const options = this.getNodeParameter('options');
|
|
160
115
|
const credentials = await this.getCredentials('cribopsApi');
|
|
161
116
|
const workflowId = this.getWorkflow().id;
|
|
162
117
|
const workflowName = this.getWorkflow().name;
|
|
118
|
+
if (!webhookPath) {
|
|
119
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Webhook path is required');
|
|
120
|
+
}
|
|
163
121
|
const cribopsHttp = new CribopsHttp_1.CribopsHttp({
|
|
164
122
|
baseUrl: credentials.baseUrl,
|
|
165
123
|
apiToken: credentials.apiToken,
|
|
166
124
|
});
|
|
167
125
|
try {
|
|
168
|
-
//
|
|
169
|
-
const
|
|
170
|
-
|
|
171
|
-
|
|
126
|
+
// Register this N8N endpoint with Cribops so it knows where to send webhooks
|
|
127
|
+
const registrationData = {
|
|
128
|
+
webhook_path: webhookPath,
|
|
129
|
+
n8n_webhook_url: webhookUrl,
|
|
172
130
|
test_webhook_url: webhookUrl.replace('/webhook/', '/webhook-test/'),
|
|
131
|
+
workflow_id: workflowId,
|
|
173
132
|
workflow_name: workflowName || 'Unnamed Workflow',
|
|
133
|
+
report_performance: options.reportPerformance !== false,
|
|
134
|
+
report_errors: options.reportErrors !== false,
|
|
135
|
+
signature_secret: options.signatureSecret ? String(options.signatureSecret) : null,
|
|
174
136
|
};
|
|
175
|
-
|
|
176
|
-
await cribopsHttp.request('POST', `/api/v1/webhooks/${webhookId}/link`, body);
|
|
137
|
+
await cribopsHttp.registerN8NEndpoint(registrationData);
|
|
177
138
|
// Store webhook data for later use
|
|
178
139
|
const webhookData = this.getWorkflowStaticData('node');
|
|
179
|
-
webhookData.
|
|
140
|
+
webhookData.webhookPath = webhookPath;
|
|
180
141
|
webhookData.webhookUrl = webhookUrl;
|
|
181
142
|
return true;
|
|
182
143
|
}
|
|
183
144
|
catch (error) {
|
|
184
|
-
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Failed to
|
|
145
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Failed to register N8N endpoint with Cribops: ${error instanceof Error ? error.message : String(error)}`);
|
|
185
146
|
}
|
|
186
147
|
},
|
|
187
148
|
async delete() {
|
|
188
149
|
const webhookData = this.getWorkflowStaticData('node');
|
|
189
150
|
const credentials = await this.getCredentials('cribopsApi');
|
|
190
|
-
if (!webhookData.
|
|
151
|
+
if (!webhookData.webhookPath) {
|
|
191
152
|
return true;
|
|
192
153
|
}
|
|
193
154
|
const cribopsHttp = new CribopsHttp_1.CribopsHttp({
|
|
@@ -195,15 +156,15 @@ class CribopsTrigger {
|
|
|
195
156
|
apiToken: credentials.apiToken,
|
|
196
157
|
});
|
|
197
158
|
try {
|
|
198
|
-
//
|
|
199
|
-
await cribopsHttp.
|
|
200
|
-
delete webhookData.
|
|
159
|
+
// Unregister the N8N endpoint
|
|
160
|
+
await cribopsHttp.unregisterN8NEndpoint(webhookData.webhookPath);
|
|
161
|
+
delete webhookData.webhookPath;
|
|
201
162
|
delete webhookData.webhookUrl;
|
|
202
163
|
return true;
|
|
203
164
|
}
|
|
204
165
|
catch (error) {
|
|
205
166
|
// Log error but don't fail
|
|
206
|
-
console.error('Failed to
|
|
167
|
+
console.error('Failed to unregister N8N endpoint:', error);
|
|
207
168
|
return true;
|
|
208
169
|
}
|
|
209
170
|
},
|
|
@@ -212,68 +173,70 @@ class CribopsTrigger {
|
|
|
212
173
|
async webhook() {
|
|
213
174
|
const body = this.getBodyData();
|
|
214
175
|
const headers = this.getHeaderData();
|
|
215
|
-
const
|
|
216
|
-
const
|
|
217
|
-
const
|
|
218
|
-
|
|
219
|
-
if (
|
|
220
|
-
|
|
221
|
-
const signature = headers['x-cribops-signature']
|
|
222
|
-
const
|
|
223
|
-
|
|
224
|
-
// For now, simple token comparison
|
|
225
|
-
if (additionalFields.secretToken !== signature && `Bearer ${additionalFields.secretToken}` !== authHeader) {
|
|
176
|
+
const options = this.getNodeParameter('options');
|
|
177
|
+
const webhookPath = this.getNodeParameter('webhookPath');
|
|
178
|
+
const credentials = await this.getCredentials('cribopsApi');
|
|
179
|
+
const startTime = Date.now();
|
|
180
|
+
// Validate signature if enabled (Cribops signs webhooks it sends)
|
|
181
|
+
if (options.validateSignature) {
|
|
182
|
+
const signature = headers['x-cribops-signature'];
|
|
183
|
+
const secret = options.signatureSecret;
|
|
184
|
+
if (!signature) {
|
|
226
185
|
return {
|
|
227
186
|
webhookResponse: {
|
|
228
187
|
status: 401,
|
|
229
|
-
body: { error: '
|
|
188
|
+
body: { error: 'Missing Cribops signature' },
|
|
230
189
|
},
|
|
231
190
|
};
|
|
232
191
|
}
|
|
192
|
+
// TODO: Implement HMAC validation with shared secret
|
|
233
193
|
}
|
|
234
|
-
//
|
|
235
|
-
const
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
194
|
+
// Extract Cribops metadata from the webhook
|
|
195
|
+
const cribopsMetadata = {
|
|
196
|
+
webhook_id: body.webhook_id || headers['x-cribops-webhook-id'],
|
|
197
|
+
queue_name: body.queue_name || headers['x-cribops-queue'],
|
|
198
|
+
original_source: body.original_source || headers['x-cribops-source'],
|
|
199
|
+
received_at: body.received_at || headers['x-cribops-received-at'],
|
|
200
|
+
attempt_number: body.attempt_number || headers['x-cribops-attempt'] || 1,
|
|
201
|
+
};
|
|
202
|
+
// Prepare webhook data
|
|
203
|
+
const webhookData = {
|
|
204
|
+
// The actual webhook payload
|
|
205
|
+
payload: body.payload || body,
|
|
206
|
+
// Processing metadata
|
|
207
|
+
processed_at: new Date().toISOString(),
|
|
208
|
+
webhook_path: webhookPath,
|
|
209
|
+
};
|
|
210
|
+
// Include Cribops metadata if requested
|
|
211
|
+
if (options.includeCribopsMetadata !== false) {
|
|
212
|
+
webhookData.cribops = cribopsMetadata;
|
|
213
|
+
}
|
|
214
|
+
// Include original headers if requested
|
|
215
|
+
if (options.includeHeaders) {
|
|
216
|
+
webhookData.original_headers = body.original_headers || headers;
|
|
217
|
+
}
|
|
218
|
+
// Track processing time for performance reporting
|
|
219
|
+
const processingTime = Date.now() - startTime;
|
|
220
|
+
// If performance reporting is enabled, we'll report after workflow completes
|
|
221
|
+
if (options.reportPerformance !== false && cribopsMetadata.webhook_id) {
|
|
222
|
+
// Store for later reporting
|
|
223
|
+
const staticData = this.getWorkflowStaticData('node');
|
|
224
|
+
staticData.performanceTracking = {
|
|
225
|
+
webhook_id: cribopsMetadata.webhook_id,
|
|
226
|
+
start_time: startTime,
|
|
227
|
+
receive_time: processingTime,
|
|
242
228
|
};
|
|
243
229
|
}
|
|
244
|
-
// Prepare output data with all relevant fields
|
|
245
|
-
const outputData = {
|
|
246
|
-
// Core webhook data
|
|
247
|
-
webhook_id: webhookId,
|
|
248
|
-
event_type: eventType,
|
|
249
|
-
// Message content
|
|
250
|
-
message: body.message || body.content || body.text,
|
|
251
|
-
// Conversation/thread tracking
|
|
252
|
-
conversation_id: body.conversation_id || body.conversationId || body.thread_id || body.threadId,
|
|
253
|
-
// User/agent identification
|
|
254
|
-
user_id: body.user_id || body.userId || body.from_user || body.fromUser,
|
|
255
|
-
agent_id: body.agent_id || body.agentId || body.to_agent || body.toAgent,
|
|
256
|
-
// Response handling
|
|
257
|
-
response_webhook: body.response_webhook || body.responseWebhook || body.callback_url || body.callbackUrl,
|
|
258
|
-
// Metadata
|
|
259
|
-
metadata: body.metadata || {},
|
|
260
|
-
// File attachments if any
|
|
261
|
-
attachments: body.attachments || body.files || [],
|
|
262
|
-
// Timestamp
|
|
263
|
-
timestamp: body.timestamp || body.created_at || body.createdAt || new Date().toISOString(),
|
|
264
|
-
// Include any other fields from the webhook
|
|
265
|
-
...body,
|
|
266
|
-
};
|
|
267
|
-
// Include headers if requested
|
|
268
|
-
const workflowData = additionalFields.includeHeaders
|
|
269
|
-
? { json: outputData, headers }
|
|
270
|
-
: { json: outputData };
|
|
271
230
|
// Return the data to the workflow
|
|
272
231
|
return {
|
|
273
|
-
workflowData: [[
|
|
232
|
+
workflowData: [[{ json: webhookData }]],
|
|
274
233
|
webhookResponse: {
|
|
275
234
|
status: 200,
|
|
276
|
-
body: {
|
|
235
|
+
body: {
|
|
236
|
+
received: true,
|
|
237
|
+
webhook_id: cribopsMetadata.webhook_id,
|
|
238
|
+
processing_time_ms: processingTime,
|
|
239
|
+
},
|
|
277
240
|
},
|
|
278
241
|
};
|
|
279
242
|
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { IExecuteFunctions, INodeExecutionData, INodeType, INodeTypeDescription } from 'n8n-workflow';
|
|
2
|
+
export declare class HiveAccelerator implements INodeType {
|
|
3
|
+
description: INodeTypeDescription;
|
|
4
|
+
execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]>;
|
|
5
|
+
}
|