@bellaxchuu/flowred 0.8.6

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 (142) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +214 -0
  3. package/WAProto/GenerateStatics.sh +3 -0
  4. package/WAProto/WAProto.proto +6902 -0
  5. package/WAProto/fix-imports.js +85 -0
  6. package/WAProto/index.js +242946 -0
  7. package/engine-requirements.js +10 -0
  8. package/lib/Defaults/index.js +190 -0
  9. package/lib/Defaults/phonenumber-mcc.json +223 -0
  10. package/lib/Signal/Group/ciphertext-message.js +15 -0
  11. package/lib/Signal/Group/group-session-builder.js +92 -0
  12. package/lib/Signal/Group/group_cipher.js +89 -0
  13. package/lib/Signal/Group/index.js +136 -0
  14. package/lib/Signal/Group/keyhelper.js +73 -0
  15. package/lib/Signal/Group/sender-chain-key.js +32 -0
  16. package/lib/Signal/Group/sender-key-distribution-message.js +66 -0
  17. package/lib/Signal/Group/sender-key-message.js +69 -0
  18. package/lib/Signal/Group/sender-key-name.js +50 -0
  19. package/lib/Signal/Group/sender-key-record.js +44 -0
  20. package/lib/Signal/Group/sender-key-state.js +97 -0
  21. package/lib/Signal/Group/sender-message-key.js +30 -0
  22. package/lib/Signal/libsignal.js +490 -0
  23. package/lib/Signal/lid-mapping.js +262 -0
  24. package/lib/Socket/Client/index.js +30 -0
  25. package/lib/Socket/Client/types.js +13 -0
  26. package/lib/Socket/Client/websocket.js +62 -0
  27. package/lib/Socket/aigroups.js +240 -0
  28. package/lib/Socket/business.js +422 -0
  29. package/lib/Socket/chats.js +1816 -0
  30. package/lib/Socket/communities.js +549 -0
  31. package/lib/Socket/graphql.js +656 -0
  32. package/lib/Socket/groups.js +764 -0
  33. package/lib/Socket/index.js +39 -0
  34. package/lib/Socket/interactive-handler.js +522 -0
  35. package/lib/Socket/interop.js +549 -0
  36. package/lib/Socket/luxu.js +387 -0
  37. package/lib/Socket/managed-account.js +183 -0
  38. package/lib/Socket/messages-recv.js +2440 -0
  39. package/lib/Socket/messages-send.js +1853 -0
  40. package/lib/Socket/mex.js +60 -0
  41. package/lib/Socket/newsletter.js +820 -0
  42. package/lib/Socket/privacy.js +449 -0
  43. package/lib/Socket/registration.js +427 -0
  44. package/lib/Socket/socket.js +1092 -0
  45. package/lib/Socket/text-router.js +83 -0
  46. package/lib/Socket/username.js +243 -0
  47. package/lib/Store/index.js +36 -0
  48. package/lib/Store/keyed-db.js +108 -0
  49. package/lib/Store/make-cache-manager-store.js +90 -0
  50. package/lib/Store/make-in-memory-store.js +604 -0
  51. package/lib/Store/make-ordered-dictionary.js +81 -0
  52. package/lib/Store/object-repository.js +29 -0
  53. package/lib/Types/Auth.js +38 -0
  54. package/lib/Types/Bussines.js +2 -0
  55. package/lib/Types/Call.js +2 -0
  56. package/lib/Types/Chat.js +4 -0
  57. package/lib/Types/Contact.js +2 -0
  58. package/lib/Types/Events.js +2 -0
  59. package/lib/Types/GroupMetadata.js +2 -0
  60. package/lib/Types/Label.js +27 -0
  61. package/lib/Types/LabelAssociation.js +9 -0
  62. package/lib/Types/Message.js +95 -0
  63. package/lib/Types/Mex.js +112 -0
  64. package/lib/Types/Newsletter.js +121 -0
  65. package/lib/Types/Product.js +2 -0
  66. package/lib/Types/Signal.js +2 -0
  67. package/lib/Types/Socket.js +2 -0
  68. package/lib/Types/State.js +70 -0
  69. package/lib/Types/USync.js +2 -0
  70. package/lib/Types/index.js +55 -0
  71. package/lib/Utils/auth-utils.js +306 -0
  72. package/lib/Utils/browser-utils.js +114 -0
  73. package/lib/Utils/business.js +247 -0
  74. package/lib/Utils/chat-utils.js +1208 -0
  75. package/lib/Utils/command-loader.js +100 -0
  76. package/lib/Utils/companion-reg-client-utils.js +42 -0
  77. package/lib/Utils/consumer-application.js +107 -0
  78. package/lib/Utils/crypto.js +155 -0
  79. package/lib/Utils/curve25519-js.js +275 -0
  80. package/lib/Utils/decode-wa-message.js +560 -0
  81. package/lib/Utils/event-buffer.js +607 -0
  82. package/lib/Utils/generics.js +563 -0
  83. package/lib/Utils/group-history.js +60 -0
  84. package/lib/Utils/history.js +244 -0
  85. package/lib/Utils/identity-change-handler.js +52 -0
  86. package/lib/Utils/index.js +57 -0
  87. package/lib/Utils/jid-display-normalization.js +218 -0
  88. package/lib/Utils/link-preview.js +143 -0
  89. package/lib/Utils/logger.js +9 -0
  90. package/lib/Utils/lt-hash.js +39 -0
  91. package/lib/Utils/make-mutex.js +36 -0
  92. package/lib/Utils/message-composer.js +479 -0
  93. package/lib/Utils/message-retry-manager.js +270 -0
  94. package/lib/Utils/messages-media.js +896 -0
  95. package/lib/Utils/messages.js +2904 -0
  96. package/lib/Utils/meta-ai-msmsg.js +262 -0
  97. package/lib/Utils/native-bridge.js +82 -0
  98. package/lib/Utils/noise-handler.js +196 -0
  99. package/lib/Utils/offline-node-processor.js +42 -0
  100. package/lib/Utils/pre-key-manager.js +107 -0
  101. package/lib/Utils/process-message.js +1048 -0
  102. package/lib/Utils/reporting-utils.js +262 -0
  103. package/lib/Utils/session-pool.js +94 -0
  104. package/lib/Utils/signal.js +224 -0
  105. package/lib/Utils/stanza-ack.js +40 -0
  106. package/lib/Utils/sticker.js +145 -0
  107. package/lib/Utils/sync-action-utils.js +54 -0
  108. package/lib/Utils/tc-token-utils.js +161 -0
  109. package/lib/Utils/use-multi-file-auth-state.js +121 -0
  110. package/lib/Utils/validate-connection.js +219 -0
  111. package/lib/Utils/view-once-cache.js +79 -0
  112. package/lib/Utils/voip-rekey.js +22 -0
  113. package/lib/WABinary/constants.js +1304 -0
  114. package/lib/WABinary/decode.js +343 -0
  115. package/lib/WABinary/encode.js +228 -0
  116. package/lib/WABinary/generic-utils.js +240 -0
  117. package/lib/WABinary/index.js +33 -0
  118. package/lib/WABinary/jid-utils.js +361 -0
  119. package/lib/WABinary/types.js +2 -0
  120. package/lib/WAM/BinaryInfo.js +13 -0
  121. package/lib/WAM/constants.js +39486 -0
  122. package/lib/WAM/encode.js +142 -0
  123. package/lib/WAM/index.js +31 -0
  124. package/lib/WAUSync/Protocols/USyncBotProfileProtocol.js +55 -0
  125. package/lib/WAUSync/Protocols/USyncBusinessProtocol.js +43 -0
  126. package/lib/WAUSync/Protocols/USyncContactProtocol.js +54 -0
  127. package/lib/WAUSync/Protocols/USyncDeviceProtocol.js +57 -0
  128. package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.js +30 -0
  129. package/lib/WAUSync/Protocols/USyncFeatureProtocol.js +59 -0
  130. package/lib/WAUSync/Protocols/USyncLIDProtocol.js +31 -0
  131. package/lib/WAUSync/Protocols/USyncPictureProtocol.js +32 -0
  132. package/lib/WAUSync/Protocols/USyncSidelistProtocol.js +29 -0
  133. package/lib/WAUSync/Protocols/USyncStatusProtocol.js +39 -0
  134. package/lib/WAUSync/Protocols/USyncTextStatusProtocol.js +38 -0
  135. package/lib/WAUSync/Protocols/USyncUsernameProtocol.js +27 -0
  136. package/lib/WAUSync/Protocols/index.js +39 -0
  137. package/lib/WAUSync/USyncQuery.js +133 -0
  138. package/lib/WAUSync/USyncUser.js +50 -0
  139. package/lib/WAUSync/index.js +31 -0
  140. package/lib/antiban.js +4637 -0
  141. package/lib/index.js +45 -0
  142. package/package.json +107 -0
@@ -0,0 +1,764 @@
1
+ 'use strict'
2
+ Object.defineProperty(exports, '__esModule', { value: true })
3
+ exports.extractGroupMetadata = exports.makeGroupsSocket = void 0
4
+ const index_js_1 = require('../../WAProto/index.js')
5
+ const Types_1 = require('../Types')
6
+ const Utils_1 = require('../Utils')
7
+ const WABinary_1 = require('../WABinary')
8
+ const chats_1 = require('./chats')
9
+ const mex_1 = require('./mex')
10
+
11
+ const GROUP_MEX_QUERY_IDS = {
12
+ QUERY_INFO: '25530136513328492', // QueryGroupInfo
13
+ QUERY_INFO_BY_CODE: '24576337542042464', // QueryGroupInfoByCode
14
+ QUERY_BATCH: '26440064815661176', // QueryBatchGetGroups
15
+ QUERY_INVITE_LINK: '24558418350455204', // QueryInviteLink
16
+ QUERY_PARTICIPATING: '26664341543184776', // QueryParticipatingGroups
17
+ QUERY_SUGGESTED: '26012055225051916', // QuerySuggestedGroups
18
+ QUERY_LINKED: '25629003043401452', // QueryLinkedGroupInfo
19
+ QUERY_SUBGROUPS: '25554052094203120', // QuerySubgroups
20
+ ADD_PARTICIPANTS_V2: '32627550323510250', // AddParticipantsToGroupV2
21
+ ADD_PARTICIPANTS_V3: '26581073158212628', // AddParticipantsToGroupsV3
22
+ SET_PROPERTY: '24688994337458820', // SetGroupProperty
23
+ RESET_INVITE_LINK: '24812851838367452', // SetGroupResetInviteLink
24
+ CREATE_INVITE_CODE: '25207706598901440', // CreateInviteCode
25
+ CREATE_GROUP: '32341779532133480', // CreateGroup
26
+ ALLOW_NON_ADMIN_GROUP_CREATION: '32024438593867696', // AllowNonAdminGroupCreation
27
+ GET_INVITE_INFO: '24745668928467084', // GetInviteInfo
28
+ GET_PRE_REG_ADD_REQUESTS: '25018599251091280', // GetPreRegGroupAddRequestsQuery
29
+ GET_SUGGESTED_CONTACTS: '27208468032086900', // GetSuggestedContacts
30
+ STORE_INVITES_SMS: '25508574885415376', // GroupsStoreInvitesSMSMutation
31
+ LOG_SERVER_SENT_INVITE: '26580640204871220', // LogServerSentInviteIntent
32
+ QUERY_ONLINE_STATUS: '24599444653063564', // QueryOnlineStatusFromPDP
33
+ QUERY_ONLINE_STATUS_LAST_SEEN: '24653084284365540' // QueryOnlineStatusLastSeenFromPDP
34
+ }
35
+
36
+ const makeGroupsSocket = config => {
37
+ const sock = (0, chats_1.makeChatsSocket)(config)
38
+ const { authState, ev, query, generateMessageTag, upsertMessage } = sock
39
+ const groupQuery = async (jid, type, content) =>
40
+ query({
41
+ tag: 'iq',
42
+ attrs: {
43
+ type,
44
+ xmlns: 'w:g2',
45
+ to: jid
46
+ },
47
+ content
48
+ })
49
+
50
+ const mexQuery = (variables, queryId, dataPath) =>
51
+ (0, mex_1.executeWMexQuery)(variables, queryId, dataPath, query, generateMessageTag)
52
+ const groupMetadata = async jid => {
53
+ const result = await groupQuery(jid, 'get', [{ tag: 'query', attrs: { request: 'interactive' } }])
54
+ return (0, exports.extractGroupMetadata)(result)
55
+ }
56
+ /**
57
+ * Acknowledge a group. Ported from WhatsApp Web's WASmaxGroupsAcknowledgeGroupRPC
58
+ * (`<iq to=jid xmlns=w:g2 type=set><ack/></iq>`).
59
+ */
60
+ const groupAcknowledge = async jid => {
61
+ await groupQuery(jid, 'set', [{ tag: 'ack', attrs: {} }])
62
+ }
63
+ /**
64
+ * Get the participants of a community's linked/sub groups. Ported from
65
+ * WhatsApp Web's WASmaxGroupsGetLinkedGroupsParticipantsRPC.
66
+ * @returns {Promise<Array<{ jid: string, phoneNumber?: string }>>}
67
+ */
68
+ const groupGetLinkedParticipants = async jid => {
69
+ const result = await groupQuery(jid, 'get', [{ tag: 'linked_groups_participants', attrs: {} }])
70
+ const node = (0, WABinary_1.getBinaryNodeChild)(result, 'linked_groups_participants')
71
+ return (0, WABinary_1.getBinaryNodeChildren)(node, 'participant').map(p => ({
72
+ jid: p.attrs.jid,
73
+ phoneNumber: p.attrs.phone_number || p.attrs.pn || undefined
74
+ }))
75
+ }
76
+ /**
77
+ * Join a community's linked/sub group (may raise a membership approval request).
78
+ * Ported from WhatsApp Web's WASmaxGroupsJoinLinkedGroupRPC.
79
+ * @param {string} parentJid community/parent group to address
80
+ * @param {string} linkedGroupJid linked/sub group to join
81
+ * @param {string} [type]
82
+ */
83
+ const groupJoinLinked = async (parentJid, linkedGroupJid, type) => {
84
+ const result = await groupQuery(parentJid, 'set', [
85
+ { tag: 'join_linked_group', attrs: { jid: linkedGroupJid, ...(type ? { type } : {}) } }
86
+ ])
87
+ return { approvalRequested: !!(0, WABinary_1.getBinaryNodeChild)(result, 'membership_approval_request') }
88
+ }
89
+ /**
90
+ * Batch-fetch group profile pictures via w:g2. Ported from WhatsApp Web's
91
+ * WASmaxGroupsGetGroupProfilePicturesRPC. NOTE: untested against live WhatsApp —
92
+ * for a single group prefer profilePictureUrl().
93
+ * @param {string[]} jids group jids
94
+ * @param {'preview' | 'image'} [type]
95
+ */
96
+ const getGroupProfilePictures = async (jids, type = 'preview') => {
97
+ const result = await groupQuery(WABinary_1.S_WHATSAPP_NET, 'get', [
98
+ {
99
+ tag: 'pictures',
100
+ attrs: {},
101
+ content: jids.map(id => ({ tag: 'picture', attrs: { id, type } }))
102
+ }
103
+ ])
104
+ return (0, WABinary_1.getBinaryNodeChildren)(result, 'picture').map(pic => ({
105
+ jid: pic.attrs.id || pic.attrs.jid,
106
+ type: pic.attrs.type,
107
+ directPath: pic.attrs['direct_path'],
108
+ url: pic.attrs.url
109
+ }))
110
+ }
111
+ /**
112
+ * Create a sub-group suggestion for a community. Ported from WhatsApp Web's
113
+ * WASmaxGroupsCreateSubGroupSuggestionRPC. The suggestion body (new vs existing
114
+ * groups) is caller-provided. NOTE: untested against live WhatsApp.
115
+ * @param {string} parentJid community/parent group to address
116
+ * @param {Array<{ tag: string, attrs?: object, content?: any }>} suggestion child node(s)
117
+ */
118
+ const groupCreateSubGroupSuggestion = async (parentJid, suggestion) => {
119
+ await groupQuery(parentJid, 'set', [{ tag: 'sub_group_suggestion', attrs: {}, content: suggestion }])
120
+ }
121
+ /**
122
+ * Approve or reject sub-group suggestions for a community. Ported from WhatsApp
123
+ * Web's WASmaxGroupsSubGroupSuggestionsActionRPC. NOTE: untested against live WhatsApp.
124
+ * @param {string} parentJid community/parent group to address
125
+ * @param {'approve' | 'reject'} action
126
+ * @param {Array<{ creator: string, jid?: string }>} suggestions
127
+ */
128
+ const groupSubGroupSuggestionsAction = async (parentJid, action, suggestions) => {
129
+ await groupQuery(parentJid, 'set', [
130
+ {
131
+ tag: action,
132
+ attrs: {},
133
+ content: suggestions.map(s => ({
134
+ tag: 'sub_group_suggestion',
135
+ attrs: { creator: s.creator, ...(s.jid ? { jid: s.jid } : {}) }
136
+ }))
137
+ }
138
+ ])
139
+ }
140
+ const groupFetchAllParticipating = async () => {
141
+ const result = await query({
142
+ tag: 'iq',
143
+ attrs: {
144
+ to: '@g.us',
145
+ xmlns: 'w:g2',
146
+ type: 'get'
147
+ },
148
+ content: [
149
+ {
150
+ tag: 'participating',
151
+ attrs: {},
152
+ content: [
153
+ { tag: 'participants', attrs: {} },
154
+ { tag: 'description', attrs: {} }
155
+ ]
156
+ }
157
+ ]
158
+ })
159
+ const data = {}
160
+ const groupsChild = (0, WABinary_1.getBinaryNodeChild)(result, 'groups')
161
+ if (groupsChild) {
162
+ const groups = (0, WABinary_1.getBinaryNodeChildren)(groupsChild, 'group')
163
+ for (const groupNode of groups) {
164
+ const meta = (0, exports.extractGroupMetadata)({
165
+ tag: 'result',
166
+ attrs: {},
167
+ content: [groupNode]
168
+ })
169
+ data[meta.id] = meta
170
+ }
171
+ }
172
+ // TODO: properly parse LID / PN DATA
173
+ sock.ev.emit('groups.update', Object.values(data))
174
+ return data
175
+ }
176
+ sock.ws.on('CB:ib,,dirty', async node => {
177
+ const { attrs } = (0, WABinary_1.getBinaryNodeChild)(node, 'dirty')
178
+ if (attrs.type !== 'groups') {
179
+ return
180
+ }
181
+ await groupFetchAllParticipating()
182
+ await sock.cleanDirtyBits('groups')
183
+ })
184
+ return {
185
+ ...sock,
186
+ groupMetadata,
187
+ groupAcknowledge,
188
+ groupGetLinkedParticipants,
189
+ groupJoinLinked,
190
+ getGroupProfilePictures,
191
+ groupCreateSubGroupSuggestion,
192
+ groupSubGroupSuggestionsAction,
193
+ groupCreate: async (subject, participants) => {
194
+ const key = (0, Utils_1.generateMessageIDV2)()
195
+ const result = await groupQuery('@g.us', 'set', [
196
+ {
197
+ tag: 'create',
198
+ attrs: {
199
+ subject,
200
+ key
201
+ },
202
+ content: participants.map(jid => ({
203
+ tag: 'participant',
204
+ attrs: { jid }
205
+ }))
206
+ }
207
+ ])
208
+ return (0, exports.extractGroupMetadata)(result)
209
+ },
210
+ groupLeave: async id => {
211
+ await groupQuery('@g.us', 'set', [
212
+ {
213
+ tag: 'leave',
214
+ attrs: {},
215
+ content: [{ tag: 'group', attrs: { id } }]
216
+ }
217
+ ])
218
+ },
219
+ groupUpdateSubject: async (jid, subject) => {
220
+ await groupQuery(jid, 'set', [
221
+ {
222
+ tag: 'subject',
223
+ attrs: {},
224
+ content: Buffer.from(subject, 'utf-8')
225
+ }
226
+ ])
227
+ },
228
+ groupRequestParticipantsList: async jid => {
229
+ const result = await groupQuery(jid, 'get', [
230
+ {
231
+ tag: 'membership_approval_requests',
232
+ attrs: {}
233
+ }
234
+ ])
235
+ const node = (0, WABinary_1.getBinaryNodeChild)(result, 'membership_approval_requests')
236
+ const participants = (0, WABinary_1.getBinaryNodeChildren)(node, 'membership_approval_request')
237
+ return participants.map(v => v.attrs)
238
+ },
239
+ groupRequestParticipantsUpdate: async (jid, participants, action) => {
240
+ const result = await groupQuery(jid, 'set', [
241
+ {
242
+ tag: 'membership_requests_action',
243
+ attrs: {},
244
+ content: [
245
+ {
246
+ tag: action,
247
+ attrs: {},
248
+ content: participants.map(jid => ({
249
+ tag: 'participant',
250
+ attrs: { jid }
251
+ }))
252
+ }
253
+ ]
254
+ }
255
+ ])
256
+ const node = (0, WABinary_1.getBinaryNodeChild)(result, 'membership_requests_action')
257
+ const nodeAction = (0, WABinary_1.getBinaryNodeChild)(node, action)
258
+ const participantsAffected = (0, WABinary_1.getBinaryNodeChildren)(nodeAction, 'participant')
259
+ return participantsAffected.map(p => {
260
+ return { status: p.attrs.error || '200', jid: p.attrs.jid }
261
+ })
262
+ },
263
+ groupParticipantsUpdate: async (jid, participants, action) => {
264
+ const result = await groupQuery(jid, 'set', [
265
+ {
266
+ tag: action,
267
+ attrs: {},
268
+ content: participants.map(jid => ({
269
+ tag: 'participant',
270
+ attrs: { jid }
271
+ }))
272
+ }
273
+ ])
274
+ const node = (0, WABinary_1.getBinaryNodeChild)(result, action)
275
+ const participantsAffected = (0, WABinary_1.getBinaryNodeChildren)(node, 'participant')
276
+ return participantsAffected.map(p => {
277
+ return { status: p.attrs.error || '200', jid: p.attrs.jid, content: p }
278
+ })
279
+ },
280
+ groupUpdateDescription: async (jid, description) => {
281
+ const metadata = await groupMetadata(jid)
282
+ const prev = metadata.descId ?? null
283
+ await groupQuery(jid, 'set', [
284
+ {
285
+ tag: 'description',
286
+ attrs: {
287
+ ...(description ? { id: (0, Utils_1.generateMessageIDV2)() } : { delete: 'true' }),
288
+ ...(prev ? { prev } : {})
289
+ },
290
+ content: description ? [{ tag: 'body', attrs: {}, content: Buffer.from(description, 'utf-8') }] : undefined
291
+ }
292
+ ])
293
+ },
294
+ groupInviteCode: async jid => {
295
+ const result = await groupQuery(jid, 'get', [{ tag: 'invite', attrs: {} }])
296
+ const inviteNode = (0, WABinary_1.getBinaryNodeChild)(result, 'invite')
297
+ return inviteNode?.attrs.code
298
+ },
299
+ groupRevokeInvite: async jid => {
300
+ const result = await groupQuery(jid, 'set', [{ tag: 'invite', attrs: {} }])
301
+ const inviteNode = (0, WABinary_1.getBinaryNodeChild)(result, 'invite')
302
+ return inviteNode?.attrs.code
303
+ },
304
+ groupAcceptInvite: async code => {
305
+ const results = await groupQuery('@g.us', 'set', [{ tag: 'invite', attrs: { code } }])
306
+ const result = (0, WABinary_1.getBinaryNodeChild)(results, 'group')
307
+ return result?.attrs.jid
308
+ },
309
+ /**
310
+ * revoke a v4 invite for someone
311
+ * @param groupJid group jid
312
+ * @param invitedJid jid of person you invited
313
+ * @returns true if successful
314
+ */
315
+ groupRevokeInviteV4: async (groupJid, invitedJid) => {
316
+ const result = await groupQuery(groupJid, 'set', [
317
+ { tag: 'revoke', attrs: {}, content: [{ tag: 'participant', attrs: { jid: invitedJid } }] }
318
+ ])
319
+ return !!result
320
+ },
321
+ /**
322
+ * accept a GroupInviteMessage
323
+ * @param key the key of the invite message, or optionally only provide the jid of the person who sent the invite
324
+ * @param inviteMessage the message to accept
325
+ */
326
+ groupAcceptInviteV4: ev.createBufferedFunction(async (key, inviteMessage) => {
327
+ key = typeof key === 'string' ? { remoteJid: key } : key
328
+ const results = await groupQuery(inviteMessage.groupJid, 'set', [
329
+ {
330
+ tag: 'accept',
331
+ attrs: {
332
+ code: inviteMessage.inviteCode,
333
+ expiration: inviteMessage.inviteExpiration.toString(),
334
+ admin: key.remoteJid
335
+ }
336
+ }
337
+ ])
338
+ // if we have the full message key
339
+ // update the invite message to be expired
340
+ if (key.id) {
341
+ // create new invite message that is expired
342
+ inviteMessage = index_js_1.proto.Message.GroupInviteMessage.fromObject(inviteMessage)
343
+ inviteMessage.inviteExpiration = 0
344
+ inviteMessage.inviteCode = ''
345
+ ev.emit('messages.update', [
346
+ {
347
+ key,
348
+ update: {
349
+ message: {
350
+ groupInviteMessage: inviteMessage
351
+ }
352
+ }
353
+ }
354
+ ])
355
+ }
356
+ // generate the group add message
357
+ await upsertMessage(
358
+ {
359
+ key: {
360
+ remoteJid: inviteMessage.groupJid,
361
+ id: (0, Utils_1.generateMessageIDV2)(sock.user?.id),
362
+ fromMe: false,
363
+ participant: key.remoteJid
364
+ },
365
+ messageStubType: Types_1.WAMessageStubType.GROUP_PARTICIPANT_ADD,
366
+ messageStubParameters: [JSON.stringify(authState.creds.me)],
367
+ participant: key.remoteJid,
368
+ messageTimestamp: (0, Utils_1.unixTimestampSeconds)()
369
+ },
370
+ 'notify'
371
+ )
372
+ return results.attrs.from
373
+ }),
374
+ groupGetInviteInfo: async code => {
375
+ const results = await groupQuery('@g.us', 'get', [{ tag: 'invite', attrs: { code } }])
376
+ return (0, exports.extractGroupMetadata)(results)
377
+ },
378
+ groupToggleEphemeral: async (jid, ephemeralExpiration) => {
379
+ const content = ephemeralExpiration
380
+ ? { tag: 'ephemeral', attrs: { expiration: ephemeralExpiration.toString() } }
381
+ : { tag: 'not_ephemeral', attrs: {} }
382
+ await groupQuery(jid, 'set', [content])
383
+ },
384
+ groupSettingUpdate: async (jid, setting) => {
385
+ await groupQuery(jid, 'set', [{ tag: setting, attrs: {} }])
386
+ },
387
+ groupMemberAddMode: async (jid, mode) => {
388
+ await groupQuery(jid, 'set', [{ tag: 'member_add_mode', attrs: {}, content: mode }])
389
+ },
390
+ groupJoinApprovalMode: async (jid, mode) => {
391
+ await groupQuery(jid, 'set', [
392
+ { tag: 'membership_approval_mode', attrs: {}, content: [{ tag: 'group_join', attrs: { state: mode } }] }
393
+ ])
394
+ },
395
+ /**
396
+ * Get past participants of a group (left/removed members)
397
+ */
398
+ groupGetPastParticipants: async jid => {
399
+ const result = await groupQuery(jid, 'get', [{ tag: 'past_participants', attrs: {} }])
400
+ const node = (0, WABinary_1.getBinaryNodeChild)(result, 'past_participants')
401
+ if (!node) return []
402
+ const participants = (0, WABinary_1.getBinaryNodeChildren)(node, 'past_participant')
403
+ return participants.map(p => ({
404
+ jid: p.attrs.jid,
405
+ leaveReason: p.attrs.reason,
406
+ leaveTimestamp: p.attrs.t ? Number(p.attrs.t) : undefined
407
+ }))
408
+ },
409
+ /**
410
+ * Create a subgroup within a community
411
+ */
412
+ groupCreateSubgroup: async (communityJid, subject, participants = []) => {
413
+ const key = (0, Utils_1.generateMessageIDV2)()
414
+ const result = await groupQuery('@g.us', 'set', [
415
+ {
416
+ tag: 'create',
417
+ attrs: { subject, key, parent_group_id: communityJid },
418
+ content: participants.map(jid => ({ tag: 'participant', attrs: { jid } }))
419
+ }
420
+ ])
421
+ return (0, exports.extractGroupMetadata)(result)
422
+ },
423
+ /**
424
+ * Link an existing group to a community
425
+ */
426
+ groupLinkToCommunity: async (communityJid, groupJid) => {
427
+ await groupQuery(communityJid, 'set', [
428
+ {
429
+ tag: 'links',
430
+ attrs: {},
431
+ content: [
432
+ { tag: 'link', attrs: { link_type: 'sub_group' }, content: [{ tag: 'group', attrs: { jid: groupJid } }] }
433
+ ]
434
+ }
435
+ ])
436
+ },
437
+ /**
438
+ * Unlink a group from a community
439
+ */
440
+ groupUnlinkFromCommunity: async (communityJid, groupJid) => {
441
+ await groupQuery(communityJid, 'set', [
442
+ {
443
+ tag: 'unlinks',
444
+ attrs: {},
445
+ content: [
446
+ { tag: 'unlink', attrs: { link_type: 'sub_group' }, content: [{ tag: 'group', attrs: { jid: groupJid } }] }
447
+ ]
448
+ }
449
+ ])
450
+ },
451
+ /**
452
+ * Set a member label/tag in a group
453
+ * @param jid group JID
454
+ * @param participantJid participant JID to label
455
+ * @param label the label string ('' to remove)
456
+ */
457
+ groupSetMemberLabel: async (jid, participantJid, label) => {
458
+ await groupQuery(jid, 'set', [
459
+ {
460
+ tag: 'member_add_mode',
461
+ attrs: {},
462
+ content: [
463
+ {
464
+ tag: 'participant',
465
+ attrs: { jid: participantJid, label: label || '' }
466
+ }
467
+ ]
468
+ }
469
+ ])
470
+ },
471
+ /**
472
+ * Get community-linked subgroups for a community JID
473
+ */
474
+ groupGetLinkedSubgroups: async communityJid => {
475
+ const result = await groupQuery(communityJid, 'get', [{ tag: 'links', attrs: { link_type: 'sub_group' } }])
476
+ const linksNode = (0, WABinary_1.getBinaryNodeChild)(result, 'links')
477
+ if (!linksNode) return []
478
+ return (0, WABinary_1.getBinaryNodeChildren)(linksNode, 'link')
479
+ .map(link => {
480
+ const group = (0, WABinary_1.getBinaryNodeChild)(link, 'group')
481
+ return { jid: group?.attrs?.jid, linkType: link.attrs?.link_type }
482
+ })
483
+ .filter(l => !!l.jid)
484
+ },
485
+ groupFetchAllParticipating,
486
+
487
+ // ── MEX queries (JSON responses) ──────────────────────────────────────
488
+
489
+ /**
490
+ * Fetch group info via MEX (richer than IQ — includes invite link, LID addressing, etc.)
491
+ * @param {string} jid - Group JID
492
+ */
493
+ groupQueryInfo: jid =>
494
+ mexQuery({ group_id: jid }, GROUP_MEX_QUERY_IDS.QUERY_INFO, 'xwa2_group_query_by_id'),
495
+
496
+ /**
497
+ * Fetch group info by invite code via MEX.
498
+ * @param {string} code - Group invite code (without the link prefix)
499
+ */
500
+ groupQueryInfoByCode: code =>
501
+ mexQuery({ group_input: { invite_code: code } }, GROUP_MEX_QUERY_IDS.QUERY_INFO_BY_CODE, 'xwa2_group_query_by_id'),
502
+
503
+ /**
504
+ * Fetch multiple groups at once via MEX.
505
+ * @param {string[]} jids - Array of group JIDs
506
+ */
507
+ groupQueryBatch: jids =>
508
+ mexQuery(
509
+ { groups_input: jids.map(group_id => ({ group_id })) },
510
+ GROUP_MEX_QUERY_IDS.QUERY_BATCH,
511
+ 'xwa2_group_query_batch'
512
+ ),
513
+
514
+ /**
515
+ * Fetch invite link info via MEX (includes expiration, creator, etc.)
516
+ * @param {string} jid - Group JID
517
+ */
518
+ groupQueryInviteLink: jid =>
519
+ mexQuery({ group_input: { group_id: jid } }, GROUP_MEX_QUERY_IDS.QUERY_INVITE_LINK, 'xwa2_group_query_by_id'),
520
+
521
+ /**
522
+ * Fetch all groups the current user is participating in via MEX.
523
+ * Returns richer data than the IQ-based groupFetchAllParticipating.
524
+ */
525
+ groupQueryParticipating: () =>
526
+ mexQuery({}, GROUP_MEX_QUERY_IDS.QUERY_PARTICIPATING, 'xwa2_group_query_participating'),
527
+
528
+ /**
529
+ * Fetch suggested groups (community sub-group suggestions) via MEX.
530
+ * @param {string} communityJid - Community JID to get suggestions for
531
+ */
532
+ groupQuerySuggested: communityJid =>
533
+ mexQuery(
534
+ { group_input: { group_id: communityJid } },
535
+ GROUP_MEX_QUERY_IDS.QUERY_SUGGESTED,
536
+ 'xwa2_group_query_by_id'
537
+ ),
538
+
539
+ /**
540
+ * Fetch linked subgroup info for a community group via MEX.
541
+ * @param {string} jid - Group or community JID
542
+ */
543
+ groupQueryLinked: jid =>
544
+ mexQuery({ group_input: { group_id: jid } }, GROUP_MEX_QUERY_IDS.QUERY_LINKED, 'xwa2_group_query_by_id'),
545
+
546
+ /**
547
+ * Fetch subgroups of a community via MEX.
548
+ * @param {string} communityJid - Community JID
549
+ */
550
+ groupQuerySubgroups: communityJid =>
551
+ mexQuery(
552
+ { group_input: { group_id: communityJid } },
553
+ GROUP_MEX_QUERY_IDS.QUERY_SUBGROUPS,
554
+ 'xwa2_group_query_by_id'
555
+ ),
556
+
557
+ /**
558
+ * Add participants to a group via MEX (V2 — supports LID, privacy metadata).
559
+ * Falls back to the IQ-based groupParticipantsUpdate for older servers.
560
+ * @param {string} jid - Group JID
561
+ * @param {string[]} participants - Array of JIDs to add
562
+ */
563
+ groupAddParticipantsMex: (jid, participants) =>
564
+ mexQuery(
565
+ { group_id: jid, participants: participants.map(p => ({ user_jid: p })) },
566
+ GROUP_MEX_QUERY_IDS.ADD_PARTICIPANTS_V2,
567
+ 'xwa2_group_add_participants'
568
+ ),
569
+
570
+ /**
571
+ * Set a group property via MEX.
572
+ * Known properties: member_add_mode, membership_approval_mode_enabled, member_share_group_history_mode
573
+ * @param {string} jid - Group JID
574
+ * @param {string} property - Property name
575
+ * @param {*} value - Property value
576
+ */
577
+ groupSetProperty: (jid, property, value) =>
578
+ mexQuery({ group_id: jid, [property]: value }, GROUP_MEX_QUERY_IDS.SET_PROPERTY, 'xwa2_group_set_property'),
579
+
580
+ /**
581
+ * Reset a group's invite link via MEX (generates new code, invalidates old one).
582
+ * @param {string} jid - Group JID
583
+ */
584
+ groupResetInviteLinkMex: jid =>
585
+ mexQuery({ group_jid: jid }, GROUP_MEX_QUERY_IDS.RESET_INVITE_LINK, 'xwa2_group_reset_invite_link'),
586
+
587
+ /**
588
+ * Create a group via MEX.
589
+ * Confirmed from CreateGroup mutation — input: { subject, participants: [{jid}] }
590
+ * @param {string} subject - Group name
591
+ * @param {string[]} participantJids
592
+ */
593
+ groupCreateMex: (subject, participantJids) =>
594
+ mexQuery(
595
+ { input: { subject, participants: participantJids.map(jid => ({ jid })) } },
596
+ GROUP_MEX_QUERY_IDS.CREATE_GROUP,
597
+ 'xwa2_group_create'
598
+ ),
599
+
600
+ /**
601
+ * Allow non-admin community members to create subgroups.
602
+ * @param {string} communityJid - Community JID
603
+ * @param {boolean} allow
604
+ */
605
+ groupAllowNonAdminCreation: (communityJid, allow) =>
606
+ mexQuery(
607
+ { group_jid: communityJid, allow_non_admin_sub_group_creation: allow },
608
+ GROUP_MEX_QUERY_IDS.ALLOW_NON_ADMIN_GROUP_CREATION,
609
+ 'xwa2_group_allow_non_admin_creation'
610
+ ),
611
+
612
+ /**
613
+ * Get info about a group invite link (before joining).
614
+ * @param {string} inviteCode - The raw invite code (not full URL)
615
+ */
616
+ groupGetInviteInfo: inviteCode =>
617
+ mexQuery({ invite_code: inviteCode }, GROUP_MEX_QUERY_IDS.GET_INVITE_INFO, 'xwa2_group_get_invite_info'),
618
+
619
+ /**
620
+ * Fetch pending add requests for pre-registration group invites.
621
+ * @param {string} jid - Group JID
622
+ */
623
+ groupPreRegAddRequests: jid =>
624
+ mexQuery({ group_jid: jid }, GROUP_MEX_QUERY_IDS.GET_PRE_REG_ADD_REQUESTS, 'xwa2_group_pre_reg_add_requests'),
625
+
626
+ /**
627
+ * Get suggested contacts to add to a group.
628
+ * @param {string} jid - Group JID
629
+ */
630
+ groupSuggestedContacts: jid =>
631
+ mexQuery({ group_jid: jid }, GROUP_MEX_QUERY_IDS.GET_SUGGESTED_CONTACTS, 'xwa2_group_suggested_contacts'),
632
+
633
+ /**
634
+ * Store SMS invite links for a group.
635
+ * @param {string} jid - Group JID
636
+ * @param {{ phone: string, inviteCode: string }[]} invites
637
+ */
638
+ groupStoreInvitesSms: (jid, invites) =>
639
+ mexQuery(
640
+ { group_jid: jid, invites: invites.map(({ phone, inviteCode }) => ({ phone, invite_code: inviteCode })) },
641
+ GROUP_MEX_QUERY_IDS.STORE_INVITES_SMS,
642
+ 'xwa2_group_store_invites_sms'
643
+ ),
644
+
645
+ /**
646
+ * Log a server-sent invite intent (analytics).
647
+ * @param {string} jid - Group JID
648
+ * @param {string} inviteCode
649
+ */
650
+ groupLogServerSentInvite: (jid, inviteCode) =>
651
+ mexQuery(
652
+ { group_jid: jid, invite_code: inviteCode },
653
+ GROUP_MEX_QUERY_IDS.LOG_SERVER_SENT_INVITE,
654
+ 'xwa2_group_log_server_sent_invite'
655
+ ),
656
+
657
+ /**
658
+ * Query online status of users from PDP.
659
+ * @param {string[]} jids - User JIDs
660
+ */
661
+ queryOnlineStatus: jids =>
662
+ mexQuery({ jids }, GROUP_MEX_QUERY_IDS.QUERY_ONLINE_STATUS, 'xwa2_query_online_status'),
663
+
664
+ /**
665
+ * Query online status and last seen of users from PDP.
666
+ * @param {string[]} jids - User JIDs
667
+ */
668
+ queryOnlineStatusLastSeen: jids =>
669
+ mexQuery({ jids }, GROUP_MEX_QUERY_IDS.QUERY_ONLINE_STATUS_LAST_SEEN, 'xwa2_query_online_status_last_seen'),
670
+
671
+ GROUP_MEX_QUERY_IDS
672
+ }
673
+ }
674
+ exports.makeGroupsSocket = makeGroupsSocket
675
+ const extractGroupMetadata = result => {
676
+ const group = (0, WABinary_1.getBinaryNodeChild)(result, 'group')
677
+ const descChild = (0, WABinary_1.getBinaryNodeChild)(group, 'description')
678
+ let desc
679
+ let descId
680
+ let descOwner
681
+ let descOwnerPn
682
+ let descOwnerUsername
683
+ let descTime
684
+ if (descChild) {
685
+ desc = (0, WABinary_1.getBinaryNodeChildString)(descChild, 'body')
686
+ descOwner = descChild.attrs.participant ? (0, WABinary_1.jidNormalizedUser)(descChild.attrs.participant) : undefined
687
+ descOwnerPn = descChild.attrs.participant_pn
688
+ ? (0, WABinary_1.jidNormalizedUser)(descChild.attrs.participant_pn)
689
+ : undefined
690
+ descOwnerUsername = descChild.attrs.participant_username || undefined
691
+ descTime = +descChild.attrs.t
692
+ descId = descChild.attrs.id
693
+ }
694
+ const groupId = group.attrs.id.includes('@') ? group.attrs.id : (0, WABinary_1.jidEncode)(group.attrs.id, 'g.us')
695
+ const eph = (0, WABinary_1.getBinaryNodeChild)(group, 'ephemeral')?.attrs.expiration
696
+ const memberAddMode = (0, WABinary_1.getBinaryNodeChildString)(group, 'member_add_mode') === 'all_member_add'
697
+ const linkedParentNode = (0, WABinary_1.getBinaryNodeChild)(group, 'linked_parent')
698
+ const communityMemberAddGroupNode = (0, WABinary_1.getBinaryNodeChild)(group, 'allow_non_admin_sub_group_creation')
699
+ const subGroupVisibilityNode = (0, WABinary_1.getBinaryNodeChild)(group, 'sub_groups_list')
700
+ const membershipApprovalNode = (0, WABinary_1.getBinaryNodeChild)(group, 'membership_approval_mode')
701
+ const metadata = {
702
+ id: groupId,
703
+ notify: group.attrs.notify,
704
+ addressingMode:
705
+ group.attrs.addressing_mode === 'lid' ? Types_1.WAMessageAddressingMode.LID : Types_1.WAMessageAddressingMode.PN,
706
+ subject: group.attrs.subject,
707
+ subjectOwner: group.attrs.s_o,
708
+ subjectOwnerPn: group.attrs.s_o_pn,
709
+ subjectOwnerUsername: group.attrs.s_o_username,
710
+ subjectTime: +group.attrs.s_t,
711
+ size: group.attrs.size ? +group.attrs.size : (0, WABinary_1.getBinaryNodeChildren)(group, 'participant').length,
712
+ creation: +group.attrs.creation,
713
+ owner: group.attrs.creator ? (0, WABinary_1.jidNormalizedUser)(group.attrs.creator) : undefined,
714
+ ownerPn: group.attrs.creator_pn ? (0, WABinary_1.jidNormalizedUser)(group.attrs.creator_pn) : undefined,
715
+ ownerUsername: group.attrs.creator_username || undefined,
716
+ owner_country_code: group.attrs.creator_country_code,
717
+ desc,
718
+ descId,
719
+ descOwner,
720
+ descOwnerPn,
721
+ descOwnerUsername,
722
+ descTime,
723
+ linkedParent: linkedParentNode?.attrs.jid || undefined,
724
+ restrict: !!(0, WABinary_1.getBinaryNodeChild)(group, 'locked'),
725
+ announce: !!(0, WABinary_1.getBinaryNodeChild)(group, 'announcement'),
726
+ isCommunity: !!(0, WABinary_1.getBinaryNodeChild)(group, 'parent'),
727
+ isCommunityAnnounce: !!(0, WABinary_1.getBinaryNodeChild)(group, 'default_sub_group'),
728
+ joinApprovalMode: !!membershipApprovalNode,
729
+ memberAddMode,
730
+ memberShareHistoryMode: (0, WABinary_1.getBinaryNodeChildString)(group, 'member_share_group_history_mode') || undefined,
731
+ memberLinkMode: (0, WABinary_1.getBinaryNodeChildString)(group, 'member_link_mode') || undefined,
732
+ limitSharing: !!(0, WABinary_1.getBinaryNodeChild)(group, 'limit_sharing_enabled'),
733
+ communityMemberAddGroupMode: communityMemberAddGroupNode?.attrs.state || undefined,
734
+ capiCreatedGroup: group.attrs.capi_created === 'true' || undefined,
735
+ appealStatus: group.attrs.appeal_status || undefined,
736
+ isSubGroupHidden: group.attrs.sub_group_visibility === 'hidden' || undefined,
737
+ participants: (0, WABinary_1.getBinaryNodeChildren)(group, 'participant').map(({ attrs }) => {
738
+ // TODO: Store LID MAPPINGS
739
+ return {
740
+ id: attrs.jid,
741
+ phoneNumber:
742
+ (0, WABinary_1.isLidUser)(attrs.jid) && (0, WABinary_1.isPnUser)(attrs.phone_number)
743
+ ? attrs.phone_number
744
+ : undefined,
745
+ lid: (0, WABinary_1.isPnUser)(attrs.jid) && (0, WABinary_1.isLidUser)(attrs.lid) ? attrs.lid : undefined,
746
+ username: attrs.participant_username || attrs.username || undefined,
747
+ admin: attrs.type || null,
748
+ memberLabel: attrs.label || undefined,
749
+ memberLabelTimestamp: attrs.label_ts ? +attrs.label_ts : undefined,
750
+ isBanned: attrs.error === '403' || attrs.ban === 'true' || undefined
751
+ }
752
+ }),
753
+ bannedParticipants: (0, WABinary_1.getBinaryNodeChildren)(group, 'participant')
754
+ .filter(({ attrs }) => attrs.error === '403' || attrs.ban === 'true')
755
+ .map(({ attrs }) => ({
756
+ id: attrs.jid,
757
+ phoneNumber: attrs.phone_number || undefined,
758
+ lid: attrs.lid || undefined
759
+ })),
760
+ ephemeralDuration: eph ? +eph : undefined
761
+ }
762
+ return metadata
763
+ }
764
+ exports.extractGroupMetadata = extractGroupMetadata