@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.
Files changed (31) hide show
  1. package/README.md +98 -25
  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 +213 -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 +99 -0
  26. package/lib/Client/Normalizers/JidNormalizer.js +96 -0
  27. package/lib/Client/Normalizers/MessageNormalizer.js +422 -0
  28. package/lib/Client/WaClient.js +438 -0
  29. package/lib/Client/index.d.ts +547 -0
  30. package/lib/Client/index.js +76 -0
  31. package/package.json +29 -23
@@ -0,0 +1,92 @@
1
+ "use strict"
2
+
3
+ Object.defineProperty(exports, "__esModule", { value: true })
4
+
5
+ const { JidNormalizer } = require("../Normalizers/JidNormalizer")
6
+
7
+ class ProfileManager {
8
+ /**
9
+ * @param {import('../WaClient').WaClient} client
10
+ */
11
+ constructor(client) {
12
+ this.client = client
13
+ }
14
+
15
+ _getSock() {
16
+ if (!this.client.sock) {
17
+ throw new Error('Socket is not connected.')
18
+ }
19
+ return this.client.sock
20
+ }
21
+
22
+ /**
23
+ * Atualiza o nome de exibição (pushName) do bot
24
+ * @param {string} name
25
+ */
26
+ async updateName(name) {
27
+ const sock = this._getSock()
28
+ return sock.updateProfileName(name)
29
+ }
30
+
31
+ /**
32
+ * Atualiza o recado / status de texto da conta
33
+ * @param {string} aboutText
34
+ */
35
+ async updateAbout(aboutText) {
36
+ const sock = this._getSock()
37
+ return sock.updateProfileStatus(aboutText)
38
+ }
39
+
40
+ /**
41
+ * Obtém o recado de um contato ou da própria conta
42
+ * @param {string} [jid]
43
+ */
44
+ async getAbout(jid) {
45
+ const sock = this._getSock()
46
+ const targetJid = jid ? JidNormalizer.toJid(jid) : sock.user?.id
47
+ return sock.fetchStatus(targetJid)
48
+ }
49
+
50
+ /**
51
+ * Atualiza a foto de perfil da conta ou de um grupo
52
+ * @param {string} jidOrSelf - 'me' ou JID
53
+ * @param {string|Buffer|Object} imageSource
54
+ */
55
+ async updatePicture(jidOrSelf, imageSource) {
56
+ const sock = this._getSock()
57
+ const isSelf = !jidOrSelf || jidOrSelf === 'me'
58
+ const targetJid = isSelf ? sock.user?.id : JidNormalizer.toJid(jidOrSelf)
59
+ const content = typeof imageSource === 'string' ? { url: imageSource } : imageSource
60
+ return sock.updateProfilePicture(targetJid, content)
61
+ }
62
+
63
+ /**
64
+ * Remove a foto de perfil
65
+ * @param {string} [jidOrSelf]
66
+ */
67
+ async removePicture(jidOrSelf) {
68
+ const sock = this._getSock()
69
+ const isSelf = !jidOrSelf || jidOrSelf === 'me'
70
+ const targetJid = isSelf ? sock.user?.id : JidNormalizer.toJid(jidOrSelf)
71
+ return sock.removeProfilePicture(targetJid)
72
+ }
73
+
74
+ /**
75
+ * Obtém a URL da foto de perfil
76
+ * @param {string} jid
77
+ * @param {boolean} [highRes=true] - Se true, busca imagem em alta resolução
78
+ * @returns {Promise<string|null>}
79
+ */
80
+ async getPictureUrl(jid, highRes = true) {
81
+ const sock = this._getSock()
82
+ const targetJid = JidNormalizer.toJid(jid)
83
+ try {
84
+ return await sock.profilePictureUrl(targetJid, highRes ? 'image' : 'preview')
85
+ } catch {
86
+ return null
87
+ }
88
+ }
89
+ }
90
+
91
+ exports.ProfileManager = ProfileManager
92
+ exports.default = ProfileManager
@@ -0,0 +1,92 @@
1
+ "use strict"
2
+
3
+ Object.defineProperty(exports, "__esModule", { value: true })
4
+
5
+ const { JidNormalizer } = require("../Normalizers/JidNormalizer")
6
+
7
+ class UserManager {
8
+ /**
9
+ * @param {import('../WaClient').WaClient} client
10
+ */
11
+ constructor(client) {
12
+ this.client = client
13
+ }
14
+
15
+ _getSock() {
16
+ if (!this.client.sock) {
17
+ throw new Error('Socket is not connected.')
18
+ }
19
+ return this.client.sock
20
+ }
21
+
22
+ /**
23
+ * Verifica se um número ou JID existe no WhatsApp
24
+ * @param {string} phoneOrJid
25
+ * @returns {Promise<{ exists: boolean, jid: string } | null>}
26
+ */
27
+ async isOnWhatsApp(phoneOrJid) {
28
+ return this.client.isOnWhatsApp(phoneOrJid)
29
+ }
30
+
31
+ /**
32
+ * Resolve um JID de forma transparente para PN ou LID
33
+ * @param {string} jidOrPhone
34
+ * @param {boolean} [fetchIfMissing=false]
35
+ * @returns {Promise<string>} JID canônico resolvido
36
+ */
37
+ async resolveJid(jidOrPhone, fetchIfMissing = false) {
38
+ const sock = this._getSock()
39
+ if (sock.resolveJid) {
40
+ return sock.resolveJid(jidOrPhone, fetchIfMissing)
41
+ }
42
+ return JidNormalizer.toJid(jidOrPhone)
43
+ }
44
+
45
+ /**
46
+ * Converte um identificador LID (@lid) para o número de telefone (@s.whatsapp.net)
47
+ * @param {string} lidJid
48
+ * @param {boolean} [fetchIfMissing=false]
49
+ * @returns {Promise<string|null>} Telefone no formato JID
50
+ */
51
+ async getPnForLid(lidJid, fetchIfMissing = false) {
52
+ const sock = this._getSock()
53
+ if (sock.toPn) {
54
+ return sock.toPn(lidJid, fetchIfMissing)
55
+ }
56
+ return null
57
+ }
58
+
59
+ /**
60
+ * Converte um telefone (@s.whatsapp.net) para seu LID (@lid) correspondente
61
+ * @param {string} pnJid
62
+ * @param {boolean} [fetchIfMissing=false]
63
+ * @returns {Promise<string|null>} LID no formato JID
64
+ */
65
+ async getLidForPn(pnJid, fetchIfMissing = false) {
66
+ const sock = this._getSock()
67
+ if (sock.toLid) {
68
+ return sock.toLid(pnJid, fetchIfMissing)
69
+ }
70
+ return null
71
+ }
72
+
73
+ /**
74
+ * Obtém o perfil comercial de uma conta WhatsApp Business
75
+ * @param {string} jid
76
+ */
77
+ async getBusinessProfile(jid) {
78
+ const sock = this._getSock()
79
+ const targetJid = JidNormalizer.toJid(jid)
80
+ if (!sock.getBusinessProfile) {
81
+ return null
82
+ }
83
+ try {
84
+ return await sock.getBusinessProfile(targetJid)
85
+ } catch {
86
+ return null
87
+ }
88
+ }
89
+ }
90
+
91
+ exports.UserManager = UserManager
92
+ exports.default = UserManager
@@ -0,0 +1,117 @@
1
+ "use strict"
2
+
3
+ Object.defineProperty(exports, "__esModule", { value: true })
4
+
5
+ const { JidNormalizer } = require("../Normalizers/JidNormalizer")
6
+ const { CallContext } = require("../Context/CallContext")
7
+
8
+ class VoipManager {
9
+ /**
10
+ * @param {import('../WaClient').WaClient} client
11
+ */
12
+ constructor(client) {
13
+ this.client = client
14
+ }
15
+
16
+ _getSock() {
17
+ if (!this.client.sock) {
18
+ throw new Error('Socket is not connected.')
19
+ }
20
+ return this.client.sock
21
+ }
22
+
23
+ /**
24
+ * Realiza uma chamada de voz WhatsApp via WebAssembly
25
+ * @param {string} phoneNumber - Telefone ou JID de destino
26
+ * @param {Object} [options={}]
27
+ * @returns {Promise<CallContext>}
28
+ */
29
+ async call(phoneNumber, options = {}) {
30
+ const sock = this._getSock()
31
+ if (!sock.call) {
32
+ throw new Error('VoIP engine is not enabled in this WaSockets build.')
33
+ }
34
+ const cleanNumber = JidNormalizer.toPhoneNumber(phoneNumber) || phoneNumber
35
+ const activeCall = await sock.call(cleanNumber, { ...options, isVideo: false })
36
+ return new CallContext(this.client, {
37
+ id: activeCall.callId,
38
+ from: cleanNumber,
39
+ isVideo: false,
40
+ status: 'calling'
41
+ }, activeCall)
42
+ }
43
+
44
+ /**
45
+ * Realiza uma chamada de vídeo WhatsApp
46
+ * @param {string} phoneNumber
47
+ * @param {Object} [options={}]
48
+ * @returns {Promise<CallContext>}
49
+ */
50
+ async callVideo(phoneNumber, options = {}) {
51
+ const sock = this._getSock()
52
+ if (!sock.callVideo && !sock.call) {
53
+ throw new Error('VoIP engine is not enabled in this WaSockets build.')
54
+ }
55
+ const cleanNumber = JidNormalizer.toPhoneNumber(phoneNumber) || phoneNumber
56
+ const fn = sock.callVideo ? sock.callVideo.bind(sock) : (num, opts) => sock.call(num, { ...opts, isVideo: true })
57
+ const activeCall = await fn(cleanNumber, options)
58
+ return new CallContext(this.client, {
59
+ id: activeCall.callId,
60
+ from: cleanNumber,
61
+ isVideo: true,
62
+ status: 'calling'
63
+ }, activeCall)
64
+ }
65
+
66
+ /**
67
+ * Retorna a chamada ativa no momento ou null
68
+ * @returns {CallContext|null}
69
+ */
70
+ get activeCall() {
71
+ const sock = this.client.sock
72
+ const rawCall = sock?.activeCall
73
+ if (!rawCall) return null
74
+
75
+ return new CallContext(this.client, {
76
+ id: rawCall.callId,
77
+ from: rawCall.target,
78
+ isVideo: Boolean(rawCall.isVideo),
79
+ status: rawCall.state || 'active'
80
+ }, rawCall.instance || rawCall)
81
+ }
82
+
83
+ /**
84
+ * Limpa o estado da chamada ativa atual
85
+ */
86
+ clearActiveCall() {
87
+ const sock = this.client.sock
88
+ if (sock?.clearActiveCall) {
89
+ sock.clearActiveCall()
90
+ }
91
+ }
92
+
93
+ /**
94
+ * Atende uma chamada recebida diretamente pelo ID
95
+ * @param {string} callId
96
+ * @param {string} from
97
+ * @param {Object} [options={}]
98
+ */
99
+ async acceptCall(callId, from, options = {}) {
100
+ const ctx = new CallContext(this.client, { id: callId, from, isVideo: options.isVideo })
101
+ return ctx.accept(options)
102
+ }
103
+
104
+ /**
105
+ * Rejeita uma chamada recebida
106
+ * @param {string} callId
107
+ * @param {string} from
108
+ * @param {number|string} [reason=0]
109
+ */
110
+ async rejectCall(callId, from, reason = 0) {
111
+ const ctx = new CallContext(this.client, { id: callId, from })
112
+ return ctx.reject(reason)
113
+ }
114
+ }
115
+
116
+ exports.VoipManager = VoipManager
117
+ exports.default = VoipManager
@@ -0,0 +1,29 @@
1
+ "use strict"
2
+
3
+ Object.defineProperty(exports, "__esModule", { value: true })
4
+
5
+ const { MessageManager } = require("./MessageManager")
6
+ const { GroupManager } = require("./GroupManager")
7
+ const { ChannelManager } = require("./ChannelManager")
8
+ const { PresenceManager } = require("./PresenceManager")
9
+ const { ProfileManager } = require("./ProfileManager")
10
+ const { PrivacyManager } = require("./PrivacyManager")
11
+ const { UserManager } = require("./UserManager")
12
+ const { ChatManager } = require("./ChatManager")
13
+ const { VoipManager } = require("./VoipManager")
14
+ const { BusinessManager } = require("./BusinessManager")
15
+ const { CommunityManager } = require("./CommunityManager")
16
+ const { LabelManager } = require("./LabelManager")
17
+
18
+ exports.MessageManager = MessageManager
19
+ exports.GroupManager = GroupManager
20
+ exports.ChannelManager = ChannelManager
21
+ exports.PresenceManager = PresenceManager
22
+ exports.ProfileManager = ProfileManager
23
+ exports.PrivacyManager = PrivacyManager
24
+ exports.UserManager = UserManager
25
+ exports.ChatManager = ChatManager
26
+ exports.VoipManager = VoipManager
27
+ exports.BusinessManager = BusinessManager
28
+ exports.CommunityManager = CommunityManager
29
+ exports.LabelManager = LabelManager
@@ -0,0 +1,99 @@
1
+ "use strict"
2
+
3
+ Object.defineProperty(exports, "__esModule", { value: true })
4
+
5
+ const { Events } = require("../Constants")
6
+ const { MessageContext } = require("../Context/MessageContext")
7
+ const { CallContext } = require("../Context/CallContext")
8
+
9
+ class EventNormalizer {
10
+ /**
11
+ * Binds low-level socket events and maps them to semantic WaClient events
12
+ * @param {import('../WaClient').WaClient} client
13
+ */
14
+ static bindSocketEvents(client) {
15
+ const sock = client.sock
16
+ if (!sock || !sock.ev) return
17
+
18
+ // 1. Message reception and outgoing events
19
+ sock.ev.on('messages.upsert', async ({ messages, type }) => {
20
+ if (!Array.isArray(messages)) return
21
+
22
+ for (const rawMsg of messages) {
23
+ // Ignore stub or protocol messages if completely empty
24
+ if (!rawMsg.message && !rawMsg.messageStubType) continue
25
+
26
+ // Handle protocol revoke messages explicitly
27
+ const isRevoke = rawMsg.message?.protocolMessage?.type === 0
28
+ if (isRevoke) {
29
+ client.emit(Events.MESSAGE_DELETE, {
30
+ keys: [rawMsg.message.protocolMessage.key || rawMsg.key]
31
+ })
32
+ }
33
+
34
+ const ctx = new MessageContext(client, rawMsg)
35
+
36
+ if (ctx.isFromMe) {
37
+ client.emit(Events.MESSAGE_SENT, ctx, rawMsg)
38
+ } else {
39
+ client.emit(Events.MESSAGE_RECEIVED, ctx, rawMsg)
40
+ }
41
+
42
+ // If message is an edit, also notify on MESSAGE_UPDATE
43
+ if (ctx.isEdited) {
44
+ client.emit(Events.MESSAGE_UPDATE, [{
45
+ key: ctx.raw.key,
46
+ update: { message: ctx.raw.message },
47
+ ctx
48
+ }])
49
+ }
50
+ }
51
+ })
52
+
53
+ // 2. Message updates (reactions, poll updates, edits, delivery/read receipts)
54
+ sock.ev.on('messages.update', (updates) => {
55
+ client.emit(Events.MESSAGE_UPDATE, updates)
56
+ })
57
+
58
+ // 3. Message deletion (revoke)
59
+ sock.ev.on('messages.delete', (item) => {
60
+ client.emit(Events.MESSAGE_DELETE, item)
61
+ })
62
+
63
+ // 4. Presence updates (typing, online, offline)
64
+ sock.ev.on('presence.update', (presence) => {
65
+ client.emit(Events.PRESENCE_UPDATE, presence)
66
+ })
67
+
68
+ // 5. Contacts upsert
69
+ sock.ev.on('contacts.upsert', (contacts) => {
70
+ client.emit(Events.CONTACTS_UPSERT, contacts)
71
+ })
72
+
73
+ // 6. Group participants updates (join, leave, promote, demote)
74
+ sock.ev.on('group-participants.update', (update) => {
75
+ client.emit(Events.GROUP_PARTICIPANTS_UPDATE, update)
76
+ })
77
+
78
+ // 7. VoIP incoming calls & status
79
+ sock.ev.on('call.received', (incomingCall) => {
80
+ const callCtx = new CallContext(client, incomingCall)
81
+ client.emit(Events.CALL_INCOMING, callCtx)
82
+ })
83
+
84
+ sock.ev.on('call', (calls) => {
85
+ client.emit(Events.CALL_STATUS, calls)
86
+ if (Array.isArray(calls)) {
87
+ for (const call of calls) {
88
+ if (call.status === 'offer') {
89
+ const callCtx = new CallContext(client, call)
90
+ client.emit(Events.CALL_INCOMING, callCtx)
91
+ }
92
+ }
93
+ }
94
+ })
95
+ }
96
+ }
97
+
98
+ exports.EventNormalizer = EventNormalizer
99
+ exports.default = EventNormalizer
@@ -0,0 +1,96 @@
1
+ "use strict"
2
+
3
+ Object.defineProperty(exports, "__esModule", { value: true })
4
+
5
+ class JidNormalizer {
6
+ /**
7
+ * Sanitizes and normalizes any phone number or JID string into a canonical JID,
8
+ * stripping device specifiers (e.g., ":1@s.whatsapp.net" -> "@s.whatsapp.net")
9
+ * @param {string} input - Phone number (e.g., "+55 (11) 99999-9999") or existing JID
10
+ * @returns {string} Normalized JID (e.g., "5511999999999@s.whatsapp.net")
11
+ */
12
+ static toJid(input) {
13
+ if (!input || typeof input !== 'string') return ''
14
+ const cleaned = input.trim()
15
+
16
+ if (cleaned.includes('@')) {
17
+ const [userPart, server] = cleaned.split('@')
18
+ const cleanUser = userPart.split(':')[0]
19
+ return `${cleanUser}@${server}`
20
+ }
21
+
22
+ const digits = cleaned.replace(/\D/g, '')
23
+ if (!digits) return ''
24
+
25
+ return `${digits}@s.whatsapp.net`
26
+ }
27
+
28
+ /**
29
+ * Extracts pure numeric phone number from a JID
30
+ * @param {string} jid - WhatsApp JID
31
+ * @returns {string} Extracted phone number or empty string
32
+ */
33
+ static toPhoneNumber(jid) {
34
+ if (!jid || typeof jid !== 'string') return ''
35
+ const base = jid.split('@')[0]
36
+ const withoutDevice = base.split(':')[0]
37
+ return withoutDevice.replace(/\D/g, '')
38
+ }
39
+
40
+ /**
41
+ * Checks if JID represents a WhatsApp Group
42
+ * @param {string} jid
43
+ * @returns {boolean}
44
+ */
45
+ static isGroup(jid) {
46
+ return typeof jid === 'string' && jid.endsWith('@g.us')
47
+ }
48
+
49
+ /**
50
+ * Checks if JID represents a WhatsApp Channel / Newsletter
51
+ * @param {string} jid
52
+ * @returns {boolean}
53
+ */
54
+ static isNewsletter(jid) {
55
+ return typeof jid === 'string' && jid.endsWith('@newsletter')
56
+ }
57
+
58
+ /**
59
+ * Checks if JID is an internal LID (Linked Identity)
60
+ * @param {string} jid
61
+ * @returns {boolean}
62
+ */
63
+ static isLid(jid) {
64
+ return typeof jid === 'string' && jid.endsWith('@lid')
65
+ }
66
+
67
+ /**
68
+ * Checks if JID is a regular user chat (Phone Number based)
69
+ * @param {string} jid
70
+ * @returns {boolean}
71
+ */
72
+ static isUser(jid) {
73
+ return typeof jid === 'string' && jid.endsWith('@s.whatsapp.net')
74
+ }
75
+
76
+ /**
77
+ * Checks if JID represents WhatsApp Status Broadcast
78
+ * @param {string} jid
79
+ * @returns {boolean}
80
+ */
81
+ static isStatusBroadcast(jid) {
82
+ return typeof jid === 'string' && jid === 'status@broadcast'
83
+ }
84
+
85
+ /**
86
+ * Checks if JID represents any Broadcast list
87
+ * @param {string} jid
88
+ * @returns {boolean}
89
+ */
90
+ static isBroadcast(jid) {
91
+ return typeof jid === 'string' && jid.endsWith('@broadcast')
92
+ }
93
+ }
94
+
95
+ exports.JidNormalizer = JidNormalizer
96
+ exports.default = JidNormalizer