n8n-nodes-idb2b 3.2.8 → 3.3.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.
@@ -1,8 +1,10 @@
1
- import { ICredentialTestRequest, ICredentialType, INodeProperties } from 'n8n-workflow';
1
+ import { ICredentialTestRequest, ICredentialType, INodeProperties, IHttpRequestOptions } from "n8n-workflow";
2
2
  export declare class IDB2BApi implements ICredentialType {
3
3
  name: string;
4
4
  displayName: string;
5
5
  documentationUrl: string;
6
+ icon: "file:IDB2B.svg";
7
+ authenticate: (this: any, credentials: any, requestOptions: IHttpRequestOptions) => Promise<IHttpRequestOptions>;
6
8
  properties: INodeProperties[];
7
9
  test: ICredentialTestRequest;
8
10
  }
@@ -1,45 +1,52 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.IDB2BApi = void 0;
4
+ const httpClient_1 = require("../nodes/IDB2B/utils/httpClient");
4
5
  class IDB2BApi {
5
6
  constructor() {
6
- this.name = 'idb2bApi';
7
- this.displayName = 'IDB2B WhatsApp AI Agents';
8
- this.documentationUrl = 'https://idb2b.com/en';
7
+ this.name = "idb2bApi";
8
+ this.displayName = "IDB2B WhatsApp AI Agents";
9
+ this.documentationUrl = "https://idb2b.com/en";
10
+ this.icon = "file:IDB2B.svg";
11
+ this.authenticate = async function (credentials, requestOptions) {
12
+ const accessToken = await (0, httpClient_1.getAccessToken)(this, credentials);
13
+ requestOptions.headers = Object.assign(Object.assign({}, requestOptions.headers), { Authorization: `Bearer ${accessToken}` });
14
+ return requestOptions;
15
+ };
9
16
  this.properties = [
10
17
  {
11
- displayName: 'Email',
12
- name: 'email',
13
- type: 'string',
14
- default: '',
18
+ displayName: "Email",
19
+ name: "email",
20
+ type: "string",
21
+ default: "",
15
22
  required: true,
16
- placeholder: 'your@email.com',
23
+ placeholder: "your@email.com",
17
24
  },
18
25
  {
19
- displayName: 'Password',
20
- name: 'password',
21
- type: 'string',
26
+ displayName: "Password",
27
+ name: "password",
28
+ type: "string",
22
29
  typeOptions: { password: true },
23
- default: '',
30
+ default: "",
24
31
  required: true,
25
32
  },
26
33
  {
27
- displayName: 'Base URL',
28
- name: 'baseUrl',
29
- type: 'string',
30
- default: 'https://api.idb2b.com',
34
+ displayName: "Base URL",
35
+ name: "baseUrl",
36
+ type: "string",
37
+ default: "https://api.idb2b.com",
31
38
  required: true,
32
- description: 'The IDB2B API base URL. Use https://api-stage.idb2b.com for staging environment.',
39
+ description: "The IDB2B API base URL. Use https://api-stage.idb2b.com for staging environment.",
33
40
  },
34
41
  ];
35
42
  this.test = {
36
43
  request: {
37
- baseURL: '={{$credentials.baseUrl}}',
38
- url: '/login',
39
- method: 'POST',
44
+ baseURL: "={{$credentials.baseUrl}}",
45
+ url: "/login",
46
+ method: "POST",
40
47
  body: {
41
- email: '={{$credentials.email}}',
42
- password: '={{$credentials.password}}',
48
+ email: "={{$credentials.email}}",
49
+ password: "={{$credentials.password}}",
43
50
  },
44
51
  },
45
52
  };
@@ -25,8 +25,8 @@ class IDB2B {
25
25
  defaults: {
26
26
  name: "IDB2B",
27
27
  },
28
- inputs: ["main"],
29
- outputs: ["main"],
28
+ inputs: [n8n_workflow_1.NodeConnectionTypes.Main],
29
+ outputs: [n8n_workflow_1.NodeConnectionTypes.Main],
30
30
  credentials: [
31
31
  {
32
32
  name: "idb2bApi",
@@ -78,7 +78,6 @@ class IDB2B {
78
78
  if (!credentialsValidation.isValid) {
79
79
  throw new n8n_workflow_1.NodeOperationError(this.getNode(), credentialsValidation.error || "Invalid credentials");
80
80
  }
81
- const accessToken = await (0, httpClient_1.getAccessToken)(this, credentials);
82
81
  const httpClient = new httpClient_1.HttpClient(this);
83
82
  for (let i = 0; i < items.length; i++) {
84
83
  try {
@@ -171,28 +170,35 @@ class IDB2B {
171
170
  }
172
171
  else if (operation === "get") {
173
172
  method = "GET";
173
+ const activityScope = this.getNodeParameter("activityScope", i);
174
174
  const activityId = this.getNodeParameter("activityId", i);
175
- endpoint = `${constants_1.ENDPOINTS.ACTIVITIES}/${(0, common_1.sanitizeId)(activityId)}`;
175
+ if (activityScope === "contact") {
176
+ const parentContactId = this.getNodeParameter("activityParentContactId", i);
177
+ endpoint = `/contacts/${(0, common_1.sanitizeId)(parentContactId)}/activities/${(0, common_1.sanitizeId)(activityId)}`;
178
+ }
179
+ else {
180
+ const parentCompanyId = this.getNodeParameter("activityParentCompanyId", i);
181
+ endpoint = `/leads/${(0, common_1.sanitizeId)(parentCompanyId)}/activities/${(0, common_1.sanitizeId)(activityId)}`;
182
+ }
176
183
  }
177
184
  else if (operation === "create") {
178
185
  method = "POST";
179
- endpoint = constants_1.ENDPOINTS.ACTIVITIES;
180
- const subject = this.getNodeParameter("subject", i);
181
186
  const associateWith = this.getNodeParameter("associateWith", i);
187
+ const subject = this.getNodeParameter("subject", i);
182
188
  const additionalFields = this.getNodeParameter("additionalFields", i, {});
183
189
  if (!subject || !subject.trim()) {
184
190
  throw new Error("Subject is required to create an activity");
185
191
  }
186
- // Must send as multipart/form-data — the /activities endpoint uses
187
- // FilesInterceptor which does not parse JSON bodies reliably
188
- const formPayload = { subject: subject.trim() };
192
+ const formPayload = {
193
+ subject: subject.trim(),
194
+ };
189
195
  if (associateWith === "company") {
190
196
  const companyId = this.getNodeParameter("activityCompanyId", i);
191
- formPayload.company_id = companyId;
197
+ endpoint = `/leads/${(0, common_1.sanitizeId)(companyId)}/activities`;
192
198
  }
193
199
  else {
194
200
  const contactId = this.getNodeParameter("activityContactId", i);
195
- formPayload.contact_id = contactId;
201
+ endpoint = `/contacts/${(0, common_1.sanitizeId)(contactId)}/activities`;
196
202
  }
197
203
  // Merge optional additional fields
198
204
  Object.entries(additionalFields).forEach(([key, value]) => {
@@ -206,8 +212,16 @@ class IDB2B {
206
212
  }
207
213
  else if (operation === "update") {
208
214
  method = "PATCH";
215
+ const activityScope = this.getNodeParameter("activityScope", i);
209
216
  const activityId = this.getNodeParameter("activityId", i);
210
- endpoint = `${constants_1.ENDPOINTS.ACTIVITIES}/${(0, common_1.sanitizeId)(activityId)}`;
217
+ if (activityScope === "contact") {
218
+ const parentContactId = this.getNodeParameter("activityParentContactId", i);
219
+ endpoint = `/contacts/${(0, common_1.sanitizeId)(parentContactId)}/activities/${(0, common_1.sanitizeId)(activityId)}`;
220
+ }
221
+ else {
222
+ const parentCompanyId = this.getNodeParameter("activityParentCompanyId", i);
223
+ endpoint = `/leads/${(0, common_1.sanitizeId)(parentCompanyId)}/activities/${(0, common_1.sanitizeId)(activityId)}`;
224
+ }
211
225
  const additionalFields = this.getNodeParameter("additionalFields", i, {});
212
226
  const updatePayload = {};
213
227
  Object.entries(additionalFields).forEach(([key, value]) => {
@@ -221,8 +235,16 @@ class IDB2B {
221
235
  }
222
236
  else if (operation === "delete") {
223
237
  method = "DELETE";
238
+ const activityScope = this.getNodeParameter("activityScope", i);
224
239
  const activityId = this.getNodeParameter("activityId", i);
225
- endpoint = `${constants_1.ENDPOINTS.ACTIVITIES}/${(0, common_1.sanitizeId)(activityId)}`;
240
+ if (activityScope === "contact") {
241
+ const parentContactId = this.getNodeParameter("activityParentContactId", i);
242
+ endpoint = `/contacts/${(0, common_1.sanitizeId)(parentContactId)}/activities/${(0, common_1.sanitizeId)(activityId)}`;
243
+ }
244
+ else {
245
+ const parentCompanyId = this.getNodeParameter("activityParentCompanyId", i);
246
+ endpoint = `/leads/${(0, common_1.sanitizeId)(parentCompanyId)}/activities/${(0, common_1.sanitizeId)(activityId)}`;
247
+ }
226
248
  }
227
249
  }
228
250
  else if (resource === "company") {
@@ -283,9 +305,7 @@ class IDB2B {
283
305
  endpoint = `${constants_1.ENDPOINTS.COMPANIES}/${(0, common_1.sanitizeId)(companyId)}`;
284
306
  }
285
307
  }
286
- const response = await httpClient.makeRequest(Object.assign(Object.assign({ method, url: `${credentials.baseUrl}${endpoint}`, headers: {
287
- Authorization: `Bearer ${accessToken}`,
288
- } }, (useFormData ? { formData: body } : { body })), { qs, json: true }));
308
+ const response = await httpClient.makeRequest(Object.assign(Object.assign({ method, url: `${credentials.baseUrl}${endpoint}` }, (useFormData ? { formData: body } : { body })), { qs, json: true }));
289
309
  let processedResponse = (0, common_1.processResponse)(response, operation, initialBody);
290
310
  // Apply field filtering for getAll operations
291
311
  if (operation === "getAll") {
@@ -323,7 +343,7 @@ class IDB2B {
323
343
  });
324
344
  continue;
325
345
  }
326
- throw new n8n_workflow_1.NodeOperationError(this.getNode(), error, {
346
+ throw new n8n_workflow_1.NodeApiError(this.getNode(), error, {
327
347
  itemIndex: i,
328
348
  });
329
349
  }
@@ -15,8 +15,8 @@ exports.activityOperations = {
15
15
  {
16
16
  name: 'Get All',
17
17
  value: 'getAll',
18
- action: 'Get all activities for a company',
19
- description: 'Retrieve all activities for a specific company/lead',
18
+ action: 'Get all activities',
19
+ description: 'Retrieve all activities for a specific company or contact',
20
20
  },
21
21
  {
22
22
  name: 'Get',
@@ -46,6 +46,55 @@ exports.activityOperations = {
46
46
  default: 'getAll',
47
47
  };
48
48
  exports.activityFields = [
49
+ // Scope selector for get, update, delete
50
+ {
51
+ displayName: 'Scope',
52
+ name: 'activityScope',
53
+ type: 'options',
54
+ default: 'company',
55
+ required: true,
56
+ displayOptions: {
57
+ show: {
58
+ resource: ['activity'],
59
+ operation: ['get', 'update', 'delete'],
60
+ },
61
+ },
62
+ options: [
63
+ { name: 'Company (Lead)', value: 'company' },
64
+ { name: 'Contact', value: 'contact' },
65
+ ],
66
+ description: 'Whether this activity belongs to a company (lead) or a contact',
67
+ },
68
+ {
69
+ displayName: 'Company ID',
70
+ name: 'activityParentCompanyId',
71
+ type: 'string',
72
+ default: '',
73
+ required: true,
74
+ displayOptions: {
75
+ show: {
76
+ resource: ['activity'],
77
+ operation: ['get', 'update', 'delete'],
78
+ activityScope: ['company'],
79
+ },
80
+ },
81
+ description: 'ID of the company (lead) that owns this activity',
82
+ },
83
+ {
84
+ displayName: 'Contact ID',
85
+ name: 'activityParentContactId',
86
+ type: 'string',
87
+ default: '',
88
+ required: true,
89
+ displayOptions: {
90
+ show: {
91
+ resource: ['activity'],
92
+ operation: ['get', 'update', 'delete'],
93
+ activityScope: ['contact'],
94
+ },
95
+ },
96
+ description: 'ID of the contact that owns this activity',
97
+ },
49
98
  // Activity ID — required for get, update, delete
50
99
  {
51
100
  displayName: 'Activity ID',
@@ -11,6 +11,7 @@ export interface RequestOptions {
11
11
  formData?: any;
12
12
  qs?: any;
13
13
  json?: boolean;
14
+ skipAuth?: boolean;
14
15
  }
15
16
  export interface HttpClientConfig {
16
17
  maxRetries: number;
@@ -28,7 +28,10 @@ class HttpClient {
28
28
  let lastError;
29
29
  for (let attempt = 0; attempt <= this.config.maxRetries; attempt++) {
30
30
  try {
31
- return await this.executeFunctions.helpers.httpRequest(options);
31
+ if (options.skipAuth) {
32
+ return await this.executeFunctions.helpers.httpRequest(options);
33
+ }
34
+ return await this.executeFunctions.helpers.httpRequestWithAuthentication.call(this.executeFunctions, "idb2bApi", options);
32
35
  }
33
36
  catch (error) {
34
37
  lastError = error;
@@ -113,6 +116,7 @@ async function getAccessToken(executeFunctions, credentials) {
113
116
  password: credentials.password,
114
117
  },
115
118
  json: true,
119
+ skipAuth: true,
116
120
  });
117
121
  // Try to extract token from various possible response formats
118
122
  const accessToken = ((_b = (_a = loginResponse === null || loginResponse === void 0 ? void 0 : loginResponse.data) === null || _a === void 0 ? void 0 : _a.session) === null || _b === void 0 ? void 0 : _b.access_token) ||
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "n8n-nodes-idb2b",
3
- "version": "3.2.8",
3
+ "version": "3.3.0",
4
4
  "description": "n8n community node for IDB2B - WhatsApp AI Agents",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -47,5 +47,8 @@
47
47
  },
48
48
  "peerDependencies": {
49
49
  "n8n-workflow": "*"
50
+ },
51
+ "publishConfig": {
52
+ "access": "public"
50
53
  }
51
54
  }