@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.
Files changed (31) hide show
  1. package/README.md +74 -16
  2. package/lib/Client/Builders/Buttons.js +127 -0
  3. package/lib/Client/Builders/EventBuilder.js +122 -0
  4. package/lib/Client/Builders/InteractiveMessage.js +150 -0
  5. package/lib/Client/Builders/Lists.js +78 -0
  6. package/lib/Client/Builders/PollBuilder.js +84 -0
  7. package/lib/Client/Builders/index.js +21 -0
  8. package/lib/Client/Constants.js +54 -0
  9. package/lib/Client/Context/CallContext.js +96 -0
  10. package/lib/Client/Context/MediaObject.js +155 -0
  11. package/lib/Client/Context/MessageContext.js +146 -0
  12. package/lib/Client/Modules/BusinessManager.js +155 -0
  13. package/lib/Client/Modules/ChannelManager.js +144 -0
  14. package/lib/Client/Modules/ChatManager.js +113 -0
  15. package/lib/Client/Modules/CommunityManager.js +136 -0
  16. package/lib/Client/Modules/GroupManager.js +194 -0
  17. package/lib/Client/Modules/LabelManager.js +123 -0
  18. package/lib/Client/Modules/MessageManager.js +198 -0
  19. package/lib/Client/Modules/PresenceManager.js +68 -0
  20. package/lib/Client/Modules/PrivacyManager.js +98 -0
  21. package/lib/Client/Modules/ProfileManager.js +92 -0
  22. package/lib/Client/Modules/UserManager.js +92 -0
  23. package/lib/Client/Modules/VoipManager.js +117 -0
  24. package/lib/Client/Modules/index.js +29 -0
  25. package/lib/Client/Normalizers/EventNormalizer.js +82 -0
  26. package/lib/Client/Normalizers/JidNormalizer.js +93 -0
  27. package/lib/Client/Normalizers/MessageNormalizer.js +134 -0
  28. package/lib/Client/WaClient.js +438 -0
  29. package/lib/Client/index.d.ts +464 -0
  30. package/lib/Client/index.js +76 -0
  31. 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 13 Submódulos Especializados](#os-13-submódulos-especializados)
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 13 Submódulos Especializados
425
+ ### Os 12 Submódulos Especializados
367
426
 
368
- O `WaClient` divide as operações em 13 módulos focados, acessíveis diretamente na instância:
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** | `client.messages` | Envio inteligente com validação `isOnWhatsApp`, textos, mídias, álbuns (`sendAlbum`), enquetes (`sendPoll`), vCards (`sendContacts`), reações e encaminhamento. |
373
- | **Grupos** | `client.groups` | Criar grupos, adicionar/remover membros, promover/rebaixar admins, convites, permissões de grupo e menção em massa (`mentionAll`). |
374
- | **Canais / Newsletters** | `client.channels` | Criação e gestão de Newsletters v2, busca por código de convite ou JID, seguir, deixar de seguir, silenciar e buscar reações. |
375
- | **Privacidade** | `client.privacy` | Bloquear/desbloquear contatos, gerenciar lista de bloqueio (`getBlocklist`) e configurar privacidade de Visto por Último, Online, Foto e Recado. |
376
- | **Perfil** | `client.profile` | Atualizar nome de exibição (`updateName`), recado/status (`updateStatus`), foto de perfil (`updatePicture`) e obter foto em alta resolução. |
377
- | **Chats** | `client.chat` | Fixar conversas no topo (`pin`/`unpin`), silenciar (`mute`/`unmute`), arquivar (`archive`/`unarchive`), limpar e excluir histórico. |
378
- | **Presença** | `client.presence` | `startTyping()`, `startRecording()`, marcar conta como online/offline e assinar atualizações de presença de contatos específicos. |
379
- | **Status / Stories** | `client.stories` | Publicar Status em texto, imagem, áudio ou vídeo, com suporte a menções direcionadas (`statusJidList`) ou broadcast público. |
380
- | **WhatsApp Business** | `client.business` | Gestão de catálogo comercial, cadastro de produtos (`createProduct`), coleções, perfil da empresa e detalhes de pedidos (`getOrderDetails`). |
381
- | **Etiquetas / Labels** | `client.labels` | CRUD completo de etiquetas do WhatsApp Business, associação de etiquetas a chats e mensagens específicas. |
382
- | **Comunidades** | `client.communities` | Criação de comunidades, vinculação de subgrupos (`addSubgroups`), remoção e gestão do grupo de avisos gerais. |
383
- | **Usuários** | `client.users` | Verificação de existência no WhatsApp (`isOnWhatsApp`), metadados, busca de perfil comercial e resolução reversa de LID para PN (`getPnForLid`). |
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