@areumtecnologia/wasockets 2.2.3 → 2.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/README.md +74 -16
- package/lib/Client/Builders/Buttons.js +127 -0
- package/lib/Client/Builders/EventBuilder.js +122 -0
- package/lib/Client/Builders/InteractiveMessage.js +150 -0
- package/lib/Client/Builders/Lists.js +78 -0
- package/lib/Client/Builders/PollBuilder.js +84 -0
- package/lib/Client/Builders/index.js +21 -0
- package/lib/Client/Constants.js +54 -0
- package/lib/Client/Context/CallContext.js +96 -0
- package/lib/Client/Context/MediaObject.js +155 -0
- package/lib/Client/Context/MessageContext.js +146 -0
- package/lib/Client/Modules/BusinessManager.js +155 -0
- package/lib/Client/Modules/ChannelManager.js +144 -0
- package/lib/Client/Modules/ChatManager.js +113 -0
- package/lib/Client/Modules/CommunityManager.js +136 -0
- package/lib/Client/Modules/GroupManager.js +194 -0
- package/lib/Client/Modules/LabelManager.js +123 -0
- package/lib/Client/Modules/MessageManager.js +198 -0
- package/lib/Client/Modules/PresenceManager.js +68 -0
- package/lib/Client/Modules/PrivacyManager.js +98 -0
- package/lib/Client/Modules/ProfileManager.js +92 -0
- package/lib/Client/Modules/UserManager.js +92 -0
- package/lib/Client/Modules/VoipManager.js +117 -0
- package/lib/Client/Modules/index.js +29 -0
- package/lib/Client/Normalizers/EventNormalizer.js +82 -0
- package/lib/Client/Normalizers/JidNormalizer.js +93 -0
- package/lib/Client/Normalizers/MessageNormalizer.js +134 -0
- package/lib/Client/WaClient.js +438 -0
- package/lib/Client/index.d.ts +464 -0
- package/lib/Client/index.js +76 -0
- package/package.json +29 -23
package/README.md
CHANGED
|
@@ -59,7 +59,8 @@ O **WaSockets** foi criado para resolver problemas crônicos de estabilidade e a
|
|
|
59
59
|
- [O Contexto de Mensagem (MessageContext / ctx)](#o-contexto-de-mensagem-messagecontext--ctx)
|
|
60
60
|
- [Builders de Botões Interativos (InteractiveMessage)](#builders-de-botões-interativos-interactivemessage)
|
|
61
61
|
- [Controle de Presença Fluente (Typing / Recording)](#controle-de-presença-fluente-typing--recording)
|
|
62
|
-
- [Os
|
|
62
|
+
- [Os 12 Submódulos Especializados](#os-12-submódulos-especializados)
|
|
63
|
+
- [Guia Detalhado da Abstração (docs/CLIENT_GUIDE.md)](./docs/CLIENT_GUIDE.md)
|
|
63
64
|
- [Opções de Configuração (WaClientOptions)](#opções-de-configuração-waclientoptions)
|
|
64
65
|
- [Instalação](#-instalação)
|
|
65
66
|
- [API de Baixo Nível (makeWASocket Legado)](#-conectando-a-conta)
|
|
@@ -341,6 +342,64 @@ await client.sendInteractive('5511999999999@s.whatsapp.net', lista);
|
|
|
341
342
|
|
|
342
343
|
---
|
|
343
344
|
|
|
345
|
+
### Enquetes (PollBuilder) e Eventos (EventBuilder)
|
|
346
|
+
|
|
347
|
+
Crie enquetes interativas e convites de eventos para grupos de forma declarativa:
|
|
348
|
+
|
|
349
|
+
`javascript
|
|
350
|
+
const { PollBuilder, EventBuilder } = require('@areumtecnologia/wasockets/client');
|
|
351
|
+
|
|
352
|
+
// 1. Enquete com contagem de votos configurável
|
|
353
|
+
const enquete = new PollBuilder()
|
|
354
|
+
.setName('Qual recurso você mais utiliza no WaSockets?')
|
|
355
|
+
.addOption('VoIP e Ligações WebAssembly')
|
|
356
|
+
.addOption('Botões Interativos e PIX')
|
|
357
|
+
.addOption('Canais / Newsletters v2')
|
|
358
|
+
.setSelectableCount(1);
|
|
359
|
+
|
|
360
|
+
await client.sendPoll('5511999999999', enquete);
|
|
361
|
+
|
|
362
|
+
// 2. Convite de Evento com RSVP para Grupo
|
|
363
|
+
const evento = new EventBuilder()
|
|
364
|
+
.setName('Reunião de Alinhamento Trimestral')
|
|
365
|
+
.setDescription('Apresentação de resultados e novos objetivos')
|
|
366
|
+
.setStartDate(new Date(2026, 11, 20, 10, 0))
|
|
367
|
+
.setEndDate(new Date(2026, 11, 20, 12, 0))
|
|
368
|
+
.setLocation('Sala Virtual / Meet', -23.55052, -46.633308)
|
|
369
|
+
.setCall('voice');
|
|
370
|
+
|
|
371
|
+
await client.sendEvent('120363000000000000@g.us', evento);
|
|
372
|
+
`
|
|
373
|
+
|
|
374
|
+
---
|
|
375
|
+
|
|
376
|
+
### Controle de Chamadas VoIP (CallContext)
|
|
377
|
+
|
|
378
|
+
Gerencie chamadas ativas ou recebidas com facilidade via WebAssembly:
|
|
379
|
+
|
|
380
|
+
`javascript
|
|
381
|
+
const { Events } = require('@areumtecnologia/wasockets/client');
|
|
382
|
+
|
|
383
|
+
// 1. Receber e atender chamada recebida
|
|
384
|
+
client.on(Events.CALL_INCOMING, async (call) => {
|
|
385
|
+
console.log(Chamada recebida de: ());
|
|
386
|
+
|
|
387
|
+
if (call.isVideo) {
|
|
388
|
+
await call.reject('Não aceitamos chamadas de vídeo');
|
|
389
|
+
} else {
|
|
390
|
+
await call.accept();
|
|
391
|
+
await call.playAudio('./audios/atendimento-ura.opus');
|
|
392
|
+
}
|
|
393
|
+
});
|
|
394
|
+
|
|
395
|
+
// 2. Realizar chamada ativa de voz ou vídeo
|
|
396
|
+
const call = await client.voip.call('5511999999999');
|
|
397
|
+
await call.playAudio('./alerta.opus');
|
|
398
|
+
await call.hangup();
|
|
399
|
+
`
|
|
400
|
+
|
|
401
|
+
---
|
|
402
|
+
|
|
344
403
|
### Controle de Presença Fluente (Typing / Recording)
|
|
345
404
|
|
|
346
405
|
Indique que o bot está digitando ou gravando áudio de forma segura, com cancelamento automático ao enviar ou via objeto retornado:
|
|
@@ -363,25 +422,24 @@ await recording.stop();
|
|
|
363
422
|
|
|
364
423
|
---
|
|
365
424
|
|
|
366
|
-
### Os
|
|
425
|
+
### Os 12 Submódulos Especializados
|
|
367
426
|
|
|
368
|
-
O
|
|
427
|
+
O WaClient divide as operações em 12 módulos focados, acessíveis diretamente na instância (consulte o [Guia Completo da Abstração](./docs/CLIENT_GUIDE.md) para a documentação detalhada de cada método):
|
|
369
428
|
|
|
370
429
|
| Submódulo | Acesso | Descrição e Principais Métodos |
|
|
371
430
|
| :--- | :--- | :--- |
|
|
372
|
-
| **Mensagens** |
|
|
373
|
-
| **
|
|
374
|
-
| **
|
|
375
|
-
| **
|
|
376
|
-
| **
|
|
377
|
-
| **
|
|
378
|
-
| **
|
|
379
|
-
| **
|
|
380
|
-
| **
|
|
381
|
-
| **
|
|
382
|
-
| **
|
|
383
|
-
| **
|
|
384
|
-
| **Contatos** | `client.contacts` | Cache unificado de contatos em memória com resolução profunda assíncrona de informações completas (`fetchDeep`). |
|
|
431
|
+
| **Mensagens** | client.messages | Envio inteligente com validação isOnWhatsApp, textos, mídias, álbuns (sendAlbum), enquetes, vCards, localizações, reações e encaminhamento. |
|
|
432
|
+
| **VoIP / Chamadas** | client.voip | Chamadas ativas de voz e vídeo (call/callVideo), controle de chamada em andamento (ctiveCall), atender e rejeitar. |
|
|
433
|
+
| **Grupos** | client.groups | Criar grupos, adicionar/remover membros, promover/rebaixar admins, convites, permissões de grupo e menção em massa (mentionAll). |
|
|
434
|
+
| **Canais / Newsletters** | client.channels | Criação e gestão de Newsletters v2, seguir, deixar de seguir, silenciar, listar inscritos (listSubscribed) e buscar reações. |
|
|
435
|
+
| **WhatsApp Business** | client.business | Gestão de catálogo comercial, cadastro de produtos (createProduct), coleções, perfil da empresa e detalhes de pedidos (getOrderDetails). |
|
|
436
|
+
| **Comunidades** | client.communities | Criação de comunidades, vinculação de subgrupos (createSubgroup/linkSubgroup), desvinculação e gestão de subgrupos. |
|
|
437
|
+
| **Etiquetas / Labels** | client.labels | CRUD completo de etiquetas do WhatsApp Business, associação de etiquetas a chats e mensagens específicas. |
|
|
438
|
+
| **Presença** | client.presence | startTyping(), startRecording(), marcar conta como online/offline e assinar atualizações de presença de contatos específicos. |
|
|
439
|
+
| **Perfil** | client.profile | Atualizar nome de exibição (updateName), recado/status (updateAbout), foto de perfil (updatePicture com TC Token) e obter foto em alta resolução. |
|
|
440
|
+
| **Privacidade** | client.privacy | Bloquear/desbloquear contatos, gerenciar lista de bloqueio (getBlocklist) e configurar privacidade de Visto por Último, Online, Foto e Recado. |
|
|
441
|
+
| **Usuários** | client.users | Verificação de existência no WhatsApp (isOnWhatsApp), perfil comercial e resolução bidirecional de LID para PN (getPnForLid/getLidForPn). |
|
|
442
|
+
| **Chats** | client.chat | Fixar conversas no topo (pin/unpin), silenciar (mute/unmute), arquivar (rchive/unarchive), favoritos e anotações privadas de contato. |
|
|
385
443
|
|
|
386
444
|
---
|
|
387
445
|
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
"use strict"
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true })
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Quick Reply Button - user clicks and sends a predetermined text/id response
|
|
7
|
+
*/
|
|
8
|
+
class QuickReplyButton {
|
|
9
|
+
constructor(displayText, id) {
|
|
10
|
+
this.displayText = displayText || ''
|
|
11
|
+
this.id = id || displayText || 'quick_reply'
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
build() {
|
|
15
|
+
return {
|
|
16
|
+
name: 'quick_reply',
|
|
17
|
+
buttonParamsJson: JSON.stringify({
|
|
18
|
+
display_text: this.displayText,
|
|
19
|
+
id: this.id
|
|
20
|
+
})
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* URL Button - user clicks and opens a webpage
|
|
27
|
+
*/
|
|
28
|
+
class UrlButton {
|
|
29
|
+
constructor(displayText, url, merchantUrl) {
|
|
30
|
+
this.displayText = displayText || ''
|
|
31
|
+
this.url = url || ''
|
|
32
|
+
this.merchantUrl = merchantUrl || url || ''
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
build() {
|
|
36
|
+
return {
|
|
37
|
+
name: 'cta_url',
|
|
38
|
+
buttonParamsJson: JSON.stringify({
|
|
39
|
+
display_text: this.displayText,
|
|
40
|
+
url: this.url,
|
|
41
|
+
merchant_url: this.merchantUrl
|
|
42
|
+
})
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Copy Code Button - user clicks to copy a coupon/token to clipboard
|
|
49
|
+
*/
|
|
50
|
+
class CopyCodeButton {
|
|
51
|
+
constructor(displayText, copyCode, id) {
|
|
52
|
+
this.displayText = displayText || ''
|
|
53
|
+
this.copyCode = copyCode || ''
|
|
54
|
+
this.id = id || 'copy_code'
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
build() {
|
|
58
|
+
return {
|
|
59
|
+
name: 'cta_copy',
|
|
60
|
+
buttonParamsJson: JSON.stringify({
|
|
61
|
+
display_text: this.displayText,
|
|
62
|
+
id: this.id,
|
|
63
|
+
copy_code: this.copyCode
|
|
64
|
+
})
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Call Button - user clicks to initiate a standard voice call
|
|
71
|
+
*/
|
|
72
|
+
class CallButton {
|
|
73
|
+
constructor(displayText, phoneNumber) {
|
|
74
|
+
this.displayText = displayText || ''
|
|
75
|
+
this.phoneNumber = phoneNumber || ''
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
build() {
|
|
79
|
+
return {
|
|
80
|
+
name: 'cta_call',
|
|
81
|
+
buttonParamsJson: JSON.stringify({
|
|
82
|
+
display_text: this.displayText,
|
|
83
|
+
phone_number: this.phoneNumber
|
|
84
|
+
})
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Native PIX Payment Button (WhatsApp Payment Info)
|
|
91
|
+
*/
|
|
92
|
+
class PixButton {
|
|
93
|
+
/**
|
|
94
|
+
* @param {string} displayText - Text displayed on button (e.g., 'Pagar com PIX')
|
|
95
|
+
* @param {string} pixKey - Chave PIX (CPF/CNPJ, Email, Telefone ou EVP)
|
|
96
|
+
* @param {string} [keyType='CPF'] - Tipo da chave: 'CPF', 'EMAIL', 'PHONE', 'EVP'
|
|
97
|
+
* @param {string} [merchantName='Comerciante'] - Nome do beneficiário exibido
|
|
98
|
+
*/
|
|
99
|
+
constructor(displayText, pixKey, keyType = 'CPF', merchantName = 'Comerciante') {
|
|
100
|
+
this.displayText = displayText || 'Pagar via PIX'
|
|
101
|
+
this.pixKey = pixKey || ''
|
|
102
|
+
this.keyType = (keyType || 'CPF').toUpperCase()
|
|
103
|
+
this.merchantName = merchantName || 'Comerciante'
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
build() {
|
|
107
|
+
return {
|
|
108
|
+
name: 'payment_info',
|
|
109
|
+
buttonParamsJson: JSON.stringify({
|
|
110
|
+
payment_settings: [{
|
|
111
|
+
type: 'pix_static_code',
|
|
112
|
+
pix_static_code: {
|
|
113
|
+
merchant_name: this.merchantName,
|
|
114
|
+
key: this.pixKey,
|
|
115
|
+
key_type: this.keyType
|
|
116
|
+
}
|
|
117
|
+
}]
|
|
118
|
+
})
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
exports.QuickReplyButton = QuickReplyButton
|
|
124
|
+
exports.UrlButton = UrlButton
|
|
125
|
+
exports.CopyCodeButton = CopyCodeButton
|
|
126
|
+
exports.CallButton = CallButton
|
|
127
|
+
exports.PixButton = PixButton
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
"use strict"
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true })
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Fluent builder for WhatsApp Calendar / Group Event Messages
|
|
7
|
+
*/
|
|
8
|
+
class EventBuilder {
|
|
9
|
+
constructor() {
|
|
10
|
+
this._name = ''
|
|
11
|
+
this._description = ''
|
|
12
|
+
this._startTime = null
|
|
13
|
+
this._endTime = null
|
|
14
|
+
this._location = null
|
|
15
|
+
this._call = null
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Sets event title
|
|
20
|
+
* @param {string} name
|
|
21
|
+
* @returns {this}
|
|
22
|
+
*/
|
|
23
|
+
setName(name) {
|
|
24
|
+
this._name = name || ''
|
|
25
|
+
return this
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Sets event description
|
|
30
|
+
* @param {string} description
|
|
31
|
+
* @returns {this}
|
|
32
|
+
*/
|
|
33
|
+
setDescription(description) {
|
|
34
|
+
this._description = description || ''
|
|
35
|
+
return this
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Sets start time as Date, timestamp in seconds or milliseconds
|
|
40
|
+
* @param {Date|number} date
|
|
41
|
+
* @returns {this}
|
|
42
|
+
*/
|
|
43
|
+
setStartDate(date) {
|
|
44
|
+
if (date instanceof Date) {
|
|
45
|
+
this._startTime = Math.floor(date.getTime() / 1000)
|
|
46
|
+
} else if (typeof date === 'number') {
|
|
47
|
+
this._startTime = date > 10000000000 ? Math.floor(date / 1000) : Math.floor(date)
|
|
48
|
+
}
|
|
49
|
+
return this
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Sets end time as Date, timestamp in seconds or milliseconds
|
|
54
|
+
* @param {Date|number} date
|
|
55
|
+
* @returns {this}
|
|
56
|
+
*/
|
|
57
|
+
setEndDate(date) {
|
|
58
|
+
if (date instanceof Date) {
|
|
59
|
+
this._endTime = Math.floor(date.getTime() / 1000)
|
|
60
|
+
} else if (typeof date === 'number') {
|
|
61
|
+
this._endTime = date > 10000000000 ? Math.floor(date / 1000) : Math.floor(date)
|
|
62
|
+
}
|
|
63
|
+
return this
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Sets event location
|
|
68
|
+
* @param {string} name - Location name
|
|
69
|
+
* @param {number} [degreesLatitude]
|
|
70
|
+
* @param {number} [degreesLongitude]
|
|
71
|
+
* @returns {this}
|
|
72
|
+
*/
|
|
73
|
+
setLocation(name, degreesLatitude, degreesLongitude) {
|
|
74
|
+
this._location = {
|
|
75
|
+
name: name || '',
|
|
76
|
+
degreesLatitude: degreesLatitude || 0,
|
|
77
|
+
degreesLongitude: degreesLongitude || 0
|
|
78
|
+
}
|
|
79
|
+
return this
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Sets WhatsApp voice or video call for the event
|
|
84
|
+
* @param {'voice'|'video'|1|2} callType
|
|
85
|
+
* @returns {this}
|
|
86
|
+
*/
|
|
87
|
+
setCall(callType = 'voice') {
|
|
88
|
+
this._call = {
|
|
89
|
+
callType: callType === 'video' || callType === 2 ? 2 : 1
|
|
90
|
+
}
|
|
91
|
+
return this
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Compiles event into a payload ready for sendMessage()
|
|
96
|
+
* @returns {Object}
|
|
97
|
+
*/
|
|
98
|
+
build() {
|
|
99
|
+
if (!this._name) {
|
|
100
|
+
throw new Error('EventBuilder requires an event title via setName().')
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const nowSec = Math.floor(Date.now() / 1000)
|
|
104
|
+
const startTime = this._startTime || (nowSec + 3600) // Default 1 hour from now
|
|
105
|
+
|
|
106
|
+
const eventPayload = {
|
|
107
|
+
name: this._name,
|
|
108
|
+
description: this._description || undefined,
|
|
109
|
+
startTime,
|
|
110
|
+
endTime: this._endTime || undefined,
|
|
111
|
+
location: this._location || undefined,
|
|
112
|
+
call: this._call || undefined
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
return {
|
|
116
|
+
event: eventPayload
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
exports.EventBuilder = EventBuilder
|
|
122
|
+
exports.default = EventBuilder
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
"use strict"
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true })
|
|
4
|
+
|
|
5
|
+
const { ListButton } = require("./Lists")
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Fluent builder for Interactive WhatsApp Messages (Buttons, Cards, Menus, PIX)
|
|
9
|
+
*/
|
|
10
|
+
class InteractiveMessage {
|
|
11
|
+
constructor() {
|
|
12
|
+
this._title = ''
|
|
13
|
+
this._subtitle = ''
|
|
14
|
+
this._text = ''
|
|
15
|
+
this._footer = ''
|
|
16
|
+
this._header = null
|
|
17
|
+
this._buttons = []
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Sets card title
|
|
22
|
+
* @param {string} title
|
|
23
|
+
* @returns {this}
|
|
24
|
+
*/
|
|
25
|
+
setTitle(title) {
|
|
26
|
+
this._title = title || ''
|
|
27
|
+
return this
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Sets subtitle or secondary header
|
|
32
|
+
* @param {string} subtitle
|
|
33
|
+
* @returns {this}
|
|
34
|
+
*/
|
|
35
|
+
setSubtitle(subtitle) {
|
|
36
|
+
this._subtitle = subtitle || ''
|
|
37
|
+
return this
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Sets the main text body (required)
|
|
42
|
+
* @param {string} text
|
|
43
|
+
* @returns {this}
|
|
44
|
+
*/
|
|
45
|
+
setText(text) {
|
|
46
|
+
this._text = text || ''
|
|
47
|
+
return this
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Sets smaller footer text at the bottom
|
|
52
|
+
* @param {string} footer
|
|
53
|
+
* @returns {this}
|
|
54
|
+
*/
|
|
55
|
+
setFooter(footer) {
|
|
56
|
+
this._footer = footer || ''
|
|
57
|
+
return this
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Sets an image header for the interactive card
|
|
62
|
+
* @param {string|Buffer|{ url: string }} image
|
|
63
|
+
* @returns {this}
|
|
64
|
+
*/
|
|
65
|
+
setHeaderImage(image) {
|
|
66
|
+
this._header = {
|
|
67
|
+
image: typeof image === 'string' ? { url: image } : image
|
|
68
|
+
}
|
|
69
|
+
return this
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Sets a video header for the interactive card
|
|
74
|
+
* @param {string|Buffer|{ url: string }} video
|
|
75
|
+
* @returns {this}
|
|
76
|
+
*/
|
|
77
|
+
setHeaderVideo(video) {
|
|
78
|
+
this._header = {
|
|
79
|
+
video: typeof video === 'string' ? { url: video } : video
|
|
80
|
+
}
|
|
81
|
+
return this
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Adds an interactive button (QuickReply, Url, CopyCode, Call, Pix or ListButton)
|
|
86
|
+
* @param {Object} button
|
|
87
|
+
* @returns {this}
|
|
88
|
+
*/
|
|
89
|
+
addButton(button) {
|
|
90
|
+
if (button) {
|
|
91
|
+
this._buttons.push(button)
|
|
92
|
+
}
|
|
93
|
+
return this
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Adds multiple buttons at once
|
|
98
|
+
* @param {Array<Object>} buttons
|
|
99
|
+
* @returns {this}
|
|
100
|
+
*/
|
|
101
|
+
addButtons(buttons) {
|
|
102
|
+
if (Array.isArray(buttons)) {
|
|
103
|
+
for (const b of buttons) {
|
|
104
|
+
this.addButton(b)
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return this
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Compiles the interactive message into a payload ready for sock.sendMessage()
|
|
112
|
+
* @returns {Object}
|
|
113
|
+
*/
|
|
114
|
+
build() {
|
|
115
|
+
if (!this._text && !this._title) {
|
|
116
|
+
throw new Error('InteractiveMessage requires at least a text or title.')
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// Check if there is a ListButton
|
|
120
|
+
const listBtn = this._buttons.find(b => b instanceof ListButton || b.sections)
|
|
121
|
+
|
|
122
|
+
if (listBtn) {
|
|
123
|
+
const builtList = typeof listBtn.build === 'function' ? listBtn.build() : listBtn
|
|
124
|
+
return {
|
|
125
|
+
text: this._text,
|
|
126
|
+
title: this._title || undefined,
|
|
127
|
+
subtitle: this._subtitle || undefined,
|
|
128
|
+
footer: this._footer || undefined,
|
|
129
|
+
buttonText: builtList.buttonText,
|
|
130
|
+
sections: builtList.sections,
|
|
131
|
+
...(this._header || {})
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// Standard interactive buttons
|
|
136
|
+
return {
|
|
137
|
+
text: this._text,
|
|
138
|
+
title: this._title || undefined,
|
|
139
|
+
subtitle: this._subtitle || undefined,
|
|
140
|
+
footer: this._footer || undefined,
|
|
141
|
+
...(this._header || {}),
|
|
142
|
+
interactiveButtons: this._buttons.map(btn => (
|
|
143
|
+
typeof btn.build === 'function' ? btn.build() : btn
|
|
144
|
+
))
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
exports.InteractiveMessage = InteractiveMessage
|
|
150
|
+
exports.default = InteractiveMessage
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"use strict"
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true })
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Individual row in an interactive list section
|
|
7
|
+
*/
|
|
8
|
+
class ListRow {
|
|
9
|
+
constructor(title, description = '', rowId = '') {
|
|
10
|
+
this.title = title || ''
|
|
11
|
+
this.description = description || ''
|
|
12
|
+
this.rowId = rowId || title || 'row'
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
build() {
|
|
16
|
+
return {
|
|
17
|
+
title: this.title,
|
|
18
|
+
description: this.description,
|
|
19
|
+
rowId: this.rowId
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Categorized section containing multiple rows
|
|
26
|
+
*/
|
|
27
|
+
class ListSection {
|
|
28
|
+
constructor(title, rows = []) {
|
|
29
|
+
this.title = title || ''
|
|
30
|
+
this.rows = Array.isArray(rows) ? rows : []
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
addRow(titleOrRow, description, rowId) {
|
|
34
|
+
if (titleOrRow instanceof ListRow) {
|
|
35
|
+
this.rows.push(titleOrRow)
|
|
36
|
+
} else {
|
|
37
|
+
this.rows.push(new ListRow(titleOrRow, description, rowId))
|
|
38
|
+
}
|
|
39
|
+
return this
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
build() {
|
|
43
|
+
return {
|
|
44
|
+
title: this.title,
|
|
45
|
+
rows: this.rows.map(row => typeof row.build === 'function' ? row.build() : row)
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* List Dropdown Button configuration
|
|
52
|
+
*/
|
|
53
|
+
class ListButton {
|
|
54
|
+
constructor(buttonText, sections = []) {
|
|
55
|
+
this.buttonText = buttonText || 'Ver Opções'
|
|
56
|
+
this.sections = Array.isArray(sections) ? sections : []
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
addSection(titleOrSection, rows) {
|
|
60
|
+
if (titleOrSection instanceof ListSection) {
|
|
61
|
+
this.sections.push(titleOrSection)
|
|
62
|
+
} else {
|
|
63
|
+
this.sections.push(new ListSection(titleOrSection, rows))
|
|
64
|
+
}
|
|
65
|
+
return this
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
build() {
|
|
69
|
+
return {
|
|
70
|
+
buttonText: this.buttonText,
|
|
71
|
+
sections: this.sections.map(sec => typeof sec.build === 'function' ? sec.build() : sec)
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
exports.ListRow = ListRow
|
|
77
|
+
exports.ListSection = ListSection
|
|
78
|
+
exports.ListButton = ListButton
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
"use strict"
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true })
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Fluent builder for WhatsApp Polls
|
|
7
|
+
*/
|
|
8
|
+
class PollBuilder {
|
|
9
|
+
constructor() {
|
|
10
|
+
this._name = ''
|
|
11
|
+
this._options = []
|
|
12
|
+
this._selectableCount = 1
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Sets poll question / title
|
|
17
|
+
* @param {string} name
|
|
18
|
+
* @returns {this}
|
|
19
|
+
*/
|
|
20
|
+
setName(name) {
|
|
21
|
+
this._name = name || ''
|
|
22
|
+
return this
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Adds an option to the poll
|
|
27
|
+
* @param {string} option
|
|
28
|
+
* @returns {this}
|
|
29
|
+
*/
|
|
30
|
+
addOption(option) {
|
|
31
|
+
if (option && typeof option === 'string') {
|
|
32
|
+
this._options.push(option.trim())
|
|
33
|
+
}
|
|
34
|
+
return this
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Adds multiple options to the poll
|
|
39
|
+
* @param {Array<string>} options
|
|
40
|
+
* @returns {this}
|
|
41
|
+
*/
|
|
42
|
+
addOptions(options) {
|
|
43
|
+
if (Array.isArray(options)) {
|
|
44
|
+
for (const opt of options) {
|
|
45
|
+
this.addOption(opt)
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return this
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Sets how many options can be selected (1 for single choice, > 1 for multiple choices)
|
|
53
|
+
* @param {number} count
|
|
54
|
+
* @returns {this}
|
|
55
|
+
*/
|
|
56
|
+
setSelectableCount(count) {
|
|
57
|
+
this._selectableCount = Math.max(1, Number(count) || 1)
|
|
58
|
+
return this
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Compiles poll into a payload for sendMessage()
|
|
63
|
+
* @returns {Object}
|
|
64
|
+
*/
|
|
65
|
+
build() {
|
|
66
|
+
if (!this._name) {
|
|
67
|
+
throw new Error('PollBuilder requires a question name via setName().')
|
|
68
|
+
}
|
|
69
|
+
if (this._options.length < 2) {
|
|
70
|
+
throw new Error('PollBuilder requires at least 2 options.')
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return {
|
|
74
|
+
poll: {
|
|
75
|
+
name: this._name,
|
|
76
|
+
values: this._options,
|
|
77
|
+
selectableCount: this._selectableCount
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
exports.PollBuilder = PollBuilder
|
|
84
|
+
exports.default = PollBuilder
|