@areumtecnologia/wasockets 1.1.6 → 2.0.0-alpha.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.
@@ -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
- return extractGroupMetadata(result)
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: async (jid, participants, action) => {
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
- await groupQuery(jid, 'set', [{ tag: 'membership_approval_mode', attrs: {}, content: [{ tag: 'group_join', attrs: { state: mode } }] }])
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
  }
@@ -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
- return makeCommunitiesSocket(newConfig)
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
  }
@@ -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: serverId,
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
- newsletterFetchMessages: async (jid, count, since, after) => {
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',
@@ -0,0 +1,4 @@
1
+ import { InMemoryStore, InMemoryStoreConfig } from '../index'
2
+
3
+ export declare function makeInMemoryStore(config?: InMemoryStoreConfig): InMemoryStore
4
+ export declare function makeCacheManagerAuthState(store: any, sessionKey: string): Promise<any>