@areumtecnologia/wasockets 2.2.3 → 2.3.1
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 +98 -25
- 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 +213 -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 +99 -0
- package/lib/Client/Normalizers/JidNormalizer.js +96 -0
- package/lib/Client/Normalizers/MessageNormalizer.js +422 -0
- package/lib/Client/WaClient.js +438 -0
- package/lib/Client/index.d.ts +547 -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)
|
|
@@ -223,18 +224,33 @@ client.on(Events.LABELS_UPDATE, (labels) => { /* Criação ou associação de et
|
|
|
223
224
|
Ao escutar `Events.MESSAGE_RECEIVED`, você recebe um objeto `ctx` que já contém todos os dados mastigados e métodos de ação vinculados diretamente àquela mensagem:
|
|
224
225
|
|
|
225
226
|
#### Propriedades de `ctx`:
|
|
226
|
-
- `ctx.id`: ID único da mensagem.
|
|
227
|
+
- `ctx.id`: ID único da mensagem (se for mensagem editada, preserva o ID original rastreável).
|
|
227
228
|
- `ctx.chatId`: JID do chat (usuário, grupo ou canal).
|
|
228
|
-
- `ctx.
|
|
229
|
-
- `ctx.
|
|
230
|
-
- `ctx.
|
|
229
|
+
- `ctx.fromMe` / `ctx.isFromMe`: Booleano se a mensagem foi enviada pelo próprio bot.
|
|
230
|
+
- `ctx.from`: JID de origem (remetente em recebidas, ou JID do bot em enviadas).
|
|
231
|
+
- `ctx.to`: JID de destino (bot em recebidas, ou JID do chat/destinatário em enviadas).
|
|
232
|
+
- `ctx.fromPushName` / `ctx.senderName`: Nome de exibição formatado ou pushName ('Você' se `fromMe`).
|
|
233
|
+
- `ctx.fromNumber` / `ctx.senderNumber`: Apenas os números de telefone do remetente (sem sufixos ou `@s.whatsapp.net`).
|
|
234
|
+
- `ctx.sender`: JID de quem enviou a mensagem no chat.
|
|
231
235
|
- `ctx.isGroup`: Booleano indicando se é grupo (`@g.us`).
|
|
232
236
|
- `ctx.isChannel`: Booleano indicando se é newsletter/canal (`@newsletter`).
|
|
233
|
-
- `ctx.
|
|
234
|
-
- `ctx.body`: Texto principal da mensagem (já
|
|
235
|
-
- `ctx.type`: Tipo normalizado (`text`, `image`, `video`, `
|
|
236
|
-
- `ctx.
|
|
237
|
-
- `ctx.
|
|
237
|
+
- `ctx.isBroadcast`: Booleano se é lista de transmissão ou status.
|
|
238
|
+
- `ctx.body`: Texto principal da mensagem (já desempacotado recursivamente de `viewOnce`, `ephemeral`, botões, listas, etc.).
|
|
239
|
+
- `ctx.type`: Tipo normalizado e amigável (28 tipos identificados: `text`, `image`, `video`, `voice`, `document`, `sticker`, `native_flow_response`, `poll_creation`, `event`, etc.).
|
|
240
|
+
- `ctx.isEdited`: Booleano indicando se a mensagem é uma edição de mensagem prévia (`protocolMessage.editedMessage`).
|
|
241
|
+
- `ctx.editTimestamp`: Instância de `Date` informando quando a mensagem foi editada (ou `null`).
|
|
242
|
+
- `ctx.interactiveReply`: Resposta estruturada de botões, listas e fluxos nativos (`{ id, text, params, flowName, type }`).
|
|
243
|
+
- `ctx.contacts`: Array com contatos e vCards parseados (`[{ name, number, org, vcard }]`), com suporte a `waid` e fallback `TEL`.
|
|
244
|
+
- `ctx.location`: Coordenadas e endereço (`{ latitude, longitude, name, address, url, isLive }`).
|
|
245
|
+
- `ctx.reaction`: Detalhes de reação (`{ emoji, reactedMessageId, targetKey, isRemoval, senderTimestamp }`).
|
|
246
|
+
- `ctx.poll`: Dados completos de enquetes (`{ name, options, selectableOptionsCount, allowsMultipleAnswers }`).
|
|
247
|
+
- `ctx.mediaDetails`: Metadados da mídia (`{ mimetype, fileName, caption, duration, isPtt, isGif, isViewOnce }`).
|
|
248
|
+
- `ctx.media`: Instância de `MediaObject` para conversão rápida para buffer, base64, salvamento em disco ou Sharp.
|
|
249
|
+
- `ctx.isMentioningMe`: Booleano indicando se o bot foi mencionado diretamente no texto (suporta Phone JID e LID JID).
|
|
250
|
+
- `ctx.mentions` / `ctx.mentionedJids`: Array de JIDs mencionados na mensagem.
|
|
251
|
+
- `ctx.isForwarded` & `ctx.forwardingScore`: Rastreamento de encaminhamento.
|
|
252
|
+
- `ctx.isReply`: Booleano indicando se esta mensagem está citando outra.
|
|
253
|
+
- `ctx.quoted`: Instância recursiva de `MessageContext` da mensagem citada/respondida (com controle de profundidade).
|
|
238
254
|
- `ctx.raw`: O nó bruto original do WhatsApp/Baileys para casos de baixo nível.
|
|
239
255
|
|
|
240
256
|
#### Ações Disponíveis em `ctx`:
|
|
@@ -341,6 +357,64 @@ await client.sendInteractive('5511999999999@s.whatsapp.net', lista);
|
|
|
341
357
|
|
|
342
358
|
---
|
|
343
359
|
|
|
360
|
+
### Enquetes (PollBuilder) e Eventos (EventBuilder)
|
|
361
|
+
|
|
362
|
+
Crie enquetes interativas e convites de eventos para grupos de forma declarativa:
|
|
363
|
+
|
|
364
|
+
`javascript
|
|
365
|
+
const { PollBuilder, EventBuilder } = require('@areumtecnologia/wasockets/client');
|
|
366
|
+
|
|
367
|
+
// 1. Enquete com contagem de votos configurável
|
|
368
|
+
const enquete = new PollBuilder()
|
|
369
|
+
.setName('Qual recurso você mais utiliza no WaSockets?')
|
|
370
|
+
.addOption('VoIP e Ligações WebAssembly')
|
|
371
|
+
.addOption('Botões Interativos e PIX')
|
|
372
|
+
.addOption('Canais / Newsletters v2')
|
|
373
|
+
.setSelectableCount(1);
|
|
374
|
+
|
|
375
|
+
await client.sendPoll('5511999999999', enquete);
|
|
376
|
+
|
|
377
|
+
// 2. Convite de Evento com RSVP para Grupo
|
|
378
|
+
const evento = new EventBuilder()
|
|
379
|
+
.setName('Reunião de Alinhamento Trimestral')
|
|
380
|
+
.setDescription('Apresentação de resultados e novos objetivos')
|
|
381
|
+
.setStartDate(new Date(2026, 11, 20, 10, 0))
|
|
382
|
+
.setEndDate(new Date(2026, 11, 20, 12, 0))
|
|
383
|
+
.setLocation('Sala Virtual / Meet', -23.55052, -46.633308)
|
|
384
|
+
.setCall('voice');
|
|
385
|
+
|
|
386
|
+
await client.sendEvent('120363000000000000@g.us', evento);
|
|
387
|
+
`
|
|
388
|
+
|
|
389
|
+
---
|
|
390
|
+
|
|
391
|
+
### Controle de Chamadas VoIP (CallContext)
|
|
392
|
+
|
|
393
|
+
Gerencie chamadas ativas ou recebidas com facilidade via WebAssembly:
|
|
394
|
+
|
|
395
|
+
`javascript
|
|
396
|
+
const { Events } = require('@areumtecnologia/wasockets/client');
|
|
397
|
+
|
|
398
|
+
// 1. Receber e atender chamada recebida
|
|
399
|
+
client.on(Events.CALL_INCOMING, async (call) => {
|
|
400
|
+
console.log(Chamada recebida de: ());
|
|
401
|
+
|
|
402
|
+
if (call.isVideo) {
|
|
403
|
+
await call.reject('Não aceitamos chamadas de vídeo');
|
|
404
|
+
} else {
|
|
405
|
+
await call.accept();
|
|
406
|
+
await call.playAudio('./audios/atendimento-ura.opus');
|
|
407
|
+
}
|
|
408
|
+
});
|
|
409
|
+
|
|
410
|
+
// 2. Realizar chamada ativa de voz ou vídeo
|
|
411
|
+
const call = await client.voip.call('5511999999999');
|
|
412
|
+
await call.playAudio('./alerta.opus');
|
|
413
|
+
await call.hangup();
|
|
414
|
+
`
|
|
415
|
+
|
|
416
|
+
---
|
|
417
|
+
|
|
344
418
|
### Controle de Presença Fluente (Typing / Recording)
|
|
345
419
|
|
|
346
420
|
Indique que o bot está digitando ou gravando áudio de forma segura, com cancelamento automático ao enviar ou via objeto retornado:
|
|
@@ -363,25 +437,24 @@ await recording.stop();
|
|
|
363
437
|
|
|
364
438
|
---
|
|
365
439
|
|
|
366
|
-
### Os
|
|
440
|
+
### Os 12 Submódulos Especializados
|
|
367
441
|
|
|
368
|
-
O
|
|
442
|
+
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
443
|
|
|
370
444
|
| Submódulo | Acesso | Descrição e Principais Métodos |
|
|
371
445
|
| :--- | :--- | :--- |
|
|
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`). |
|
|
446
|
+
| **Mensagens** | client.messages | Envio inteligente com validação isOnWhatsApp, textos, mídias, álbuns (sendAlbum), enquetes, vCards, localizações, reações e encaminhamento. |
|
|
447
|
+
| **VoIP / Chamadas** | client.voip | Chamadas ativas de voz e vídeo (call/callVideo), controle de chamada em andamento (ctiveCall), atender e rejeitar. |
|
|
448
|
+
| **Grupos** | client.groups | Criar grupos, adicionar/remover membros, promover/rebaixar admins, convites, permissões de grupo e menção em massa (mentionAll). |
|
|
449
|
+
| **Canais / Newsletters** | client.channels | Criação e gestão de Newsletters v2, seguir, deixar de seguir, silenciar, listar inscritos (listSubscribed) e buscar reações. |
|
|
450
|
+
| **WhatsApp Business** | client.business | Gestão de catálogo comercial, cadastro de produtos (createProduct), coleções, perfil da empresa e detalhes de pedidos (getOrderDetails). |
|
|
451
|
+
| **Comunidades** | client.communities | Criação de comunidades, vinculação de subgrupos (createSubgroup/linkSubgroup), desvinculação e gestão de subgrupos. |
|
|
452
|
+
| **Etiquetas / Labels** | client.labels | CRUD completo de etiquetas do WhatsApp Business, associação de etiquetas a chats e mensagens específicas. |
|
|
453
|
+
| **Presença** | client.presence | startTyping(), startRecording(), marcar conta como online/offline e assinar atualizações de presença de contatos específicos. |
|
|
454
|
+
| **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. |
|
|
455
|
+
| **Privacidade** | client.privacy | Bloquear/desbloquear contatos, gerenciar lista de bloqueio (getBlocklist) e configurar privacidade de Visto por Último, Online, Foto e Recado. |
|
|
456
|
+
| **Usuários** | client.users | Verificação de existência no WhatsApp (isOnWhatsApp), perfil comercial e resolução bidirecional de LID para PN (getPnForLid/getLidForPn). |
|
|
457
|
+
| **Chats** | client.chat | Fixar conversas no topo (pin/unpin), silenciar (mute/unmute), arquivar (rchive/unarchive), favoritos e anotações privadas de contato. |
|
|
385
458
|
|
|
386
459
|
---
|
|
387
460
|
|
|
@@ -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
|