n8n-nodes-waapy 0.3.1 → 0.5.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.
@@ -14,7 +14,7 @@ class WaapyApi {
14
14
  type: "string",
15
15
  default: "https://localhost",
16
16
  placeholder: "Please enter the server URL",
17
- description: "The base URL of the WaaPy API",
17
+ description: "The base URL of the WaaPy API. Do not include a trailing slash.",
18
18
  },
19
19
  {
20
20
  displayName: "API Key",
@@ -1 +1 @@
1
- {"version":3,"file":"WaapyApi.credentials.js","sourceRoot":"","sources":["../../credentials/WaapyApi.credentials.ts"],"names":[],"mappings":";;;AAOA,MAAa,QAAQ;IAArB;QACE,SAAI,GAAG,UAAU,CAAC;QAClB,gBAAW,GAAG,WAAW,CAAC;QAC1B,qBAAgB,GAAG,kBAAkB,CAAC;QACtC,SAAI,GAAG,oCAA6C,CAAC;QACrD,eAAU,GAAsB;YAC9B;gBACE,WAAW,EAAE,YAAY;gBACzB,IAAI,EAAE,YAAY;gBAClB,IAAI,EAAE,QAAQ;gBACd,OAAO,EAAE,mBAAmB;gBAC5B,WAAW,EAAE,6BAA6B;gBAC1C,WAAW,EAAE,+BAA+B;aAC7C;YACD;gBACE,WAAW,EAAE,SAAS;gBACtB,IAAI,EAAE,QAAQ;gBACd,IAAI,EAAE,QAAQ;gBACd,OAAO,EAAE,EAAE;gBACX,WAAW,EAAE;oBACX,QAAQ,EAAE,IAAI;iBACf;gBACD,WAAW,EAAE,wCAAwC;aACtD;SACF,CAAC;QAEF,iBAAY,GAAyB;YACnC,IAAI,EAAE,SAAS;YACf,UAAU,EAAE;gBACV,OAAO,EAAE;oBACP,aAAa,EAAE,iCAAiC;iBACjD;aACF;SACF,CAAC;QAEF,SAAI,GAA2B;YAC7B,OAAO,EAAE;gBACP,OAAO,EAAE,iCAAiC;gBAC1C,GAAG,EAAE,aAAa;gBAClB,MAAM,EAAE,KAAK;aACd;SACF,CAAC;IACJ,CAAC;CAAA;AA1CD,4BA0CC"}
1
+ {"version":3,"file":"WaapyApi.credentials.js","sourceRoot":"","sources":["../../credentials/WaapyApi.credentials.ts"],"names":[],"mappings":";;;AAOA,MAAa,QAAQ;IAArB;QACE,SAAI,GAAG,UAAU,CAAC;QAClB,gBAAW,GAAG,WAAW,CAAC;QAC1B,qBAAgB,GAAG,kBAAkB,CAAC;QACtC,SAAI,GAAG,oCAA6C,CAAC;QACrD,eAAU,GAAsB;YAC9B;gBACE,WAAW,EAAE,YAAY;gBACzB,IAAI,EAAE,YAAY;gBAClB,IAAI,EAAE,QAAQ;gBACd,OAAO,EAAE,mBAAmB;gBAC5B,WAAW,EAAE,6BAA6B;gBAC1C,WAAW,EAAE,iEAAiE;aAC/E;YACD;gBACE,WAAW,EAAE,SAAS;gBACtB,IAAI,EAAE,QAAQ;gBACd,IAAI,EAAE,QAAQ;gBACd,OAAO,EAAE,EAAE;gBACX,WAAW,EAAE;oBACX,QAAQ,EAAE,IAAI;iBACf;gBACD,WAAW,EAAE,wCAAwC;aACtD;SACF,CAAC;QAEF,iBAAY,GAAyB;YACnC,IAAI,EAAE,SAAS;YACf,UAAU,EAAE;gBACV,OAAO,EAAE;oBACP,aAAa,EAAE,iCAAiC;iBACjD;aACF;SACF,CAAC;QAEF,SAAI,GAA2B;YAC7B,OAAO,EAAE;gBACP,OAAO,EAAE,iCAAiC;gBAC1C,GAAG,EAAE,aAAa;gBAClB,MAAM,EAAE,KAAK;aACd;SACF,CAAC;IACJ,CAAC;CAAA;AA1CD,4BA0CC"}
@@ -4,8 +4,11 @@ export declare class Waapy implements INodeType {
4
4
  methods: {
5
5
  listSearch: {
6
6
  searchConnections(this: ILoadOptionsFunctions, filter?: string): Promise<INodeListSearchResult>;
7
+ searchWhatsAppConnections(this: ILoadOptionsFunctions, filter?: string): Promise<INodeListSearchResult>;
7
8
  searchTemplates(this: ILoadOptionsFunctions, filter?: string): Promise<INodeListSearchResult>;
8
9
  searchLabels(this: ILoadOptionsFunctions, filter?: string): Promise<INodeListSearchResult>;
10
+ searchQueues(this: ILoadOptionsFunctions, filter?: string): Promise<INodeListSearchResult>;
11
+ searchUsers(this: ILoadOptionsFunctions, filter?: string): Promise<INodeListSearchResult>;
9
12
  };
10
13
  };
11
14
  execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]>;
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Waapy = void 0;
4
4
  const n8n_workflow_1 = require("n8n-workflow");
5
+ const normalizeBaseUrl = (url) => url.replace(/\/+$/, "");
5
6
  const TEMPLATE_VARIABLE_PATTERN = /\{\{\s*(\d+)\s*\}\}/g;
6
7
  const ensureArray = (value) => Array.isArray(value) ? value : [];
7
8
  const countTemplateVariables = (value) => {
@@ -145,6 +146,14 @@ class Waapy {
145
146
  name: "Message",
146
147
  value: "message",
147
148
  },
149
+ {
150
+ name: "Queue",
151
+ value: "queue",
152
+ },
153
+ {
154
+ name: "Ticket",
155
+ value: "ticket",
156
+ },
148
157
  ],
149
158
  default: "message",
150
159
  },
@@ -200,6 +209,144 @@ class Waapy {
200
209
  ],
201
210
  default: "assignLabel",
202
211
  },
212
+ {
213
+ displayName: "Operation",
214
+ name: "operation",
215
+ type: "options",
216
+ noDataExpression: true,
217
+ displayOptions: {
218
+ show: {
219
+ resource: ["queue"],
220
+ },
221
+ },
222
+ options: [
223
+ {
224
+ name: "Assign Queue",
225
+ value: "assignQueue",
226
+ description: "Assign a ticket to a queue",
227
+ action: "Assign a queue",
228
+ },
229
+ ],
230
+ default: "assignQueue",
231
+ },
232
+ {
233
+ displayName: "Operation",
234
+ name: "operation",
235
+ type: "options",
236
+ noDataExpression: true,
237
+ displayOptions: {
238
+ show: {
239
+ resource: ["ticket"],
240
+ },
241
+ },
242
+ options: [
243
+ {
244
+ name: "Update Status",
245
+ value: "updateStatus",
246
+ description: "Update the status of a ticket",
247
+ action: "Update ticket status",
248
+ },
249
+ ],
250
+ default: "updateStatus",
251
+ },
252
+ {
253
+ displayName: "Ticket ID",
254
+ name: "ticketId",
255
+ type: "string",
256
+ required: true,
257
+ displayOptions: {
258
+ show: {
259
+ resource: ["ticket"],
260
+ operation: ["updateStatus"],
261
+ },
262
+ },
263
+ default: "",
264
+ description: "The ticket ID to update",
265
+ },
266
+ {
267
+ displayName: "Status",
268
+ name: "status",
269
+ type: "options",
270
+ required: true,
271
+ options: [
272
+ {
273
+ name: "Open",
274
+ value: "IN_PROGRESS",
275
+ },
276
+ {
277
+ name: "Pending",
278
+ value: "PENDING",
279
+ },
280
+ {
281
+ name: "Closed",
282
+ value: "CLOSED",
283
+ },
284
+ ],
285
+ default: "IN_PROGRESS",
286
+ displayOptions: {
287
+ show: {
288
+ resource: ["ticket"],
289
+ operation: ["updateStatus"],
290
+ },
291
+ },
292
+ description: "The new status for the ticket",
293
+ },
294
+ {
295
+ displayName: "User Email",
296
+ name: "userEmail",
297
+ type: "string",
298
+ required: true,
299
+ default: "",
300
+ placeholder: "user@example.com",
301
+ displayOptions: {
302
+ show: {
303
+ resource: ["ticket"],
304
+ operation: ["updateStatus"],
305
+ status: ["IN_PROGRESS"],
306
+ },
307
+ },
308
+ description: "The email of the user to assign the ticket to",
309
+ },
310
+ {
311
+ displayName: "Ticket ID",
312
+ name: "ticketId",
313
+ type: "string",
314
+ required: true,
315
+ displayOptions: {
316
+ show: {
317
+ resource: ["queue"],
318
+ operation: ["assignQueue"],
319
+ },
320
+ },
321
+ default: "",
322
+ description: "The ticket ID to assign to the queue",
323
+ },
324
+ {
325
+ displayName: "Queue",
326
+ name: "queueId",
327
+ type: "resourceLocator",
328
+ default: { mode: "list", value: "" },
329
+ required: true,
330
+ modes: [
331
+ {
332
+ displayName: "From List",
333
+ name: "list",
334
+ type: "list",
335
+ hint: "Select a queue",
336
+ typeOptions: {
337
+ searchListMethod: "searchQueues",
338
+ searchable: true,
339
+ },
340
+ },
341
+ ],
342
+ displayOptions: {
343
+ show: {
344
+ resource: ["queue"],
345
+ operation: ["assignQueue"],
346
+ },
347
+ },
348
+ description: "The queue to assign the ticket to",
349
+ },
203
350
  {
204
351
  displayName: "Ticket ID",
205
352
  name: "ticketId",
@@ -377,11 +524,37 @@ class Waapy {
377
524
  displayOptions: {
378
525
  show: {
379
526
  resource: ["message"],
380
- operation: ["sendText", "sendImage", "sendTemplate"],
527
+ operation: ["sendText", "sendImage"],
381
528
  },
382
529
  },
383
530
  description: "The connection to use for sending the message",
384
531
  },
532
+ {
533
+ displayName: "WhatsApp Connection",
534
+ name: "whatsappConnectionName",
535
+ type: "resourceLocator",
536
+ default: { mode: "list", value: "" },
537
+ required: true,
538
+ modes: [
539
+ {
540
+ displayName: "From List",
541
+ name: "list",
542
+ type: "list",
543
+ hint: "Select a WhatsApp connection",
544
+ typeOptions: {
545
+ searchListMethod: "searchWhatsAppConnections",
546
+ searchable: true,
547
+ },
548
+ },
549
+ ],
550
+ displayOptions: {
551
+ show: {
552
+ resource: ["message"],
553
+ operation: ["sendTemplate"],
554
+ },
555
+ },
556
+ description: "The WhatsApp connection to use for sending the template message",
557
+ },
385
558
  {
386
559
  displayName: "Recipient Number",
387
560
  name: "toNumber",
@@ -699,29 +872,6 @@ class Waapy {
699
872
  },
700
873
  description: "Optional reply buttons for this text message. Maximum 10 buttons.",
701
874
  },
702
- {
703
- displayName: "Image Source",
704
- name: "imageUploadMethod",
705
- type: "options",
706
- options: [
707
- {
708
- name: "From URL",
709
- value: "url",
710
- },
711
- {
712
- name: "Upload File",
713
- value: "upload",
714
- },
715
- ],
716
- default: "url",
717
- displayOptions: {
718
- show: {
719
- resource: ["message"],
720
- operation: ["sendImage"],
721
- },
722
- },
723
- description: "Whether to send an image from a URL or upload a file",
724
- },
725
875
  {
726
876
  displayName: "Image URL",
727
877
  name: "mediaUrl",
@@ -731,27 +881,11 @@ class Waapy {
731
881
  show: {
732
882
  resource: ["message"],
733
883
  operation: ["sendImage"],
734
- imageUploadMethod: ["url"],
735
884
  },
736
885
  },
737
886
  default: "",
738
887
  description: "The URL of the image to send",
739
888
  },
740
- {
741
- displayName: "Input Binary Field",
742
- name: "binaryPropertyName",
743
- type: "string",
744
- default: "data",
745
- required: true,
746
- displayOptions: {
747
- show: {
748
- resource: ["message"],
749
- operation: ["sendImage"],
750
- imageUploadMethod: ["upload"],
751
- },
752
- },
753
- description: "Name of the binary property containing the image data",
754
- },
755
889
  {
756
890
  displayName: "Caption",
757
891
  name: "caption",
@@ -771,7 +905,7 @@ class Waapy {
771
905
  listSearch: {
772
906
  async searchConnections(filter) {
773
907
  const credentials = await this.getCredentials("waapyApi");
774
- const baseUrl = credentials["server-url"];
908
+ const baseUrl = normalizeBaseUrl(credentials["server-url"]);
775
909
  let url = `${baseUrl}/n8n/connections`;
776
910
  if (filter) {
777
911
  url += `?searchParam=${encodeURIComponent(filter)}`;
@@ -796,9 +930,39 @@ class Waapy {
796
930
  throw new n8n_workflow_1.NodeApiError(this.getNode(), error);
797
931
  }
798
932
  },
933
+ async searchWhatsAppConnections(filter) {
934
+ const credentials = await this.getCredentials("waapyApi");
935
+ const baseUrl = normalizeBaseUrl(credentials["server-url"]);
936
+ let url = `${baseUrl}/n8n/connections`;
937
+ if (filter) {
938
+ url += `?searchParam=${encodeURIComponent(filter)}`;
939
+ }
940
+ try {
941
+ const responseData = await this.helpers.httpRequestWithAuthentication.call(this, "waapyApi", {
942
+ method: "GET",
943
+ url,
944
+ json: true,
945
+ });
946
+ const results = ensureArray(responseData.connections)
947
+ .filter((connection) => typeof connection.name === "string" &&
948
+ connection.name.length > 0 &&
949
+ typeof connection.type === "string" &&
950
+ connection.type.toUpperCase().startsWith("WHATSAPP"))
951
+ .map((connection) => ({
952
+ name: connection.name,
953
+ value: connection.name,
954
+ }));
955
+ return {
956
+ results,
957
+ };
958
+ }
959
+ catch (error) {
960
+ throw new n8n_workflow_1.NodeApiError(this.getNode(), error);
961
+ }
962
+ },
799
963
  async searchTemplates(filter) {
800
964
  const credentials = await this.getCredentials("waapyApi");
801
- const baseUrl = credentials["server-url"];
965
+ const baseUrl = normalizeBaseUrl(credentials["server-url"]);
802
966
  let url = `${baseUrl}/n8n/templates`;
803
967
  if (filter) {
804
968
  url += `?searchName=${encodeURIComponent(filter)}`;
@@ -830,7 +994,7 @@ class Waapy {
830
994
  },
831
995
  async searchLabels(filter) {
832
996
  const credentials = await this.getCredentials("waapyApi");
833
- const baseUrl = credentials["server-url"];
997
+ const baseUrl = normalizeBaseUrl(credentials["server-url"]);
834
998
  let url = `${baseUrl}/n8n/labels`;
835
999
  if (filter) {
836
1000
  url += `?searchName=${encodeURIComponent(filter)}`;
@@ -859,6 +1023,68 @@ class Waapy {
859
1023
  throw new n8n_workflow_1.NodeApiError(this.getNode(), error);
860
1024
  }
861
1025
  },
1026
+ async searchQueues(filter) {
1027
+ const credentials = await this.getCredentials("waapyApi");
1028
+ const baseUrl = normalizeBaseUrl(credentials["server-url"]);
1029
+ let url = `${baseUrl}/n8n/queues`;
1030
+ if (filter) {
1031
+ url += `?searchName=${encodeURIComponent(filter)}`;
1032
+ }
1033
+ try {
1034
+ const responseData = await this.helpers.httpRequestWithAuthentication.call(this, "waapyApi", {
1035
+ method: "GET",
1036
+ url,
1037
+ json: true,
1038
+ });
1039
+ const queues = ensureArray(responseData.queues);
1040
+ const results = queues
1041
+ .map((queue) => {
1042
+ var _a, _b, _c;
1043
+ return ({
1044
+ name: (_b = (_a = queue.name) !== null && _a !== void 0 ? _a : queue.id) !== null && _b !== void 0 ? _b : "Unnamed Queue",
1045
+ value: (_c = queue.id) !== null && _c !== void 0 ? _c : "",
1046
+ });
1047
+ })
1048
+ .filter((queue) => queue.value !== "");
1049
+ return {
1050
+ results,
1051
+ };
1052
+ }
1053
+ catch (error) {
1054
+ throw new n8n_workflow_1.NodeApiError(this.getNode(), error);
1055
+ }
1056
+ },
1057
+ async searchUsers(filter) {
1058
+ const credentials = await this.getCredentials("waapyApi");
1059
+ const baseUrl = normalizeBaseUrl(credentials["server-url"]);
1060
+ let url = `${baseUrl}/n8n/users`;
1061
+ if (filter) {
1062
+ url += `?searchName=${encodeURIComponent(filter)}`;
1063
+ }
1064
+ try {
1065
+ const responseData = await this.helpers.httpRequestWithAuthentication.call(this, "waapyApi", {
1066
+ method: "GET",
1067
+ url,
1068
+ json: true,
1069
+ });
1070
+ const users = ensureArray(responseData.users);
1071
+ const results = users
1072
+ .map((user) => {
1073
+ var _a, _b, _c, _d;
1074
+ return ({
1075
+ name: (_c = (_b = (_a = user.name) !== null && _a !== void 0 ? _a : user.email) !== null && _b !== void 0 ? _b : user.id) !== null && _c !== void 0 ? _c : "Unnamed User",
1076
+ value: (_d = user.id) !== null && _d !== void 0 ? _d : "",
1077
+ });
1078
+ })
1079
+ .filter((user) => user.value !== "");
1080
+ return {
1081
+ results,
1082
+ };
1083
+ }
1084
+ catch (error) {
1085
+ throw new n8n_workflow_1.NodeApiError(this.getNode(), error);
1086
+ }
1087
+ },
862
1088
  },
863
1089
  };
864
1090
  }
@@ -877,7 +1103,7 @@ class Waapy {
877
1103
  const target = this.getNodeParameter("target", i);
878
1104
  const action = this.getNodeParameter("action", i);
879
1105
  const credentials = await this.getCredentials("waapyApi");
880
- const baseUrl = credentials["server-url"];
1106
+ const baseUrl = normalizeBaseUrl(credentials["server-url"]);
881
1107
  if (ticketId.length === 0) {
882
1108
  throw new n8n_workflow_1.NodeOperationError(this.getNode(), "Ticket ID is required.", { itemIndex: i });
883
1109
  }
@@ -919,10 +1145,65 @@ class Waapy {
919
1145
  });
920
1146
  }
921
1147
  }
1148
+ else if (resource === "queue") {
1149
+ if (operation === "assignQueue") {
1150
+ const ticketId = `${this.getNodeParameter("ticketId", i)}`.trim();
1151
+ const queueId = `${this.getNodeParameter("queueId", i, "", {
1152
+ extractValue: true,
1153
+ })}`.trim();
1154
+ const credentials = await this.getCredentials("waapyApi");
1155
+ const baseUrl = normalizeBaseUrl(credentials["server-url"]);
1156
+ if (ticketId.length === 0) {
1157
+ throw new n8n_workflow_1.NodeOperationError(this.getNode(), "Ticket ID is required.", { itemIndex: i });
1158
+ }
1159
+ if (queueId.length === 0) {
1160
+ throw new n8n_workflow_1.NodeOperationError(this.getNode(), "Queue is required.", { itemIndex: i });
1161
+ }
1162
+ responseData =
1163
+ await this.helpers.httpRequestWithAuthentication.call(this, "waapyApi", {
1164
+ method: "POST",
1165
+ url: `${baseUrl}/n8n/tickets/queue`,
1166
+ body: {
1167
+ ticketId,
1168
+ queueId,
1169
+ },
1170
+ json: true,
1171
+ });
1172
+ }
1173
+ }
1174
+ else if (resource === "ticket") {
1175
+ if (operation === "updateStatus") {
1176
+ const ticketId = `${this.getNodeParameter("ticketId", i)}`.trim();
1177
+ const status = this.getNodeParameter("status", i);
1178
+ const credentials = await this.getCredentials("waapyApi");
1179
+ const baseUrl = normalizeBaseUrl(credentials["server-url"]);
1180
+ if (ticketId.length === 0) {
1181
+ throw new n8n_workflow_1.NodeOperationError(this.getNode(), "Ticket ID is required.", { itemIndex: i });
1182
+ }
1183
+ const body = {
1184
+ ticketId,
1185
+ status,
1186
+ };
1187
+ if (status === "IN_PROGRESS") {
1188
+ const userEmail = `${this.getNodeParameter("userEmail", i, "")}`.trim();
1189
+ if (userEmail.length === 0) {
1190
+ throw new n8n_workflow_1.NodeOperationError(this.getNode(), "User Email is required when status is Open.", { itemIndex: i });
1191
+ }
1192
+ body.userEmail = userEmail;
1193
+ }
1194
+ responseData =
1195
+ await this.helpers.httpRequestWithAuthentication.call(this, "waapyApi", {
1196
+ method: "POST",
1197
+ url: `${baseUrl}/n8n/tickets/status`,
1198
+ body,
1199
+ json: true,
1200
+ });
1201
+ }
1202
+ }
922
1203
  else if (resource === "message") {
923
1204
  const toNumber = this.getNodeParameter("toNumber", i);
924
1205
  const credentials = await this.getCredentials("waapyApi");
925
- const baseUrl = credentials["server-url"];
1206
+ const baseUrl = normalizeBaseUrl(credentials["server-url"]);
926
1207
  if (operation === "sendText") {
927
1208
  const text = this.getNodeParameter("text", i);
928
1209
  const textButtons = (_a = this.getNodeParameter("textButtons", i, {}).values) !== null && _a !== void 0 ? _a : [];
@@ -965,7 +1246,6 @@ class Waapy {
965
1246
  });
966
1247
  }
967
1248
  else if (operation === "sendImage") {
968
- const imageUploadMethod = this.getNodeParameter("imageUploadMethod", i);
969
1249
  const caption = this.getNodeParameter("caption", i);
970
1250
  const body = {
971
1251
  connectionName: this.getNodeParameter("connectionName", i, "", {
@@ -975,16 +1255,9 @@ class Waapy {
975
1255
  message: {
976
1256
  body: caption,
977
1257
  type: "text",
1258
+ mediaUrl: this.getNodeParameter("mediaUrl", i),
978
1259
  },
979
1260
  };
980
- if (imageUploadMethod === "url") {
981
- body.message.mediaUrl = this.getNodeParameter("mediaUrl", i);
982
- }
983
- else {
984
- const binaryPropertyName = this.getNodeParameter("binaryPropertyName", i);
985
- const binaryData = this.helpers.assertBinaryData(i, binaryPropertyName);
986
- body.message.mediaBase64 = `data:${binaryData.mimeType};base64,${binaryData.data}`;
987
- }
988
1261
  responseData =
989
1262
  await this.helpers.httpRequestWithAuthentication.call(this, "waapyApi", {
990
1263
  method: "POST",
@@ -1042,7 +1315,7 @@ class Waapy {
1042
1315
  const normalizedButtonParameters = buttonParameters;
1043
1316
  const fetchTemplateDetail = async (templateId) => await this.helpers.httpRequestWithAuthentication.call(this, "waapyApi", {
1044
1317
  method: "GET",
1045
- url: `${baseUrl}/n8n/templates/${templateId}?connectionName=${this.getNodeParameter("connectionName", i, "", {
1318
+ url: `${baseUrl}/n8n/templates/${templateId}?connectionName=${this.getNodeParameter("whatsappConnectionName", i, "", {
1046
1319
  extractValue: true,
1047
1320
  })}`,
1048
1321
  json: true,
@@ -1146,7 +1419,7 @@ class Waapy {
1146
1419
  method: "POST",
1147
1420
  url: `${baseUrl}/n8n/messages/send-template`,
1148
1421
  body: {
1149
- connectionName: this.getNodeParameter("connectionName", i, "", {
1422
+ connectionName: this.getNodeParameter("whatsappConnectionName", i, "", {
1150
1423
  extractValue: true,
1151
1424
  }),
1152
1425
  recipient: toNumber,