n8n-nodes-cribops 0.1.18 → 0.1.24

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.
@@ -41,7 +41,7 @@ class CribopsTrigger {
41
41
  loadOptionsMethod: 'getWebhooks',
42
42
  },
43
43
  default: '',
44
- description: 'The Cribops webhook to use. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>.',
44
+ description: 'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>',
45
45
  },
46
46
  {
47
47
  displayName: 'Event Types',
@@ -109,18 +109,40 @@ class CribopsTrigger {
109
109
  apiToken: credentials.apiToken,
110
110
  });
111
111
  try {
112
- // Call the API to get available webhooks
113
- // The API endpoint would be something like GET /api/v1/webhooks
114
- const response = await cribopsHttp.request('GET', '/api/v1/webhooks');
115
- const webhooks = response.data || [];
116
- return webhooks.map((webhook) => ({
117
- name: webhook.name || webhook.id,
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,
118
120
  value: webhook.id,
119
- description: webhook.description || `Webhook ID: ${webhook.id}`,
121
+ description: webhook.description || `Type: ${webhook.type}`,
120
122
  }));
121
123
  }
122
124
  catch (error) {
123
- throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Failed to load webhooks: ${error instanceof Error ? error.message : String(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);
124
146
  }
125
147
  },
126
148
  },
@@ -135,37 +157,37 @@ class CribopsTrigger {
135
157
  async create() {
136
158
  const webhookUrl = this.getNodeWebhookUrl('default');
137
159
  const webhookId = this.getNodeParameter('webhookId');
138
- const eventTypes = this.getNodeParameter('eventTypes', []);
139
- const additionalFields = this.getNodeParameter('additionalFields', {});
140
160
  const credentials = await this.getCredentials('cribopsApi');
161
+ const workflowId = this.getWorkflow().id;
162
+ const workflowName = this.getWorkflow().name;
141
163
  const cribopsHttp = new CribopsHttp_1.CribopsHttp({
142
164
  baseUrl: credentials.baseUrl,
143
165
  apiToken: credentials.apiToken,
144
166
  });
145
167
  try {
146
- // Register this n8n webhook URL with the Cribops webhook
168
+ // Link this workflow to the webhook entity
147
169
  const body = {
148
- webhook_id: webhookId,
149
- target_url: webhookUrl,
150
- event_types: eventTypes,
151
- secret: additionalFields.secretToken || undefined,
170
+ workflow_id: workflowId,
171
+ webhook_url: webhookUrl,
172
+ test_webhook_url: webhookUrl.replace('/webhook/', '/webhook-test/'),
173
+ workflow_name: workflowName || 'Unnamed Workflow',
152
174
  };
153
- // Register the n8n webhook URL with Cribops
154
- await cribopsHttp.request('POST', `/api/v1/webhooks/${webhookId}/targets`, body);
175
+ // Link the n8n workflow to the webhook entity
176
+ await cribopsHttp.request('POST', `/api/v1/webhooks/${webhookId}/link`, body);
155
177
  // Store webhook data for later use
156
178
  const webhookData = this.getWorkflowStaticData('node');
157
179
  webhookData.webhookId = webhookId;
158
- webhookData.targetUrl = webhookUrl;
180
+ webhookData.webhookUrl = webhookUrl;
159
181
  return true;
160
182
  }
161
183
  catch (error) {
162
- throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Failed to register webhook target: ${error instanceof Error ? error.message : String(error)}`);
184
+ throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Failed to link webhook: ${error instanceof Error ? error.message : String(error)}`);
163
185
  }
164
186
  },
165
187
  async delete() {
166
188
  const webhookData = this.getWorkflowStaticData('node');
167
189
  const credentials = await this.getCredentials('cribopsApi');
168
- if (!webhookData.webhookId || !webhookData.targetUrl) {
190
+ if (!webhookData.webhookId) {
169
191
  return true;
170
192
  }
171
193
  const cribopsHttp = new CribopsHttp_1.CribopsHttp({
@@ -173,17 +195,15 @@ class CribopsTrigger {
173
195
  apiToken: credentials.apiToken,
174
196
  });
175
197
  try {
176
- // Unregister the n8n webhook URL from Cribops
177
- await cribopsHttp.request('DELETE', `/api/v1/webhooks/${webhookData.webhookId}/targets`, {
178
- target_url: webhookData.targetUrl,
179
- });
198
+ // Unlink the workflow from the webhook entity
199
+ await cribopsHttp.request('DELETE', `/api/v1/webhooks/${webhookData.webhookId}/link`);
180
200
  delete webhookData.webhookId;
181
- delete webhookData.targetUrl;
201
+ delete webhookData.webhookUrl;
182
202
  return true;
183
203
  }
184
204
  catch (error) {
185
205
  // Log error but don't fail
186
- console.error('Failed to unregister webhook target:', error);
206
+ console.error('Failed to unlink webhook:', error);
187
207
  return true;
188
208
  }
189
209
  },
package/dist/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "n8n-nodes-cribops",
3
- "version": "0.1.18",
3
+ "version": "0.1.24",
4
4
  "description": "n8n community node for Cribops AI platform integration",
5
5
  "keywords": [
6
6
  "n8n-community-node-package"
@@ -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,5 +69,13 @@ export declare class CribopsHttp {
57
69
  status: string;
58
70
  updated_count: number;
59
71
  }>;
72
+ getWebhooks(): 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>;
60
80
  request<T = any>(method: IHttpRequestMethods, endpoint: string, data?: IDataObject, options?: Partial<IHttpRequestOptions>): Promise<T>;
61
81
  }
@@ -10,7 +10,22 @@ class CribopsHttp {
10
10
  };
11
11
  }
12
12
  async makeRequest(method, endpoint, data, options) {
13
- const url = `${this.config.baseUrl}${endpoint}`;
13
+ let url = `${this.config.baseUrl}${endpoint}`;
14
+ // Handle query parameters for GET requests
15
+ if (method === 'GET' && data && Object.keys(data).length > 0) {
16
+ const params = new URLSearchParams();
17
+ Object.entries(data).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
+ // Clear data for GET requests as params are in URL
27
+ data = undefined;
28
+ }
14
29
  const requestHeaders = {
15
30
  'Authorization': `Bearer ${this.config.apiToken}`,
16
31
  'Content-Type': 'application/json',
@@ -25,11 +40,20 @@ class CribopsHttp {
25
40
  const response = await fetch(url, {
26
41
  method,
27
42
  headers: requestHeaders,
28
- body: data ? JSON.stringify(data) : undefined,
43
+ body: (method !== 'GET' && data) ? JSON.stringify(data) : undefined,
29
44
  });
30
45
  if (!response.ok) {
31
- const errorText = await response.text();
32
- throw new Error(`HTTP ${response.status}: ${errorText}`);
46
+ let errorText = await response.text();
47
+ let errorDetail = '';
48
+ // Try to parse error response as JSON
49
+ try {
50
+ const errorJson = JSON.parse(errorText);
51
+ errorDetail = errorJson.message || errorJson.error || errorText;
52
+ }
53
+ catch {
54
+ errorDetail = errorText;
55
+ }
56
+ throw new Error(`HTTP ${response.status}: ${errorDetail}`);
33
57
  }
34
58
  const result = await response.json();
35
59
  return result;
@@ -73,8 +97,17 @@ class CribopsHttp {
73
97
  },
74
98
  });
75
99
  if (!response.ok) {
76
- const errorText = await response.text();
77
- throw new Error(`HTTP ${response.status}: ${errorText}`);
100
+ let errorText = await response.text();
101
+ let errorDetail = '';
102
+ // Try to parse error response as JSON
103
+ try {
104
+ const errorJson = JSON.parse(errorText);
105
+ errorDetail = errorJson.message || errorJson.error || errorText;
106
+ }
107
+ catch {
108
+ errorDetail = errorText;
109
+ }
110
+ throw new Error(`HTTP ${response.status}: ${errorDetail}`);
78
111
  }
79
112
  const arrayBuffer = await response.arrayBuffer();
80
113
  return Buffer.from(arrayBuffer);
@@ -144,6 +177,47 @@ class CribopsHttp {
144
177
  throw new Error(`Failed to mark messages as failed for tenant ${tenantId}: ${error}`);
145
178
  }
146
179
  }
180
+ // Webhook-specific methods
181
+ async getWebhooks() {
182
+ try {
183
+ // Organization is automatically determined from API key
184
+ const response = await this.makeRequest('GET', '/api/v1/webhooks');
185
+ // Handle different response structures
186
+ // The API might return webhooks directly as array or wrapped in data property
187
+ if (Array.isArray(response)) {
188
+ return response;
189
+ }
190
+ else if (response.data && Array.isArray(response.data)) {
191
+ return response.data;
192
+ }
193
+ else if (response.webhooks && Array.isArray(response.webhooks)) {
194
+ return response.webhooks;
195
+ }
196
+ else {
197
+ // If we can't find webhooks, return empty array
198
+ return [];
199
+ }
200
+ }
201
+ catch (error) {
202
+ throw new Error(`Failed to fetch webhooks: ${error}`);
203
+ }
204
+ }
205
+ async linkWebhook(webhookId, linkData) {
206
+ try {
207
+ return await this.makeRequest('POST', `/api/v1/webhooks/${webhookId}/link`, linkData);
208
+ }
209
+ catch (error) {
210
+ throw new Error(`Failed to link webhook: ${error}`);
211
+ }
212
+ }
213
+ async unlinkWebhook(webhookId) {
214
+ try {
215
+ return await this.makeRequest('DELETE', `/api/v1/webhooks/${webhookId}/link`);
216
+ }
217
+ catch (error) {
218
+ throw new Error(`Failed to unlink webhook: ${error}`);
219
+ }
220
+ }
147
221
  // Generic request method for custom API calls
148
222
  async request(method, endpoint, data, options) {
149
223
  return this.makeRequest(method, endpoint, data, options);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "n8n-nodes-cribops",
3
- "version": "0.1.18",
3
+ "version": "0.1.24",
4
4
  "description": "n8n community node for Cribops AI platform integration",
5
5
  "keywords": [
6
6
  "n8n-community-node-package"