@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.
- package/README.md +74 -16
- package/lib/Client/Builders/Buttons.js +127 -0
- package/lib/Client/Builders/EventBuilder.js +122 -0
- package/lib/Client/Builders/InteractiveMessage.js +150 -0
- package/lib/Client/Builders/Lists.js +78 -0
- package/lib/Client/Builders/PollBuilder.js +84 -0
- package/lib/Client/Builders/index.js +21 -0
- package/lib/Client/Constants.js +54 -0
- package/lib/Client/Context/CallContext.js +96 -0
- package/lib/Client/Context/MediaObject.js +155 -0
- package/lib/Client/Context/MessageContext.js +146 -0
- package/lib/Client/Modules/BusinessManager.js +155 -0
- package/lib/Client/Modules/ChannelManager.js +144 -0
- package/lib/Client/Modules/ChatManager.js +113 -0
- package/lib/Client/Modules/CommunityManager.js +136 -0
- package/lib/Client/Modules/GroupManager.js +194 -0
- package/lib/Client/Modules/LabelManager.js +123 -0
- package/lib/Client/Modules/MessageManager.js +198 -0
- package/lib/Client/Modules/PresenceManager.js +68 -0
- package/lib/Client/Modules/PrivacyManager.js +98 -0
- package/lib/Client/Modules/ProfileManager.js +92 -0
- package/lib/Client/Modules/UserManager.js +92 -0
- package/lib/Client/Modules/VoipManager.js +117 -0
- package/lib/Client/Modules/index.js +29 -0
- package/lib/Client/Normalizers/EventNormalizer.js +82 -0
- package/lib/Client/Normalizers/JidNormalizer.js +93 -0
- package/lib/Client/Normalizers/MessageNormalizer.js +134 -0
- package/lib/Client/WaClient.js +438 -0
- package/lib/Client/index.d.ts +464 -0
- package/lib/Client/index.js +76 -0
- package/package.json +29 -23
|
@@ -0,0 +1,82 @@
|
|
|
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 empty
|
|
24
|
+
if (!rawMsg.message && !rawMsg.messageStubType) continue
|
|
25
|
+
|
|
26
|
+
const ctx = new MessageContext(client, rawMsg)
|
|
27
|
+
|
|
28
|
+
if (ctx.isFromMe) {
|
|
29
|
+
client.emit(Events.MESSAGE_SENT, ctx, rawMsg)
|
|
30
|
+
} else {
|
|
31
|
+
client.emit(Events.MESSAGE_RECEIVED, ctx, rawMsg)
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
// 2. Message updates (reactions, poll updates, edits, delivery/read receipts)
|
|
37
|
+
sock.ev.on('messages.update', (updates) => {
|
|
38
|
+
client.emit(Events.MESSAGE_UPDATE, updates)
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
// 3. Message deletion (revoke)
|
|
42
|
+
sock.ev.on('messages.delete', (item) => {
|
|
43
|
+
client.emit(Events.MESSAGE_DELETE, item)
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
// 4. Presence updates (typing, online, offline)
|
|
47
|
+
sock.ev.on('presence.update', (presence) => {
|
|
48
|
+
client.emit(Events.PRESENCE_UPDATE, presence)
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
// 5. Contacts upsert
|
|
52
|
+
sock.ev.on('contacts.upsert', (contacts) => {
|
|
53
|
+
client.emit(Events.CONTACTS_UPSERT, contacts)
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
// 6. Group participants updates (join, leave, promote, demote)
|
|
57
|
+
sock.ev.on('group-participants.update', (update) => {
|
|
58
|
+
client.emit(Events.GROUP_PARTICIPANTS_UPDATE, update)
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
// 7. VoIP incoming calls & status
|
|
62
|
+
sock.ev.on('call.received', (incomingCall) => {
|
|
63
|
+
const callCtx = new CallContext(client, incomingCall)
|
|
64
|
+
client.emit(Events.CALL_INCOMING, callCtx)
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
sock.ev.on('call', (calls) => {
|
|
68
|
+
client.emit(Events.CALL_STATUS, calls)
|
|
69
|
+
if (Array.isArray(calls)) {
|
|
70
|
+
for (const call of calls) {
|
|
71
|
+
if (call.status === 'offer') {
|
|
72
|
+
const callCtx = new CallContext(client, call)
|
|
73
|
+
client.emit(Events.CALL_INCOMING, callCtx)
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
})
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
exports.EventNormalizer = EventNormalizer
|
|
82
|
+
exports.default = EventNormalizer
|
|
@@ -0,0 +1,93 @@
|
|
|
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
|
+
* @param {string} input - Phone number (e.g., "+55 (11) 99999-9999") or existing JID
|
|
9
|
+
* @returns {string} Normalized JID (e.g., "5511999999999@s.whatsapp.net")
|
|
10
|
+
*/
|
|
11
|
+
static toJid(input) {
|
|
12
|
+
if (!input || typeof input !== 'string') return ''
|
|
13
|
+
const cleaned = input.trim()
|
|
14
|
+
|
|
15
|
+
if (cleaned.includes('@')) {
|
|
16
|
+
return cleaned
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const digits = cleaned.replace(/\D/g, '')
|
|
20
|
+
if (!digits) return ''
|
|
21
|
+
|
|
22
|
+
return `${digits}@s.whatsapp.net`
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Extracts pure numeric phone number from a JID
|
|
27
|
+
* @param {string} jid - WhatsApp JID
|
|
28
|
+
* @returns {string} Extracted phone number or empty string
|
|
29
|
+
*/
|
|
30
|
+
static toPhoneNumber(jid) {
|
|
31
|
+
if (!jid || typeof jid !== 'string') return ''
|
|
32
|
+
const base = jid.split('@')[0]
|
|
33
|
+
const withoutDevice = base.split(':')[0]
|
|
34
|
+
return withoutDevice.replace(/\D/g, '')
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Checks if JID represents a WhatsApp Group
|
|
39
|
+
* @param {string} jid
|
|
40
|
+
* @returns {boolean}
|
|
41
|
+
*/
|
|
42
|
+
static isGroup(jid) {
|
|
43
|
+
return typeof jid === 'string' && jid.endsWith('@g.us')
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Checks if JID represents a WhatsApp Channel / Newsletter
|
|
48
|
+
* @param {string} jid
|
|
49
|
+
* @returns {boolean}
|
|
50
|
+
*/
|
|
51
|
+
static isNewsletter(jid) {
|
|
52
|
+
return typeof jid === 'string' && jid.endsWith('@newsletter')
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Checks if JID is an internal LID (Linked Identity)
|
|
57
|
+
* @param {string} jid
|
|
58
|
+
* @returns {boolean}
|
|
59
|
+
*/
|
|
60
|
+
static isLid(jid) {
|
|
61
|
+
return typeof jid === 'string' && jid.endsWith('@lid')
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Checks if JID is a regular user chat (Phone Number based)
|
|
66
|
+
* @param {string} jid
|
|
67
|
+
* @returns {boolean}
|
|
68
|
+
*/
|
|
69
|
+
static isUser(jid) {
|
|
70
|
+
return typeof jid === 'string' && jid.endsWith('@s.whatsapp.net')
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Checks if JID represents WhatsApp Status Broadcast
|
|
75
|
+
* @param {string} jid
|
|
76
|
+
* @returns {boolean}
|
|
77
|
+
*/
|
|
78
|
+
static isStatusBroadcast(jid) {
|
|
79
|
+
return typeof jid === 'string' && jid === 'status@broadcast'
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Checks if JID represents any Broadcast list
|
|
84
|
+
* @param {string} jid
|
|
85
|
+
* @returns {boolean}
|
|
86
|
+
*/
|
|
87
|
+
static isBroadcast(jid) {
|
|
88
|
+
return typeof jid === 'string' && jid.endsWith('@broadcast')
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
exports.JidNormalizer = JidNormalizer
|
|
93
|
+
exports.default = JidNormalizer
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
"use strict"
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true })
|
|
4
|
+
|
|
5
|
+
class MessageNormalizer {
|
|
6
|
+
/**
|
|
7
|
+
* Unwraps container wrappers (ephemeral, viewOnce, documentWithCaption, etc.)
|
|
8
|
+
* @param {Object} rawMessageContent - raw message node from proto
|
|
9
|
+
* @returns {Object} Unwrapped message object
|
|
10
|
+
*/
|
|
11
|
+
static unwrapMessage(rawMessageContent) {
|
|
12
|
+
if (!rawMessageContent) return null
|
|
13
|
+
|
|
14
|
+
let msg = rawMessageContent
|
|
15
|
+
while (
|
|
16
|
+
msg.ephemeralMessage ||
|
|
17
|
+
msg.viewOnceMessage ||
|
|
18
|
+
msg.viewOnceMessageV2 ||
|
|
19
|
+
msg.viewOnceMessageV2Extension ||
|
|
20
|
+
msg.documentWithCaptionMessage
|
|
21
|
+
) {
|
|
22
|
+
msg =
|
|
23
|
+
msg.ephemeralMessage?.message ||
|
|
24
|
+
msg.viewOnceMessage?.message ||
|
|
25
|
+
msg.viewOnceMessageV2?.message ||
|
|
26
|
+
msg.viewOnceMessageV2Extension?.message ||
|
|
27
|
+
msg.documentWithCaptionMessage?.message ||
|
|
28
|
+
msg
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return msg
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Identifies the primary content type of the message
|
|
36
|
+
* @param {Object} messageContent - Unwrapped message content
|
|
37
|
+
* @returns {string} Normalized type (e.g., 'text', 'image', 'video', 'audio', etc.)
|
|
38
|
+
*/
|
|
39
|
+
static extractType(messageContent) {
|
|
40
|
+
const msg = this.unwrapMessage(messageContent)
|
|
41
|
+
if (!msg) return 'unknown'
|
|
42
|
+
|
|
43
|
+
if (msg.conversation || msg.extendedTextMessage) return 'text'
|
|
44
|
+
if (msg.imageMessage) return 'image'
|
|
45
|
+
if (msg.videoMessage) return msg.videoMessage.gifPlayback ? 'gif' : 'video'
|
|
46
|
+
if (msg.audioMessage) return msg.audioMessage.ptt ? 'voice' : 'audio'
|
|
47
|
+
if (msg.documentMessage) return 'document'
|
|
48
|
+
if (msg.stickerMessage) return 'sticker'
|
|
49
|
+
if (msg.contactMessage || msg.contactsArrayMessage) return 'contact'
|
|
50
|
+
if (msg.locationMessage || msg.liveLocationMessage) return 'location'
|
|
51
|
+
if (msg.pollCreationMessage || msg.pollCreationMessageV2 || msg.pollCreationMessageV3) return 'poll'
|
|
52
|
+
if (msg.reactionMessage) return 'reaction'
|
|
53
|
+
if (msg.interactiveMessage || msg.interactiveResponseMessage) return 'interactive'
|
|
54
|
+
if (msg.buttonsResponseMessage || msg.templateButtonReplyMessage) return 'button_reply'
|
|
55
|
+
if (msg.listResponseMessage) return 'list_reply'
|
|
56
|
+
if (msg.protocolMessage) return 'protocol'
|
|
57
|
+
|
|
58
|
+
const keys = Object.keys(msg).filter(k => k !== 'messageContextInfo' && k !== 'senderKeyDistributionMessage')
|
|
59
|
+
return keys[0] ? keys[0].replace('Message', '').toLowerCase() : 'unknown'
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Extracts readable text content across diverse message structures
|
|
64
|
+
* @param {Object} messageContent - Unwrapped message content
|
|
65
|
+
* @returns {string} Text body
|
|
66
|
+
*/
|
|
67
|
+
static extractBody(messageContent) {
|
|
68
|
+
const msg = this.unwrapMessage(messageContent)
|
|
69
|
+
if (!msg) return ''
|
|
70
|
+
|
|
71
|
+
if (msg.conversation) return msg.conversation
|
|
72
|
+
if (msg.extendedTextMessage?.text) return msg.extendedTextMessage.text
|
|
73
|
+
if (msg.imageMessage?.caption) return msg.imageMessage.caption
|
|
74
|
+
if (msg.videoMessage?.caption) return msg.videoMessage.caption
|
|
75
|
+
if (msg.documentMessage?.caption) return msg.documentMessage.caption
|
|
76
|
+
if (msg.buttonsResponseMessage?.selectedDisplayText) return msg.buttonsResponseMessage.selectedDisplayText
|
|
77
|
+
if (msg.listResponseMessage?.title) return msg.listResponseMessage.title
|
|
78
|
+
if (msg.templateButtonReplyMessage?.selectedId) return msg.templateButtonReplyMessage.selectedId
|
|
79
|
+
if (msg.interactiveResponseMessage?.nativeFlowResponseMessage?.paramsJson) {
|
|
80
|
+
return msg.interactiveResponseMessage.nativeFlowResponseMessage.paramsJson
|
|
81
|
+
}
|
|
82
|
+
if (msg.pollCreationMessage?.name) return msg.pollCreationMessage.name
|
|
83
|
+
if (msg.pollCreationMessageV2?.name) return msg.pollCreationMessageV2.name
|
|
84
|
+
if (msg.pollCreationMessageV3?.name) return msg.pollCreationMessageV3.name
|
|
85
|
+
if (msg.reactionMessage?.text) return msg.reactionMessage.text
|
|
86
|
+
|
|
87
|
+
return ''
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Extracts media node if present
|
|
92
|
+
* @param {Object} messageContent - Unwrapped message content
|
|
93
|
+
* @returns {Object|null}
|
|
94
|
+
*/
|
|
95
|
+
static extractMediaNode(messageContent) {
|
|
96
|
+
const msg = this.unwrapMessage(messageContent)
|
|
97
|
+
if (!msg) return null
|
|
98
|
+
|
|
99
|
+
return (
|
|
100
|
+
msg.imageMessage ||
|
|
101
|
+
msg.videoMessage ||
|
|
102
|
+
msg.audioMessage ||
|
|
103
|
+
msg.documentMessage ||
|
|
104
|
+
msg.stickerMessage ||
|
|
105
|
+
null
|
|
106
|
+
)
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Extracts quoted message context info
|
|
111
|
+
* @param {Object} messageContent - Unwrapped message content
|
|
112
|
+
* @returns {Object|null}
|
|
113
|
+
*/
|
|
114
|
+
static extractContextInfo(messageContent) {
|
|
115
|
+
const msg = this.unwrapMessage(messageContent)
|
|
116
|
+
if (!msg) return null
|
|
117
|
+
|
|
118
|
+
return (
|
|
119
|
+
msg.extendedTextMessage?.contextInfo ||
|
|
120
|
+
msg.imageMessage?.contextInfo ||
|
|
121
|
+
msg.videoMessage?.contextInfo ||
|
|
122
|
+
msg.audioMessage?.contextInfo ||
|
|
123
|
+
msg.documentMessage?.contextInfo ||
|
|
124
|
+
msg.stickerMessage?.contextInfo ||
|
|
125
|
+
msg.buttonsResponseMessage?.contextInfo ||
|
|
126
|
+
msg.listResponseMessage?.contextInfo ||
|
|
127
|
+
msg.interactiveResponseMessage?.contextInfo ||
|
|
128
|
+
null
|
|
129
|
+
)
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
exports.MessageNormalizer = MessageNormalizer
|
|
134
|
+
exports.default = MessageNormalizer
|