@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.
- 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
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export declare namespace proto {
|
|
2
|
+
interface IMessage {
|
|
3
|
+
[key: string]: any
|
|
4
|
+
}
|
|
5
|
+
interface IHistorySyncNotification {
|
|
6
|
+
[key: string]: any
|
|
7
|
+
}
|
|
8
|
+
interface IWebMessageInfo {
|
|
9
|
+
[key: string]: any
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export declare const proto: {
|
|
14
|
+
[key: string]: any
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export default proto
|
|
@@ -7,6 +7,33 @@ const { default: logger } = require("../Utils/logger")
|
|
|
7
7
|
const { makeLibSignalRepository } = require("../Signal/libsignal")
|
|
8
8
|
const { version } = require("./baileys-version.json")
|
|
9
9
|
|
|
10
|
+
const createGroupMetadataCache = (ttlMs = 300000, maxSize = 250) => {
|
|
11
|
+
const cache = new Map()
|
|
12
|
+
|
|
13
|
+
const get = async (jid) => {
|
|
14
|
+
const item = cache.get(jid)
|
|
15
|
+
if (!item) return undefined
|
|
16
|
+
if (Date.now() - item.time > ttlMs) {
|
|
17
|
+
cache.delete(jid)
|
|
18
|
+
return undefined
|
|
19
|
+
}
|
|
20
|
+
return item.metadata
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
get.set = (jid, metadata) => {
|
|
24
|
+
if (cache.size >= maxSize) {
|
|
25
|
+
const oldestKey = cache.keys().next().value
|
|
26
|
+
if (oldestKey) cache.delete(oldestKey)
|
|
27
|
+
}
|
|
28
|
+
cache.set(jid, { metadata, time: Date.now() })
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
get.delete = (jid) => cache.delete(jid)
|
|
32
|
+
get.clear = () => cache.clear()
|
|
33
|
+
|
|
34
|
+
return get
|
|
35
|
+
}
|
|
36
|
+
|
|
10
37
|
const DEFAULT_CONNECTION_CONFIG = {
|
|
11
38
|
version,
|
|
12
39
|
browser: Browsers.windows('Chrome'),
|
|
@@ -35,6 +62,10 @@ const DEFAULT_CONNECTION_CONFIG = {
|
|
|
35
62
|
generateHighQualityLinkPreview: false,
|
|
36
63
|
enableAutoSessionRecreation: true,
|
|
37
64
|
enableRecentMessageCache: true,
|
|
65
|
+
enableMessageQueue: true,
|
|
66
|
+
messageQueueTtlMs: 300000,
|
|
67
|
+
maxReconnectAttempts: 15,
|
|
68
|
+
enableGroupCache: true,
|
|
38
69
|
options: {},
|
|
39
70
|
appStateMacVerification: {
|
|
40
71
|
patch: false,
|
|
@@ -42,10 +73,11 @@ const DEFAULT_CONNECTION_CONFIG = {
|
|
|
42
73
|
},
|
|
43
74
|
countryCode: 'US',
|
|
44
75
|
getMessage: async () => undefined,
|
|
45
|
-
cachedGroupMetadata:
|
|
76
|
+
cachedGroupMetadata: createGroupMetadataCache(),
|
|
46
77
|
makeSignalRepository: makeLibSignalRepository
|
|
47
78
|
}
|
|
48
79
|
|
|
49
80
|
module.exports = {
|
|
50
|
-
DEFAULT_CONNECTION_CONFIG
|
|
81
|
+
DEFAULT_CONNECTION_CONFIG,
|
|
82
|
+
createGroupMetadataCache
|
|
51
83
|
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { Browsers } from '../Utils'
|
|
2
|
+
import { UserFacingSocketConfig } from '../index'
|
|
3
|
+
|
|
4
|
+
export { Browsers }
|
|
5
|
+
export declare const DEFAULT_CONNECTION_CONFIG: UserFacingSocketConfig
|
|
6
|
+
export declare function createGroupMetadataCache(ttlMs?: number, maxSize?: number): any
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { WASocket } from '../index'
|
|
2
|
+
|
|
3
|
+
export interface PluginMetadata {
|
|
4
|
+
name: string
|
|
5
|
+
version?: string
|
|
6
|
+
description?: string
|
|
7
|
+
author?: string
|
|
8
|
+
install?: (sock: WASocket, options?: any, manager?: PluginManager) => void
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export type PluginFunction = (sock: WASocket, options?: any, manager?: PluginManager) => void
|
|
12
|
+
export type Plugin = PluginMetadata | PluginFunction
|
|
13
|
+
|
|
14
|
+
export type MiddlewareHook =
|
|
15
|
+
| 'beforeSendMessage'
|
|
16
|
+
| 'afterSendMessage'
|
|
17
|
+
| 'beforeRecvMessage'
|
|
18
|
+
| 'afterRecvMessage'
|
|
19
|
+
| 'connectionUpdate'
|
|
20
|
+
|
|
21
|
+
export declare class PluginManager {
|
|
22
|
+
constructor(sock: WASocket)
|
|
23
|
+
sock: WASocket
|
|
24
|
+
plugins: Map<string, any>
|
|
25
|
+
middlewares: Record<string, Function[]>
|
|
26
|
+
|
|
27
|
+
use(plugin: Plugin, options?: any): this
|
|
28
|
+
registerMiddleware(hook: MiddlewareHook, fn: (context: any, sock: WASocket) => Promise<boolean | void> | boolean | void): () => void
|
|
29
|
+
runMiddlewares(hook: string, context: any): Promise<boolean>
|
|
30
|
+
hasPlugin(name: string): boolean
|
|
31
|
+
getPlugin(name: string): any
|
|
32
|
+
listPlugins(): Array<{ name: string; registeredAt: number; version: string; description: string }>
|
|
33
|
+
}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
"use strict"
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true })
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Plugin and Middleware Manager for WaSockets
|
|
7
|
+
* Enables modular extensions, event interception, and pipeline middleware.
|
|
8
|
+
*/
|
|
9
|
+
class PluginManager {
|
|
10
|
+
constructor(sock) {
|
|
11
|
+
this.sock = sock
|
|
12
|
+
this.plugins = new Map()
|
|
13
|
+
this.middlewares = {
|
|
14
|
+
beforeSendMessage: [],
|
|
15
|
+
afterSendMessage: [],
|
|
16
|
+
beforeRecvMessage: [],
|
|
17
|
+
afterRecvMessage: [],
|
|
18
|
+
connectionUpdate: []
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Install a plugin
|
|
24
|
+
* @param {Object|Function} plugin - Plugin object with install() or function (sock, options)
|
|
25
|
+
* @param {Object} [options={}] - Options passed to plugin
|
|
26
|
+
*/
|
|
27
|
+
use(plugin, options = {}) {
|
|
28
|
+
if (!plugin) return this
|
|
29
|
+
|
|
30
|
+
if (typeof plugin === 'function') {
|
|
31
|
+
plugin(this.sock, options, this)
|
|
32
|
+
return this
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const name = plugin.name || `plugin_${this.plugins.size + 1}`
|
|
36
|
+
if (this.plugins.has(name)) {
|
|
37
|
+
throw new Error(`Plugin with name "${name}" is already registered`)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
this.plugins.set(name, {
|
|
41
|
+
plugin,
|
|
42
|
+
options,
|
|
43
|
+
registeredAt: Date.now()
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
if (typeof plugin.install === 'function') {
|
|
47
|
+
plugin.install(this.sock, options, this)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return this
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Register a middleware hook
|
|
55
|
+
* @param {'beforeSendMessage'|'afterSendMessage'|'beforeRecvMessage'|'afterRecvMessage'|'connectionUpdate'} hook
|
|
56
|
+
* @param {Function} fn - Async middleware function
|
|
57
|
+
* @returns {Function} Unregister function
|
|
58
|
+
*/
|
|
59
|
+
registerMiddleware(hook, fn) {
|
|
60
|
+
if (!this.middlewares[hook]) {
|
|
61
|
+
this.middlewares[hook] = []
|
|
62
|
+
}
|
|
63
|
+
this.middlewares[hook].push(fn)
|
|
64
|
+
return () => {
|
|
65
|
+
this.middlewares[hook] = this.middlewares[hook].filter(f => f !== fn)
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Execute all middlewares for a specific hook
|
|
71
|
+
* @param {string} hook
|
|
72
|
+
* @param {Object} context
|
|
73
|
+
* @returns {Promise<boolean>} returns false if any middleware explicitly returned false (cancelled)
|
|
74
|
+
*/
|
|
75
|
+
async runMiddlewares(hook, context) {
|
|
76
|
+
const hooks = this.middlewares[hook] || []
|
|
77
|
+
for (const fn of hooks) {
|
|
78
|
+
try {
|
|
79
|
+
const result = await fn(context, this.sock)
|
|
80
|
+
if (result === false) {
|
|
81
|
+
return false
|
|
82
|
+
}
|
|
83
|
+
} catch (error) {
|
|
84
|
+
if (this.sock.logger) {
|
|
85
|
+
this.sock.logger.error({ error, hook }, 'Error executing plugin middleware')
|
|
86
|
+
} else {
|
|
87
|
+
console.error(`[PluginManager] Error executing middleware on hook ${hook}:`, error)
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return true
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Check if a plugin is installed
|
|
96
|
+
* @param {string} name
|
|
97
|
+
*/
|
|
98
|
+
hasPlugin(name) {
|
|
99
|
+
return this.plugins.has(name)
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Retrieve an installed plugin
|
|
104
|
+
* @param {string} name
|
|
105
|
+
*/
|
|
106
|
+
getPlugin(name) {
|
|
107
|
+
return this.plugins.get(name)
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* List all installed plugins
|
|
112
|
+
*/
|
|
113
|
+
listPlugins() {
|
|
114
|
+
return Array.from(this.plugins.entries()).map(([name, data]) => ({
|
|
115
|
+
name,
|
|
116
|
+
registeredAt: data.registeredAt,
|
|
117
|
+
version: data.plugin?.version || '1.0.0',
|
|
118
|
+
description: data.plugin?.description || ''
|
|
119
|
+
}))
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
module.exports = {
|
|
124
|
+
PluginManager
|
|
125
|
+
}
|
package/lib/Socket/business.js
CHANGED
|
@@ -7,6 +7,7 @@ const {
|
|
|
7
7
|
parseCatalogNode,
|
|
8
8
|
parseCollectionsNode,
|
|
9
9
|
parseOrderDetailsNode,
|
|
10
|
+
parseProductNode,
|
|
10
11
|
getRawMediaUploadData,
|
|
11
12
|
uploadingNecessaryImagesOfProduct
|
|
12
13
|
} = require("../Utils")
|
|
@@ -408,12 +409,44 @@ const makeBusinessSocket = (config) => {
|
|
|
408
409
|
deleted: +(productCatalogDelNode?.attrs?.deleted_count || 0)
|
|
409
410
|
}
|
|
410
411
|
}
|
|
412
|
+
const getProduct = async (jid, productId) => {
|
|
413
|
+
jid = jid || authState.creds.me?.id
|
|
414
|
+
jid = jidNormalizedUser(jid)
|
|
415
|
+
|
|
416
|
+
const result = await query({
|
|
417
|
+
tag: 'iq',
|
|
418
|
+
attrs: {
|
|
419
|
+
to: S_WHATSAPP_NET,
|
|
420
|
+
type: 'get',
|
|
421
|
+
xmlns: 'w:biz:catalog'
|
|
422
|
+
},
|
|
423
|
+
content: [
|
|
424
|
+
{
|
|
425
|
+
tag: 'product',
|
|
426
|
+
attrs: {
|
|
427
|
+
jid
|
|
428
|
+
},
|
|
429
|
+
content: [
|
|
430
|
+
{
|
|
431
|
+
tag: 'id',
|
|
432
|
+
attrs: {},
|
|
433
|
+
content: Buffer.from(productId)
|
|
434
|
+
}
|
|
435
|
+
]
|
|
436
|
+
}
|
|
437
|
+
]
|
|
438
|
+
})
|
|
439
|
+
const productNode = getBinaryNodeChild(result, 'product')
|
|
440
|
+
return productNode ? parseProductNode(productNode) : null
|
|
441
|
+
}
|
|
442
|
+
|
|
411
443
|
return {
|
|
412
444
|
...suki,
|
|
413
445
|
logger: config.logger,
|
|
414
446
|
getOrderDetails,
|
|
415
447
|
getCatalog,
|
|
416
448
|
getCollections,
|
|
449
|
+
getProduct,
|
|
417
450
|
productCreate,
|
|
418
451
|
productDelete,
|
|
419
452
|
productUpdate,
|
package/lib/Socket/chats.js
CHANGED
|
@@ -253,7 +253,19 @@ const makeChatsSocket = (config) => {
|
|
|
253
253
|
|
|
254
254
|
const result = await suki.executeUSyncQuery(usyncQuery)
|
|
255
255
|
|
|
256
|
-
if (result) {
|
|
256
|
+
if (result && result.list) {
|
|
257
|
+
const mappingsToStore = []
|
|
258
|
+
for (const item of result.list) {
|
|
259
|
+
const lid = item.lid || item.val
|
|
260
|
+
if (lid && isPnUser(targetJid)) {
|
|
261
|
+
mappingsToStore.push({ lid, pn: targetJid })
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
if (mappingsToStore.length && signalRepository?.lidMapping?.storeLIDPNMappings) {
|
|
265
|
+
await signalRepository.lidMapping.storeLIDPNMappings(mappingsToStore).catch(err => {
|
|
266
|
+
logger.debug({ err }, 'Failed to auto-store LID-PN mapping in getLidUser')
|
|
267
|
+
})
|
|
268
|
+
}
|
|
257
269
|
return result.list
|
|
258
270
|
}
|
|
259
271
|
}
|
|
@@ -286,10 +298,95 @@ const makeChatsSocket = (config) => {
|
|
|
286
298
|
|
|
287
299
|
const result = await suki.executeUSyncQuery(usyncQuery)
|
|
288
300
|
|
|
289
|
-
if (result) {
|
|
301
|
+
if (result && result.list) {
|
|
302
|
+
const mappingsToStore = []
|
|
303
|
+
for (const item of result.list) {
|
|
304
|
+
const rawPhone = item.phone_number || item.val
|
|
305
|
+
if (rawPhone && isLidUser(targetJid)) {
|
|
306
|
+
const cleanPhone = rawPhone.replace('+', '')
|
|
307
|
+
const pnJid = `${cleanPhone}@s.whatsapp.net`
|
|
308
|
+
mappingsToStore.push({ lid: targetJid, pn: pnJid })
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
if (mappingsToStore.length && signalRepository?.lidMapping?.storeLIDPNMappings) {
|
|
312
|
+
await signalRepository.lidMapping.storeLIDPNMappings(mappingsToStore).catch(err => {
|
|
313
|
+
logger.debug({ err }, 'Failed to auto-store LID-PN mapping in getPnUser')
|
|
314
|
+
})
|
|
315
|
+
}
|
|
290
316
|
return result.list
|
|
291
317
|
}
|
|
292
318
|
}
|
|
319
|
+
|
|
320
|
+
const toPn = async (jid, fetchIfMissing = false) => {
|
|
321
|
+
if (!jid) return null
|
|
322
|
+
if (isPnUser(jid)) return jidNormalizedUser(jid)
|
|
323
|
+
if (!isLidUser(jid)) return jidNormalizedUser(jid)
|
|
324
|
+
|
|
325
|
+
const normLid = jidNormalizedUser(jid)
|
|
326
|
+
let pn = await signalRepository?.lidMapping?.getPNForLID(normLid)
|
|
327
|
+
if (pn) return jidNormalizedUser(pn)
|
|
328
|
+
|
|
329
|
+
if (fetchIfMissing) {
|
|
330
|
+
try {
|
|
331
|
+
const list = await getPnUser(normLid)
|
|
332
|
+
if (list && list.length > 0) {
|
|
333
|
+
const phone = list[0].phone_number || list[0].val
|
|
334
|
+
if (phone) {
|
|
335
|
+
return `${phone.replace('+', '')}@s.whatsapp.net`
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
} catch (err) {
|
|
339
|
+
logger.debug({ err, jid }, 'Failed to fetch PN for LID via USync')
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
return null
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
const toLid = async (jid, fetchIfMissing = false) => {
|
|
346
|
+
if (!jid) return null
|
|
347
|
+
if (isLidUser(jid)) return jidNormalizedUser(jid)
|
|
348
|
+
if (!isPnUser(jid)) return jidNormalizedUser(jid)
|
|
349
|
+
|
|
350
|
+
const normPn = jidNormalizedUser(jid)
|
|
351
|
+
let lid = await signalRepository?.lidMapping?.getLIDForPN(normPn)
|
|
352
|
+
if (lid) return jidNormalizedUser(lid)
|
|
353
|
+
|
|
354
|
+
if (fetchIfMissing) {
|
|
355
|
+
try {
|
|
356
|
+
const list = await getLidUser(normPn)
|
|
357
|
+
if (list && list.length > 0) {
|
|
358
|
+
const foundLid = list[0].lid || list[0].val
|
|
359
|
+
if (foundLid) {
|
|
360
|
+
return jidNormalizedUser(foundLid)
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
} catch (err) {
|
|
364
|
+
logger.debug({ err, jid }, 'Failed to fetch LID for PN via USync')
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
return null
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
const resolveJid = async (jid, fetchIfMissing = false) => {
|
|
371
|
+
if (!jid) return { pn: null, lid: null, jid: null }
|
|
372
|
+
if (isPnUser(jid)) {
|
|
373
|
+
const pn = jidNormalizedUser(jid)
|
|
374
|
+
const lid = await toLid(pn, fetchIfMissing)
|
|
375
|
+
return { pn, lid, jid: pn }
|
|
376
|
+
}
|
|
377
|
+
if (isLidUser(jid)) {
|
|
378
|
+
const lid = jidNormalizedUser(jid)
|
|
379
|
+
const pn = await toPn(lid, fetchIfMissing)
|
|
380
|
+
return { pn, lid, jid: lid }
|
|
381
|
+
}
|
|
382
|
+
return { pn: null, lid: null, jid }
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
const storeLidPnMapping = async (pn, lid) => {
|
|
386
|
+
if (!pn || !lid || !signalRepository?.lidMapping) return false
|
|
387
|
+
await signalRepository.lidMapping.storeLIDPNMappings([{ pn, lid }])
|
|
388
|
+
return true
|
|
389
|
+
}
|
|
293
390
|
|
|
294
391
|
const fetchStatus = async (...jids) => {
|
|
295
392
|
const usyncQuery = new USyncQuery().withStatusProtocol()
|
|
@@ -1325,6 +1422,10 @@ const makeChatsSocket = (config) => {
|
|
|
1325
1422
|
notificationMutex,
|
|
1326
1423
|
getLidUser,
|
|
1327
1424
|
getPnUser,
|
|
1425
|
+
toPn,
|
|
1426
|
+
toLid,
|
|
1427
|
+
resolveJid,
|
|
1428
|
+
storeLidPnMapping,
|
|
1328
1429
|
updateFavorite,
|
|
1329
1430
|
updateChatNote,
|
|
1330
1431
|
removeChatNote,
|
package/lib/Socket/community.js
CHANGED
|
@@ -119,6 +119,76 @@ const makeCommunitiesSocket = (config) => {
|
|
|
119
119
|
await cleanDirtyBits('groups')
|
|
120
120
|
})
|
|
121
121
|
|
|
122
|
+
const communityRequestParticipantsUpdate = async (jid, participants, action) => {
|
|
123
|
+
const result = await communityQuery(jid, 'set', [
|
|
124
|
+
{
|
|
125
|
+
tag: 'membership_requests_action',
|
|
126
|
+
attrs: {},
|
|
127
|
+
content: [
|
|
128
|
+
{
|
|
129
|
+
tag: action,
|
|
130
|
+
attrs: {},
|
|
131
|
+
content: participants.map(jid => ({
|
|
132
|
+
tag: 'participant',
|
|
133
|
+
attrs: { jid }
|
|
134
|
+
}))
|
|
135
|
+
}
|
|
136
|
+
]
|
|
137
|
+
}
|
|
138
|
+
])
|
|
139
|
+
|
|
140
|
+
const node = getBinaryNodeChild(result, 'membership_requests_action')
|
|
141
|
+
const nodeAction = getBinaryNodeChild(node, action)
|
|
142
|
+
const participantsAffected = getBinaryNodeChildren(nodeAction, 'participant')
|
|
143
|
+
|
|
144
|
+
return participantsAffected.map(p => {
|
|
145
|
+
return { status: p.attrs.error || '200', jid: p.attrs.jid }
|
|
146
|
+
})
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
const communityFetchLinkedGroups = async (jid) => {
|
|
150
|
+
let communityJid = jid
|
|
151
|
+
let isCommunity = false
|
|
152
|
+
|
|
153
|
+
// Try to determine if it is a subgroup or a community
|
|
154
|
+
const metadata = await groupMetadata(jid)
|
|
155
|
+
|
|
156
|
+
if (metadata.linkedParent) {
|
|
157
|
+
// It is a subgroup, get the community jid
|
|
158
|
+
communityJid = metadata.linkedParent
|
|
159
|
+
} else {
|
|
160
|
+
// It is a community
|
|
161
|
+
isCommunity = true
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// Fetch all subgroups of the community
|
|
165
|
+
const result = await communityQuery(communityJid, 'get', [{ tag: 'sub_groups', attrs: {} }])
|
|
166
|
+
const linkedGroupsData = []
|
|
167
|
+
const subGroupsNode = getBinaryNodeChild(result, 'sub_groups')
|
|
168
|
+
|
|
169
|
+
if (subGroupsNode) {
|
|
170
|
+
const groupNodes = getBinaryNodeChildren(subGroupsNode, 'group')
|
|
171
|
+
|
|
172
|
+
for (const groupNode of groupNodes) {
|
|
173
|
+
const isDefault = groupNode.attrs.default_sub_group === 'true' || !!getBinaryNodeChild(groupNode, 'default_sub_group')
|
|
174
|
+
linkedGroupsData.push({
|
|
175
|
+
id: groupNode.attrs.id ? jidEncode(groupNode.attrs.id, 'g.us') : undefined,
|
|
176
|
+
subject: groupNode.attrs.subject || '',
|
|
177
|
+
creation: groupNode.attrs.creation ? Number(groupNode.attrs.creation) : undefined,
|
|
178
|
+
owner: groupNode.attrs.creator ? jidNormalizedUser(groupNode.attrs.creator) : undefined,
|
|
179
|
+
size: groupNode.attrs.size ? Number(groupNode.attrs.size) : undefined,
|
|
180
|
+
isDefaultSubGroup: isDefault
|
|
181
|
+
})
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
return {
|
|
186
|
+
communityJid,
|
|
187
|
+
isCommunity,
|
|
188
|
+
linkedGroups: linkedGroupsData
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
122
192
|
return {
|
|
123
193
|
...suki,
|
|
124
194
|
communityQuery,
|
|
@@ -225,46 +295,15 @@ const makeCommunitiesSocket = (config) => {
|
|
|
225
295
|
}
|
|
226
296
|
])
|
|
227
297
|
},
|
|
228
|
-
communityFetchLinkedGroups
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
const metadata = await groupMetadata(jid)
|
|
234
|
-
|
|
235
|
-
if (metadata.linkedParent) {
|
|
236
|
-
// It is a subgroup, get the community jid
|
|
237
|
-
communityJid = metadata.linkedParent
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
else {
|
|
241
|
-
// It is a community
|
|
242
|
-
isCommunity = true
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
// Fetch all subgroups of the community
|
|
246
|
-
const result = await communityQuery(communityJid, 'get', [{ tag: 'sub_groups', attrs: {} }])
|
|
247
|
-
const linkedGroupsData = []
|
|
248
|
-
const subGroupsNode = getBinaryNodeChild(result, 'sub_groups')
|
|
249
|
-
|
|
250
|
-
if (subGroupsNode) {
|
|
251
|
-
const groupNodes = getBinaryNodeChildren(subGroupsNode, 'group')
|
|
252
|
-
|
|
253
|
-
for (const groupNode of groupNodes) {
|
|
254
|
-
linkedGroupsData.push({
|
|
255
|
-
id: groupNode.attrs.id ? jidEncode(groupNode.attrs.id, 'g.us') : undefined,
|
|
256
|
-
subject: groupNode.attrs.subject || '',
|
|
257
|
-
creation: groupNode.attrs.creation ? Number(groupNode.attrs.creation) : undefined,
|
|
258
|
-
owner: groupNode.attrs.creator ? jidNormalizedUser(groupNode.attrs.creator) : undefined,
|
|
259
|
-
size: groupNode.attrs.size ? Number(groupNode.attrs.size) : undefined
|
|
260
|
-
})
|
|
261
|
-
}
|
|
262
|
-
}
|
|
263
|
-
|
|
298
|
+
communityFetchLinkedGroups,
|
|
299
|
+
communityFetchSubGroups: async (jid) => {
|
|
300
|
+
const data = await communityFetchLinkedGroups(jid)
|
|
301
|
+
const defaultSubGroup = data.linkedGroups.find(g => g.isDefaultSubGroup) || null
|
|
302
|
+
const subGroups = data.linkedGroups.filter(g => !g.isDefaultSubGroup)
|
|
264
303
|
return {
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
304
|
+
...data,
|
|
305
|
+
defaultSubGroup,
|
|
306
|
+
subGroups
|
|
268
307
|
}
|
|
269
308
|
},
|
|
270
309
|
communityRequestParticipantsList: async (jid) => {
|
|
@@ -280,32 +319,7 @@ const makeCommunitiesSocket = (config) => {
|
|
|
280
319
|
|
|
281
320
|
return participants.map(v => v.attrs)
|
|
282
321
|
},
|
|
283
|
-
communityRequestParticipantsUpdate
|
|
284
|
-
const result = await communityQuery(jid, 'set', [
|
|
285
|
-
{
|
|
286
|
-
tag: 'membership_requests_action',
|
|
287
|
-
attrs: {},
|
|
288
|
-
content: [
|
|
289
|
-
{
|
|
290
|
-
tag: action,
|
|
291
|
-
attrs: {},
|
|
292
|
-
content: participants.map(jid => ({
|
|
293
|
-
tag: 'participant',
|
|
294
|
-
attrs: { jid }
|
|
295
|
-
}))
|
|
296
|
-
}
|
|
297
|
-
]
|
|
298
|
-
}
|
|
299
|
-
])
|
|
300
|
-
|
|
301
|
-
const node = getBinaryNodeChild(result, 'membership_requests_action')
|
|
302
|
-
const nodeAction = getBinaryNodeChild(node, action)
|
|
303
|
-
const participantsAffected = getBinaryNodeChildren(nodeAction, 'participant')
|
|
304
|
-
|
|
305
|
-
return participantsAffected.map(p => {
|
|
306
|
-
return { status: p.attrs.error || '200', jid: p.attrs.jid }
|
|
307
|
-
})
|
|
308
|
-
},
|
|
322
|
+
communityRequestParticipantsUpdate,
|
|
309
323
|
communityParticipantsUpdate: async (jid, participants, action) => {
|
|
310
324
|
const result = await communityQuery(jid, 'set', [
|
|
311
325
|
{
|
|
@@ -442,10 +456,53 @@ const makeCommunitiesSocket = (config) => {
|
|
|
442
456
|
await communityQuery(jid, 'set', [{ tag: 'member_add_mode', attrs: {}, content: mode }])
|
|
443
457
|
},
|
|
444
458
|
communityJoinApprovalMode: async (jid, mode) => {
|
|
459
|
+
const state = (mode === true || mode === 'on') ? 'on' : (mode === false || mode === 'off' ? 'off' : mode)
|
|
445
460
|
await communityQuery(jid, 'set', [
|
|
446
|
-
{ tag: 'membership_approval_mode', attrs: {}, content: [{ tag: 'community_join', attrs: { state
|
|
461
|
+
{ tag: 'membership_approval_mode', attrs: {}, content: [{ tag: 'community_join', attrs: { state } }] }
|
|
447
462
|
])
|
|
448
463
|
},
|
|
464
|
+
communityMembershipApprovalMode: async (jid, mode) => {
|
|
465
|
+
const state = (mode === true || mode === 'on') ? 'on' : 'off'
|
|
466
|
+
await communityQuery(jid, 'set', [
|
|
467
|
+
{ tag: 'membership_approval_mode', attrs: {}, content: [{ tag: 'community_join', attrs: { state } }] }
|
|
468
|
+
])
|
|
469
|
+
},
|
|
470
|
+
communityApprovePendingParticipants: async (jid, participants) => {
|
|
471
|
+
const list = Array.isArray(participants) ? participants : [participants]
|
|
472
|
+
return communityRequestParticipantsUpdate(jid, list, 'approve')
|
|
473
|
+
},
|
|
474
|
+
communityRejectPendingParticipants: async (jid, participants) => {
|
|
475
|
+
const list = Array.isArray(participants) ? participants : [participants]
|
|
476
|
+
return communityRequestParticipantsUpdate(jid, list, 'reject')
|
|
477
|
+
},
|
|
478
|
+
communityUpdatePermissions: async (jid, policies = {}) => {
|
|
479
|
+
const results = {}
|
|
480
|
+
if (typeof policies.announce === 'boolean') {
|
|
481
|
+
await communityQuery(jid, 'set', [{ tag: policies.announce ? 'announcement' : 'not_announcement', attrs: {} }])
|
|
482
|
+
results.announce = policies.announce
|
|
483
|
+
}
|
|
484
|
+
if (typeof policies.restrict === 'boolean') {
|
|
485
|
+
await communityQuery(jid, 'set', [{ tag: policies.restrict ? 'locked' : 'unlocked', attrs: {} }])
|
|
486
|
+
results.restrict = policies.restrict
|
|
487
|
+
}
|
|
488
|
+
if (policies.memberAddMode) {
|
|
489
|
+
await communityQuery(jid, 'set', [{ tag: 'member_add_mode', attrs: {}, content: policies.memberAddMode }])
|
|
490
|
+
results.memberAddMode = policies.memberAddMode
|
|
491
|
+
}
|
|
492
|
+
if (typeof policies.approvalMode !== 'undefined') {
|
|
493
|
+
const state = (policies.approvalMode === true || policies.approvalMode === 'on') ? 'on' : 'off'
|
|
494
|
+
await communityQuery(jid, 'set', [{ tag: 'membership_approval_mode', attrs: {}, content: [{ tag: 'community_join', attrs: { state } }] }])
|
|
495
|
+
results.approvalMode = state
|
|
496
|
+
}
|
|
497
|
+
if (typeof policies.ephemeral !== 'undefined') {
|
|
498
|
+
const content = policies.ephemeral ?
|
|
499
|
+
{ tag: 'ephemeral', attrs: { expiration: policies.ephemeral.toString() } } :
|
|
500
|
+
{ tag: 'not_ephemeral', attrs: {} }
|
|
501
|
+
await communityQuery(jid, 'set', [content])
|
|
502
|
+
results.ephemeral = policies.ephemeral
|
|
503
|
+
}
|
|
504
|
+
return results
|
|
505
|
+
},
|
|
449
506
|
communityFetchAllParticipating
|
|
450
507
|
}
|
|
451
508
|
}
|
|
@@ -489,12 +546,12 @@ const extractCommunityMetadata = (result) => {
|
|
|
489
546
|
memberAddMode,
|
|
490
547
|
participants: getBinaryNodeChildren(community, 'participant').map(({ attrs }) => {
|
|
491
548
|
return {
|
|
492
|
-
id: mode === WAMessageAddressingMode.LID ?
|
|
493
|
-
lid: mode === WAMessageAddressingMode.LID ?
|
|
549
|
+
id: mode === WAMessageAddressingMode.LID ? attrs.phone_number : attrs.jid,
|
|
550
|
+
lid: mode === WAMessageAddressingMode.LID ? attrs.jid : attrs.lid,
|
|
494
551
|
admin: (attrs.type || null),
|
|
495
552
|
}
|
|
496
553
|
}),
|
|
497
|
-
ephemeralDuration: eph ? Number(
|
|
554
|
+
ephemeralDuration: eph ? Number(eph) : undefined,
|
|
498
555
|
addressingMode: mode
|
|
499
556
|
}
|
|
500
557
|
|