@areumtecnologia/wasockets 2.3.1 → 2.3.3

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 CHANGED
@@ -288,22 +288,37 @@ await ctx.unstar();
288
288
  ```
289
289
 
290
290
  #### Utilitários de Mídia (`MediaObject`):
291
- Se a mensagem contiver imagem, vídeo, áudio ou documento, `ctx.media` fornece métodos instantâneos:
291
+ Se a mensagem contiver imagem, vídeo, áudio, figurinha ou documento, `ctx.media` centraliza todos os metadados e métodos de manipulação em uma única instância:
292
292
 
293
+ ##### Propriedades de `ctx.media`:
294
+ - `ctx.media.mimetype`: Tipo MIME real (ex: `'image/jpeg'`, `'audio/ogg; codecs=opus'`).
295
+ - `ctx.media.extension`: Extensão inferida do arquivo (ex: `'jpg'`, `'ogg'`, `'pdf'`, `'mp4'`).
296
+ - `ctx.media.fileLength`: Tamanho do arquivo em bytes.
297
+ - `ctx.media.fileName`: Nome original do arquivo (se enviado como documento).
298
+ - `ctx.media.caption`: Legenda de texto anexada à mídia.
299
+ - `ctx.media.seconds` / `duration`: Duração em segundos (para áudios e vídeos).
300
+ - `ctx.media.isVoice` / `isPtt`: Booleano se é áudio gravado no WhatsApp (Push-To-Talk).
301
+ - `ctx.media.isGif`: Booleano se é vídeo reproduzido como GIF animado.
302
+ - `ctx.media.isViewOnce`: Booleano se é mídia de visualização única.
303
+
304
+ ##### Métodos de `ctx.media`:
293
305
  ```javascript
294
306
  if (ctx.media) {
295
- // 1. Salva diretamente em disco
307
+ // 1. Salva diretamente em disco (cria diretórios se não existirem)
296
308
  await ctx.media.save('./pasta/comprovante.pdf');
297
309
 
298
- // 2. Converte para Base64 (ideal para enviar para APIs de IA ou frontend)
299
- const base64 = ctx.media.toBase64();
300
- const dataUri = ctx.media.toDataUri(); // 'data:image/jpeg;base64,...'
310
+ // 2. Obtém como Buffer em memória (com cache automático)
311
+ const buffer = await ctx.media.toBuffer();
312
+
313
+ // 3. Converte para Base64 (ideal para LLMs como Gemini / OpenAI)
314
+ const base64 = await ctx.media.toBase64();
315
+ const dataUri = await ctx.media.toDataUri(); // 'data:image/jpeg;base64,...'
301
316
 
302
- // 3. Obtém como Stream legível (Node Readable)
303
- const stream = ctx.media.toStream();
317
+ // 4. Obtém como Stream legível (Node Readable)
318
+ const stream = await ctx.media.toStream();
304
319
 
305
- // 4. Integração nativa com Sharp (se instalado) para redimensionamento/corte
306
- const sharpInstance = ctx.media.toSharp();
320
+ // 5. Integração nativa com Sharp (se instalado) para recorte/redimensionamento
321
+ const sharpInstance = await ctx.media.toSharp();
307
322
  }
308
323
  ```
309
324
 
@@ -19,8 +19,14 @@ class MediaObject {
19
19
  this.mimetype = this.mediaNode.mimetype || this._defaultMimetype(this.mediaType)
20
20
  this.fileLength = Number(this.mediaNode.fileLength || 0)
21
21
  this.fileName = this.mediaNode.fileName || ''
22
+ this.caption = this.mediaNode.caption || ''
22
23
  this.seconds = Number(this.mediaNode.seconds || 0)
24
+ this.duration = this.seconds || null
25
+
23
26
  this.isVoice = Boolean(this.mediaNode.ptt)
27
+ this.isPtt = this.isVoice
28
+ this.isGif = Boolean(this.mediaNode.gifPlayback)
29
+ this.isViewOnce = Boolean(this.mediaNode.viewOnce)
24
30
  this.isAnimated = Boolean(this.mediaNode.gifPlayback || this.mediaNode.isAnimated)
25
31
  this.extension = this._inferExtension()
26
32
 
@@ -26,11 +26,13 @@ class MessageContext {
26
26
 
27
27
  const effectiveMessage = editedMsg || rawMessage?.message || null
28
28
 
29
- // 2. Identity and Routing
29
+ // 2. Single-pass message unwrapping (eliminates repeated while-loops)
30
+ const unwrapped = MessageNormalizer.unwrapMessage(effectiveMessage)
31
+
32
+ // 3. Identity and Routing
30
33
  this.id = effectiveKey.id || rawMessage?.key?.id || ''
31
34
  this.chatId = effectiveKey.remoteJid || rawMessage?.key?.remoteJid || ''
32
35
  this.fromMe = Boolean(effectiveKey.fromMe)
33
- this.isFromMe = this.fromMe
34
36
 
35
37
  this.isGroup = JidNormalizer.isGroup(this.chatId)
36
38
  this.isChannel = JidNormalizer.isNewsletter(this.chatId)
@@ -54,10 +56,7 @@ class MessageContext {
54
56
  this.fromPushName = rawMessage?.pushName || JidNormalizer.toPhoneNumber(this.from) || 'Desconhecido'
55
57
  }
56
58
 
57
- this.sender = this.from
58
59
  this.fromNumber = JidNormalizer.toPhoneNumber(this.from)
59
- this.senderNumber = this.fromNumber
60
- this.senderName = this.fromPushName
61
60
 
62
61
  // Timestamps
63
62
  const rawTs = Number(rawMessage?.messageTimestamp || Math.floor(Date.now() / 1000))
@@ -66,25 +65,22 @@ class MessageContext {
66
65
  ? new Date(Number(rawMessage.message.protocolMessage.timestampMs || Date.now()))
67
66
  : null
68
67
 
69
- // 3. Content Decoupling & Typed Parsers
70
- this.type = MessageNormalizer.extractType(effectiveMessage)
71
- this.body = MessageNormalizer.extractBody(effectiveMessage)
72
- this.interactiveReply = MessageNormalizer.extractInteractiveReply(effectiveMessage)
73
- this.contacts = MessageNormalizer.extractContacts(effectiveMessage)
74
- this.location = MessageNormalizer.extractLocation(effectiveMessage)
75
- this.reaction = MessageNormalizer.extractReaction(effectiveMessage)
76
- this.poll = MessageNormalizer.extractPollCreation(effectiveMessage, rawMessage)
77
-
78
- // 4. Media Normalization
79
- this.mediaNode = MessageNormalizer.extractMediaNode(effectiveMessage)
80
- this.hasMedia = Boolean(this.mediaNode)
81
- this.media = this.hasMedia ? new MediaObject(this.mediaNode, this.type) : null
82
- this.mediaDetails = MessageNormalizer.extractMediaDetails(effectiveMessage)
83
-
84
- // 5. Context Info, Mentions & Forwarding
85
- this.contextInfo = MessageNormalizer.extractContextInfo(effectiveMessage)
68
+ // 4. Content Decoupling & Typed Parsers (Single-pass unwrapped nodes)
69
+ this.type = MessageNormalizer.extractType(unwrapped)
70
+ this.body = MessageNormalizer.extractBody(unwrapped)
71
+ this.interactiveReply = MessageNormalizer.extractInteractiveReply(unwrapped)
72
+ this.contacts = MessageNormalizer.extractContacts(unwrapped)
73
+ this.location = MessageNormalizer.extractLocation(unwrapped)
74
+ this.reaction = MessageNormalizer.extractReaction(unwrapped)
75
+ this.poll = MessageNormalizer.extractPollCreation(unwrapped, rawMessage)
76
+
77
+ // 5. Media Normalization (Centralized directly into MediaObject)
78
+ this.mediaNode = MessageNormalizer.extractMediaNode(unwrapped)
79
+ this.media = this.mediaNode ? new MediaObject(this.mediaNode, this.type) : null
80
+
81
+ // 6. Context Info, Mentions & Forwarding
82
+ this.contextInfo = MessageNormalizer.extractContextInfo(unwrapped)
86
83
  this.mentions = this.contextInfo?.mentionedJid || []
87
- this.mentionedJids = this.mentions
88
84
  this.isForwarded = Boolean(this.contextInfo?.isForwarded)
89
85
  this.forwardingScore = Number(this.contextInfo?.forwardingScore || 0)
90
86
 
@@ -94,7 +90,7 @@ class MessageContext {
94
90
  (clientLid && this.mentions.includes(clientLid))
95
91
  )
96
92
 
97
- // 6. Quoted Message Parsing (Recursion with depth limit 1)
93
+ // 7. Quoted Message Parsing (Recursion with depth limit 1)
98
94
  this.isReply = Boolean(this.contextInfo?.quotedMessage)
99
95
  this.quoted = null
100
96
 
@@ -125,6 +121,58 @@ class MessageContext {
125
121
  }
126
122
  }
127
123
 
124
+ // ==========================================
125
+ // Zero-Cost Memory Aliases & Compatibility Getters
126
+ // ==========================================
127
+
128
+ /** Alias for this.fromMe */
129
+ get isFromMe() {
130
+ return this.fromMe
131
+ }
132
+
133
+ /** Alias for this.from */
134
+ get sender() {
135
+ return this.from
136
+ }
137
+
138
+ /** Alias for this.fromNumber */
139
+ get senderNumber() {
140
+ return this.fromNumber
141
+ }
142
+
143
+ /** Alias for this.fromPushName */
144
+ get senderName() {
145
+ return this.fromPushName
146
+ }
147
+
148
+ /** Alias for this.mentions */
149
+ get mentionedJids() {
150
+ return this.mentions
151
+ }
152
+
153
+ /** Boolean check whether message contains media */
154
+ get hasMedia() {
155
+ return Boolean(this.media)
156
+ }
157
+
158
+ /** Backward-compatible media details accessor backed by MediaObject */
159
+ get mediaDetails() {
160
+ if (!this.media) return null
161
+ return {
162
+ mimetype: this.media.mimetype,
163
+ fileName: this.media.fileName,
164
+ caption: this.media.caption,
165
+ duration: this.media.duration,
166
+ isPtt: this.media.isPtt,
167
+ isGif: this.media.isGif,
168
+ isViewOnce: this.media.isViewOnce
169
+ }
170
+ }
171
+
172
+ // ==========================================
173
+ // Context Action Methods
174
+ // ==========================================
175
+
128
176
  /**
129
177
  * Responde citando esta mensagem automaticamente
130
178
  * @param {string|Object} content - Texto ou payload de mensagem
@@ -23,12 +23,13 @@ class EventNormalizer {
23
23
  // Ignore stub or protocol messages if completely empty
24
24
  if (!rawMsg.message && !rawMsg.messageStubType) continue
25
25
 
26
- // Handle protocol revoke messages explicitly
26
+ // Handle protocol revoke messages explicitly (delete for everyone)
27
27
  const isRevoke = rawMsg.message?.protocolMessage?.type === 0
28
28
  if (isRevoke) {
29
29
  client.emit(Events.MESSAGE_DELETE, {
30
30
  keys: [rawMsg.message.protocolMessage.key || rawMsg.key]
31
31
  })
32
+ continue // Do not emit as a new received/sent message
32
33
  }
33
34
 
34
35
  const ctx = new MessageContext(client, rawMsg)
@@ -58,8 +58,13 @@ export declare class MediaObject {
58
58
  mimetype: string
59
59
  fileLength: number
60
60
  fileName: string
61
+ caption: string
61
62
  seconds: number
63
+ duration: number | null
62
64
  isVoice: boolean
65
+ isPtt: boolean
66
+ isGif: boolean
67
+ isViewOnce: boolean
63
68
  isAnimated: boolean
64
69
  extension: string
65
70
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@areumtecnologia/wasockets",
3
- "version": "2.3.1",
3
+ "version": "2.3.3",
4
4
  "whatsappVersion": "2.3000.1053049953",
5
5
  "description": "Communication Library By areumtecnologia",
6
6
  "keywords": [],