@natyapp/meta 1.6.6 → 1.7.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 (95) hide show
  1. package/.github/copilot-instructions.md +1540 -0
  2. package/README.md +513 -40
  3. package/dist/elements/index.d.ts +1 -0
  4. package/dist/elements/index.js +1 -0
  5. package/dist/elements/mediaTemplate.d.ts +45 -0
  6. package/dist/elements/mediaTemplate.js +47 -0
  7. package/dist/elements/textTemplate.d.ts +12 -1
  8. package/dist/elements/textTemplate.js +13 -6
  9. package/dist/index.d.ts +7 -2
  10. package/dist/index.js +11 -2
  11. package/dist/interfaces/IConnection.d.ts +2 -2
  12. package/dist/interfaces/ILog.d.ts +2 -2
  13. package/dist/interfaces/ILogger.d.ts +62 -0
  14. package/dist/interfaces/ILogger.js +2 -0
  15. package/dist/interfaces/ISdk.d.ts +4 -2
  16. package/dist/interfaces/IWebhook.d.ts +2 -2
  17. package/dist/interfaces/index.d.ts +1 -0
  18. package/dist/interfaces/index.js +1 -0
  19. package/dist/queue/messageQueue.d.ts +1 -1
  20. package/dist/queue/messageQueue.js +45 -0
  21. package/dist/routes/webhooks/methods/connection.js +78 -11
  22. package/dist/routes/webhooks/methods/messages.js +18 -3
  23. package/dist/services/axiosInstances.d.ts +14 -5
  24. package/dist/services/axiosInstances.js +111 -23
  25. package/dist/services/middlewares/validations.d.ts +2 -2
  26. package/dist/services/middlewares/validations.js +1 -2
  27. package/dist/services/mutations/connection.js +1 -1
  28. package/dist/services/mutations/logs.js +1 -1
  29. package/dist/services/mutations/messages.js +1 -1
  30. package/dist/services/mutations/validation.d.ts +1 -1
  31. package/dist/services/mutations/validation.js +1 -1
  32. package/dist/services/mutations/webhooks.js +1 -1
  33. package/dist/types/logs.d.ts +1 -1
  34. package/dist/types/requestTypes.d.ts +2 -0
  35. package/dist/useCases/connection/index.d.ts +9 -9
  36. package/dist/useCases/connection/index.js +156 -7
  37. package/dist/useCases/events/NatyEvents.d.ts +4 -2
  38. package/dist/useCases/events/NatyEvents.js +13 -1
  39. package/dist/useCases/log/index.d.ts +5 -5
  40. package/dist/useCases/log/index.js +65 -3
  41. package/dist/useCases/message/whatsappResponse.d.ts +48 -22
  42. package/dist/useCases/message/whatsappResponse.js +672 -105
  43. package/dist/useCases/messages/index.d.ts +5 -5
  44. package/dist/useCases/messages/index.js +66 -3
  45. package/dist/useCases/sdk/index.d.ts +8 -4
  46. package/dist/useCases/sdk/index.js +38 -6
  47. package/dist/useCases/webhook/index.d.ts +9 -9
  48. package/dist/useCases/webhook/index.js +154 -7
  49. package/dist/utils/consoleLogger.d.ts +20 -0
  50. package/dist/utils/consoleLogger.js +51 -0
  51. package/dist/utils/index.d.ts +6 -0
  52. package/dist/utils/index.js +6 -0
  53. package/dist/utils/loggerContext.d.ts +57 -0
  54. package/dist/utils/loggerContext.js +90 -0
  55. package/dist/utils/methodContext.d.ts +34 -0
  56. package/dist/utils/methodContext.js +48 -0
  57. package/dist/utils/parseError.d.ts +12 -0
  58. package/dist/utils/parseError.js +27 -3
  59. package/dist/utils/pinoAdapter.d.ts +30 -0
  60. package/dist/utils/pinoAdapter.js +68 -0
  61. package/dist/utils/sanitize.d.ts +42 -0
  62. package/dist/utils/sanitize.js +120 -0
  63. package/dist/utils/tryCatch.d.ts +10 -1
  64. package/dist/utils/tryCatch.js +40 -5
  65. package/docs/01-visao-geral.md +355 -0
  66. package/docs/02-contexto-negocio.md +596 -0
  67. package/docs/03-arquitetura.md +925 -0
  68. package/docs/04-fluxos-funcionais.md +887 -0
  69. package/docs/05-integracoes.md +960 -0
  70. package/docs/06-entidades.md +849 -0
  71. package/docs/07-guia-pratico.md +1133 -0
  72. package/docs/08-troubleshooting.md +816 -0
  73. package/docs/README.md +125 -0
  74. package/examples/logger-example.ts +279 -0
  75. package/package.json +2 -2
  76. /package/dist/{Entities → entities}/Logs.d.ts +0 -0
  77. /package/dist/{Entities → entities}/Logs.js +0 -0
  78. /package/dist/{Entities → entities}/connection.d.ts +0 -0
  79. /package/dist/{Entities → entities}/connection.js +0 -0
  80. /package/dist/{Entities → entities}/errorLogs.d.ts +0 -0
  81. /package/dist/{Entities → entities}/errorLogs.js +0 -0
  82. /package/dist/{Entities → entities}/index.d.ts +0 -0
  83. /package/dist/{Entities → entities}/index.js +0 -0
  84. /package/dist/{Entities → entities}/messages.d.ts +0 -0
  85. /package/dist/{Entities → entities}/messages.js +0 -0
  86. /package/dist/{Entities → entities}/webhooks.d.ts +0 -0
  87. /package/dist/{Entities → entities}/webhooks.js +0 -0
  88. /package/dist/{Entities → entities}/whatsappMessage.d.ts +0 -0
  89. /package/dist/{Entities → entities}/whatsappMessage.js +0 -0
  90. /package/dist/{Errors → errors}/Either.d.ts +0 -0
  91. /package/dist/{Errors → errors}/Either.js +0 -0
  92. /package/dist/{Errors → errors}/ErrorHandling.d.ts +0 -0
  93. /package/dist/{Errors → errors}/ErrorHandling.js +0 -0
  94. /package/dist/{Errors → errors}/index.d.ts +0 -0
  95. /package/dist/{Errors → errors}/index.js +0 -0
@@ -0,0 +1,887 @@
1
+ # 04 - Fluxos Funcionais
2
+
3
+ [⬅️ Voltar ao Índice](README.md)
4
+
5
+ ---
6
+
7
+ ## 📋 Sumário
8
+ - [Fluxo 1: Inicialização do SDK](#fluxo-1-inicialização-do-sdk)
9
+ - [Fluxo 2: Envio de Mensagens](#fluxo-2-envio-de-mensagens)
10
+ - [Fluxo 3: Recebimento de Mensagens (Webhooks)](#fluxo-3-recebimento-de-mensagens-webhooks)
11
+ - [Fluxo 4: Verificação de Conexão](#fluxo-4-verificação-de-conexão)
12
+ - [Fluxo 5: Upload e Download de Mídia](#fluxo-5-upload-e-download-de-mídia)
13
+ - [Fluxo 6: Gestão de Tokens](#fluxo-6-gestão-de-tokens)
14
+ - [Fluxos Alternativos e Tratamento de Erros](#fluxos-alternativos-e-tratamento-de-erros)
15
+
16
+ ---
17
+
18
+ ## Fluxo 1: Inicialização do SDK
19
+
20
+ ### Objetivo
21
+ Autenticar a aplicação no SDK e preparar o ambiente para envio/recepção de mensagens.
22
+
23
+ ### Pré-condições
24
+ - Aplicação possui um `appToken` válido fornecido pela plataforma Naty
25
+ - Variável de ambiente `API_META` configurada
26
+ - (Opcional) Instância do Express.js para webhooks
27
+
28
+ ### Atores
29
+ - **Desenvolvedor/Aplicação:** Inicializa e configura o SDK
30
+ - **SDK Naty Meta:** Processa autenticação e configuração
31
+ - **Naty Meta API:** Valida credenciais
32
+
33
+ ### Fluxo Principal
34
+
35
+ ```mermaid
36
+ sequenceDiagram
37
+ participant Dev as Desenvolvedor
38
+ participant App as Aplicação
39
+ participant SDK as NatyMeta SDK
40
+ participant Interceptor as Axios Interceptor
41
+ participant Naty as Naty Meta API
42
+ participant Express as Express App
43
+
44
+ Note over Dev,App: 1. Instanciação
45
+ Dev->>App: Implementa código de inicialização
46
+ App->>SDK: new NatyMeta()
47
+ SDK-->>App: Instância criada (não autenticada)
48
+
49
+ Note over App,Naty: 2. Autenticação
50
+ App->>SDK: connect({ appToken, app?, pathname? })
51
+ SDK->>SDK: Valida parâmetros obrigatórios
52
+
53
+ SDK->>Naty: POST /validate/validateAppToken<br/>{ appToken }
54
+ alt Token válido
55
+ Naty-->>SDK: 200 OK { valid: true, data }
56
+
57
+ Note over SDK,Interceptor: 3. Configuração
58
+ SDK->>Interceptor: updateAxiosInterceptor(appToken)
59
+ Interceptor->>Interceptor: Injeta header 'x-access-token'
60
+
61
+ alt Express fornecido
62
+ SDK->>Express: app.use(pathname, webhookRoutes)
63
+ Express-->>SDK: Rotas registradas
64
+ end
65
+
66
+ SDK->>SDK: Inicializa managers<br/>(Connection, Message, Webhook, Log)
67
+
68
+ SDK-->>App: Either.right({ success: true })
69
+ App-->>Dev: SDK pronto para uso
70
+ else Token inválido
71
+ Naty-->>SDK: 401 Unauthorized
72
+ SDK-->>App: Either.left(Error: 'Invalid appToken')
73
+ App-->>Dev: Erro de autenticação
74
+ end
75
+ ```
76
+
77
+ ### Código Exemplo
78
+
79
+ ```typescript
80
+ import express from 'express';
81
+ import { NatyMeta } from '@natyapp/meta';
82
+
83
+ const app = express();
84
+ app.use(express.json());
85
+
86
+ // Inicializar SDK
87
+ const sdk = new NatyMeta();
88
+ const result = await sdk.connect({
89
+ appToken: process.env.NATY_APP_TOKEN,
90
+ app: app, // (Opcional) Express para webhooks
91
+ pathname: '/webhooks' // (Opcional) Base path
92
+ });
93
+
94
+ if (result.isRight()) {
95
+ console.log('SDK inicializado com sucesso!');
96
+
97
+ // Acessar módulos
98
+ const connectionManager = sdk.Connection;
99
+ const messageManager = sdk.Message;
100
+
101
+ app.listen(3000, () => {
102
+ console.log('Servidor rodando na porta 3000');
103
+ });
104
+ } else {
105
+ console.error('Erro ao inicializar SDK:', result.value);
106
+ process.exit(1);
107
+ }
108
+ ```
109
+
110
+ ### Pós-condições (Sucesso)
111
+ - ✅ SDK autenticado com appToken válido
112
+ - ✅ Interceptores configurados (header automático)
113
+ - ✅ Webhooks registrados (se Express fornecido)
114
+ - ✅ Managers disponíveis para uso
115
+
116
+ ### Pós-condições (Falha)
117
+ - ❌ SDK não autenticado
118
+ - ❌ Managers não disponíveis
119
+ - ❌ Erro retornado via Either.left
120
+
121
+ ---
122
+
123
+ ## Fluxo 2: Envio de Mensagens
124
+
125
+ ### Objetivo
126
+ Enviar mensagem de qualquer tipo (texto, mídia, interativa) para um número WhatsApp.
127
+
128
+ ### Pré-condições
129
+ - SDK inicializado e conectado
130
+ - Conexão WhatsApp cadastrada no sistema (companyId + phoneNumberId)
131
+ - Número destinatário no formato E.164
132
+
133
+ ### Atores
134
+ - **Aplicação:** Solicita envio de mensagem
135
+ - **WhatsappResponse:** Orquestra o fluxo de envio
136
+ - **Connection Manager:** Busca e atualiza credenciais
137
+ - **Meta Graph API:** Entrega mensagem ao WhatsApp
138
+
139
+ ### Fluxo Principal
140
+
141
+ ```mermaid
142
+ sequenceDiagram
143
+ participant App as Aplicação
144
+ participant WR as WhatsappResponse
145
+ participant ConnMgr as Connection Manager
146
+ participant NatyAPI as Naty Meta API
147
+ participant MetaAPI as Meta Graph API
148
+ participant WA as WhatsApp
149
+
150
+ Note over App,WR: 1. Criação da Instância
151
+ App->>WR: new WhatsappResponse({<br/>companyId, phone_number_id })
152
+
153
+ Note over WR,NatyAPI: 2. Buscar Conexão
154
+ WR->>ConnMgr: getConnection(companyId, phoneNumberId)
155
+ ConnMgr->>NatyAPI: GET /connection?companyId&phoneNumberId
156
+ NatyAPI-->>ConnMgr: ConnectionEntity { accessToken, appId, appSecret }
157
+ ConnMgr-->>WR: ConnectionEntity
158
+
159
+ Note over WR,MetaAPI: 3. Refresh Token (se necessário)
160
+ WR->>WR: update_long_lived_token(connection)
161
+ WR->>MetaAPI: POST /oauth/access_token<br/>{ grant_type, client_id, client_secret, fb_exchange_token }
162
+ MetaAPI-->>WR: { access_token: newToken, expires_in: 5184000 }
163
+ WR->>NatyAPI: PUT /connection { accessToken: newToken }
164
+
165
+ Note over WR,WR: 4. Criar Cliente Meta
166
+ WR->>WR: createMetaAxios(newAccessToken, phoneNumberId)
167
+
168
+ Note over App,MetaAPI: 5. Enviar Mensagem
169
+ App->>WR: send_text({ to: '5511999999999', message: 'Olá!' })
170
+ WR->>WR: Monta payload JSON<br/>{ messaging_product: 'whatsapp', to, type: 'text', text: { body } }
171
+ WR->>MetaAPI: POST /{phoneNumberId}/messages<br/>Authorization: Bearer {accessToken}
172
+
173
+ MetaAPI->>WA: Processa e entrega
174
+ WA-->>MetaAPI: Mensagem entregue
175
+
176
+ MetaAPI-->>WR: 200 OK { messages: [{ id: 'wamid.xxx' }] }
177
+ WR-->>App: Either.right({ id: 'wamid.xxx' })
178
+
179
+ Note over App: 6. Mensagem enviada com sucesso
180
+ ```
181
+
182
+ ### Código Exemplo - Texto Simples
183
+
184
+ ```typescript
185
+ // Criar instância WhatsappResponse
186
+ const whatsapp = sdk.Message.WhatsappResponse({
187
+ companyId: 'abc123',
188
+ phone_number_id: '123456789012345'
189
+ });
190
+
191
+ // Enviar mensagem de texto
192
+ const result = await whatsapp.send_text({
193
+ to: '5511999999999',
194
+ message: 'Olá! Como posso ajudar você hoje?'
195
+ });
196
+
197
+ if (result.isRight()) {
198
+ console.log('Mensagem enviada! ID:', result.value.messages[0].id);
199
+ } else {
200
+ console.error('Erro ao enviar:', result.value);
201
+ }
202
+ ```
203
+
204
+ ### Código Exemplo - Botões Interativos
205
+
206
+ ```typescript
207
+ import { Button } from '@natyapp/meta';
208
+
209
+ // Construir mensagem com botões
210
+ const buttonPayload = new Button()
211
+ .setBody('Escolha uma opção:')
212
+ .addButton({ id: 'opt_suporte', title: '💬 Suporte' })
213
+ .addButton({ id: 'opt_vendas', title: '🛒 Vendas' })
214
+ .addButton({ id: 'opt_financeiro', title: '💰 Financeiro' })
215
+ .build();
216
+
217
+ // Enviar
218
+ const result = await whatsapp.send_buttons({
219
+ to: '5511999999999',
220
+ ...buttonPayload
221
+ });
222
+ ```
223
+
224
+ ### Código Exemplo - Lista de Opções
225
+
226
+ ```typescript
227
+ import { List } from '@natyapp/meta';
228
+
229
+ const listPayload = new List()
230
+ .setBody('Confira nossos produtos:')
231
+ .setButtonText('Ver Produtos')
232
+ .addSection('Eletrônicos')
233
+ .addItem({ id: 'prod_001', title: 'Smartphone', description: 'R$ 2.000,00' })
234
+ .addItem({ id: 'prod_002', title: 'Notebook', description: 'R$ 4.500,00' })
235
+ .addSection('Eletrodomésticos')
236
+ .addItem({ id: 'prod_101', title: 'Geladeira', description: 'R$ 3.200,00' })
237
+ .addItem({ id: 'prod_102', title: 'Máquina Lavar', description: 'R$ 2.800,00' })
238
+ .build();
239
+
240
+ const result = await whatsapp.send_list({
241
+ to: '5511999999999',
242
+ ...listPayload
243
+ });
244
+ ```
245
+
246
+ ### Pós-condições (Sucesso)
247
+ - ✅ Mensagem enviada ao WhatsApp do destinatário
248
+ - ✅ ID da mensagem retornado (`wamid.xxx`)
249
+ - ✅ Token atualizado (se estava próximo de expirar)
250
+
251
+ ### Pós-condições (Falha)
252
+ - ❌ Mensagem não enviada
253
+ - ❌ Erro retornado via Either.left com contexto
254
+
255
+ ---
256
+
257
+ ## Fluxo 3: Recebimento de Mensagens (Webhooks)
258
+
259
+ ### Objetivo
260
+ Receber mensagens enviadas por clientes via WhatsApp e disponibilizá-las à aplicação via eventos.
261
+
262
+ ### Pré-condições
263
+ - SDK inicializado com Express integrado
264
+ - Webhook URL configurada no Meta for Developers
265
+ - Aplicação possui listener para evento `'message'`
266
+
267
+ ### Atores
268
+ - **Cliente WhatsApp:** Envia mensagem
269
+ - **Meta WhatsApp Platform:** Recebe mensagem e envia webhook
270
+ - **Webhook Route:** Processa payload e emite evento
271
+ - **Aplicação:** Escuta evento e processa mensagem
272
+
273
+ ### Fluxo Principal
274
+
275
+ ```mermaid
276
+ sequenceDiagram
277
+ participant Client as Cliente WhatsApp
278
+ participant WA as WhatsApp Platform
279
+ participant Meta as Meta Webhook Service
280
+ participant Route as Webhook Route<br/>(SDK)
281
+ participant SDK as NatyMeta EventEmitter
282
+ participant App as Aplicação
283
+
284
+ Note over Client,Meta: 1. Cliente Envia Mensagem
285
+ Client->>WA: Envia mensagem pelo WhatsApp
286
+ WA->>Meta: Processa e prepara webhook
287
+
288
+ Note over Meta,Route: 2. Meta Envia Webhook
289
+ Meta->>Route: POST /webhooks/messages<br/>{ object: 'whatsapp_business_account', entry: [...] }
290
+
291
+ Note over Route: 3. Processamento do Payload
292
+ Route->>Route: Valida estrutura do payload
293
+ Route->>Route: Extrai dados:<br/>- companyId (de phoneNumberId)<br/>- sender (número do cliente)<br/>- message (conteúdo)
294
+
295
+ Route->>Route: Cria WhatsappMessage entity
296
+ Route->>Route: Instancia WhatsappResponse<br/>(para responder)
297
+
298
+ Note over SDK,App: 4. Emissão de Evento
299
+ Route->>SDK: emit('message', {<br/>companyId, sender, message, whatsappResponse })
300
+ SDK->>App: Dispara listeners registrados
301
+
302
+ Note over App: 5. Processamento pela Aplicação
303
+ App->>App: Executa lógica de negócio<br/>(chatbot, IA, regras)
304
+
305
+ alt Resposta Automática
306
+ App->>Route: whatsappResponse.send_text({ to: sender, message })
307
+ Route->>Meta: POST /messages
308
+ Meta->>WA: Envia resposta
309
+ WA->>Client: Cliente recebe resposta
310
+ end
311
+
312
+ Route-->>Meta: 200 OK (confirma recebimento)
313
+ ```
314
+
315
+ ### Estrutura do Payload (Meta)
316
+
317
+ <details>
318
+ <summary>Ver payload completo de exemplo (clique para expandir)</summary>
319
+
320
+ ```json
321
+ {
322
+ "object": "whatsapp_business_account",
323
+ "entry": [
324
+ {
325
+ "id": "123456789",
326
+ "changes": [
327
+ {
328
+ "value": {
329
+ "messaging_product": "whatsapp",
330
+ "metadata": {
331
+ "display_phone_number": "5511999999999",
332
+ "phone_number_id": "123456789012345"
333
+ },
334
+ "contacts": [
335
+ {
336
+ "profile": { "name": "João Silva" },
337
+ "wa_id": "5511888888888"
338
+ }
339
+ ],
340
+ "messages": [
341
+ {
342
+ "from": "5511888888888",
343
+ "id": "wamid.HBgNNTUxMTk4ODg4ODg4OBUCABIYIDNBNjdGMzQ5QzE5MEFCMTY1MjU0",
344
+ "timestamp": "1709740800",
345
+ "type": "text",
346
+ "text": { "body": "Olá, preciso de ajuda!" }
347
+ }
348
+ ]
349
+ },
350
+ "field": "messages"
351
+ }
352
+ ]
353
+ }
354
+ ]
355
+ }
356
+ ```
357
+ </details>
358
+
359
+ ### Código Exemplo - Listener
360
+
361
+ ```typescript
362
+ // Registrar listener para mensagens
363
+ sdk.on('message', async (data) => {
364
+ console.log(`Nova mensagem de ${data.sender}:`);
365
+ console.log(`Tipo: ${data.message.type}`);
366
+
367
+ // Processar diferentes tipos de mensagem
368
+ if (data.message.type === 'text') {
369
+ const userText = data.message.text.body.toLowerCase();
370
+
371
+ // Lógica de chatbot simples
372
+ let response = '';
373
+
374
+ if (userText.includes('oi') || userText.includes('olá')) {
375
+ response = 'Olá! Como posso ajudar você hoje?';
376
+ } else if (userText.includes('horário')) {
377
+ response = 'Atendemos de segunda a sexta, das 9h às 18h.';
378
+ } else if (userText.includes('preço')) {
379
+ response = 'Para consultar preços, envie "CATALOGO".';
380
+ } else {
381
+ response = 'Desculpe, não entendi. Digite MENU para ver as opções.';
382
+ }
383
+
384
+ // Responder automaticamente
385
+ await data.whatsappResponse.send_text({
386
+ to: data.sender,
387
+ message: response
388
+ });
389
+ } else if (data.message.type === 'interactive') {
390
+ // Cliente clicou em botão ou selecionou item de lista
391
+ const buttonId = data.message.interactive.button_reply?.id ||
392
+ data.message.interactive.list_reply?.id;
393
+
394
+ console.log(`Cliente selecionou: ${buttonId}`);
395
+
396
+ // Processar seleção
397
+ await handleInteraction(buttonId, data);
398
+ } else if (data.message.type === 'image') {
399
+ // Cliente enviou imagem
400
+ const mediaId = data.message.image.id;
401
+
402
+ // Download da imagem
403
+ const imageResult = await data.whatsappResponse.download_media(mediaId);
404
+
405
+ if (imageResult.isRight()) {
406
+ const buffer = imageResult.value;
407
+ // Salvar ou processar imagem (ex: OCR, análise de IA)
408
+ await processImage(buffer);
409
+ }
410
+ }
411
+ });
412
+ ```
413
+
414
+ ### Código Exemplo - Sistema Avançado de Roteamento
415
+
416
+ ```typescript
417
+ // Gerenciador de conversação
418
+ class ConversationManager {
419
+ private contexts = new Map<string, string>(); // sender -> context
420
+
421
+ async handleMessage(data: MessageEventData) {
422
+ const sender = data.sender;
423
+ const context = this.contexts.get(sender) || 'initial';
424
+
425
+ // Máquina de estados
426
+ switch (context) {
427
+ case 'initial':
428
+ await this.showMainMenu(data);
429
+ this.contexts.set(sender, 'menu');
430
+ break;
431
+
432
+ case 'menu':
433
+ await this.handleMenuSelection(data);
434
+ break;
435
+
436
+ case 'collecting_name':
437
+ await this.collectName(data);
438
+ this.contexts.set(sender, 'collecting_email');
439
+ break;
440
+
441
+ case 'collecting_email':
442
+ await this.collectEmail(data);
443
+ this.contexts.set(sender, 'completed');
444
+ break;
445
+
446
+ default:
447
+ this.contexts.delete(sender);
448
+ await this.showMainMenu(data);
449
+ }
450
+ }
451
+
452
+ private async showMainMenu(data: MessageEventData) {
453
+ const buttons = new Button()
454
+ .setBody('Bem-vindo! Escolha uma opção:')
455
+ .addButton({ id: 'info', title: 'Informações' })
456
+ .addButton({ id: 'support', title: 'Suporte' })
457
+ .addButton({ id: 'register', title: 'Cadastrar' })
458
+ .build();
459
+
460
+ await data.whatsappResponse.send_buttons({
461
+ to: data.sender,
462
+ ...buttons
463
+ });
464
+ }
465
+
466
+ // ... outros métodos
467
+ }
468
+
469
+ const conversationMgr = new ConversationManager();
470
+
471
+ sdk.on('message', (data) => {
472
+ conversationMgr.handleMessage(data);
473
+ });
474
+ ```
475
+
476
+ ### Pós-condições (Sucesso)
477
+ - ✅ Mensagem recebida e processada
478
+ - ✅ Evento emitido para todos os listeners
479
+ - ✅ Webhook confirmado (200 OK) para Meta
480
+ - ✅ Resposta enviada (se aplicável)
481
+
482
+ ### Pós-condições (Falha)
483
+ - ❌ Se webhook falhar (erro 5xx), Meta retentar até 3x
484
+ - ❌ Se timeout (>15s), Meta considerar falha
485
+
486
+ ---
487
+
488
+ ## Fluxo 4: Verificação de Conexão
489
+
490
+ ### Objetivo
491
+ Validar se uma conexão WhatsApp está ativa e obter informações da conta.
492
+
493
+ ### Pré-condições
494
+ - Conexão criada no sistema (ConnectionEntity)
495
+ - Webhook de verificação configurado na Meta
496
+
497
+ ### Fluxo Principal
498
+
499
+ ```mermaid
500
+ sequenceDiagram
501
+ participant Meta as Meta Webhook<br/>Verification
502
+ participant Route as Webhook Route<br/>/webhooks/connections
503
+ participant NatyAPI as Naty Meta API
504
+ participant MetaAPI as Meta Graph API
505
+ participant SDK as NatyMeta EventEmitter
506
+ participant App as Aplicação
507
+
508
+ Note over Meta,Route: 1. Verification Request (GET)
509
+ Meta->>Route: GET /webhooks/connections?<br/>hub.mode=subscribe&<br/>hub.challenge=xyz&<br/>hub.verify_token=conn_abc123
510
+
511
+ Route->>Route: Extrai connectionId do verify_token
512
+ Route-->>Meta: 200 OK { challenge: 'xyz' }
513
+
514
+ Note over Meta,Route: 2. Connection Event (POST)
515
+ Meta->>Route: POST /webhooks/connections<br/>{ verify_token: 'conn_abc123', ... }
516
+
517
+ Note over Route,MetaAPI: 3. Buscar Informações
518
+ Route->>Route: Extrai connectionId
519
+ Route->>NatyAPI: GET /connection?id=conn_abc123
520
+ NatyAPI-->>Route: ConnectionEntity { phoneNumberId, accessToken }
521
+
522
+ Route->>MetaAPI: GET /{phoneNumberId}<br/>Authorization: Bearer {accessToken}
523
+ MetaAPI-->>Route: {<br/> id: '123',<br/> verified_name: 'Minha Empresa',<br/> display_phone_number: '+55...',<br/> quality_rating: 'GREEN'<br/>}
524
+
525
+ Note over SDK,App: 4. Emitir Evento
526
+ Route->>SDK: emit('connection', {<br/>connectionId, accountInfo })
527
+ SDK->>App: Dispara listener
528
+
529
+ App->>App: Confirma conexão ativa<br/>Atualiza dashboard
530
+
531
+ Route-->>Meta: 200 OK
532
+ ```
533
+
534
+ ### Código Exemplo
535
+
536
+ ```typescript
537
+ sdk.on('connection', (data) => {
538
+ console.log('=== Conexão Verificada ===');
539
+ console.log(`Connection ID: ${data.connectionId}`);
540
+ console.log(`Nome Verificado: ${data.accountInfo.verified_name}`);
541
+ console.log(`Número: ${data.accountInfo.display_phone_number}`);
542
+ console.log(`Quality Rating: ${data.accountInfo.quality_rating}`);
543
+
544
+ // Atualizar status no banco de dados
545
+ updateConnectionStatus(data.connectionId, 'active');
546
+
547
+ // Alertar equipe se quality rating estiver baixo
548
+ if (data.accountInfo.quality_rating !== 'GREEN') {
549
+ notifyAdmins(`ALERTA: Quality rating ${data.accountInfo.quality_rating} para ${data.accountInfo.display_phone_number}`);
550
+ }
551
+ });
552
+ ```
553
+
554
+ ### Pós-condições
555
+ - ✅ Conexão confirmada como ativa
556
+ - ✅ Informações da conta atualizadas
557
+ - ✅ Quality rating monitorado
558
+
559
+ ---
560
+
561
+ ## Fluxo 5: Upload e Download de Mídia
562
+
563
+ ### Objetivo
564
+ Fazer upload de mídia (imagem, vídeo, documento) e fazer download de mídia recebida.
565
+
566
+ ### Fluxo 5A: Upload de Mídia
567
+
568
+ ```mermaid
569
+ sequenceDiagram
570
+ participant App as Aplicação
571
+ participant WR as WhatsappResponse
572
+ participant MetaAPI as Meta Graph API
573
+
574
+ Note over App,WR: 1. Preparar Stream
575
+ App->>App: Ler arquivo do disco<br/>const stream = fs.createReadStream('image.jpg')
576
+
577
+ Note over App,MetaAPI: 2. Upload
578
+ App->>WR: createMedia(stream)
579
+ WR->>WR: Prepara FormData<br/>{ file: stream, messaging_product: 'whatsapp' }
580
+ WR->>MetaAPI: POST /{phoneNumberId}/media<br/>Content-Type: multipart/form-data
581
+ MetaAPI-->>WR: 200 OK { id: 'media_123abc' }
582
+ WR-->>App: Either.right({ id: 'media_123abc' })
583
+
584
+ Note over App,MetaAPI: 3. Usar Media ID
585
+ App->>WR: send_image({<br/> to: '5511999999999',<br/> media_id: 'media_123abc',<br/> caption: 'Veja esta imagem!'<br/>})
586
+ WR->>MetaAPI: POST /messages { type: 'image', image: { id: 'media_123abc' } }
587
+ MetaAPI-->>WR: Mensagem enviada
588
+ WR-->>App: Either.right({ id: 'wamid.xxx' })
589
+ ```
590
+
591
+ #### Código Exemplo - Upload
592
+
593
+ ```typescript
594
+ import fs from 'fs';
595
+
596
+ // Upload de imagem
597
+ const stream = fs.createReadStream('./assets/product.jpg');
598
+ const uploadResult = await whatsapp.createMedia(stream);
599
+
600
+ if (uploadResult.isRight()) {
601
+ const mediaId = uploadResult.value.id;
602
+ console.log('Mídia enviada! ID:', mediaId);
603
+
604
+ // Enviar imagem usando media_id
605
+ const sendResult = await whatsapp.send_image({
606
+ to: '5511999999999',
607
+ media_id: mediaId,
608
+ caption: 'Confira nosso novo produto!'
609
+ });
610
+ } else {
611
+ console.error('Erro no upload:', uploadResult.value);
612
+ }
613
+ ```
614
+
615
+ ### Fluxo 5B: Download de Mídia
616
+
617
+ ```mermaid
618
+ sequenceDiagram
619
+ participant App as Aplicação
620
+ participant WR as WhatsappResponse
621
+ participant MetaAPI as Meta Graph API
622
+
623
+ Note over App: 1. Receber Media ID (via webhook)
624
+ App->>App: message.image.id = 'media_123abc'
625
+
626
+ Note over App,MetaAPI: 2. Obter URL Temporária
627
+ App->>WR: get_media_url('media_123abc')
628
+ WR->>MetaAPI: GET /media_123abc<br/>Authorization: Bearer {token}
629
+ MetaAPI-->>WR: 200 OK {<br/> url: 'https://mmg.whatsapp.net/d/...',<br/> mime_type: 'image/jpeg',<br/> file_size: 52431<br/>}
630
+ WR-->>App: Either.right({ url, mime_type, file_size })
631
+
632
+ Note over App,MetaAPI: 3. Download do Arquivo
633
+ App->>WR: download_media('media_123abc')
634
+ WR->>MetaAPI: GET {url} (URL temporária, válida ~5min)
635
+ MetaAPI-->>WR: Binary data (Buffer)
636
+ WR-->>App: Either.right(Buffer)
637
+
638
+ Note over App: 4. Salvar ou Processar
639
+ App->>App: fs.writeFileSync('downloads/image.jpg', buffer)<br/>ou processImage(buffer)
640
+ ```
641
+
642
+ #### Código Exemplo - Download
643
+
644
+ ```typescript
645
+ sdk.on('message', async (data) => {
646
+ if (data.message.type === 'image') {
647
+ const mediaId = data.message.image.id;
648
+
649
+ // Método 1: Obter URL temporária
650
+ const urlResult = await data.whatsappResponse.get_media_url(mediaId);
651
+ if (urlResult.isRight()) {
652
+ console.log('URL da mídia:', urlResult.value.url);
653
+ console.log('MIME Type:', urlResult.value.mime_type);
654
+ console.log('Tamanho:', urlResult.value.file_size, 'bytes');
655
+ }
656
+
657
+ // Método 2: Download direto como Buffer
658
+ const downloadResult = await data.whatsappResponse.download_media(mediaId);
659
+ if (downloadResult.isRight()) {
660
+ const imageBuffer = downloadResult.value;
661
+
662
+ // Salvar no disco
663
+ fs.writeFileSync(`./downloads/${mediaId}.jpg`, imageBuffer);
664
+ console.log('Imagem salva!');
665
+
666
+ // Ou processar (ex: análise de IA, OCR)
667
+ const analysis = await analyzeImage(imageBuffer);
668
+ await data.whatsappResponse.send_text({
669
+ to: data.sender,
670
+ message: `Análise da imagem: ${analysis}`
671
+ });
672
+ }
673
+ }
674
+ });
675
+ ```
676
+
677
+ ### Pós-condições
678
+ - ✅ Mídia enviada/baixada com sucesso
679
+ - ✅ Media ID retornado para uso posterior
680
+
681
+ ---
682
+
683
+ ## Fluxo 6: Gestão de Tokens
684
+
685
+ ### Objetivo
686
+ Garantir que tokens de acesso estejam sempre válidos através de refresh automático.
687
+
688
+ ### Fluxo Principal
689
+
690
+ ```mermaid
691
+ sequenceDiagram
692
+ participant App as Aplicação
693
+ participant WR as WhatsappResponse
694
+ participant Conn as Connection Manager
695
+ participant NatyAPI as Naty Meta API
696
+ participant MetaAPI as Meta OAuth API
697
+
698
+ Note over App,WR: 1. Aplicação Solicita Envio
699
+ App->>WR: new WhatsappResponse({ companyId, phone_number_id })
700
+
701
+ Note over WR,NatyAPI: 2. Buscar Token Atual
702
+ WR->>Conn: getConnection(companyId, phoneNumberId)
703
+ Conn->>NatyAPI: GET /connection
704
+ NatyAPI-->>Conn: { accessToken: 'token_antigo', appId, appSecret }
705
+ Conn-->>WR: ConnectionEntity
706
+
707
+ Note over WR,MetaAPI: 3. Refresh Automático
708
+ WR->>WR: Verifica se token precisa refresh<br/>(executado sempre por segurança)
709
+ WR->>MetaAPI: POST /oauth/access_token<br/>{<br/> grant_type: 'fb_exchange_token',<br/> client_id: appId,<br/> client_secret: appSecret,<br/> fb_exchange_token: token_antigo<br/>}
710
+
711
+ alt Token Refreshed com Sucesso
712
+ MetaAPI-->>WR: {<br/> access_token: 'token_novo',<br/> token_type: 'bearer',<br/> expires_in: 5184000<br/>}
713
+
714
+ Note over WR,NatyAPI: 4. Salvar Novo Token
715
+ WR->>Conn: updateConnection(id, { accessToken: 'token_novo' })
716
+ Conn->>NatyAPI: PUT /connection { accessToken: 'token_novo' }
717
+ NatyAPI-->>Conn: ConnectionEntity atualizada
718
+
719
+ WR->>WR: Usa token_novo para requisição
720
+ else Token Expirado Definitivamente
721
+ MetaAPI-->>WR: 401 Unauthorized { error: 'invalid_grant' }
722
+ WR-->>App: Either.left(Error: 'Token expirado, reautenticação necessária')
723
+ App->>App: Alertar administrador<br/>Solicitar novo short-lived token da Meta
724
+ end
725
+ ```
726
+
727
+ ### Ciclo de Vida do Token
728
+
729
+ ```mermaid
730
+ stateDiagram-v2
731
+ [*] --> ShortLived: Meta gera token inicial
732
+ ShortLived --> LongLived: Exchange via OAuth (1h)
733
+ LongLived --> Refreshed: Auto-refresh a cada uso
734
+ Refreshed --> LongLived: Token atualizado (60 dias)
735
+ LongLived --> Expired: Sem uso por >60 dias
736
+ Expired --> ShortLived: Reautenticação manual
737
+ Expired --> [*]
738
+ ```
739
+
740
+ ### Código Exemplo - Detecção de Expiração
741
+
742
+ ```typescript
743
+ // O SDK faz refresh automaticamente, mas você pode monitorar
744
+ sdk.on('error', (error) => {
745
+ if (error.message.includes('Token expirado')) {
746
+ // Alertar equipe
747
+ sendAlert({
748
+ priority: 'HIGH',
749
+ message: 'Token WhatsApp expirado! Reautenticação necessária.',
750
+ connectionId: error.context?.connectionId
751
+ });
752
+
753
+ // Desativar conexão temporariamente
754
+ disableConnection(error.context?.connectionId);
755
+ }
756
+ });
757
+ ```
758
+
759
+ ---
760
+
761
+ ## Fluxos Alternativos e Tratamento de Erros
762
+
763
+ ### Cenário 1: Número Inválido
764
+
765
+ **Trigger:** Aplicação tenta enviar para número mal formatado.
766
+
767
+ ```typescript
768
+ // Número sem código do país
769
+ const result = await whatsapp.send_text({
770
+ to: '11999999999', // ❌ Falta +55
771
+ message: 'Teste'
772
+ });
773
+
774
+ // Meta API retorna erro
775
+ if (result.isLeft()) {
776
+ console.error(result.value);
777
+ // Error: [Meta API] Invalid phone number format
778
+ }
779
+ ```
780
+
781
+ **Solução:** Sempre usar formato E.164 (`+5511999999999`).
782
+
783
+ ---
784
+
785
+ ### Cenário 2: Rate Limit Excedido
786
+
787
+ **Trigger:** Envio de mensagens acima do limite diário (Tier).
788
+
789
+ ```typescript
790
+ // Meta retorna 429 Too Many Requests
791
+ const result = await whatsapp.send_text({
792
+ to: '5511999999999',
793
+ message: 'Mensagem 1001' // Excedeu limite do Tier 1
794
+ });
795
+
796
+ if (result.isLeft()) {
797
+ const error = result.value;
798
+ if (error.statusCode === 429) {
799
+ console.log('Rate limit atingido. Aguardar até amanhã.');
800
+ // Implementar fila com retry após 24h
801
+ }
802
+ }
803
+ ```
804
+
805
+ ---
806
+
807
+ ### Cenário 3: Webhook Timeout
808
+
809
+ **Trigger:** Processamento de webhook demora mais de 15 segundos.
810
+
811
+ ```typescript
812
+ sdk.on('message', async (data) => {
813
+ // ❌ Operação demorada (ex: consulta lenta no DB)
814
+ const result = await slowDatabaseQuery(); // 20 segundos
815
+
816
+ // Meta já desistiu (timeout), mas SDK ainda processa
817
+ await data.whatsappResponse.send_text({
818
+ to: data.sender,
819
+ message: result
820
+ });
821
+ });
822
+ ```
823
+
824
+ **Solução:** Responder webhook imediatamente (200 OK) e processar assíncrono.
825
+
826
+ ```typescript
827
+ sdk.on('message', async (data) => {
828
+ // Processar em background
829
+ processMessageAsync(data).catch(console.error);
830
+
831
+ // Não aguardar processamento completo
832
+ });
833
+
834
+ async function processMessageAsync(data) {
835
+ const result = await slowDatabaseQuery();
836
+ await data.whatsappResponse.send_text({
837
+ to: data.sender,
838
+ message: result
839
+ });
840
+ }
841
+ ```
842
+
843
+ ---
844
+
845
+ ### Cenário 4: Mensagem Fora da Janela de 24h
846
+
847
+ **Trigger:** Enviar mensagem livre após 24h da última interação do cliente.
848
+
849
+ ```typescript
850
+ // Cliente interagiu há 2 dias
851
+ const result = await whatsapp.send_text({
852
+ to: '5511999999999',
853
+ message: 'Oi! Tudo bem?' // ❌ Não é template aprovado
854
+ });
855
+
856
+ if (result.isLeft()) {
857
+ console.error(result.value);
858
+ // Error: [Meta API] Message failed to send because more than 24 hours have passed
859
+ }
860
+ ```
861
+
862
+ **Solução:** Usar template aprovado.
863
+
864
+ ```typescript
865
+ const result = await whatsapp.send_text_template({
866
+ to: '5511999999999',
867
+ template: {
868
+ name: 'follow_up_aprovado', // Template aprovado pela Meta
869
+ language: 'pt_BR',
870
+ components: []
871
+ }
872
+ });
873
+ ```
874
+
875
+ ---
876
+
877
+ ## 🔗 Próximos Passos
878
+
879
+ Com os fluxos compreendidos, explore:
880
+
881
+ - **[Integrações](05-integracoes.md)** - Detalhes das APIs externas
882
+ - **[Entidades](06-entidades.md)** - Estrutura de dados
883
+ - **[Guia Prático](07-guia-pratico.md)** - Mais exemplos de código
884
+
885
+ ---
886
+
887
+ [⬅️ Anterior: Arquitetura](03-arquitetura.md) | [⬆️ Voltar ao Índice](README.md) | [➡️ Próximo: Integrações](05-integracoes.md)