@areumtecnologia/wasockets 1.1.3 → 1.1.5

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
@@ -543,6 +543,46 @@ await sock.chatModify({ pin: true }, jid)
543
543
 
544
544
  ---
545
545
 
546
+ ## 🏷️ Etiquetas de Negócio (Labels - WhatsApp Business)
547
+
548
+ O **WaSockets** permite que você gerencie etiquetas e organize contatos ou mensagens diretamente pelo aplicativo WhatsApp Business.
549
+
550
+ ### Criando, Editando e Deletando Etiquetas (CRUD de Sistema)
551
+
552
+ Você pode criar, editar e excluir as etiquetas globais da sua conta:
553
+
554
+ ```javascript
555
+ // Criar uma nova etiqueta com cor específica
556
+ // Cores suportadas: de 0 a 19 correspondentes à paleta do WhatsApp Business
557
+ const novaLabel = await sock.createLabel('Lead Qualificado', 5)
558
+
559
+ // Atualizar o nome e a cor de uma etiqueta existente
560
+ await sock.updateLabel('label_id_123', 'Pagamento Aprovado', 2)
561
+
562
+ // Deletar uma etiqueta definitivamente da conta
563
+ await sock.deleteLabel('label_id_123')
564
+ ```
565
+
566
+ ### Associando Etiquetas a Conversas e Mensagens
567
+
568
+ Para categorizar chats específicos ou marcar mensagens individuais dentro de uma conversa:
569
+
570
+ ```javascript
571
+ // Associar etiqueta a uma conversa (JID)
572
+ await sock.addChatLabel(jid, 'label_id_123')
573
+
574
+ // Remover etiqueta de uma conversa (JID)
575
+ await sock.removeChatLabel(jid, 'label_id_123')
576
+
577
+ // Associar etiqueta a uma mensagem específica
578
+ await sock.addMessageLabel(jid, 'mensagem_id_456', 'label_id_123')
579
+
580
+ // Remover etiqueta de uma mensagem específica
581
+ await sock.removeMessageLabel(jid, 'mensagem_id_456', 'label_id_123')
582
+ ```
583
+
584
+ ---
585
+
546
586
  ## 👥 Gerenciamento de Grupos
547
587
 
548
588
  As operações de alteração estrutural em grupos requerem que a conta conectada seja administradora do grupo correspondente.
@@ -580,6 +620,30 @@ console.log(`Título: ${metadados.subject}, Membros: ${metadados.participants.le
580
620
 
581
621
  ---
582
622
 
623
+ ## 👥 Etiquetas de Membro (Member Tags) em Grupos
624
+
625
+ O WhatsApp permite que os participantes de um grupo criem um rótulo ou descrição curta de até 30 caracteres para si mesmos (ex: definir seu papel ou cargo no grupo).
626
+
627
+ ### Definindo sua própria Etiqueta de Membro no Grupo
628
+
629
+ ```javascript
630
+ // Define a sua etiqueta como "Suporte Técnico" no grupo especificado
631
+ await sock.updateMemberLabel(grupoJid, "Suporte Técnico")
632
+ ```
633
+
634
+ ### Monitorando Atualizações de Etiquetas de Outros Membros
635
+
636
+ Você pode escutar o evento `group.member-tag.update` para monitorar quando qualquer participante alterar a etiqueta de membro dele no grupo:
637
+
638
+ ```javascript
639
+ sock.ev.on('group.member-tag.update', (update) => {
640
+ const { groupId, label, participant } = update
641
+ console.log(`O usuário ${participant} definiu a etiqueta "${label}" no grupo ${groupId}`)
642
+ })
643
+ ```
644
+
645
+ ---
646
+
583
647
  ## 📢 Newsletters (Canais)
584
648
 
585
649
  O **WaSockets** traz suporte avançado para a criação e monitoramento de Newsletters (Canais de Transmissão públicos do WhatsApp).
@@ -608,6 +672,86 @@ await sock.newsletterUnmute(canal.id)
608
672
 
609
673
  ---
610
674
 
675
+ ## 💼 WhatsApp Business (Catálogo, Produtos e Perfil Comercial)
676
+
677
+ Caso a conta conectada seja comercial (WhatsApp Business), o **WaSockets** oferece suporte para interagir com o catálogo de produtos, obter detalhes de pedidos e gerenciar o perfil público e as mídias da empresa.
678
+
679
+ ### Gerenciamento de Perfil e Capa Comercial
680
+
681
+ Você pode atualizar dados públicos de endereço, e-mail, descrição, websites, horários de funcionamento e foto de capa:
682
+
683
+ ```javascript
684
+ // Atualizar o perfil comercial do usuário
685
+ await sock.updateBussinesProfile({
686
+ address: 'Av. Paulista, 1000 - São Paulo, SP',
687
+ email: 'contato@suaempresa.com.br',
688
+ description: 'Empresa especializada em soluções de tecnologia.',
689
+ websites: ['https://suaempresa.com.br', 'https://blog.suaempresa.com.br'],
690
+ hours: {
691
+ timezone: 'America/Sao_Paulo',
692
+ days: [
693
+ { day: '1', mode: 'open_24_h' }, // Segunda-feira (1=Segunda, 7=Domingo)
694
+ {
695
+ day: '2',
696
+ mode: 'specific_hours',
697
+ openTimeInMinutes: 540, // 09:00 (9h * 60)
698
+ closeTimeInMinutes: 1080 // 18:00 (18h * 60)
699
+ }
700
+ ]
701
+ }
702
+ })
703
+
704
+ // Atualizar ou definir a foto de capa comercial
705
+ const coverPhotoId = await sock.updateCoverPhoto('./capa_empresa.jpg')
706
+
707
+ // Remover a foto de capa atual
708
+ await sock.removeCoverPhoto(coverPhotoId)
709
+ ```
710
+
711
+ ### Consulta de Catálogo, Coleções e Pedidos
712
+
713
+ ```javascript
714
+ // Obter a lista de produtos do catálogo de um contato (ou do seu próprio)
715
+ const catalogo = await sock.getCatalog({
716
+ jid: '5511999999999@s.whatsapp.net',
717
+ limit: 15
718
+ })
719
+ console.log('Produtos:', catalogo.products)
720
+
721
+ // Obter as coleções de produtos organizadas do catálogo
722
+ const colecoes = await sock.getCollections('5511999999999@s.whatsapp.net', 10)
723
+
724
+ // Obter os detalhes completos de um pedido comercial a partir do ID e do Token da mensagem de carrinho
725
+ const detalhesPedido = await sock.getOrderDetails('ID_DO_PEDIDO', 'TOKEN_DO_PEDIDO')
726
+ console.log('Itens do Pedido:', detalhesPedido.items)
727
+ ```
728
+
729
+ ### Cadastro e Modificação de Produtos no Catálogo
730
+
731
+ ```javascript
732
+ // Adicionar um novo produto no catálogo
733
+ const novoProduto = await sock.productCreate({
734
+ name: 'Caneca Personalizada WaSockets',
735
+ description: 'Caneca de cerâmica de alta qualidade.',
736
+ price: 4990, // R$ 49,90 (valor representado sem decimais, multiplicado por 100)
737
+ currency: 'BRL',
738
+ isHidden: false,
739
+ image: { url: './caneca.jpg' } // Caminho local, buffer ou stream
740
+ })
741
+ console.log('Produto Criado com ID:', novoProduto.id)
742
+
743
+ // Atualizar dados de um produto existente
744
+ await sock.productUpdate(novoProduto.id, {
745
+ name: 'Caneca Personalizada WaSockets (Edição Especial)',
746
+ price: 5990
747
+ })
748
+
749
+ // Remover produtos do catálogo (aceita um array de IDs de produtos)
750
+ await sock.productDelete([novoProduto.id])
751
+ ```
752
+
753
+ ---
754
+
611
755
  ## 🔒 Configurações de Privacidade
612
756
 
613
757
  ```javascript
@@ -925,6 +925,67 @@ const makeChatsSocket = (config) => {
925
925
  }, jid)
926
926
  }
927
927
 
928
+ /**
929
+ * Creates a new business label
930
+ */
931
+ const createLabel = async (name, color, predefinedId = 0) => {
932
+ const id = (Math.floor(Math.random() * 1000000) + 1).toString()
933
+ await chatModify({
934
+ addLabel: {
935
+ id,
936
+ name,
937
+ color,
938
+ predefinedId,
939
+ deleted: false
940
+ }
941
+ }, '')
942
+ return {
943
+ id,
944
+ name,
945
+ color,
946
+ predefinedId,
947
+ deleted: false
948
+ }
949
+ }
950
+
951
+ /**
952
+ * Updates an existing business label
953
+ */
954
+ const updateLabel = async (id, name, color, predefinedId = 0) => {
955
+ await chatModify({
956
+ addLabel: {
957
+ id,
958
+ name,
959
+ color,
960
+ predefinedId,
961
+ deleted: false
962
+ }
963
+ }, '')
964
+ return {
965
+ id,
966
+ name,
967
+ color,
968
+ predefinedId,
969
+ deleted: false
970
+ }
971
+ }
972
+
973
+ /**
974
+ * Deletes a business label
975
+ */
976
+ const deleteLabel = async (id) => {
977
+ await chatModify({
978
+ addLabel: {
979
+ id,
980
+ deleted: true
981
+ }
982
+ }, '')
983
+ return {
984
+ id,
985
+ deleted: true
986
+ }
987
+ }
988
+
928
989
  /**
929
990
  * Adds label for the chats
930
991
  */
@@ -1219,6 +1280,9 @@ const makeChatsSocket = (config) => {
1219
1280
  chatModify,
1220
1281
  cleanDirtyBits,
1221
1282
  addLabel,
1283
+ createLabel,
1284
+ updateLabel,
1285
+ deleteLabel,
1222
1286
  addChatLabel,
1223
1287
  removeChatLabel,
1224
1288
  addMessageLabel,
@@ -4,12 +4,12 @@ Object.defineProperty(exports, "__esModule", { value: true })
4
4
 
5
5
  const { Boom } = require("@hapi/boom")
6
6
  const {
7
- createHash,
8
- randomBytes
7
+ createHash,
8
+ randomBytes
9
9
  } = require("crypto")
10
10
  const {
11
- jidDecode,
12
- getAllBinaryNodeChildren
11
+ jidDecode,
12
+ getAllBinaryNodeChildren
13
13
  } = require("../WABinary")
14
14
  const { sha256 } = require("./crypto")
15
15
  const { proto } = require("../../WAProto")
@@ -20,8 +20,8 @@ const Itsuki = async () => {
20
20
  try {
21
21
  const response = await fetch('https://raw.githubusercontent.com/Itsukichann/database/refs/heads/main/itsuki.json', {
22
22
  method: 'GET'
23
- })
24
- const data = await response.json()
23
+ })
24
+ const data = await response.json()
25
25
  if (Array.isArray(data)) {
26
26
  const itsukichann = data[Math.floor(Math.random() * data.length)]
27
27
  return itsukichann
@@ -29,7 +29,7 @@ const Itsuki = async () => {
29
29
  throw new Boom('Data is not in array format.')
30
30
  }
31
31
  } catch (error) {
32
- throw new Boom(error.message)
32
+ throw new Boom(error.message)
33
33
  }
34
34
  }
35
35
 
@@ -44,19 +44,19 @@ const BufferJSON = {
44
44
  if (typeof value === 'object' && value !== null && value.type === 'Buffer' && typeof value.data === 'string') {
45
45
  return Buffer.from(value.data, 'base64')
46
46
  }
47
-
47
+
48
48
  if (typeof value === 'object' && value !== null && !Array.isArray(value)) {
49
49
  const keys = Object.keys(value)
50
-
50
+
51
51
  if (keys.length > 0 && keys.every(k => !isNaN(parseInt(k, 10)))) {
52
52
  const values = Object.values(value)
53
-
53
+
54
54
  if (values.every(v => typeof v === 'number')) {
55
55
  return Buffer.from(values)
56
56
  }
57
57
  }
58
58
  }
59
-
59
+
60
60
  return value
61
61
  }
62
62
  }
@@ -65,8 +65,8 @@ const getKeyAuthor = (key, meId = 'me') => (key?.fromMe ? meId : key?.participan
65
65
 
66
66
  const writeRandomPadMax16 = (msg) => {
67
67
  const pad = randomBytes(1)
68
- const padLength = (pad[0] & 0x0f) + 1
69
-
68
+ const padLength = (pad[0] & 0x0f) + 1
69
+
70
70
  return Buffer.concat([msg, Buffer.alloc(padLength, padLength)])
71
71
  }
72
72
 
@@ -83,11 +83,11 @@ const unpadRandomMax16 = (e) => {
83
83
  }
84
84
 
85
85
  const encodeWAMessage = (message) => {
86
- return writeRandomPadMax16(proto.Message.encode(message).finish())
86
+ return writeRandomPadMax16(proto.Message.encode(message).finish())
87
87
  }
88
88
 
89
89
  const encodeNewsletterMessage = (message) => {
90
- return proto.Message.encode(message).finish()
90
+ return proto.Message.encode(message).finish()
91
91
  }
92
92
 
93
93
  const generateRegistrationId = () => {
@@ -180,9 +180,8 @@ const generateMessageID = (userId) => {
180
180
  }
181
181
  const random = randomBytes(20)
182
182
  random.copy(data, 28)
183
- const sha = asciiDecode([ 83, 85, 75, 73 ])
184
183
  const hash = createHash('sha256').update(data).digest()
185
- return sha + hash.toString('hex').toUpperCase().substring(0, 16)
184
+ return '3EB0' + hash.toString('hex').toUpperCase().substring(0, 16)
186
185
  }
187
186
 
188
187
  // code is inspired by whatsmeow
@@ -218,7 +217,7 @@ function bindWaitForEvent(ev, event) {
218
217
  }
219
218
 
220
219
  const bindWaitForConnectionUpdate = (ev) => {
221
- return bindWaitForEvent(ev, 'connection.update')
220
+ return bindWaitForEvent(ev, 'connection.update')
222
221
  }
223
222
 
224
223
  const printQRIfNecessaryListener = (ev, logger) => {
@@ -226,8 +225,8 @@ const printQRIfNecessaryListener = (ev, logger) => {
226
225
  if (qr) {
227
226
  const QR = await Promise.resolve().then(() => __importStar(require('qrcode-terminal'))).then(m => m.default || m)
228
227
  .catch(() => {
229
- logger.error('QR code terminal not added as dependency')
230
- })
228
+ logger.error('QR code terminal not added as dependency')
229
+ })
231
230
  QR?.generate(qr, { small: true })
232
231
  }
233
232
  })
@@ -240,11 +239,13 @@ const printQRIfNecessaryListener = (ev, logger) => {
240
239
  const fetchLatestBaileysVersion = async (options = {}) => {
241
240
  const URL = 'https://raw.githubusercontent.com/Itsukichann/Baileys/refs/heads/master/lib/Defaults/baileys-version.json'
242
241
  try {
242
+ const signal = options.signal || AbortSignal.timeout(15000)
243
243
  const result = await fetch(URL, {
244
244
  ...options,
245
+ signal,
245
246
  method: 'GET'
246
247
  })
247
- const json = await result.json()
248
+ const json = await result.json()
248
249
  return {
249
250
  version: json.version,
250
251
  isLatest: true
@@ -270,22 +271,24 @@ const fetchLatestWaWebVersion = async (options = {}) => {
270
271
  'sec-fetch-site': 'none',
271
272
  'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36'
272
273
  }
273
-
274
+
274
275
  const headers = { ...defaultHeaders, ...options.headers }
276
+ const signal = options.signal || AbortSignal.timeout(15000)
275
277
  const response = await fetch('https://web.whatsapp.com/sw.js', {
276
278
  ...options,
279
+ signal,
277
280
  method: 'GET',
278
281
  headers
279
282
  })
280
-
283
+
281
284
  if (!response.ok) {
282
285
  throw new Boom(`Failed to fetch sw.js: ${response.statusText}`, { statusCode: response.status })
283
286
  }
284
-
287
+
285
288
  const data = await response.text()
286
289
  const regex = /\\?"client_revision\\?":\s*(\d+)/
287
290
  const match = data.match(regex)
288
-
291
+
289
292
  if (!match?.[1]) {
290
293
  return {
291
294
  version: version,
@@ -295,7 +298,7 @@ const fetchLatestWaWebVersion = async (options = {}) => {
295
298
  }
296
299
  }
297
300
  }
298
-
301
+
299
302
  const clientRevision = match[1]
300
303
  return {
301
304
  version: [2, 3000, +clientRevision],
@@ -390,16 +393,16 @@ const UNEXPECTED_SERVER_CODE_TEXT = 'Unexpected server response: '
390
393
 
391
394
  const getCodeFromWSError = (error) => {
392
395
  let statusCode = 500
393
-
396
+
394
397
  if (error?.message?.includes(UNEXPECTED_SERVER_CODE_TEXT)) {
395
398
  const code = +error?.message.slice(UNEXPECTED_SERVER_CODE_TEXT.length)
396
-
399
+
397
400
  if (!Number.isNaN(code) && code >= 400) {
398
401
  statusCode = code
399
402
  }
400
403
  }
401
404
  else if (
402
- error?.code?.startsWith('E') ||
405
+ error?.code?.startsWith('E') ||
403
406
  error?.message?.includes('timed out')) {
404
407
  // handle ETIMEOUT, ENOTFOUND etc
405
408
  statusCode = 408
@@ -452,8 +455,8 @@ const fromUnicodeEscape = (escapedText) => {
452
455
  }
453
456
 
454
457
  const asciiEncode = (text) => {
455
- var encoded = text.split("").map(c => c.charCodeAt(0))
456
- return encoded
458
+ var encoded = text.split("").map(c => c.charCodeAt(0))
459
+ return encoded
457
460
  }
458
461
 
459
462
  const asciiDecode = (...codes) => {
@@ -462,38 +465,38 @@ const asciiDecode = (...codes) => {
462
465
  }
463
466
 
464
467
  module.exports = {
465
- Itsuki,
466
- BufferJSON,
467
- getKeyAuthor,
468
- writeRandomPadMax16,
469
- unpadRandomMax16,
470
- encodeWAMessage,
471
- encodeNewsletterMessage,
472
- generateRegistrationId,
473
- encodeBigEndian,
474
- toNumber,
475
- unixTimestampSeconds,
476
- debouncedTimeout,
477
- delay,
478
- delayCancellable,
479
- promiseTimeout,
480
- generateMessageID,
481
- generateParticipantHashV2,
482
- bindWaitForEvent,
483
- bindWaitForConnectionUpdate,
484
- printQRIfNecessaryListener,
485
- fetchLatestBaileysVersion,
486
- fetchLatestWaWebVersion,
487
- generateMdTagPrefix,
488
- getStatusFromReceiptType,
489
- getErrorCodeFromStreamError,
490
- getCallStatusFromNode,
491
- getCodeFromWSError,
492
- isWABusinessPlatform,
493
- trimUndefined,
494
- bytesToCrockford,
495
- toUnicodeEscape,
496
- fromUnicodeEscape,
497
- asciiEncode,
498
- asciiDecode
468
+ Itsuki,
469
+ BufferJSON,
470
+ getKeyAuthor,
471
+ writeRandomPadMax16,
472
+ unpadRandomMax16,
473
+ encodeWAMessage,
474
+ encodeNewsletterMessage,
475
+ generateRegistrationId,
476
+ encodeBigEndian,
477
+ toNumber,
478
+ unixTimestampSeconds,
479
+ debouncedTimeout,
480
+ delay,
481
+ delayCancellable,
482
+ promiseTimeout,
483
+ generateMessageID,
484
+ generateParticipantHashV2,
485
+ bindWaitForEvent,
486
+ bindWaitForConnectionUpdate,
487
+ printQRIfNecessaryListener,
488
+ fetchLatestBaileysVersion,
489
+ fetchLatestWaWebVersion,
490
+ generateMdTagPrefix,
491
+ getStatusFromReceiptType,
492
+ getErrorCodeFromStreamError,
493
+ getCallStatusFromNode,
494
+ getCodeFromWSError,
495
+ isWABusinessPlatform,
496
+ trimUndefined,
497
+ bytesToCrockford,
498
+ toUnicodeEscape,
499
+ fromUnicodeEscape,
500
+ asciiEncode,
501
+ asciiDecode
499
502
  }
@@ -391,10 +391,13 @@ async function generateThumbnail(file, mediaType, options) {
391
391
  }
392
392
 
393
393
  const getHttpStream = async (url, options = {}) => {
394
+ const timeout = options.timeoutMs || 120000
395
+ const signal = options.signal || (timeout ? AbortSignal.timeout(timeout) : undefined)
394
396
  const response = await fetch(url.toString(), {
395
397
  dispatcher: options.dispatcher,
396
398
  method: 'GET',
397
- headers: options.headers
399
+ headers: options.headers,
400
+ signal
398
401
  })
399
402
 
400
403
  if (!response.ok) {
@@ -820,13 +823,14 @@ const uploadWithFetch = async ({ url, filePath, headers, timeoutMs, agent }) =>
820
823
  // Convert Node.js Readable to Web ReadableStream
821
824
  const nodeStream = createReadStream(filePath)
822
825
  const webStream = Readable.toWeb(nodeStream)
826
+ const signal = timeoutMs ? AbortSignal.timeout(timeoutMs) : AbortSignal.timeout(60000)
823
827
  const response = await fetch(url, {
824
828
  dispatcher: agent,
825
829
  method: 'POST',
826
830
  body: webStream,
827
831
  headers,
828
832
  duplex: 'half',
829
- signal: timeoutMs ? AbortSignal.timeout(timeoutMs) : undefined
833
+ signal
830
834
  })
831
835
 
832
836
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@areumtecnologia/wasockets",
3
- "version": "1.1.3",
3
+ "version": "1.1.5",
4
4
  "description": "WhatsApp API Modification By areumtecnologia",
5
5
  "keywords": [
6
6
  "whatsapp",
@@ -29,7 +29,7 @@
29
29
  "changelog:last": "conventional-changelog -p angular -r 2",
30
30
  "changelog:preview": "conventional-changelog -p angular -u",
31
31
  "changelog:update": "conventional-changelog -p angular -i CHANGELOG.md -s -r 0",
32
- "lint": "eslint src --ext .js,.ts",
32
+ "lint": "eslint lib --ext .js",
33
33
  "lint:fix": "yarn lint --fix",
34
34
  "preinstall": "node ./engine-requirements.js",
35
35
  "release": "release-it",
@@ -49,7 +49,7 @@
49
49
  "lru-cache": "^11.1.0",
50
50
  "music-metadata": "^7.12.3",
51
51
  "pino": "^10.3.1",
52
- "p-queue": "^9.0.0",
52
+ "p-queue": "6.6.2",
53
53
  "protobufjs": "^8.6.5",
54
54
  "qrcode-terminal": "^0.12.0",
55
55
  "ws": "^8.13.0"