n8n-nodes-colibly 0.1.0 → 0.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.
- package/dist/nodes/Colibly/Colibly.node.d.ts +2 -1
- package/dist/nodes/Colibly/Colibly.node.js +671 -21
- package/dist/nodes/Colibly/GenericFunctions.d.ts +1 -0
- package/dist/nodes/Colibly/GenericFunctions.js +28 -10
- package/dist/nodes/ColiblyTrigger/ColiblyTrigger.node.js +19 -2
- package/dist/package.json +1 -1
- package/package.json +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { IExecuteFunctions, INodeExecutionData, INodeType, INodeTypeDescription } from 'n8n-workflow';
|
|
2
|
-
import { getAccounts, getRunnableAutomations, getTags, getTeams, getTemplates, getUsers, getWhatsappAccounts } from './GenericFunctions';
|
|
2
|
+
import { getAccounts, getAllTemplates, getRunnableAutomations, getTags, getTeams, getTemplates, getUsers, getWhatsappAccounts } from './GenericFunctions';
|
|
3
3
|
export declare class Colibly implements INodeType {
|
|
4
4
|
description: INodeTypeDescription;
|
|
5
5
|
methods: {
|
|
@@ -10,6 +10,7 @@ export declare class Colibly implements INodeType {
|
|
|
10
10
|
getUsers: typeof getUsers;
|
|
11
11
|
getTeams: typeof getTeams;
|
|
12
12
|
getTemplates: typeof getTemplates;
|
|
13
|
+
getAllTemplates: typeof getAllTemplates;
|
|
13
14
|
getRunnableAutomations: typeof getRunnableAutomations;
|
|
14
15
|
};
|
|
15
16
|
};
|
|
@@ -57,6 +57,43 @@ function customFieldsFrom(raw) {
|
|
|
57
57
|
return undefined;
|
|
58
58
|
return Object.fromEntries(list.map((f) => [f.key, f.value === '' ? null : f.value]));
|
|
59
59
|
}
|
|
60
|
+
function jsonParam(ctx, name, i) {
|
|
61
|
+
const raw = ctx.getNodeParameter(name, i, '');
|
|
62
|
+
if (raw === '' || raw === undefined || raw === null)
|
|
63
|
+
return undefined;
|
|
64
|
+
if (typeof raw === 'object')
|
|
65
|
+
return raw;
|
|
66
|
+
let parsed;
|
|
67
|
+
try {
|
|
68
|
+
parsed = JSON.parse(raw);
|
|
69
|
+
}
|
|
70
|
+
catch (error) {
|
|
71
|
+
throw new n8n_workflow_1.NodeOperationError(ctx.getNode(), `El campo ${name} no es JSON válido: ${error.message}`, { itemIndex: i });
|
|
72
|
+
}
|
|
73
|
+
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
|
|
74
|
+
throw new n8n_workflow_1.NodeOperationError(ctx.getNode(), `El campo ${name} debe ser un objeto JSON`, { itemIndex: i });
|
|
75
|
+
}
|
|
76
|
+
return parsed;
|
|
77
|
+
}
|
|
78
|
+
const json = (displayName, name, displayOptions, description, required = true) => ({
|
|
79
|
+
displayName,
|
|
80
|
+
name,
|
|
81
|
+
type: 'json',
|
|
82
|
+
default: '',
|
|
83
|
+
required,
|
|
84
|
+
description,
|
|
85
|
+
displayOptions,
|
|
86
|
+
});
|
|
87
|
+
const WA_ACCOUNT = (operations) => ({
|
|
88
|
+
displayName: 'WhatsApp Account Name or ID',
|
|
89
|
+
name: 'waAccountId',
|
|
90
|
+
type: 'options',
|
|
91
|
+
typeOptions: { loadOptionsMethod: 'getWhatsappAccounts' },
|
|
92
|
+
required: true,
|
|
93
|
+
default: '',
|
|
94
|
+
description: 'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>',
|
|
95
|
+
displayOptions: show('whatsapp', operations),
|
|
96
|
+
});
|
|
60
97
|
class Colibly {
|
|
61
98
|
constructor() {
|
|
62
99
|
this.description = {
|
|
@@ -66,7 +103,7 @@ class Colibly {
|
|
|
66
103
|
group: ['transform'],
|
|
67
104
|
version: 1,
|
|
68
105
|
subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}',
|
|
69
|
-
description: 'Contactos, conversaciones, mensajes
|
|
106
|
+
description: 'Contactos, conversaciones, mensajes, plantillas, llamadas y administración de WhatsApp en Colibly',
|
|
70
107
|
defaults: { name: 'Colibly' },
|
|
71
108
|
inputs: [n8n_workflow_1.NodeConnectionTypes.Main],
|
|
72
109
|
outputs: [n8n_workflow_1.NodeConnectionTypes.Main],
|
|
@@ -80,9 +117,13 @@ class Colibly {
|
|
|
80
117
|
noDataExpression: true,
|
|
81
118
|
options: [
|
|
82
119
|
{ name: 'Automation', value: 'automation' },
|
|
120
|
+
{ name: 'Call', value: 'call', description: 'Llamadas de WhatsApp' },
|
|
83
121
|
{ name: 'Contact', value: 'contact' },
|
|
84
122
|
{ name: 'Conversation', value: 'conversation' },
|
|
123
|
+
{ name: 'Media', value: 'media', description: 'Archivos para reusar en varios envíos' },
|
|
85
124
|
{ name: 'Message', value: 'message' },
|
|
125
|
+
{ name: 'Template', value: 'template', description: 'Plantillas de WhatsApp: crear, editar, borrar y métricas' },
|
|
126
|
+
{ name: 'WhatsApp', value: 'whatsapp', description: 'Perfil, bloqueos, QR, costos, catálogo y Flows del número' },
|
|
86
127
|
{ name: 'Workspace', value: 'workspace', description: 'Cuentas, etiquetas, usuarios, equipos y plantillas' },
|
|
87
128
|
],
|
|
88
129
|
default: 'contact',
|
|
@@ -296,7 +337,8 @@ class Colibly {
|
|
|
296
337
|
displayOptions: { show: { resource: ['message'] } },
|
|
297
338
|
options: [
|
|
298
339
|
{ name: 'Get', value: 'get', action: 'Get a message' },
|
|
299
|
-
{ name: '
|
|
340
|
+
{ name: 'React', value: 'react', action: 'React to a message', description: 'Emoji sobre un mensaje de WhatsApp ("" la quita)' },
|
|
341
|
+
{ name: 'Send', value: 'send', action: 'Send a message', description: 'Texto, botones, lista, plantilla, archivo, ubicación, Flow, catálogo…' },
|
|
300
342
|
],
|
|
301
343
|
default: 'send',
|
|
302
344
|
},
|
|
@@ -306,7 +348,15 @@ class Colibly {
|
|
|
306
348
|
type: 'string',
|
|
307
349
|
required: true,
|
|
308
350
|
default: '',
|
|
309
|
-
displayOptions: show('message', ['get']),
|
|
351
|
+
displayOptions: show('message', ['get', 'react']),
|
|
352
|
+
},
|
|
353
|
+
{
|
|
354
|
+
displayName: 'Emoji',
|
|
355
|
+
name: 'emoji',
|
|
356
|
+
type: 'string',
|
|
357
|
+
default: '👍',
|
|
358
|
+
description: 'Un solo emoji; vacío quita la reacción',
|
|
359
|
+
displayOptions: show('message', ['react']),
|
|
310
360
|
},
|
|
311
361
|
{
|
|
312
362
|
displayName: 'Send To',
|
|
@@ -315,10 +365,31 @@ class Colibly {
|
|
|
315
365
|
options: [
|
|
316
366
|
{ name: 'Contact', value: 'contact' },
|
|
317
367
|
{ name: 'Conversation', value: 'conversation' },
|
|
368
|
+
{ name: 'Phone Number', value: 'phone', description: 'Número de WhatsApp: crea el contacto si hace falta (solo con plantilla)' },
|
|
318
369
|
],
|
|
319
370
|
default: 'contact',
|
|
320
371
|
displayOptions: show('message', ['send']),
|
|
321
372
|
},
|
|
373
|
+
{
|
|
374
|
+
displayName: 'WhatsApp Account Name or ID',
|
|
375
|
+
name: 'sendAccountId',
|
|
376
|
+
type: 'options',
|
|
377
|
+
typeOptions: { loadOptionsMethod: 'getWhatsappAccounts' },
|
|
378
|
+
required: true,
|
|
379
|
+
default: '',
|
|
380
|
+
description: 'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>',
|
|
381
|
+
displayOptions: { show: { resource: ['message'], operation: ['send'], target: ['phone'] } },
|
|
382
|
+
},
|
|
383
|
+
{
|
|
384
|
+
displayName: 'Phone',
|
|
385
|
+
name: 'sendTo',
|
|
386
|
+
type: 'string',
|
|
387
|
+
required: true,
|
|
388
|
+
default: '',
|
|
389
|
+
placeholder: '5215512345678',
|
|
390
|
+
description: 'Con código de país; 10 dígitos sin + se toman como México',
|
|
391
|
+
displayOptions: { show: { resource: ['message'], operation: ['send'], target: ['phone'] } },
|
|
392
|
+
},
|
|
322
393
|
{
|
|
323
394
|
displayName: 'Contact ID',
|
|
324
395
|
name: 'sendContactId',
|
|
@@ -340,10 +411,19 @@ class Colibly {
|
|
|
340
411
|
name: 'type',
|
|
341
412
|
type: 'options',
|
|
342
413
|
options: [
|
|
414
|
+
{ name: 'Advanced (JSON)', value: 'json', description: 'Cualquier tipo de POST /messages: product_list, contacts, plantillas de carrusel…' },
|
|
343
415
|
{ name: 'Audio', value: 'audio' },
|
|
416
|
+
{ name: 'Button With URL', value: 'cta_url', description: 'Texto con un botón que abre una URL (WhatsApp)' },
|
|
344
417
|
{ name: 'Buttons', value: 'buttons', description: 'Texto con hasta 3 botones de respuesta' },
|
|
418
|
+
{ name: 'Catalog', value: 'catalog', description: 'Botón «Ver catálogo» (WhatsApp)' },
|
|
345
419
|
{ name: 'Document', value: 'document' },
|
|
420
|
+
{ name: 'Flow', value: 'flow', description: 'Formulario de WhatsApp Flows' },
|
|
346
421
|
{ name: 'Image', value: 'image' },
|
|
422
|
+
{ name: 'List', value: 'list', description: 'Texto con un menú de hasta 10 opciones' },
|
|
423
|
+
{ name: 'Location', value: 'location', description: 'Un punto en el mapa (WhatsApp)' },
|
|
424
|
+
{ name: 'Location Request', value: 'location_request', description: 'Pide al cliente su ubicación (WhatsApp)' },
|
|
425
|
+
{ name: 'Product', value: 'product', description: 'Un producto del catálogo (WhatsApp)' },
|
|
426
|
+
{ name: 'Sticker', value: 'sticker', description: 'WebP de 512×512 (WhatsApp)' },
|
|
347
427
|
{ name: 'Template', value: 'template', description: 'Plantilla aprobada (necesaria fuera de la ventana de 24 h)' },
|
|
348
428
|
{ name: 'Text', value: 'text' },
|
|
349
429
|
{ name: 'Video', value: 'video' },
|
|
@@ -359,7 +439,148 @@ class Colibly {
|
|
|
359
439
|
typeOptions: { rows: 4 },
|
|
360
440
|
required: true,
|
|
361
441
|
default: '',
|
|
362
|
-
displayOptions: { show: { resource: ['message'], operation: ['send'], type: ['text', 'buttons'] } },
|
|
442
|
+
displayOptions: { show: { resource: ['message'], operation: ['send'], type: ['text', 'buttons', 'list', 'cta_url', 'location_request', 'flow', 'catalog'] } },
|
|
443
|
+
},
|
|
444
|
+
{
|
|
445
|
+
displayName: 'Message Fields (JSON)',
|
|
446
|
+
name: 'messageJson',
|
|
447
|
+
type: 'json',
|
|
448
|
+
required: true,
|
|
449
|
+
default: '{\n "type": "contacts",\n "contacts": [{ "name": "Laura Gómez", "phones": [{ "phone": "+52 55 1234 5678" }] }]\n}',
|
|
450
|
+
description: 'Campos de POST /messages (type y los suyos); el destino lo pone «Send To»',
|
|
451
|
+
displayOptions: { show: { resource: ['message'], operation: ['send'], type: ['json'] } },
|
|
452
|
+
},
|
|
453
|
+
{
|
|
454
|
+
displayName: 'List Button',
|
|
455
|
+
name: 'listButton',
|
|
456
|
+
type: 'string',
|
|
457
|
+
required: true,
|
|
458
|
+
default: 'Ver opciones',
|
|
459
|
+
description: 'Texto del botón que abre la lista (20 caracteres)',
|
|
460
|
+
displayOptions: { show: { resource: ['message'], operation: ['send'], type: ['list'] } },
|
|
461
|
+
},
|
|
462
|
+
{
|
|
463
|
+
displayName: 'List Options',
|
|
464
|
+
name: 'listRows',
|
|
465
|
+
type: 'fixedCollection',
|
|
466
|
+
typeOptions: { multipleValues: true },
|
|
467
|
+
placeholder: 'Add Option',
|
|
468
|
+
default: {},
|
|
469
|
+
description: 'Hasta 10 opciones',
|
|
470
|
+
displayOptions: { show: { resource: ['message'], operation: ['send'], type: ['list'] } },
|
|
471
|
+
options: [
|
|
472
|
+
{
|
|
473
|
+
name: 'row',
|
|
474
|
+
displayName: 'Option',
|
|
475
|
+
values: [
|
|
476
|
+
{ displayName: 'Title', name: 'title', type: 'string', default: '' },
|
|
477
|
+
{ displayName: 'Description', name: 'description', type: 'string', default: '' },
|
|
478
|
+
{ displayName: 'ID', name: 'id', type: 'string', default: '', description: 'Opcional; llega en la respuesta del cliente' },
|
|
479
|
+
],
|
|
480
|
+
},
|
|
481
|
+
],
|
|
482
|
+
},
|
|
483
|
+
{
|
|
484
|
+
displayName: 'Button Label',
|
|
485
|
+
name: 'ctaLabel',
|
|
486
|
+
type: 'string',
|
|
487
|
+
required: true,
|
|
488
|
+
default: '',
|
|
489
|
+
displayOptions: { show: { resource: ['message'], operation: ['send'], type: ['cta_url'] } },
|
|
490
|
+
},
|
|
491
|
+
{
|
|
492
|
+
displayName: 'Button URL',
|
|
493
|
+
name: 'ctaUrl',
|
|
494
|
+
type: 'string',
|
|
495
|
+
required: true,
|
|
496
|
+
default: '',
|
|
497
|
+
placeholder: 'https://...',
|
|
498
|
+
displayOptions: { show: { resource: ['message'], operation: ['send'], type: ['cta_url'] } },
|
|
499
|
+
},
|
|
500
|
+
{
|
|
501
|
+
displayName: 'Latitude',
|
|
502
|
+
name: 'latitude',
|
|
503
|
+
type: 'number',
|
|
504
|
+
typeOptions: { numberPrecision: 6 },
|
|
505
|
+
required: true,
|
|
506
|
+
default: 0,
|
|
507
|
+
displayOptions: { show: { resource: ['message'], operation: ['send'], type: ['location'] } },
|
|
508
|
+
},
|
|
509
|
+
{
|
|
510
|
+
displayName: 'Longitude',
|
|
511
|
+
name: 'longitude',
|
|
512
|
+
type: 'number',
|
|
513
|
+
typeOptions: { numberPrecision: 6 },
|
|
514
|
+
required: true,
|
|
515
|
+
default: 0,
|
|
516
|
+
displayOptions: { show: { resource: ['message'], operation: ['send'], type: ['location'] } },
|
|
517
|
+
},
|
|
518
|
+
{
|
|
519
|
+
displayName: 'Location Options',
|
|
520
|
+
name: 'locationOptions',
|
|
521
|
+
type: 'collection',
|
|
522
|
+
placeholder: 'Add Option',
|
|
523
|
+
default: {},
|
|
524
|
+
displayOptions: { show: { resource: ['message'], operation: ['send'], type: ['location'] } },
|
|
525
|
+
options: [
|
|
526
|
+
{ displayName: 'Name', name: 'name', type: 'string', default: '' },
|
|
527
|
+
{ displayName: 'Address', name: 'address', type: 'string', default: '' },
|
|
528
|
+
],
|
|
529
|
+
},
|
|
530
|
+
{
|
|
531
|
+
displayName: 'Product Retailer ID',
|
|
532
|
+
name: 'productId',
|
|
533
|
+
type: 'string',
|
|
534
|
+
required: true,
|
|
535
|
+
default: '',
|
|
536
|
+
description: '«ID de contenido» del producto en Commerce Manager',
|
|
537
|
+
displayOptions: { show: { resource: ['message'], operation: ['send'], type: ['product'] } },
|
|
538
|
+
},
|
|
539
|
+
{
|
|
540
|
+
displayName: 'Flow ID',
|
|
541
|
+
name: 'flowId',
|
|
542
|
+
type: 'string',
|
|
543
|
+
required: true,
|
|
544
|
+
default: '',
|
|
545
|
+
description: 'De WhatsApp → Get Flows',
|
|
546
|
+
displayOptions: { show: { resource: ['message'], operation: ['send'], type: ['flow'] } },
|
|
547
|
+
},
|
|
548
|
+
{
|
|
549
|
+
displayName: 'Flow Button',
|
|
550
|
+
name: 'flowCta',
|
|
551
|
+
type: 'string',
|
|
552
|
+
required: true,
|
|
553
|
+
default: 'Abrir',
|
|
554
|
+
displayOptions: { show: { resource: ['message'], operation: ['send'], type: ['flow'] } },
|
|
555
|
+
},
|
|
556
|
+
{
|
|
557
|
+
displayName: 'Flow Options',
|
|
558
|
+
name: 'flowOptions',
|
|
559
|
+
type: 'collection',
|
|
560
|
+
placeholder: 'Add Option',
|
|
561
|
+
default: {},
|
|
562
|
+
displayOptions: { show: { resource: ['message'], operation: ['send'], type: ['flow'] } },
|
|
563
|
+
options: [
|
|
564
|
+
{ displayName: 'Draft', name: 'draft', type: 'boolean', default: false, description: 'Whether to send a DRAFT flow to test it' },
|
|
565
|
+
{ displayName: 'First Screen', name: 'screen', type: 'string', default: '' },
|
|
566
|
+
{ displayName: 'Flow Reference', name: 'reference', type: 'string', default: '', description: 'Se manda como flow.token y vuelve en flow.completed para cruzar la respuesta; por omisión Colibly genera uno' },
|
|
567
|
+
{ displayName: 'Header', name: 'header', type: 'string', default: '' },
|
|
568
|
+
{ displayName: 'Initial Data (JSON)', name: 'data', type: 'json', default: '' },
|
|
569
|
+
],
|
|
570
|
+
},
|
|
571
|
+
{
|
|
572
|
+
displayName: 'Product Options',
|
|
573
|
+
name: 'productOptions',
|
|
574
|
+
type: 'collection',
|
|
575
|
+
placeholder: 'Add Option',
|
|
576
|
+
default: {},
|
|
577
|
+
displayOptions: { show: { resource: ['message'], operation: ['send'], type: ['product', 'catalog'] } },
|
|
578
|
+
options: [
|
|
579
|
+
{ displayName: 'Catalog ID', name: 'catalogId', type: 'string', default: '', description: 'Solo si la cuenta tiene varios catálogos (o es de coexistencia)' },
|
|
580
|
+
{ displayName: 'Footer', name: 'footer', type: 'string', default: '' },
|
|
581
|
+
{ displayName: 'Text', name: 'text', type: 'string', default: '' },
|
|
582
|
+
{ displayName: 'Thumbnail Product ID', name: 'thumbnailProductId', type: 'string', default: '', description: 'Catálogo: producto de la miniatura' },
|
|
583
|
+
],
|
|
363
584
|
},
|
|
364
585
|
{
|
|
365
586
|
displayName: 'Buttons',
|
|
@@ -399,20 +620,30 @@ class Colibly {
|
|
|
399
620
|
default: {},
|
|
400
621
|
displayOptions: { show: { resource: ['message'], operation: ['send'], type: ['template'] } },
|
|
401
622
|
options: [
|
|
402
|
-
{ displayName: '
|
|
403
|
-
{ displayName: '
|
|
623
|
+
{ displayName: 'Advanced (JSON)', name: 'advanced', type: 'json', default: '', description: 'Más campos de template: buttons (payload, couponCode…), code (OTP), offerExpiresAt, cards (carrusel), headerLocation' },
|
|
624
|
+
{ displayName: 'Body Parameters', name: 'bodyParams', type: 'string', default: '', description: 'Valores de {{1}}, {{2}}… en orden, separados por |; o un objeto JSON {"nombre": "Ana"} para variables con nombre' },
|
|
404
625
|
{ displayName: 'Button Parameter', name: 'buttonParam', type: 'string', default: '', description: 'Sufijo del botón con URL dinámica' },
|
|
626
|
+
{ displayName: 'Code (Authentication)', name: 'code', type: 'string', default: '', description: 'Código de verificación de una plantilla AUTHENTICATION' },
|
|
627
|
+
{ displayName: 'Header Parameter', name: 'headerParam', type: 'string', default: '', description: 'Texto de la cabecera, URL https o media ID (Media → Upload)' },
|
|
405
628
|
],
|
|
406
629
|
},
|
|
407
630
|
{
|
|
408
|
-
displayName: 'File URL',
|
|
631
|
+
displayName: 'File URL or Media ID',
|
|
409
632
|
name: 'mediaUrl',
|
|
410
633
|
type: 'string',
|
|
411
634
|
required: true,
|
|
412
635
|
default: '',
|
|
413
|
-
placeholder: 'https://...',
|
|
414
|
-
description: 'URL pública https del archivo',
|
|
415
|
-
displayOptions: { show: { resource: ['message'], operation: ['send'], type: ['image', 'document', 'audio', 'video'] } },
|
|
636
|
+
placeholder: 'https://... o cmmed_…',
|
|
637
|
+
description: 'URL pública https del archivo, o el ID de Media → Upload para reusarlo',
|
|
638
|
+
displayOptions: { show: { resource: ['message'], operation: ['send'], type: ['image', 'document', 'audio', 'video', 'sticker'] } },
|
|
639
|
+
},
|
|
640
|
+
{
|
|
641
|
+
displayName: 'Reply To Message ID',
|
|
642
|
+
name: 'replyTo',
|
|
643
|
+
type: 'string',
|
|
644
|
+
default: '',
|
|
645
|
+
description: 'Opcional (WhatsApp): cita ese mensaje de la misma conversación',
|
|
646
|
+
displayOptions: show('message', ['send']),
|
|
416
647
|
},
|
|
417
648
|
{
|
|
418
649
|
displayName: 'File Options',
|
|
@@ -484,6 +715,250 @@ class Colibly {
|
|
|
484
715
|
description: 'Whether to list only the active automations with a manual trigger',
|
|
485
716
|
displayOptions: show('automation', ['getAll']),
|
|
486
717
|
},
|
|
718
|
+
{
|
|
719
|
+
displayName: 'Operation',
|
|
720
|
+
name: 'operation',
|
|
721
|
+
type: 'options',
|
|
722
|
+
noDataExpression: true,
|
|
723
|
+
displayOptions: { show: { resource: ['whatsapp'] } },
|
|
724
|
+
options: [
|
|
725
|
+
{ name: 'Block Users', value: 'block', action: 'Block users' },
|
|
726
|
+
{ name: 'Create Flow', value: 'createFlow', action: 'Create a flow' },
|
|
727
|
+
{ name: 'Create Onboarding Link', value: 'createLink', action: 'Create a link to connect a number', description: 'Tu cliente conecta su número con su Facebook, sin cuenta en Colibly' },
|
|
728
|
+
{ name: 'Create QR Code', value: 'createQr', action: 'Create a QR code' },
|
|
729
|
+
{ name: 'Delete QR Code', value: 'deleteQr', action: 'Delete a QR code' },
|
|
730
|
+
{ name: 'Get Blocked Users', value: 'getBlocked', action: 'Get blocked users' },
|
|
731
|
+
{ name: 'Get Catalog', value: 'getCatalog', action: 'Get the catalog settings' },
|
|
732
|
+
{ name: 'Get Conversational Automation', value: 'getAutomation', action: 'Get prompts commands and welcome message' },
|
|
733
|
+
{ name: 'Get Costs', value: 'getCosts', action: 'Get messaging costs' },
|
|
734
|
+
{ name: 'Get Flow', value: 'getFlow', action: 'Get a flow' },
|
|
735
|
+
{ name: 'Get Flows', value: 'getFlows', action: 'Get flows' },
|
|
736
|
+
{ name: 'Get Health', value: 'getHealth', action: 'Get number health', description: 'Calidad, límite de envío y avisos de Meta' },
|
|
737
|
+
{ name: 'Get Onboarding Link', value: 'getLink', action: 'Get an onboarding link' },
|
|
738
|
+
{ name: 'Get Phone Numbers', value: 'getNumbers', action: 'Get phone numbers' },
|
|
739
|
+
{ name: 'Get Profile', value: 'getProfile', action: 'Get the business profile' },
|
|
740
|
+
{ name: 'Get QR Codes', value: 'getQr', action: 'Get QR codes' },
|
|
741
|
+
{ name: 'Publish Flow', value: 'publishFlow', action: 'Publish a flow' },
|
|
742
|
+
{ name: 'Register Number', value: 'register', action: 'Register the number' },
|
|
743
|
+
{ name: 'Set Two-Step PIN', value: 'setPin', action: 'Set the two step verification pin' },
|
|
744
|
+
{ name: 'Unblock User', value: 'unblock', action: 'Unblock a user' },
|
|
745
|
+
{ name: 'Update Conversational Automation', value: 'updateAutomation', action: 'Update prompts commands and welcome message' },
|
|
746
|
+
{ name: 'Update Profile', value: 'updateProfile', action: 'Update the business profile' },
|
|
747
|
+
],
|
|
748
|
+
default: 'getHealth',
|
|
749
|
+
},
|
|
750
|
+
WA_ACCOUNT(['block', 'createFlow', 'createQr', 'deleteQr', 'getBlocked', 'getCatalog', 'getAutomation', 'getCosts', 'getFlow', 'getFlows', 'getHealth', 'getNumbers', 'getProfile', 'getQr', 'publishFlow', 'register', 'setPin', 'unblock', 'updateAutomation', 'updateProfile']),
|
|
751
|
+
{
|
|
752
|
+
displayName: 'PIN',
|
|
753
|
+
name: 'pin',
|
|
754
|
+
type: 'string',
|
|
755
|
+
typeOptions: { password: true },
|
|
756
|
+
required: true,
|
|
757
|
+
default: '',
|
|
758
|
+
description: '6 dígitos. En Register Number puede ir vacío: se usa el guardado.',
|
|
759
|
+
displayOptions: show('whatsapp', ['setPin', 'register']),
|
|
760
|
+
},
|
|
761
|
+
{
|
|
762
|
+
displayName: 'Link Options',
|
|
763
|
+
name: 'linkOptions',
|
|
764
|
+
type: 'collection',
|
|
765
|
+
placeholder: 'Add Option',
|
|
766
|
+
default: {},
|
|
767
|
+
displayOptions: show('whatsapp', ['createLink']),
|
|
768
|
+
options: [
|
|
769
|
+
{ displayName: 'Account Name', name: 'name', type: 'string', default: '', description: 'Nombre de la cuenta que se creará' },
|
|
770
|
+
{ displayName: 'Expires In (Hours)', name: 'expiresInHours', type: 'number', typeOptions: { minValue: 1, maxValue: 720 }, default: 72 },
|
|
771
|
+
{ displayName: 'Redirect URL', name: 'redirectUrl', type: 'string', default: '', description: 'A dónde vuelve tu cliente al terminar (https)' },
|
|
772
|
+
{ displayName: 'Reference', name: 'reference', type: 'string', default: '', description: 'Tu ID del cliente; vuelve en el evento Account Connected' },
|
|
773
|
+
],
|
|
774
|
+
},
|
|
775
|
+
{
|
|
776
|
+
displayName: 'Link ID',
|
|
777
|
+
name: 'linkId',
|
|
778
|
+
type: 'string',
|
|
779
|
+
required: true,
|
|
780
|
+
default: '',
|
|
781
|
+
displayOptions: show('whatsapp', ['getLink']),
|
|
782
|
+
},
|
|
783
|
+
{
|
|
784
|
+
displayName: 'Phones',
|
|
785
|
+
name: 'phones',
|
|
786
|
+
type: 'string',
|
|
787
|
+
required: true,
|
|
788
|
+
default: '',
|
|
789
|
+
description: 'Separados por comas, con código de país',
|
|
790
|
+
displayOptions: show('whatsapp', ['block', 'unblock']),
|
|
791
|
+
},
|
|
792
|
+
{
|
|
793
|
+
displayName: 'Prefilled Message',
|
|
794
|
+
name: 'prefilledMessage',
|
|
795
|
+
type: 'string',
|
|
796
|
+
required: true,
|
|
797
|
+
default: '',
|
|
798
|
+
description: 'Lo que aparece escrito al escanear (140 caracteres)',
|
|
799
|
+
displayOptions: show('whatsapp', ['createQr']),
|
|
800
|
+
},
|
|
801
|
+
{
|
|
802
|
+
displayName: 'QR Code',
|
|
803
|
+
name: 'qrCode',
|
|
804
|
+
type: 'string',
|
|
805
|
+
required: true,
|
|
806
|
+
default: '',
|
|
807
|
+
displayOptions: show('whatsapp', ['deleteQr']),
|
|
808
|
+
},
|
|
809
|
+
{
|
|
810
|
+
displayName: 'Flow ID',
|
|
811
|
+
name: 'waFlowId',
|
|
812
|
+
type: 'string',
|
|
813
|
+
required: true,
|
|
814
|
+
default: '',
|
|
815
|
+
displayOptions: show('whatsapp', ['getFlow', 'publishFlow']),
|
|
816
|
+
},
|
|
817
|
+
{
|
|
818
|
+
displayName: 'Since',
|
|
819
|
+
name: 'since',
|
|
820
|
+
type: 'dateTime',
|
|
821
|
+
default: '',
|
|
822
|
+
description: 'Por omisión, hace 30 días',
|
|
823
|
+
displayOptions: show('whatsapp', ['getCosts']),
|
|
824
|
+
},
|
|
825
|
+
{
|
|
826
|
+
displayName: 'Until',
|
|
827
|
+
name: 'until',
|
|
828
|
+
type: 'dateTime',
|
|
829
|
+
default: '',
|
|
830
|
+
displayOptions: show('whatsapp', ['getCosts']),
|
|
831
|
+
},
|
|
832
|
+
json('Profile (JSON)', 'profileJson', show('whatsapp', ['updateProfile']), 'about, address, description, email, websites, vertical, profilePictureUrl'),
|
|
833
|
+
json('Conversational Automation (JSON)', 'automationJson', show('whatsapp', ['updateAutomation']), 'prompts (hasta 4), commands ([{ name, description }]) y/o welcomeMessage ({ enabled, text })'),
|
|
834
|
+
json('Flow (JSON)', 'flowJson', show('whatsapp', ['createFlow']), 'name, categories, flowJson y opcionalmente publish, endpointUri o useColiblyEndpoint'),
|
|
835
|
+
{
|
|
836
|
+
displayName: 'Operation',
|
|
837
|
+
name: 'operation',
|
|
838
|
+
type: 'options',
|
|
839
|
+
noDataExpression: true,
|
|
840
|
+
displayOptions: { show: { resource: ['template'] } },
|
|
841
|
+
options: [
|
|
842
|
+
{ name: 'Create', value: 'create', action: 'Create a template', description: 'La manda a revisión de Meta' },
|
|
843
|
+
{ name: 'Delete', value: 'delete', action: 'Delete a template' },
|
|
844
|
+
{ name: 'Edit', value: 'edit', action: 'Edit a template', description: 'Vuelve a revisión' },
|
|
845
|
+
{ name: 'Get', value: 'get', action: 'Get a template' },
|
|
846
|
+
{ name: 'Get Analytics', value: 'analytics', action: 'Get template analytics' },
|
|
847
|
+
{ name: 'Get Many', value: 'getAll', action: 'Get many templates' },
|
|
848
|
+
],
|
|
849
|
+
default: 'getAll',
|
|
850
|
+
},
|
|
851
|
+
{
|
|
852
|
+
displayName: 'Template Name or ID',
|
|
853
|
+
name: 'tplId',
|
|
854
|
+
type: 'options',
|
|
855
|
+
typeOptions: { loadOptionsMethod: 'getAllTemplates' },
|
|
856
|
+
required: true,
|
|
857
|
+
default: '',
|
|
858
|
+
description: 'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>',
|
|
859
|
+
displayOptions: show('template', ['delete', 'edit', 'get', 'analytics']),
|
|
860
|
+
},
|
|
861
|
+
json('Template (JSON)', 'templateJson', show('template', ['create']), 'accountId, name, language, category y components (body, bodyExamples, header, footer, buttons, limitedTimeOffer, carousel, authentication)'),
|
|
862
|
+
json('Changes (JSON)', 'templateEditJson', show('template', ['edit']), 'components (y category si no está aprobada)'),
|
|
863
|
+
{
|
|
864
|
+
displayName: 'Operation',
|
|
865
|
+
name: 'operation',
|
|
866
|
+
type: 'options',
|
|
867
|
+
noDataExpression: true,
|
|
868
|
+
displayOptions: { show: { resource: ['media'] } },
|
|
869
|
+
options: [
|
|
870
|
+
{ name: 'Delete', value: 'delete', action: 'Delete an uploaded file' },
|
|
871
|
+
{ name: 'Upload', value: 'upload', action: 'Upload a file from a URL', description: 'Devuelve un ID para reusarlo 30 días' },
|
|
872
|
+
],
|
|
873
|
+
default: 'upload',
|
|
874
|
+
},
|
|
875
|
+
{
|
|
876
|
+
displayName: 'File Type',
|
|
877
|
+
name: 'mediaType',
|
|
878
|
+
type: 'options',
|
|
879
|
+
options: [
|
|
880
|
+
{ name: 'Audio', value: 'audio' },
|
|
881
|
+
{ name: 'Document', value: 'document' },
|
|
882
|
+
{ name: 'Image', value: 'image' },
|
|
883
|
+
{ name: 'Sticker', value: 'sticker' },
|
|
884
|
+
{ name: 'Video', value: 'video' },
|
|
885
|
+
],
|
|
886
|
+
default: 'image',
|
|
887
|
+
displayOptions: show('media', ['upload']),
|
|
888
|
+
},
|
|
889
|
+
{
|
|
890
|
+
displayName: 'File URL',
|
|
891
|
+
name: 'uploadUrl',
|
|
892
|
+
type: 'string',
|
|
893
|
+
required: true,
|
|
894
|
+
default: '',
|
|
895
|
+
placeholder: 'https://...',
|
|
896
|
+
displayOptions: show('media', ['upload']),
|
|
897
|
+
},
|
|
898
|
+
{
|
|
899
|
+
displayName: 'Media ID',
|
|
900
|
+
name: 'mediaId',
|
|
901
|
+
type: 'string',
|
|
902
|
+
required: true,
|
|
903
|
+
default: '',
|
|
904
|
+
displayOptions: show('media', ['delete']),
|
|
905
|
+
},
|
|
906
|
+
{
|
|
907
|
+
displayName: 'Operation',
|
|
908
|
+
name: 'operation',
|
|
909
|
+
type: 'options',
|
|
910
|
+
noDataExpression: true,
|
|
911
|
+
displayOptions: { show: { resource: ['call'] } },
|
|
912
|
+
options: [
|
|
913
|
+
{ name: 'Get', value: 'get', action: 'Get a call' },
|
|
914
|
+
{ name: 'Get Many', value: 'getAll', action: 'Get many calls' },
|
|
915
|
+
],
|
|
916
|
+
default: 'getAll',
|
|
917
|
+
},
|
|
918
|
+
{
|
|
919
|
+
displayName: 'Call ID',
|
|
920
|
+
name: 'callId',
|
|
921
|
+
type: 'string',
|
|
922
|
+
required: true,
|
|
923
|
+
default: '',
|
|
924
|
+
displayOptions: show('call', ['get']),
|
|
925
|
+
},
|
|
926
|
+
...returnAllFields('call', 'getAll'),
|
|
927
|
+
{
|
|
928
|
+
displayName: 'Filters',
|
|
929
|
+
name: 'callFilters',
|
|
930
|
+
type: 'collection',
|
|
931
|
+
placeholder: 'Add Filter',
|
|
932
|
+
default: {},
|
|
933
|
+
displayOptions: show('call', ['getAll']),
|
|
934
|
+
options: [
|
|
935
|
+
{ displayName: 'Account Name or ID', name: 'accountId', type: 'options', typeOptions: { loadOptionsMethod: 'getWhatsappAccounts' }, default: '', description: 'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>' },
|
|
936
|
+
{ displayName: 'Contact ID', name: 'contactId', type: 'string', default: '' },
|
|
937
|
+
{
|
|
938
|
+
displayName: 'Direction',
|
|
939
|
+
name: 'direction',
|
|
940
|
+
type: 'options',
|
|
941
|
+
options: [
|
|
942
|
+
{ name: 'Inbound', value: 'inbound' },
|
|
943
|
+
{ name: 'Outbound', value: 'outbound' },
|
|
944
|
+
],
|
|
945
|
+
default: 'inbound',
|
|
946
|
+
},
|
|
947
|
+
{ displayName: 'Since', name: 'since', type: 'dateTime', default: '' },
|
|
948
|
+
{
|
|
949
|
+
displayName: 'Status',
|
|
950
|
+
name: 'status',
|
|
951
|
+
type: 'options',
|
|
952
|
+
options: [
|
|
953
|
+
{ name: 'Ended', value: 'ENDED' },
|
|
954
|
+
{ name: 'Failed', value: 'FAILED' },
|
|
955
|
+
{ name: 'Missed', value: 'MISSED' },
|
|
956
|
+
{ name: 'Rejected', value: 'REJECTED' },
|
|
957
|
+
],
|
|
958
|
+
default: 'MISSED',
|
|
959
|
+
},
|
|
960
|
+
],
|
|
961
|
+
},
|
|
487
962
|
{
|
|
488
963
|
displayName: 'Operation',
|
|
489
964
|
name: 'operation',
|
|
@@ -512,7 +987,7 @@ class Colibly {
|
|
|
512
987
|
],
|
|
513
988
|
};
|
|
514
989
|
this.methods = {
|
|
515
|
-
loadOptions: { getAccounts: GenericFunctions_1.getAccounts, getWhatsappAccounts: GenericFunctions_1.getWhatsappAccounts, getTags: GenericFunctions_1.getTags, getUsers: GenericFunctions_1.getUsers, getTeams: GenericFunctions_1.getTeams, getTemplates: GenericFunctions_1.getTemplates, getRunnableAutomations: GenericFunctions_1.getRunnableAutomations },
|
|
990
|
+
loadOptions: { getAccounts: GenericFunctions_1.getAccounts, getWhatsappAccounts: GenericFunctions_1.getWhatsappAccounts, getTags: GenericFunctions_1.getTags, getUsers: GenericFunctions_1.getUsers, getTeams: GenericFunctions_1.getTeams, getTemplates: GenericFunctions_1.getTemplates, getAllTemplates: GenericFunctions_1.getAllTemplates, getRunnableAutomations: GenericFunctions_1.getRunnableAutomations },
|
|
516
991
|
};
|
|
517
992
|
}
|
|
518
993
|
async execute() {
|
|
@@ -542,7 +1017,7 @@ class Colibly {
|
|
|
542
1017
|
}
|
|
543
1018
|
exports.Colibly = Colibly;
|
|
544
1019
|
async function runOperation(resource, operation, i) {
|
|
545
|
-
var _a, _b;
|
|
1020
|
+
var _a, _b, _c, _d;
|
|
546
1021
|
const enc = encodeURIComponent;
|
|
547
1022
|
if (resource === 'contact') {
|
|
548
1023
|
if (operation === 'get')
|
|
@@ -628,33 +1103,105 @@ async function runOperation(resource, operation, i) {
|
|
|
628
1103
|
if (resource === 'message') {
|
|
629
1104
|
if (operation === 'get')
|
|
630
1105
|
return GenericFunctions_1.coliblyApiRequest.call(this, 'GET', `/messages/${enc(this.getNodeParameter('messageId', i))}`);
|
|
1106
|
+
if (operation === 'react') {
|
|
1107
|
+
const key = (0, GenericFunctions_1.idempotencyKey)(this.getExecutionId(), this.getNode().name, i);
|
|
1108
|
+
return GenericFunctions_1.coliblyApiRequest.call(this, 'POST', `/messages/${enc(this.getNodeParameter('messageId', i))}/reaction`, { emoji: this.getNodeParameter('emoji', i, '') }, undefined, {
|
|
1109
|
+
'Idempotency-Key': key,
|
|
1110
|
+
});
|
|
1111
|
+
}
|
|
631
1112
|
if (operation === 'send') {
|
|
632
1113
|
const target = this.getNodeParameter('target', i);
|
|
633
1114
|
const type = this.getNodeParameter('type', i);
|
|
634
|
-
|
|
1115
|
+
let body = { type };
|
|
1116
|
+
if (type === 'json')
|
|
1117
|
+
body = { ...((_a = jsonParam(this, 'messageJson', i)) !== null && _a !== void 0 ? _a : {}) };
|
|
635
1118
|
if (target === 'contact')
|
|
636
1119
|
body.contactId = this.getNodeParameter('sendContactId', i);
|
|
637
|
-
else
|
|
1120
|
+
else if (target === 'conversation')
|
|
638
1121
|
body.conversationId = this.getNodeParameter('sendConversationId', i);
|
|
639
|
-
|
|
1122
|
+
else {
|
|
1123
|
+
body.accountId = this.getNodeParameter('sendAccountId', i);
|
|
1124
|
+
body.to = this.getNodeParameter('sendTo', i);
|
|
1125
|
+
}
|
|
1126
|
+
const replyTo = this.getNodeParameter('replyTo', i, '');
|
|
1127
|
+
if (replyTo)
|
|
1128
|
+
body.replyTo = replyTo;
|
|
1129
|
+
if (['text', 'buttons', 'list', 'cta_url', 'location_request', 'flow', 'catalog'].includes(type))
|
|
640
1130
|
body.text = this.getNodeParameter('text', i);
|
|
641
1131
|
if (type === 'buttons') {
|
|
642
|
-
const buttons = (
|
|
1132
|
+
const buttons = (_b = this.getNodeParameter('buttons', i, {}).button) !== null && _b !== void 0 ? _b : [];
|
|
643
1133
|
body.buttons = buttons.filter((b) => b.title).map((b) => ({ title: b.title, ...(b.id ? { id: b.id } : {}) }));
|
|
644
1134
|
}
|
|
1135
|
+
if (type === 'list') {
|
|
1136
|
+
const rows = (_c = this.getNodeParameter('listRows', i, {}).row) !== null && _c !== void 0 ? _c : [];
|
|
1137
|
+
body.list = {
|
|
1138
|
+
button: this.getNodeParameter('listButton', i),
|
|
1139
|
+
rows: rows.filter((r) => r.title).map((r) => ({ title: r.title, ...(r.description ? { description: r.description } : {}), ...(r.id ? { id: r.id } : {}) })),
|
|
1140
|
+
};
|
|
1141
|
+
}
|
|
1142
|
+
if (type === 'cta_url')
|
|
1143
|
+
body.cta = { label: this.getNodeParameter('ctaLabel', i), url: this.getNodeParameter('ctaUrl', i) };
|
|
1144
|
+
if (type === 'location') {
|
|
1145
|
+
const opts = this.getNodeParameter('locationOptions', i, {});
|
|
1146
|
+
body.location = {
|
|
1147
|
+
latitude: this.getNodeParameter('latitude', i),
|
|
1148
|
+
longitude: this.getNodeParameter('longitude', i),
|
|
1149
|
+
...(opts.name ? { name: opts.name } : {}),
|
|
1150
|
+
...(opts.address ? { address: opts.address } : {}),
|
|
1151
|
+
};
|
|
1152
|
+
}
|
|
1153
|
+
if (type === 'product' || type === 'catalog') {
|
|
1154
|
+
const opts = this.getNodeParameter('productOptions', i, {});
|
|
1155
|
+
if (type === 'product') {
|
|
1156
|
+
body.product = { id: this.getNodeParameter('productId', i), ...(opts.catalogId ? { catalogId: opts.catalogId } : {}) };
|
|
1157
|
+
if (opts.text)
|
|
1158
|
+
body.text = opts.text;
|
|
1159
|
+
}
|
|
1160
|
+
else if (opts.thumbnailProductId) {
|
|
1161
|
+
body.catalog = { thumbnailProductId: opts.thumbnailProductId };
|
|
1162
|
+
}
|
|
1163
|
+
if (opts.footer)
|
|
1164
|
+
body.footer = opts.footer;
|
|
1165
|
+
}
|
|
1166
|
+
if (type === 'flow') {
|
|
1167
|
+
const opts = this.getNodeParameter('flowOptions', i, {});
|
|
1168
|
+
let data;
|
|
1169
|
+
if (opts.data)
|
|
1170
|
+
data = typeof opts.data === 'string' ? JSON.parse(opts.data) : opts.data;
|
|
1171
|
+
body.flow = {
|
|
1172
|
+
id: this.getNodeParameter('flowId', i),
|
|
1173
|
+
cta: this.getNodeParameter('flowCta', i),
|
|
1174
|
+
...(opts.screen ? { screen: opts.screen } : {}),
|
|
1175
|
+
...(opts.header ? { header: opts.header } : {}),
|
|
1176
|
+
...(opts.reference ? { token: opts.reference } : {}),
|
|
1177
|
+
...(opts.draft ? { draft: true } : {}),
|
|
1178
|
+
...(data ? { data } : {}),
|
|
1179
|
+
};
|
|
1180
|
+
}
|
|
645
1181
|
if (type === 'template') {
|
|
646
1182
|
const p = this.getNodeParameter('templateParams', i, {});
|
|
1183
|
+
let bodyParams;
|
|
1184
|
+
if (p.bodyParams) {
|
|
1185
|
+
const raw = String(p.bodyParams).trim();
|
|
1186
|
+
bodyParams = raw.startsWith('{') ? JSON.parse(raw) : raw.split('|').map((v) => v.trim());
|
|
1187
|
+
}
|
|
1188
|
+
let advanced = {};
|
|
1189
|
+
if (p.advanced)
|
|
1190
|
+
advanced = typeof p.advanced === 'string' ? JSON.parse(p.advanced) : p.advanced;
|
|
647
1191
|
body.template = {
|
|
648
1192
|
id: this.getNodeParameter('templateId', i),
|
|
649
|
-
...(
|
|
1193
|
+
...(bodyParams ? { bodyParams } : {}),
|
|
650
1194
|
...(p.headerParam ? { headerParam: p.headerParam } : {}),
|
|
651
1195
|
...(p.buttonParam ? { buttonParam: p.buttonParam } : {}),
|
|
1196
|
+
...(p.code ? { code: p.code } : {}),
|
|
1197
|
+
...advanced,
|
|
652
1198
|
};
|
|
653
1199
|
}
|
|
654
|
-
if (['image', 'document', 'audio', 'video'].includes(type)) {
|
|
655
|
-
const
|
|
1200
|
+
if (['image', 'document', 'audio', 'video', 'sticker'].includes(type)) {
|
|
1201
|
+
const source = this.getNodeParameter('mediaUrl', i).trim();
|
|
1202
|
+
const opts = type === 'sticker' ? {} : this.getNodeParameter('mediaOptions', i, {});
|
|
656
1203
|
body.media = {
|
|
657
|
-
url:
|
|
1204
|
+
...(/^https?:\/\//i.test(source) ? { url: source } : { id: source }),
|
|
658
1205
|
...(opts.filename ? { filename: opts.filename } : {}),
|
|
659
1206
|
...(opts.mimeType ? { mimeType: opts.mimeType } : {}),
|
|
660
1207
|
};
|
|
@@ -665,13 +1212,116 @@ async function runOperation(resource, operation, i) {
|
|
|
665
1212
|
return GenericFunctions_1.coliblyApiRequest.call(this, 'POST', '/messages', body, undefined, { 'Idempotency-Key': key });
|
|
666
1213
|
}
|
|
667
1214
|
}
|
|
1215
|
+
if (resource === 'whatsapp' && (operation === 'createLink' || operation === 'getLink')) {
|
|
1216
|
+
if (operation === 'getLink')
|
|
1217
|
+
return GenericFunctions_1.coliblyApiRequest.call(this, 'GET', `/onboarding-links/${enc(this.getNodeParameter('linkId', i))}`);
|
|
1218
|
+
const opts = this.getNodeParameter('linkOptions', i, {});
|
|
1219
|
+
const body = {};
|
|
1220
|
+
for (const k of ['name', 'reference', 'redirectUrl', 'expiresInHours'])
|
|
1221
|
+
if (opts[k] !== undefined && opts[k] !== '')
|
|
1222
|
+
body[k] = opts[k];
|
|
1223
|
+
const key = (0, GenericFunctions_1.idempotencyKey)(this.getExecutionId(), this.getNode().name, i);
|
|
1224
|
+
return GenericFunctions_1.coliblyApiRequest.call(this, 'POST', '/onboarding-links', body, undefined, { 'Idempotency-Key': key });
|
|
1225
|
+
}
|
|
1226
|
+
if (resource === 'whatsapp') {
|
|
1227
|
+
const account = enc(this.getNodeParameter('waAccountId', i));
|
|
1228
|
+
const base = `/accounts/${account}`;
|
|
1229
|
+
switch (operation) {
|
|
1230
|
+
case 'getHealth':
|
|
1231
|
+
return GenericFunctions_1.coliblyApiRequest.call(this, 'GET', base);
|
|
1232
|
+
case 'getProfile':
|
|
1233
|
+
return GenericFunctions_1.coliblyApiRequest.call(this, 'GET', `${base}/profile`);
|
|
1234
|
+
case 'updateProfile':
|
|
1235
|
+
return GenericFunctions_1.coliblyApiRequest.call(this, 'PATCH', `${base}/profile`, jsonParam(this, 'profileJson', i));
|
|
1236
|
+
case 'getBlocked':
|
|
1237
|
+
return GenericFunctions_1.coliblyApiRequest.call(this, 'GET', `${base}/blocked-users`);
|
|
1238
|
+
case 'block': {
|
|
1239
|
+
const phones = String(this.getNodeParameter('phones', i)).split(',').map((v) => v.trim()).filter(Boolean);
|
|
1240
|
+
return GenericFunctions_1.coliblyApiRequest.call(this, 'POST', `${base}/blocked-users`, { phones });
|
|
1241
|
+
}
|
|
1242
|
+
case 'unblock': {
|
|
1243
|
+
const phone = String(this.getNodeParameter('phones', i)).split(',')[0].trim();
|
|
1244
|
+
return GenericFunctions_1.coliblyApiRequest.call(this, 'DELETE', `${base}/blocked-users/${enc(phone)}`);
|
|
1245
|
+
}
|
|
1246
|
+
case 'getAutomation':
|
|
1247
|
+
return GenericFunctions_1.coliblyApiRequest.call(this, 'GET', `${base}/conversational-automation`);
|
|
1248
|
+
case 'updateAutomation':
|
|
1249
|
+
return GenericFunctions_1.coliblyApiRequest.call(this, 'PATCH', `${base}/conversational-automation`, jsonParam(this, 'automationJson', i));
|
|
1250
|
+
case 'getQr':
|
|
1251
|
+
return GenericFunctions_1.coliblyList.call(this, `${base}/qr-codes`);
|
|
1252
|
+
case 'createQr':
|
|
1253
|
+
return GenericFunctions_1.coliblyApiRequest.call(this, 'POST', `${base}/qr-codes`, { prefilledMessage: this.getNodeParameter('prefilledMessage', i) });
|
|
1254
|
+
case 'deleteQr':
|
|
1255
|
+
return GenericFunctions_1.coliblyApiRequest.call(this, 'DELETE', `${base}/qr-codes/${enc(this.getNodeParameter('qrCode', i))}`);
|
|
1256
|
+
case 'getCosts': {
|
|
1257
|
+
const since = this.getNodeParameter('since', i, '');
|
|
1258
|
+
const until = this.getNodeParameter('until', i, '');
|
|
1259
|
+
return GenericFunctions_1.coliblyApiRequest.call(this, 'GET', `${base}/analytics`, undefined, {
|
|
1260
|
+
since: since ? new Date(since).toISOString() : undefined,
|
|
1261
|
+
until: until ? new Date(until).toISOString() : undefined,
|
|
1262
|
+
});
|
|
1263
|
+
}
|
|
1264
|
+
case 'getCatalog':
|
|
1265
|
+
return GenericFunctions_1.coliblyApiRequest.call(this, 'GET', `${base}/catalog`);
|
|
1266
|
+
case 'getFlows':
|
|
1267
|
+
return GenericFunctions_1.coliblyList.call(this, `${base}/flows`);
|
|
1268
|
+
case 'getFlow':
|
|
1269
|
+
return GenericFunctions_1.coliblyApiRequest.call(this, 'GET', `${base}/flows/${enc(this.getNodeParameter('waFlowId', i))}`);
|
|
1270
|
+
case 'createFlow':
|
|
1271
|
+
return GenericFunctions_1.coliblyApiRequest.call(this, 'POST', `${base}/flows`, jsonParam(this, 'flowJson', i));
|
|
1272
|
+
case 'getNumbers':
|
|
1273
|
+
return GenericFunctions_1.coliblyApiRequest.call(this, 'GET', `${base}/phone-numbers`);
|
|
1274
|
+
case 'setPin':
|
|
1275
|
+
return GenericFunctions_1.coliblyApiRequest.call(this, 'POST', `${base}/two-step-pin`, { pin: this.getNodeParameter('pin', i) });
|
|
1276
|
+
case 'register': {
|
|
1277
|
+
const pin = this.getNodeParameter('pin', i, '');
|
|
1278
|
+
return GenericFunctions_1.coliblyApiRequest.call(this, 'POST', `${base}/register`, pin ? { pin } : undefined);
|
|
1279
|
+
}
|
|
1280
|
+
case 'publishFlow':
|
|
1281
|
+
return GenericFunctions_1.coliblyApiRequest.call(this, 'POST', `${base}/flows/${enc(this.getNodeParameter('waFlowId', i))}/publish`);
|
|
1282
|
+
}
|
|
1283
|
+
}
|
|
1284
|
+
if (resource === 'template') {
|
|
1285
|
+
if (operation === 'getAll')
|
|
1286
|
+
return GenericFunctions_1.coliblyList.call(this, '/templates');
|
|
1287
|
+
if (operation === 'create')
|
|
1288
|
+
return GenericFunctions_1.coliblyApiRequest.call(this, 'POST', '/templates', jsonParam(this, 'templateJson', i));
|
|
1289
|
+
const id = enc(this.getNodeParameter('tplId', i));
|
|
1290
|
+
if (operation === 'get')
|
|
1291
|
+
return GenericFunctions_1.coliblyApiRequest.call(this, 'GET', `/templates/${id}`);
|
|
1292
|
+
if (operation === 'edit')
|
|
1293
|
+
return GenericFunctions_1.coliblyApiRequest.call(this, 'PATCH', `/templates/${id}`, jsonParam(this, 'templateEditJson', i));
|
|
1294
|
+
if (operation === 'delete')
|
|
1295
|
+
return GenericFunctions_1.coliblyApiRequest.call(this, 'DELETE', `/templates/${id}`);
|
|
1296
|
+
if (operation === 'analytics')
|
|
1297
|
+
return GenericFunctions_1.coliblyApiRequest.call(this, 'GET', `/templates/${id}/analytics`);
|
|
1298
|
+
}
|
|
1299
|
+
if (resource === 'media') {
|
|
1300
|
+
if (operation === 'upload') {
|
|
1301
|
+
return GenericFunctions_1.coliblyApiRequest.call(this, 'POST', '/media', { type: this.getNodeParameter('mediaType', i), url: this.getNodeParameter('uploadUrl', i) });
|
|
1302
|
+
}
|
|
1303
|
+
if (operation === 'delete')
|
|
1304
|
+
return GenericFunctions_1.coliblyApiRequest.call(this, 'DELETE', `/media/${enc(this.getNodeParameter('mediaId', i))}`);
|
|
1305
|
+
}
|
|
1306
|
+
if (resource === 'call') {
|
|
1307
|
+
if (operation === 'get')
|
|
1308
|
+
return GenericFunctions_1.coliblyApiRequest.call(this, 'GET', `/calls/${enc(this.getNodeParameter('callId', i))}`);
|
|
1309
|
+
if (operation === 'getAll') {
|
|
1310
|
+
const returnAll = this.getNodeParameter('returnAll', i);
|
|
1311
|
+
const limit = returnAll ? undefined : this.getNodeParameter('limit', i);
|
|
1312
|
+
const filters = { ...this.getNodeParameter('callFilters', i, {}) };
|
|
1313
|
+
if (filters.since)
|
|
1314
|
+
filters.since = new Date(filters.since).toISOString();
|
|
1315
|
+
return GenericFunctions_1.coliblyApiRequestAllItems.call(this, '/calls', filters, limit);
|
|
1316
|
+
}
|
|
1317
|
+
}
|
|
668
1318
|
if (resource === 'automation') {
|
|
669
1319
|
if (operation === 'getAll') {
|
|
670
1320
|
const onlyRunnable = this.getNodeParameter('onlyRunnable', i);
|
|
671
1321
|
return GenericFunctions_1.coliblyList.call(this, '/automations', onlyRunnable ? { runnable: 'true' } : undefined);
|
|
672
1322
|
}
|
|
673
1323
|
if (operation === 'run') {
|
|
674
|
-
const vars = (
|
|
1324
|
+
const vars = (_d = this.getNodeParameter('vars', i, {}).variable) !== null && _d !== void 0 ? _d : [];
|
|
675
1325
|
const body = { contactId: this.getNodeParameter('runContactId', i) };
|
|
676
1326
|
const filtered = vars.filter((v) => v.name);
|
|
677
1327
|
if (filtered.length)
|
|
@@ -11,5 +11,6 @@ export declare function getTags(this: ILoadOptionsFunctions): Promise<INodePrope
|
|
|
11
11
|
export declare function getUsers(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]>;
|
|
12
12
|
export declare function getTeams(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]>;
|
|
13
13
|
export declare function getTemplates(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]>;
|
|
14
|
+
export declare function getAllTemplates(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]>;
|
|
14
15
|
export declare function getRunnableAutomations(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]>;
|
|
15
16
|
export {};
|
|
@@ -11,6 +11,7 @@ exports.getTags = getTags;
|
|
|
11
11
|
exports.getUsers = getUsers;
|
|
12
12
|
exports.getTeams = getTeams;
|
|
13
13
|
exports.getTemplates = getTemplates;
|
|
14
|
+
exports.getAllTemplates = getAllTemplates;
|
|
14
15
|
exports.getRunnableAutomations = getRunnableAutomations;
|
|
15
16
|
const n8n_workflow_1 = require("n8n-workflow");
|
|
16
17
|
exports.PAGE_MAX = 100;
|
|
@@ -107,16 +108,33 @@ async function getTeams() {
|
|
|
107
108
|
}
|
|
108
109
|
async function getTemplates() {
|
|
109
110
|
const rows = await coliblyList.call(this, '/templates', { status: 'APPROVED' });
|
|
110
|
-
return rows.map((t) => {
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
111
|
+
return rows.map((t) => ({ name: `${t.name} (${t.language})`, value: t.id, description: templateNeeds(t) }));
|
|
112
|
+
}
|
|
113
|
+
async function getAllTemplates() {
|
|
114
|
+
const rows = await coliblyList.call(this, '/templates');
|
|
115
|
+
return rows
|
|
116
|
+
.filter((t) => t.status !== 'DELETED')
|
|
117
|
+
.map((t) => ({ name: `${t.name} (${t.language}) · ${t.status}`, value: t.id, description: templateNeeds(t) }));
|
|
118
|
+
}
|
|
119
|
+
function templateNeeds(t) {
|
|
120
|
+
var _a, _b, _c, _d;
|
|
121
|
+
const send = ((_a = t.send) !== null && _a !== void 0 ? _a : {});
|
|
122
|
+
if (send.requiresCode)
|
|
123
|
+
return 'Autenticación: pide Code';
|
|
124
|
+
const body = send.bodyParams;
|
|
125
|
+
const parts = [];
|
|
126
|
+
if (Array.isArray(body) && body.length)
|
|
127
|
+
parts.push(`Variables: ${body.join(', ')} (objeto JSON)`);
|
|
128
|
+
else {
|
|
129
|
+
const count = Number((_c = body !== null && body !== void 0 ? body : (_b = t.params) === null || _b === void 0 ? void 0 : _b.bodyParamCount) !== null && _c !== void 0 ? _c : 0);
|
|
130
|
+
if (count)
|
|
131
|
+
parts.push(`Pide ${count} ${count === 1 ? 'parámetro' : 'parámetros'} en el cuerpo`);
|
|
132
|
+
}
|
|
133
|
+
if (send.carouselCards)
|
|
134
|
+
parts.push(`Carrusel de ${String(send.carouselCards)} tarjetas (cards en Advanced)`);
|
|
135
|
+
if ((_d = send.offer) === null || _d === void 0 ? void 0 : _d.hasExpiration)
|
|
136
|
+
parts.push('Oferta: offerExpiresAt en Advanced');
|
|
137
|
+
return parts.join(' · ') || 'Sin parámetros';
|
|
120
138
|
}
|
|
121
139
|
async function getRunnableAutomations() {
|
|
122
140
|
const rows = await coliblyList.call(this, '/automations', { runnable: 'true' });
|
|
@@ -5,19 +5,30 @@ const n8n_workflow_1 = require("n8n-workflow");
|
|
|
5
5
|
const GenericFunctions_1 = require("../Colibly/GenericFunctions");
|
|
6
6
|
const signature_1 = require("../Colibly/signature");
|
|
7
7
|
const EVENTS = [
|
|
8
|
+
{ name: 'Account Connected', value: 'account.connected', description: 'Se conectó un número (desde el panel o con un enlace de conexión)' },
|
|
9
|
+
{ name: 'Account Quality Changed', value: 'account.quality_changed', description: 'Cambió la calidad o el límite de envío del número' },
|
|
8
10
|
{ name: 'Appointment Created', value: 'appointment.created', description: 'Cita creada' },
|
|
9
11
|
{ name: 'Appointment Status Changed', value: 'appointment.status_changed', description: 'Cambio de estado de una cita' },
|
|
12
|
+
{ name: 'Call Answered', value: 'call.answered', description: 'Llamada de WhatsApp contestada' },
|
|
13
|
+
{ name: 'Call Ended', value: 'call.ended', description: 'Llamada terminada: contestada, perdida, rechazada o fallida' },
|
|
14
|
+
{ name: 'Call Ringing', value: 'call.ringing', description: 'Llamada de WhatsApp sonando' },
|
|
10
15
|
{ name: 'Contact Created', value: 'contact.created', description: 'Contacto nuevo' },
|
|
11
16
|
{ name: 'Contact Lead Status Changed', value: 'contact.lead_status_changed', description: 'Cambio de etapa del lead' },
|
|
17
|
+
{ name: 'Contact Marketing Preference Changed', value: 'contact.marketing_preference_changed', description: 'Pidió dejar de recibir marketing (o volver a recibirlo)' },
|
|
12
18
|
{ name: 'Conversation Assigned', value: 'conversation.assigned', description: 'Conversación asignada' },
|
|
13
19
|
{ name: 'Conversation Resolved', value: 'conversation.resolved', description: 'Conversación resuelta' },
|
|
20
|
+
{ name: 'Conversation Welcome Requested', value: 'conversation.welcome_requested', description: 'Abrió el chat por primera vez sin escribir' },
|
|
21
|
+
{ name: 'Flow Completed', value: 'flow.completed', description: 'Terminó un formulario de WhatsApp (Flow)' },
|
|
14
22
|
{ name: 'Lead Ad Captured', value: 'lead.ad_captured', description: 'Lead llegado de un anuncio (CTWA o Instant Form)' },
|
|
15
23
|
{ name: 'Lead Scored', value: 'lead.scored', description: 'Lead calificado por un calificador IA' },
|
|
16
24
|
{ name: 'Message Received', value: 'message.received', description: 'Mensaje recibido de un contacto' },
|
|
17
25
|
{ name: 'Message Sent', value: 'message.sent', description: 'Mensaje enviado por cualquier vía' },
|
|
18
26
|
{ name: 'Message Status Changed', value: 'message.status_changed', description: 'Entregado, leído o fallido (solo WhatsApp)' },
|
|
19
27
|
{ name: 'Message Updated', value: 'message.updated', description: 'Un mensaje guardado cambió (su archivo quedó listo…)' },
|
|
28
|
+
{ name: 'Order Received', value: 'order.received', description: 'Pedido desde el carrito del catálogo' },
|
|
20
29
|
{ name: 'Tag Added', value: 'tag.added', description: 'Etiqueta agregada a un contacto o conversación' },
|
|
30
|
+
{ name: 'Template Category Changed', value: 'template.category_changed', description: 'Meta cambió la categoría de una plantilla' },
|
|
31
|
+
{ name: 'Template Status Changed', value: 'template.status_changed', description: 'Meta aprobó, rechazó o pausó una plantilla' },
|
|
21
32
|
];
|
|
22
33
|
class ColiblyTrigger {
|
|
23
34
|
constructor() {
|
|
@@ -55,7 +66,7 @@ class ColiblyTrigger {
|
|
|
55
66
|
type: 'multiOptions',
|
|
56
67
|
typeOptions: { loadOptionsMethod: 'getAccounts' },
|
|
57
68
|
default: [],
|
|
58
|
-
description: 'Solo eventos de estas cuentas (vacío = todas las
|
|
69
|
+
description: 'Solo eventos de estas cuentas (vacío = todas). La lista muestra solo las cuentas a las que tiene acceso la API key. Choose from the list, or specify IDs using an <a href="https://docs.n8n.io/code/expressions/">expression</a>.',
|
|
59
70
|
},
|
|
60
71
|
],
|
|
61
72
|
};
|
|
@@ -86,8 +97,14 @@ class ColiblyTrigger {
|
|
|
86
97
|
if (selected.length) {
|
|
87
98
|
const res = (await GenericFunctions_1.coliblyApiRequest.call(this, 'GET', '/accounts'));
|
|
88
99
|
const channelById = new Map(((_a = res.data) !== null && _a !== void 0 ? _a : []).map((a) => [a.id, a.channel]));
|
|
100
|
+
const unknown = selected.filter((id) => !channelById.has(id));
|
|
101
|
+
if (unknown.length) {
|
|
102
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `La API key no tiene acceso a ${unknown.length === 1 ? 'la cuenta' : 'las cuentas'} ${unknown.join(', ')}`, {
|
|
103
|
+
description: 'Quítala del campo «Account Names or IDs» o, en Colibly → Configuración → API, edita la key para incluir esa cuenta (o déjala sin restricción de cuentas). Solo aparecen en la lista las cuentas a las que la key tiene acceso.',
|
|
104
|
+
});
|
|
105
|
+
}
|
|
89
106
|
accountIds = selected.filter((id) => channelById.get(id) === 'WHATSAPP');
|
|
90
|
-
channelAccountIds = selected.filter((id) => channelById.
|
|
107
|
+
channelAccountIds = selected.filter((id) => channelById.get(id) !== 'WHATSAPP');
|
|
91
108
|
}
|
|
92
109
|
const workflowName = ((_b = this.getWorkflow().name) !== null && _b !== void 0 ? _b : 'flujo').toString();
|
|
93
110
|
const endpoint = (await GenericFunctions_1.coliblyApiRequest.call(this, 'POST', '/webhooks', {
|
package/dist/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "n8n-nodes-colibly",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Nodos de n8n para Colibly, el CRM para WhatsApp: contactos, conversaciones, mensajes, plantillas, automatizaciones y un disparador por webhook firmado.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"homepage": "https://colibly.com",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "n8n-nodes-colibly",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Nodos de n8n para Colibly, el CRM para WhatsApp: contactos, conversaciones, mensajes, plantillas, automatizaciones y un disparador por webhook firmado.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"homepage": "https://colibly.com",
|