@areumtecnologia/wasockets 1.1.6 → 2.0.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 +742 -34
- package/WAProto/index.d.ts +17 -0
- package/lib/Defaults/connection.js +34 -2
- package/lib/Defaults/index.d.ts +6 -0
- package/lib/Plugins/index.d.ts +33 -0
- package/lib/Plugins/index.js +125 -0
- package/lib/Socket/business.js +33 -0
- package/lib/Socket/chats.js +103 -2
- package/lib/Socket/community.js +126 -69
- package/lib/Socket/groups.js +103 -26
- package/lib/Socket/index.js +27 -3
- package/lib/Socket/messages-send.js +111 -0
- package/lib/Socket/newsletter.js +125 -3
- package/lib/Store/index.d.ts +4 -0
- package/lib/Store/make-in-memory-store.js +294 -25
- package/lib/Types/index.d.ts +199 -0
- package/lib/Utils/index.d.ts +33 -0
- package/lib/Utils/index.js +2 -1
- package/lib/Utils/messages.js +14 -3
- package/lib/Utils/reconnect.js +136 -0
- package/lib/Utils/validate-connection.js +5 -5
- package/lib/WABinary/index.d.ts +17 -0
- package/lib/index.d.ts +274 -0
- package/lib/index.js +1 -0
- package/package.json +19 -5
package/lib/Socket/groups.js
CHANGED
|
@@ -40,8 +40,16 @@ const makeGroupsSocket = (config) => {
|
|
|
40
40
|
}))
|
|
41
41
|
|
|
42
42
|
const groupMetadata = async (jid) => {
|
|
43
|
+
if (config.cachedGroupMetadata) {
|
|
44
|
+
const cached = await config.cachedGroupMetadata(jid)
|
|
45
|
+
if (cached) return cached
|
|
46
|
+
}
|
|
43
47
|
const result = await groupQuery(jid, 'get', [{ tag: 'query', attrs: { request: 'interactive' } }])
|
|
44
|
-
|
|
48
|
+
const metadata = extractGroupMetadata(result)
|
|
49
|
+
if (config.cachedGroupMetadata?.set && metadata) {
|
|
50
|
+
config.cachedGroupMetadata.set(jid, metadata)
|
|
51
|
+
}
|
|
52
|
+
return metadata
|
|
45
53
|
}
|
|
46
54
|
|
|
47
55
|
const groupFetchAllParticipating = async () => {
|
|
@@ -79,6 +87,14 @@ const makeGroupsSocket = (config) => {
|
|
|
79
87
|
}
|
|
80
88
|
}
|
|
81
89
|
|
|
90
|
+
if (config.cachedGroupMetadata?.set) {
|
|
91
|
+
for (const meta of Object.values(data)) {
|
|
92
|
+
if (meta?.id) {
|
|
93
|
+
config.cachedGroupMetadata.set(meta.id, meta)
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
82
98
|
suki.ev.emit('groups.update', Object.values(data))
|
|
83
99
|
return data
|
|
84
100
|
}
|
|
@@ -93,6 +109,31 @@ const makeGroupsSocket = (config) => {
|
|
|
93
109
|
await cleanDirtyBits('groups')
|
|
94
110
|
})
|
|
95
111
|
|
|
112
|
+
const groupRequestParticipantsUpdate = async (jid, participants, action) => {
|
|
113
|
+
const result = await groupQuery(jid, 'set', [{
|
|
114
|
+
tag: 'membership_requests_action',
|
|
115
|
+
attrs: {},
|
|
116
|
+
content: [
|
|
117
|
+
{
|
|
118
|
+
tag: action,
|
|
119
|
+
attrs: {},
|
|
120
|
+
content: participants.map(jid => ({
|
|
121
|
+
tag: 'participant',
|
|
122
|
+
attrs: { jid }
|
|
123
|
+
}))
|
|
124
|
+
}
|
|
125
|
+
]
|
|
126
|
+
}])
|
|
127
|
+
|
|
128
|
+
const node = getBinaryNodeChild(result, 'membership_requests_action')
|
|
129
|
+
const nodeAction = getBinaryNodeChild(node, action)
|
|
130
|
+
const participantsAffected = getBinaryNodeChildren(nodeAction, 'participant')
|
|
131
|
+
|
|
132
|
+
return participantsAffected.map(p => {
|
|
133
|
+
return { status: p.attrs.error || '200', jid: p.attrs.jid }
|
|
134
|
+
})
|
|
135
|
+
}
|
|
136
|
+
|
|
96
137
|
return {
|
|
97
138
|
...suki,
|
|
98
139
|
groupQuery,
|
|
@@ -117,6 +158,7 @@ const makeGroupsSocket = (config) => {
|
|
|
117
158
|
return extractGroupMetadata(result)
|
|
118
159
|
},
|
|
119
160
|
groupLeave: async (id) => {
|
|
161
|
+
config.cachedGroupMetadata?.delete?.(id)
|
|
120
162
|
await groupQuery('@g.us', 'set', [
|
|
121
163
|
{
|
|
122
164
|
tag: 'leave',
|
|
@@ -128,6 +170,7 @@ const makeGroupsSocket = (config) => {
|
|
|
128
170
|
])
|
|
129
171
|
},
|
|
130
172
|
groupUpdateSubject: async (jid, subject) => {
|
|
173
|
+
config.cachedGroupMetadata?.delete?.(jid)
|
|
131
174
|
await groupQuery(jid, 'set', [
|
|
132
175
|
{
|
|
133
176
|
tag: 'subject',
|
|
@@ -149,30 +192,7 @@ const makeGroupsSocket = (config) => {
|
|
|
149
192
|
|
|
150
193
|
return participants.map(v => v.attrs)
|
|
151
194
|
},
|
|
152
|
-
groupRequestParticipantsUpdate
|
|
153
|
-
const result = await groupQuery(jid, 'set', [{
|
|
154
|
-
tag: 'membership_requests_action',
|
|
155
|
-
attrs: {},
|
|
156
|
-
content: [
|
|
157
|
-
{
|
|
158
|
-
tag: action,
|
|
159
|
-
attrs: {},
|
|
160
|
-
content: participants.map(jid => ({
|
|
161
|
-
tag: 'participant',
|
|
162
|
-
attrs: { jid }
|
|
163
|
-
}))
|
|
164
|
-
}
|
|
165
|
-
]
|
|
166
|
-
}])
|
|
167
|
-
|
|
168
|
-
const node = getBinaryNodeChild(result, 'membership_requests_action')
|
|
169
|
-
const nodeAction = getBinaryNodeChild(node, action)
|
|
170
|
-
const participantsAffected = getBinaryNodeChildren(nodeAction, 'participant')
|
|
171
|
-
|
|
172
|
-
return participantsAffected.map(p => {
|
|
173
|
-
return { status: p.attrs.error || '200', jid: p.attrs.jid }
|
|
174
|
-
})
|
|
175
|
-
},
|
|
195
|
+
groupRequestParticipantsUpdate,
|
|
176
196
|
groupParticipantsUpdate: async (jid, participants, action) => {
|
|
177
197
|
const result = await groupQuery(jid, 'set', [
|
|
178
198
|
{
|
|
@@ -187,11 +207,13 @@ const makeGroupsSocket = (config) => {
|
|
|
187
207
|
const node = getBinaryNodeChild(result, action)
|
|
188
208
|
const participantsAffected = getBinaryNodeChildren(node, 'participant')
|
|
189
209
|
|
|
210
|
+
config.cachedGroupMetadata?.delete?.(jid)
|
|
190
211
|
return participantsAffected.map(p => {
|
|
191
212
|
return { status: p.attrs.error || '200', jid: p.attrs.jid, content: p }
|
|
192
213
|
})
|
|
193
214
|
},
|
|
194
215
|
groupUpdateDescription: async (jid, description) => {
|
|
216
|
+
config.cachedGroupMetadata?.delete?.(jid)
|
|
195
217
|
const metadata = await groupMetadata(jid)
|
|
196
218
|
const prev = metadata.descId ? metadata.descId : null
|
|
197
219
|
|
|
@@ -300,13 +322,68 @@ const makeGroupsSocket = (config) => {
|
|
|
300
322
|
await groupQuery(jid, 'set', [content])
|
|
301
323
|
},
|
|
302
324
|
groupSettingUpdate: async (jid, setting) => {
|
|
325
|
+
config.cachedGroupMetadata?.delete?.(jid)
|
|
303
326
|
await groupQuery(jid, 'set', [{ tag: setting, attrs: {} }])
|
|
304
327
|
},
|
|
305
328
|
groupMemberAddMode: async (jid, mode) => {
|
|
329
|
+
config.cachedGroupMetadata?.delete?.(jid)
|
|
306
330
|
await groupQuery(jid, 'set', [{ tag: 'member_add_mode', attrs: {}, content: mode }])
|
|
307
331
|
},
|
|
308
332
|
groupJoinApprovalMode: async (jid, mode) => {
|
|
309
|
-
|
|
333
|
+
config.cachedGroupMetadata?.delete?.(jid)
|
|
334
|
+
const state = (mode === true || mode === 'on') ? 'on' : (mode === false || mode === 'off' ? 'off' : mode)
|
|
335
|
+
await groupQuery(jid, 'set', [{ tag: 'membership_approval_mode', attrs: {}, content: [{ tag: 'group_join', attrs: { state } }] }])
|
|
336
|
+
},
|
|
337
|
+
groupMembershipApprovalMode: async (jid, mode) => {
|
|
338
|
+
const state = (mode === true || mode === 'on') ? 'on' : 'off'
|
|
339
|
+
await groupQuery(jid, 'set', [{ tag: 'membership_approval_mode', attrs: {}, content: [{ tag: 'group_join', attrs: { state } }] }])
|
|
340
|
+
},
|
|
341
|
+
groupApprovePendingParticipants: async (jid, participants) => {
|
|
342
|
+
const list = Array.isArray(participants) ? participants : [participants]
|
|
343
|
+
return groupRequestParticipantsUpdate(jid, list, 'approve')
|
|
344
|
+
},
|
|
345
|
+
groupRejectPendingParticipants: async (jid, participants) => {
|
|
346
|
+
const list = Array.isArray(participants) ? participants : [participants]
|
|
347
|
+
return groupRequestParticipantsUpdate(jid, list, 'reject')
|
|
348
|
+
},
|
|
349
|
+
groupUpdatePermissions: async (jid, policies = {}) => {
|
|
350
|
+
config.cachedGroupMetadata?.delete?.(jid)
|
|
351
|
+
const results = {}
|
|
352
|
+
if (typeof policies.announce === 'boolean') {
|
|
353
|
+
await groupQuery(jid, 'set', [{ tag: policies.announce ? 'announcement' : 'not_announcement', attrs: {} }])
|
|
354
|
+
results.announce = policies.announce
|
|
355
|
+
}
|
|
356
|
+
if (typeof policies.restrict === 'boolean') {
|
|
357
|
+
await groupQuery(jid, 'set', [{ tag: policies.restrict ? 'locked' : 'unlocked', attrs: {} }])
|
|
358
|
+
results.restrict = policies.restrict
|
|
359
|
+
}
|
|
360
|
+
if (policies.memberAddMode) {
|
|
361
|
+
await groupQuery(jid, 'set', [{ tag: 'member_add_mode', attrs: {}, content: policies.memberAddMode }])
|
|
362
|
+
results.memberAddMode = policies.memberAddMode
|
|
363
|
+
}
|
|
364
|
+
if (typeof policies.approvalMode !== 'undefined') {
|
|
365
|
+
const state = (policies.approvalMode === true || policies.approvalMode === 'on') ? 'on' : 'off'
|
|
366
|
+
await groupQuery(jid, 'set', [{ tag: 'membership_approval_mode', attrs: {}, content: [{ tag: 'group_join', attrs: { state } }] }])
|
|
367
|
+
results.approvalMode = state
|
|
368
|
+
}
|
|
369
|
+
if (typeof policies.ephemeral !== 'undefined') {
|
|
370
|
+
const content = policies.ephemeral ?
|
|
371
|
+
{ tag: 'ephemeral', attrs: { expiration: policies.ephemeral.toString() } } :
|
|
372
|
+
{ tag: 'not_ephemeral', attrs: {} }
|
|
373
|
+
await groupQuery(jid, 'set', [content])
|
|
374
|
+
results.ephemeral = policies.ephemeral
|
|
375
|
+
}
|
|
376
|
+
return results
|
|
377
|
+
},
|
|
378
|
+
groupGetAdminJids: async (jid) => {
|
|
379
|
+
const metadata = await groupMetadata(jid)
|
|
380
|
+
return (metadata.participants || [])
|
|
381
|
+
.filter(p => !!p.admin)
|
|
382
|
+
.map(p => p.id)
|
|
383
|
+
},
|
|
384
|
+
groupGetParticipants: async (jid) => {
|
|
385
|
+
const metadata = await groupMetadata(jid)
|
|
386
|
+
return metadata.participants || []
|
|
310
387
|
},
|
|
311
388
|
groupFetchAllParticipating
|
|
312
389
|
}
|
package/lib/Socket/index.js
CHANGED
|
@@ -2,11 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", { value: true })
|
|
4
4
|
|
|
5
|
-
const { DEFAULT_CONNECTION_CONFIG } = require("../Defaults/connection")
|
|
5
|
+
const { DEFAULT_CONNECTION_CONFIG, createGroupMetadataCache } = require("../Defaults/connection")
|
|
6
6
|
const { makeCommunitiesSocket } = require("./community")
|
|
7
|
+
const { PluginManager } = require("../Plugins")
|
|
7
8
|
|
|
8
9
|
// export the last socket layer
|
|
9
|
-
const makeWASocket = (config) => {
|
|
10
|
+
const makeWASocket = (config = {}) => {
|
|
10
11
|
const newConfig = {
|
|
11
12
|
...DEFAULT_CONNECTION_CONFIG,
|
|
12
13
|
...config
|
|
@@ -18,7 +19,30 @@ const makeWASocket = (config) => {
|
|
|
18
19
|
newConfig.shouldSyncHistoryMessage = () => !!newConfig.syncFullHistory
|
|
19
20
|
}
|
|
20
21
|
|
|
21
|
-
|
|
22
|
+
if (!config.cachedGroupMetadata && newConfig.enableGroupCache) {
|
|
23
|
+
newConfig.cachedGroupMetadata = createGroupMetadataCache()
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const sock = makeCommunitiesSocket(newConfig)
|
|
27
|
+
const pluginManager = new PluginManager(sock)
|
|
28
|
+
|
|
29
|
+
sock.plugins = pluginManager
|
|
30
|
+
sock.use = (plugin, options) => {
|
|
31
|
+
pluginManager.use(plugin, options)
|
|
32
|
+
return sock
|
|
33
|
+
}
|
|
34
|
+
sock.registerMiddleware = (hook, fn) => pluginManager.registerMiddleware(hook, fn)
|
|
35
|
+
sock.hasPlugin = (name) => pluginManager.hasPlugin(name)
|
|
36
|
+
sock.listPlugins = () => pluginManager.listPlugins()
|
|
37
|
+
|
|
38
|
+
// Auto-install plugins passed in configuration
|
|
39
|
+
if (Array.isArray(config.plugins)) {
|
|
40
|
+
for (const p of config.plugins) {
|
|
41
|
+
sock.use(p)
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return sock
|
|
22
46
|
}
|
|
23
47
|
|
|
24
48
|
exports.default = makeWASocket
|
|
@@ -105,6 +105,41 @@ const makeMessagesSocket = (config) => {
|
|
|
105
105
|
// Initialize message retry manager if enabled
|
|
106
106
|
const messageRetryManager = enableRecentMessageCache ? new MessageRetryManager(logger, maxMsgRetryCount) : null
|
|
107
107
|
|
|
108
|
+
// Pending message queue for transient disconnections
|
|
109
|
+
const pendingMessagesQueue = []
|
|
110
|
+
let isDrainingQueue = false
|
|
111
|
+
|
|
112
|
+
const drainPendingMessages = async () => {
|
|
113
|
+
if (isDrainingQueue || !pendingMessagesQueue.length) {
|
|
114
|
+
return
|
|
115
|
+
}
|
|
116
|
+
isDrainingQueue = true
|
|
117
|
+
logger.debug({ queueLength: pendingMessagesQueue.length }, 'draining pending messages queue')
|
|
118
|
+
try {
|
|
119
|
+
while (pendingMessagesQueue.length && suki.ws?.isOpen) {
|
|
120
|
+
const item = pendingMessagesQueue.shift()
|
|
121
|
+
if (Date.now() - item.queuedAt > (config.messageQueueTtlMs || 300000)) {
|
|
122
|
+
item.reject(new Boom('Message queue TTL expired', { statusCode: 408 }))
|
|
123
|
+
continue
|
|
124
|
+
}
|
|
125
|
+
try {
|
|
126
|
+
const result = await sendMessage(item.jid, item.content, item.options)
|
|
127
|
+
item.resolve(result)
|
|
128
|
+
} catch (err) {
|
|
129
|
+
item.reject(err)
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
} finally {
|
|
133
|
+
isDrainingQueue = false
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
ev.on('connection.update', ({ connection }) => {
|
|
138
|
+
if (connection === 'open') {
|
|
139
|
+
drainPendingMessages()
|
|
140
|
+
}
|
|
141
|
+
})
|
|
142
|
+
|
|
108
143
|
// Prevent race conditions in Signal session encryption by user
|
|
109
144
|
const encryptionMutex = makeKeyedMutex()
|
|
110
145
|
|
|
@@ -510,6 +545,15 @@ const makeMessagesSocket = (config) => {
|
|
|
510
545
|
return didFetchNewSession
|
|
511
546
|
}
|
|
512
547
|
|
|
548
|
+
const repairSession = async (jid) => {
|
|
549
|
+
logger.info({ jid }, 'repairing Signal session')
|
|
550
|
+
const signalId = signalRepository.jidToSignalProtocolAddress(jid)
|
|
551
|
+
peerSessionsCache.delete(signalId)
|
|
552
|
+
await signalRepository.deleteSession([jid])
|
|
553
|
+
await assertSessions([jid], true)
|
|
554
|
+
logger.info({ jid }, 'signal session repaired successfully')
|
|
555
|
+
}
|
|
556
|
+
|
|
513
557
|
const sendPeerDataOperationMessage = async (pdoMessage) => {
|
|
514
558
|
//TODO: for later, abstract the logic to send a Peer Message instead of just PDO - useful for App State Key Resync with phone
|
|
515
559
|
if (!authState.creds.me?.id) {
|
|
@@ -1395,6 +1439,8 @@ const makeMessagesSocket = (config) => {
|
|
|
1395
1439
|
...suki,
|
|
1396
1440
|
getPrivacyTokens,
|
|
1397
1441
|
assertSessions,
|
|
1442
|
+
repairSession,
|
|
1443
|
+
drainPendingMessages,
|
|
1398
1444
|
profilePictureUrl,
|
|
1399
1445
|
relayMessage,
|
|
1400
1446
|
sendReceipt,
|
|
@@ -1670,7 +1716,50 @@ const makeMessagesSocket = (config) => {
|
|
|
1670
1716
|
edit: eventKey
|
|
1671
1717
|
})
|
|
1672
1718
|
},
|
|
1719
|
+
sendAlbumMessage: async (jid, medias, options = {}) => {
|
|
1720
|
+
return sendMessage(jid, { album: medias }, options)
|
|
1721
|
+
},
|
|
1722
|
+
groupSendMentionAll: async (jid, content, options = {}) => {
|
|
1723
|
+
const metadata = await suki.groupMetadata(jid)
|
|
1724
|
+
let participants = metadata.participants || []
|
|
1725
|
+
if (options.adminsOnly) {
|
|
1726
|
+
participants = participants.filter(p => !!p.admin)
|
|
1727
|
+
}
|
|
1728
|
+
if (options.excludeMe && authState.creds.me?.id) {
|
|
1729
|
+
const myPn = jidNormalizedUser(authState.creds.me.id)
|
|
1730
|
+
participants = participants.filter(p => jidNormalizedUser(p.id) !== myPn && (!p.lid || jidNormalizedUser(p.lid) !== myPn))
|
|
1731
|
+
}
|
|
1732
|
+
const mentionJids = participants.map(p => p.id || p.lid).filter(Boolean)
|
|
1733
|
+
const msgContent = typeof content === 'string' ? { text: content } : { ...content }
|
|
1734
|
+
msgContent.mentions = [...new Set([...(msgContent.mentions || []), ...mentionJids])]
|
|
1735
|
+
return sendMessage(jid, msgContent, options)
|
|
1736
|
+
},
|
|
1673
1737
|
sendMessage: async (jid, content, options = {}) => {
|
|
1738
|
+
if (config.enableMessageQueue && (!suki.ws || !suki.ws.isOpen)) {
|
|
1739
|
+
logger.info({ jid }, 'WebSocket connection not open, queuing message')
|
|
1740
|
+
return new Promise((resolve, reject) => {
|
|
1741
|
+
pendingMessagesQueue.push({
|
|
1742
|
+
jid,
|
|
1743
|
+
content,
|
|
1744
|
+
options,
|
|
1745
|
+
queuedAt: Date.now(),
|
|
1746
|
+
resolve,
|
|
1747
|
+
reject
|
|
1748
|
+
})
|
|
1749
|
+
})
|
|
1750
|
+
}
|
|
1751
|
+
|
|
1752
|
+
const sendContext = { jid, content, options }
|
|
1753
|
+
if (suki.plugins) {
|
|
1754
|
+
const allowed = await suki.plugins.runMiddlewares('beforeSendMessage', sendContext)
|
|
1755
|
+
if (allowed === false) {
|
|
1756
|
+
logger.info({ jid }, 'Message sending cancelled by plugin middleware')
|
|
1757
|
+
return
|
|
1758
|
+
}
|
|
1759
|
+
}
|
|
1760
|
+
content = sendContext.content
|
|
1761
|
+
options = sendContext.options
|
|
1762
|
+
|
|
1674
1763
|
const userJid = authState.creds.me.id
|
|
1675
1764
|
const additionalAttributes = {}
|
|
1676
1765
|
|
|
@@ -1681,6 +1770,24 @@ const makeMessagesSocket = (config) => {
|
|
|
1681
1770
|
}
|
|
1682
1771
|
}
|
|
1683
1772
|
|
|
1773
|
+
if (isJidGroup(jid) && typeof content === 'object' && (content?.mentionAll || options?.mentionAll)) {
|
|
1774
|
+
try {
|
|
1775
|
+
const metadata = await suki.groupMetadata(jid)
|
|
1776
|
+
let participants = metadata.participants || []
|
|
1777
|
+
if (options.adminsOnly || content.adminsOnly) {
|
|
1778
|
+
participants = participants.filter(p => !!p.admin)
|
|
1779
|
+
}
|
|
1780
|
+
if ((options.excludeMe || content.excludeMe) && authState.creds.me?.id) {
|
|
1781
|
+
const myPn = jidNormalizedUser(authState.creds.me.id)
|
|
1782
|
+
participants = participants.filter(p => jidNormalizedUser(p.id) !== myPn && (!p.lid || jidNormalizedUser(p.lid) !== myPn))
|
|
1783
|
+
}
|
|
1784
|
+
const mentionJids = participants.map(p => p.id || p.lid).filter(Boolean)
|
|
1785
|
+
content.mentions = [...new Set([...(content.mentions || []), ...mentionJids])]
|
|
1786
|
+
} catch (err) {
|
|
1787
|
+
logger.warn({ err, jid }, 'Failed to resolve group participants for mentionAll')
|
|
1788
|
+
}
|
|
1789
|
+
}
|
|
1790
|
+
|
|
1684
1791
|
if (typeof content === 'object' &&
|
|
1685
1792
|
'disappearingMessagesInChat' in content &&
|
|
1686
1793
|
typeof content['disappearingMessagesInChat'] !== 'undefined' &&
|
|
@@ -1783,6 +1890,10 @@ const makeMessagesSocket = (config) => {
|
|
|
1783
1890
|
})
|
|
1784
1891
|
}
|
|
1785
1892
|
|
|
1893
|
+
if (suki.plugins) {
|
|
1894
|
+
await suki.plugins.runMiddlewares('afterSendMessage', { jid, content, options, fullMsg })
|
|
1895
|
+
}
|
|
1896
|
+
|
|
1786
1897
|
return fullMsg
|
|
1787
1898
|
}
|
|
1788
1899
|
}
|
package/lib/Socket/newsletter.js
CHANGED
|
@@ -2,12 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", { value: true })
|
|
4
4
|
|
|
5
|
+
const { proto } = require("../../WAProto")
|
|
5
6
|
const {
|
|
6
7
|
QueryIds,
|
|
7
8
|
XWAPaths
|
|
8
9
|
} = require("../Types")
|
|
9
10
|
const { generateProfilePicture } = require("../Utils")
|
|
10
|
-
const { getBinaryNodeChild } = require("../WABinary")
|
|
11
|
+
const { getBinaryNodeChild, getBinaryNodeChildren } = require("../WABinary")
|
|
11
12
|
const { makeGroupsSocket } = require("./groups")
|
|
12
13
|
const { executeWMexQuery: genericExecuteWMexQuery } = require("./mex")
|
|
13
14
|
|
|
@@ -132,13 +133,14 @@ const makeNewsletterSocket = (config) => {
|
|
|
132
133
|
return await newsletterUpdate(jid, { picture: '' })
|
|
133
134
|
},
|
|
134
135
|
newsletterReactMessage: async (jid, serverId, reaction) => {
|
|
136
|
+
const targetServerId = typeof serverId === 'object' ? (serverId.server_id || serverId.id) : serverId
|
|
135
137
|
await query({
|
|
136
138
|
tag: 'message',
|
|
137
139
|
attrs: {
|
|
138
140
|
to: jid,
|
|
139
141
|
...(reaction ? {} : { edit: '7' }),
|
|
140
142
|
type: 'reaction',
|
|
141
|
-
server_id:
|
|
143
|
+
server_id: targetServerId?.toString(),
|
|
142
144
|
id: generateMessageTag()
|
|
143
145
|
},
|
|
144
146
|
content: [
|
|
@@ -149,7 +151,87 @@ const makeNewsletterSocket = (config) => {
|
|
|
149
151
|
]
|
|
150
152
|
})
|
|
151
153
|
},
|
|
152
|
-
|
|
154
|
+
newsletterFetchReactions: async (jid, serverId) => {
|
|
155
|
+
const targetServerId = typeof serverId === 'object' ? (serverId.server_id || serverId.id) : serverId
|
|
156
|
+
const result = await query({
|
|
157
|
+
tag: 'iq',
|
|
158
|
+
attrs: {
|
|
159
|
+
id: generateMessageTag(),
|
|
160
|
+
type: 'get',
|
|
161
|
+
xmlns: 'newsletter',
|
|
162
|
+
to: jid
|
|
163
|
+
},
|
|
164
|
+
content: [
|
|
165
|
+
{
|
|
166
|
+
tag: 'reactions',
|
|
167
|
+
attrs: {
|
|
168
|
+
server_id: targetServerId?.toString()
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
]
|
|
172
|
+
})
|
|
173
|
+
|
|
174
|
+
const reactionsNode = getBinaryNodeChild(result, 'reactions')
|
|
175
|
+
if (!reactionsNode) return []
|
|
176
|
+
const reactionChildren = getBinaryNodeChildren(reactionsNode, 'reaction')
|
|
177
|
+
return reactionChildren.map(r => ({
|
|
178
|
+
code: r.attrs.code,
|
|
179
|
+
count: parseInt(r.attrs.count || '0', 10)
|
|
180
|
+
}))
|
|
181
|
+
},
|
|
182
|
+
newsletterFetchMessage: async (jid, serverId) => {
|
|
183
|
+
const targetServerId = typeof serverId === 'object' ? (serverId.server_id || serverId.id) : serverId
|
|
184
|
+
const result = await query({
|
|
185
|
+
tag: 'iq',
|
|
186
|
+
attrs: {
|
|
187
|
+
id: generateMessageTag(),
|
|
188
|
+
type: 'get',
|
|
189
|
+
xmlns: 'newsletter',
|
|
190
|
+
to: jid
|
|
191
|
+
},
|
|
192
|
+
content: [
|
|
193
|
+
{
|
|
194
|
+
tag: 'message',
|
|
195
|
+
attrs: {
|
|
196
|
+
server_id: targetServerId?.toString()
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
]
|
|
200
|
+
})
|
|
201
|
+
|
|
202
|
+
const messageNode = getBinaryNodeChild(result, 'message')
|
|
203
|
+
if (!messageNode) return null
|
|
204
|
+
|
|
205
|
+
const plaintextNode = getBinaryNodeChild(messageNode, 'plaintext')
|
|
206
|
+
let messageProto
|
|
207
|
+
if (plaintextNode?.content) {
|
|
208
|
+
try {
|
|
209
|
+
const buffer = Buffer.isBuffer(plaintextNode.content)
|
|
210
|
+
? plaintextNode.content
|
|
211
|
+
: Buffer.from(plaintextNode.content)
|
|
212
|
+
messageProto = proto.Message.decode(buffer)
|
|
213
|
+
} catch (e) {
|
|
214
|
+
// ignore decode error
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
const reactionsNode = getBinaryNodeChild(messageNode, 'reactions')
|
|
219
|
+
const reactions = reactionsNode
|
|
220
|
+
? getBinaryNodeChildren(reactionsNode, 'reaction').map(r => ({
|
|
221
|
+
code: r.attrs.code,
|
|
222
|
+
count: parseInt(r.attrs.count || '0', 10)
|
|
223
|
+
}))
|
|
224
|
+
: []
|
|
225
|
+
|
|
226
|
+
return {
|
|
227
|
+
server_id: messageNode.attrs.server_id,
|
|
228
|
+
messageTimestamp: +messageNode.attrs.t,
|
|
229
|
+
views: messageNode.attrs.views ? +messageNode.attrs.views : undefined,
|
|
230
|
+
message: messageProto,
|
|
231
|
+
reactions
|
|
232
|
+
}
|
|
233
|
+
},
|
|
234
|
+
newsletterFetchMessages: async (jid, count = 20, since, after) => {
|
|
153
235
|
const messageUpdateAttrs = {
|
|
154
236
|
count: count.toString()
|
|
155
237
|
}
|
|
@@ -178,8 +260,48 @@ const makeNewsletterSocket = (config) => {
|
|
|
178
260
|
]
|
|
179
261
|
})
|
|
180
262
|
|
|
263
|
+
const messageUpdatesNode = getBinaryNodeChild(result, 'message_updates')
|
|
264
|
+
const messageNodes = getBinaryNodeChildren(messageUpdatesNode, 'message')
|
|
265
|
+
|
|
266
|
+
const messages = messageNodes.map(node => {
|
|
267
|
+
const plaintextNode = getBinaryNodeChild(node, 'plaintext')
|
|
268
|
+
let messageProto
|
|
269
|
+
if (plaintextNode?.content) {
|
|
270
|
+
try {
|
|
271
|
+
const buffer = Buffer.isBuffer(plaintextNode.content)
|
|
272
|
+
? plaintextNode.content
|
|
273
|
+
: Buffer.from(plaintextNode.content)
|
|
274
|
+
messageProto = proto.Message.decode(buffer)
|
|
275
|
+
} catch (e) {
|
|
276
|
+
// ignore decode errors
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
const reactionsNode = getBinaryNodeChild(node, 'reactions')
|
|
281
|
+
const reactions = reactionsNode
|
|
282
|
+
? getBinaryNodeChildren(reactionsNode, 'reaction').map(r => ({
|
|
283
|
+
code: r.attrs.code,
|
|
284
|
+
count: parseInt(r.attrs.count || '0', 10)
|
|
285
|
+
}))
|
|
286
|
+
: []
|
|
287
|
+
|
|
288
|
+
return {
|
|
289
|
+
server_id: node.attrs.server_id,
|
|
290
|
+
messageTimestamp: +node.attrs.t,
|
|
291
|
+
views: node.attrs.views ? +node.attrs.views : undefined,
|
|
292
|
+
message: messageProto,
|
|
293
|
+
reactions
|
|
294
|
+
}
|
|
295
|
+
})
|
|
296
|
+
|
|
297
|
+
result.messages = messages
|
|
181
298
|
return result
|
|
182
299
|
},
|
|
300
|
+
newsletterToggleMute: async (jid, mute = true) => {
|
|
301
|
+
return mute
|
|
302
|
+
? executeWMexQuery({ newsletter_id: jid }, QueryIds.MUTE, XWAPaths.MUTE_V2)
|
|
303
|
+
: executeWMexQuery({ newsletter_id: jid }, QueryIds.UNMUTE, XWAPaths.UNMUTE_V2)
|
|
304
|
+
},
|
|
183
305
|
subscribeNewsletterUpdates: async (jid) => {
|
|
184
306
|
const result = await query({
|
|
185
307
|
tag: 'iq',
|