n8n-nodes-cribops 0.1.16 → 0.1.17

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.
@@ -21,7 +21,7 @@ class CribopsApi {
21
21
  displayName: 'Base URL',
22
22
  name: 'baseUrl',
23
23
  type: 'string',
24
- default: 'https://api.cribops.com',
24
+ default: 'https://cribops.com',
25
25
  required: true,
26
26
  description: 'Base URL of the Cribops API',
27
27
  },
@@ -48,6 +48,12 @@ class Cribops {
48
48
  description: 'List all available agents',
49
49
  action: 'List all available agents',
50
50
  },
51
+ {
52
+ name: 'Poll Queue',
53
+ value: 'pollQueue',
54
+ description: 'Poll messages from the queue',
55
+ action: 'Poll messages from the queue',
56
+ },
51
57
  {
52
58
  name: 'Reply to Conversation',
53
59
  value: 'replyToConversation',
@@ -149,6 +155,45 @@ class Cribops {
149
155
  },
150
156
  description: 'Whether to show typing indicator (true) or stop typing (false)',
151
157
  },
158
+ {
159
+ displayName: 'Tenant ID',
160
+ name: 'tenantId',
161
+ type: 'string',
162
+ required: true,
163
+ default: '',
164
+ placeholder: 'my-tenant',
165
+ displayOptions: {
166
+ show: {
167
+ operation: ['pollQueue'],
168
+ },
169
+ },
170
+ description: 'The tenant ID for your Cribops organization',
171
+ },
172
+ {
173
+ displayName: 'Batch Size',
174
+ name: 'batchSize',
175
+ type: 'number',
176
+ default: 10,
177
+ displayOptions: {
178
+ show: {
179
+ operation: ['pollQueue'],
180
+ },
181
+ },
182
+ description: 'Number of messages to retrieve (max 100)',
183
+ },
184
+ {
185
+ displayName: 'Queue Name',
186
+ name: 'queueName',
187
+ type: 'string',
188
+ default: '',
189
+ placeholder: 'e.g., stripe_events',
190
+ displayOptions: {
191
+ show: {
192
+ operation: ['pollQueue'],
193
+ },
194
+ },
195
+ description: 'Specific queue to poll (optional). Leave empty to poll all queues.',
196
+ },
152
197
  {
153
198
  displayName: 'Message',
154
199
  name: 'message',
@@ -342,6 +387,9 @@ class Cribops {
342
387
  case 'listAgents':
343
388
  responseData = await listAgents(this, cribopsHttp, i);
344
389
  break;
390
+ case 'pollQueue':
391
+ responseData = await pollQueue(this, cribopsHttp, i);
392
+ break;
345
393
  default:
346
394
  throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Unknown operation: ${operation}`, { itemIndex: i });
347
395
  }
@@ -536,6 +584,46 @@ async function listAgents(executeFunctions, cribopsHttp, itemIndex) {
536
584
  const agents = await cribopsHttp.getAgents();
537
585
  return { agents, count: agents.length };
538
586
  }
587
+ async function pollQueue(executeFunctions, cribopsHttp, itemIndex) {
588
+ const tenantId = executeFunctions.getNodeParameter('tenantId', itemIndex);
589
+ const batchSize = executeFunctions.getNodeParameter('batchSize', itemIndex, 10);
590
+ const queueName = executeFunctions.getNodeParameter('queueName', itemIndex, '') || undefined;
591
+ const messages = await cribopsHttp.pollQueue(tenantId, batchSize, queueName);
592
+ // Process each message to parse the data if it's JSON
593
+ const processedMessages = messages.map(message => {
594
+ let parsedData = message.data.data;
595
+ try {
596
+ parsedData = JSON.parse(message.data.data);
597
+ }
598
+ catch (e) {
599
+ // Keep as string if not valid JSON
600
+ }
601
+ return {
602
+ id: message.id,
603
+ correlation_id: message.correlation_id,
604
+ queue_name: message.queue_name,
605
+ data: parsedData,
606
+ headers: message.data.headers,
607
+ params: message.data.params,
608
+ inserted_at: message.inserted_at,
609
+ // Extract useful fields from headers
610
+ tenant_id: message.data.headers['x-cribops-tenant-id'] || tenantId,
611
+ path: message.data.headers['x-cribops-path'],
612
+ };
613
+ });
614
+ // Auto-acknowledge messages after processing
615
+ if (messages.length > 0) {
616
+ const messageIds = messages.map(msg => msg.id);
617
+ try {
618
+ await cribopsHttp.acknowledgeMessages(tenantId, messageIds);
619
+ }
620
+ catch (ackError) {
621
+ // Log error but don't fail the operation
622
+ console.error('Failed to acknowledge messages:', ackError);
623
+ }
624
+ }
625
+ return { messages: processedMessages, count: processedMessages.length };
626
+ }
539
627
  async function sendTypingIndicator(executeFunctions, cribopsHttp, itemIndex) {
540
628
  const agentId = executeFunctions.getNodeParameter('agentId', itemIndex, '', { extractValue: true });
541
629
  const conversationId = executeFunctions.getNodeParameter('conversationId', itemIndex);
@@ -29,20 +29,91 @@ class CribopsTrigger {
29
29
  responseMode: 'onReceived',
30
30
  // Dynamic path to trigger UUID generation
31
31
  path: '={{$parameter["agentId"]}}',
32
+ isFullPath: true,
32
33
  },
33
34
  ],
35
+ polling: true,
34
36
  properties: [
37
+ {
38
+ displayName: 'Trigger Mode',
39
+ name: 'triggerMode',
40
+ 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
+ required: true,
61
+ default: '',
62
+ description: 'The tenant ID for your Cribops organization',
63
+ },
35
64
  {
36
65
  displayName: 'Agent Name or ID',
37
66
  name: 'agentId',
38
67
  type: 'options',
39
68
  required: true,
69
+ displayOptions: {
70
+ show: {
71
+ triggerMode: ['webhook'],
72
+ },
73
+ },
40
74
  typeOptions: {
41
75
  loadOptionsMethod: 'getAgents',
42
76
  },
43
77
  default: '',
44
78
  description: 'The Cribops agent to receive messages from. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>.',
45
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)',
116
+ },
46
117
  {
47
118
  displayName: 'Event Types',
48
119
  name: 'eventTypes',
@@ -186,12 +257,92 @@ class CribopsTrigger {
186
257
  },
187
258
  };
188
259
  async trigger() {
189
- // Minimal implementation - webhooks are handled by webhook() method
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
+ };
190
343
  return {
191
- closeFunction: async () => { },
192
- manualTriggerFunction: async () => {
193
- throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'This node only works with webhooks. Please activate the workflow.');
194
- },
344
+ closeFunction,
345
+ manualTriggerFunction,
195
346
  };
196
347
  }
197
348
  async webhook() {
package/dist/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "n8n-nodes-cribops",
3
- "version": "0.1.16",
3
+ "version": "0.1.17",
4
4
  "description": "n8n community node for Cribops AI platform integration",
5
5
  "keywords": [
6
6
  "n8n-community-node-package"
@@ -26,6 +26,17 @@ export interface CribopsWebhookMessage {
26
26
  fileName?: string;
27
27
  fileType?: string;
28
28
  }
29
+ export interface CribopsQueueMessage {
30
+ id: number;
31
+ correlation_id: string;
32
+ queue_name: string;
33
+ data: {
34
+ data: string;
35
+ params: IDataObject;
36
+ headers: IDataObject;
37
+ };
38
+ inserted_at: string;
39
+ }
29
40
  export declare class CribopsHttp {
30
41
  private config;
31
42
  constructor(config: CribopsHttpConfig);
@@ -37,4 +48,13 @@ export declare class CribopsHttp {
37
48
  validateWebhook(payload: any, signature: string): Promise<boolean>;
38
49
  testConnection(): Promise<boolean>;
39
50
  sendTypingIndicator(agentId: string, conversationId: string, typing: boolean): Promise<any>;
51
+ pollQueue(tenantId: string, limit?: number, queueName?: string): Promise<CribopsQueueMessage[]>;
52
+ acknowledgeMessages(tenantId: string, messageIds: number[]): Promise<{
53
+ status: string;
54
+ deleted_count: number;
55
+ }>;
56
+ failMessages(tenantId: string, messageIds: number[], errorMessage: string): Promise<{
57
+ status: string;
58
+ updated_count: number;
59
+ }>;
40
60
  }
@@ -112,5 +112,37 @@ class CribopsHttp {
112
112
  throw new Error(`Failed to send typing indicator for agent ${agentId}: ${error}`);
113
113
  }
114
114
  }
115
+ async pollQueue(tenantId, limit = 10, queueName) {
116
+ try {
117
+ const params = { limit };
118
+ if (queueName) {
119
+ params.queue_name = queueName;
120
+ }
121
+ const url = `/api/queue/${tenantId}/poll?${new URLSearchParams(params).toString()}`;
122
+ const response = await this.makeRequest('GET', url);
123
+ return response;
124
+ }
125
+ catch (error) {
126
+ throw new Error(`Failed to poll queue for tenant ${tenantId}: ${error}`);
127
+ }
128
+ }
129
+ async acknowledgeMessages(tenantId, messageIds) {
130
+ try {
131
+ const response = await this.makeRequest('POST', `/api/queue/${tenantId}/acknowledge`, { message_ids: messageIds });
132
+ return response;
133
+ }
134
+ catch (error) {
135
+ throw new Error(`Failed to acknowledge messages for tenant ${tenantId}: ${error}`);
136
+ }
137
+ }
138
+ async failMessages(tenantId, messageIds, errorMessage) {
139
+ try {
140
+ const response = await this.makeRequest('POST', `/api/queue/${tenantId}/fail`, { message_ids: messageIds, error_message: errorMessage });
141
+ return response;
142
+ }
143
+ catch (error) {
144
+ throw new Error(`Failed to mark messages as failed for tenant ${tenantId}: ${error}`);
145
+ }
146
+ }
115
147
  }
116
148
  exports.CribopsHttp = CribopsHttp;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "n8n-nodes-cribops",
3
- "version": "0.1.16",
3
+ "version": "0.1.17",
4
4
  "description": "n8n community node for Cribops AI platform integration",
5
5
  "keywords": [
6
6
  "n8n-community-node-package"