@badzz88/baileys 8.4.9 → 8.5.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.
Files changed (154) hide show
  1. package/README.md +1 -1
  2. package/WAProto/WAProto.proto +6 -347
  3. package/WAProto/fix-imports.js +85 -86
  4. package/WAProto/index.d.ts +25 -4913
  5. package/WAProto/index.js +93 -14069
  6. package/{src → lib}/Defaults/index.js +2 -13
  7. package/{src → lib}/Signal/Group/group_cipher.js +5 -5
  8. package/{src → lib}/Signal/Group/keyhelper.js +4 -4
  9. package/{src → lib}/Signal/Group/sender-chain-key.js +2 -2
  10. package/{src → lib}/Signal/Group/sender-key-distribution-message.js +1 -1
  11. package/{src → lib}/Signal/Group/sender-key-message.js +3 -3
  12. package/{src → lib}/Signal/Group/sender-key-record.js +1 -1
  13. package/{src → lib}/Signal/Group/sender-message-key.js +2 -2
  14. package/{src → lib}/Signal/libsignal.js +26 -6
  15. package/{src → lib}/Socket/chats.js +58 -616
  16. package/{src → lib}/Socket/communities.js +28 -59
  17. package/{src → lib}/Socket/graphql.js +103 -362
  18. package/{src → lib}/Socket/groups.js +29 -77
  19. package/{src → lib}/Socket/index.js +5 -3
  20. package/{src → lib}/Socket/interactive-handler.js +60 -117
  21. package/{src → lib}/Socket/interop.js +19 -36
  22. package/lib/Socket/luxu.js +387 -0
  23. package/{src → lib}/Socket/managed-account.js +27 -58
  24. package/{src → lib}/Socket/messages-recv.js +144 -715
  25. package/{src → lib}/Socket/messages-send.js +102 -412
  26. package/lib/Socket/mex.js +60 -0
  27. package/{src → lib}/Socket/newsletter.js +23 -266
  28. package/{src → lib}/Socket/privacy.js +38 -41
  29. package/{src → lib}/Socket/registration.js +106 -113
  30. package/{src → lib}/Socket/socket.js +101 -88
  31. package/{src → lib}/Socket/text-router.js +17 -1
  32. package/lib/Socket/username.js +243 -0
  33. package/lib/Store/keyed-db.js +108 -0
  34. package/{src → lib}/Store/make-in-memory-store.js +104 -6
  35. package/lib/Types/Mex.js +112 -0
  36. package/{src → lib}/Types/Newsletter.js +41 -72
  37. package/{src → lib}/Types/index.js +1 -0
  38. package/{src → lib}/Utils/chat-utils.js +9 -73
  39. package/lib/Utils/command-loader.d.ts +31 -0
  40. package/lib/Utils/command-loader.js +100 -0
  41. package/lib/Utils/companion-reg-client-utils.js +42 -0
  42. package/lib/Utils/crypto.js +155 -0
  43. package/lib/Utils/curve25519-js.js +275 -0
  44. package/{src → lib}/Utils/decode-wa-message.js +36 -284
  45. package/{src → lib}/Utils/event-buffer.js +27 -6
  46. package/{src → lib}/Utils/generics.js +37 -114
  47. package/{src → lib}/Utils/index.js +5 -1
  48. package/lib/Utils/lt-hash.js +39 -0
  49. package/{src → lib}/Utils/message-retry-manager.js +39 -0
  50. package/{src → lib}/Utils/messages-media.js +58 -105
  51. package/{src → lib}/Utils/messages.js +529 -115
  52. package/lib/Utils/meta-ai-msmsg.js +262 -0
  53. package/lib/Utils/native-bridge.js +82 -0
  54. package/{src → lib}/Utils/noise-handler.js +15 -13
  55. package/{src → lib}/Utils/process-message.js +55 -54
  56. package/{src → lib}/Utils/reporting-utils.js +2 -2
  57. package/lib/Utils/session-pool.d.ts +16 -0
  58. package/lib/Utils/session-pool.js +94 -0
  59. package/{src → lib}/Utils/signal.js +51 -19
  60. package/{src → lib}/Utils/stanza-ack.js +2 -36
  61. package/lib/Utils/sticker.d.ts +17 -0
  62. package/lib/Utils/sticker.js +145 -0
  63. package/{src → lib}/Utils/tc-token-utils.js +1 -1
  64. package/{src → lib}/Utils/validate-connection.js +11 -40
  65. package/lib/Utils/view-once-cache.d.ts +9 -0
  66. package/lib/Utils/view-once-cache.js +79 -0
  67. package/{src → lib}/WABinary/decode.js +4 -38
  68. package/lib/WABinary/encode.js +228 -0
  69. package/{src → lib}/WABinary/generic-utils.js +93 -1
  70. package/{src → lib}/WABinary/jid-utils.js +3 -16
  71. package/{src → lib}/WAM/encode.js +1 -1
  72. package/lib/WAUSync/Protocols/USyncBusinessProtocol.js +43 -0
  73. package/{src → lib}/WAUSync/Protocols/USyncContactProtocol.js +1 -7
  74. package/{src → lib}/WAUSync/Protocols/USyncDeviceProtocol.js +5 -13
  75. package/{src → lib}/WAUSync/Protocols/USyncDisappearingModeProtocol.js +4 -1
  76. package/{src → lib}/WAUSync/Protocols/USyncFeatureProtocol.js +2 -17
  77. package/{src → lib}/WAUSync/Protocols/USyncStatusProtocol.js +2 -7
  78. package/{src → lib}/WAUSync/Protocols/USyncUsernameProtocol.js +1 -2
  79. package/{src → lib}/WAUSync/Protocols/index.js +0 -1
  80. package/{src → lib}/WAUSync/USyncQuery.js +6 -77
  81. package/{src → lib}/WAUSync/USyncUser.js +8 -16
  82. package/{src → lib}/WAUSync/index.js +0 -1
  83. package/{src → lib}/antiban.js +266 -355
  84. package/{src → lib}/index.js +2 -2
  85. package/package.json +19 -16
  86. package/WAProto/fix-import.js +0 -38
  87. package/src/Socket/mex.js +0 -47
  88. package/src/Socket/username.js +0 -234
  89. package/src/Utils/crypto.js +0 -125
  90. package/src/Utils/lt-hash.js +0 -10
  91. package/src/Utils/message-inspect.js +0 -400
  92. package/src/Utils/meta-ai-msmsg.js +0 -133
  93. package/src/WABinary/encode.js +0 -58
  94. package/src/WAUSync/Protocols/USyncBusinessProtocol.js +0 -100
  95. package/src/WAUSync/USyncBackoff.js +0 -31
  96. /package/{src → lib}/Defaults/phonenumber-mcc.json +0 -0
  97. /package/{src → lib}/Signal/Group/ciphertext-message.js +0 -0
  98. /package/{src → lib}/Signal/Group/group-session-builder.js +0 -0
  99. /package/{src → lib}/Signal/Group/index.js +0 -0
  100. /package/{src → lib}/Signal/Group/sender-key-name.js +0 -0
  101. /package/{src → lib}/Signal/Group/sender-key-state.js +0 -0
  102. /package/{src → lib}/Signal/lid-mapping.js +0 -0
  103. /package/{src → lib}/Socket/Client/index.js +0 -0
  104. /package/{src → lib}/Socket/Client/types.js +0 -0
  105. /package/{src → lib}/Socket/Client/websocket.js +0 -0
  106. /package/{src → lib}/Socket/aigroups.js +0 -0
  107. /package/{src → lib}/Socket/business.js +0 -0
  108. /package/{src → lib}/Store/index.js +0 -0
  109. /package/{src → lib}/Store/make-cache-manager-store.js +0 -0
  110. /package/{src → lib}/Store/make-ordered-dictionary.js +0 -0
  111. /package/{src → lib}/Store/object-repository.js +0 -0
  112. /package/{src → lib}/Types/Auth.js +0 -0
  113. /package/{src → lib}/Types/Bussines.js +0 -0
  114. /package/{src → lib}/Types/Call.js +0 -0
  115. /package/{src → lib}/Types/Chat.js +0 -0
  116. /package/{src → lib}/Types/Contact.js +0 -0
  117. /package/{src → lib}/Types/Events.js +0 -0
  118. /package/{src → lib}/Types/GroupMetadata.js +0 -0
  119. /package/{src → lib}/Types/Label.js +0 -0
  120. /package/{src → lib}/Types/LabelAssociation.js +0 -0
  121. /package/{src → lib}/Types/Message.js +0 -0
  122. /package/{src → lib}/Types/Product.js +0 -0
  123. /package/{src → lib}/Types/Signal.js +0 -0
  124. /package/{src → lib}/Types/Socket.js +0 -0
  125. /package/{src → lib}/Types/State.js +0 -0
  126. /package/{src → lib}/Types/USync.js +0 -0
  127. /package/{src → lib}/Utils/auth-utils.js +0 -0
  128. /package/{src → lib}/Utils/browser-utils.js +0 -0
  129. /package/{src → lib}/Utils/business.js +0 -0
  130. /package/{src → lib}/Utils/consumer-application.js +0 -0
  131. /package/{src → lib}/Utils/group-history.js +0 -0
  132. /package/{src → lib}/Utils/history.js +0 -0
  133. /package/{src → lib}/Utils/identity-change-handler.js +0 -0
  134. /package/{src → lib}/Utils/jid-display-normalization.js +0 -0
  135. /package/{src → lib}/Utils/link-preview.js +0 -0
  136. /package/{src → lib}/Utils/logger.js +0 -0
  137. /package/{src → lib}/Utils/make-mutex.js +0 -0
  138. /package/{src → lib}/Utils/message-composer.js +0 -0
  139. /package/{src → lib}/Utils/offline-node-processor.js +0 -0
  140. /package/{src → lib}/Utils/pre-key-manager.js +0 -0
  141. /package/{src → lib}/Utils/sync-action-utils.js +0 -0
  142. /package/{src → lib}/Utils/use-multi-file-auth-state.js +0 -0
  143. /package/{src → lib}/Utils/voip-rekey.js +0 -0
  144. /package/{src → lib}/WABinary/constants.js +0 -0
  145. /package/{src → lib}/WABinary/index.js +0 -0
  146. /package/{src → lib}/WABinary/types.js +0 -0
  147. /package/{src → lib}/WAM/BinaryInfo.js +0 -0
  148. /package/{src → lib}/WAM/constants.js +0 -0
  149. /package/{src → lib}/WAM/index.js +0 -0
  150. /package/{src → lib}/WAUSync/Protocols/USyncBotProfileProtocol.js +0 -0
  151. /package/{src → lib}/WAUSync/Protocols/USyncLIDProtocol.js +0 -0
  152. /package/{src → lib}/WAUSync/Protocols/USyncPictureProtocol.js +0 -0
  153. /package/{src → lib}/WAUSync/Protocols/USyncSidelistProtocol.js +0 -0
  154. /package/{src → lib}/WAUSync/Protocols/USyncTextStatusProtocol.js +0 -0
@@ -46,32 +46,12 @@ const makeGroupsSocket = config => {
46
46
  },
47
47
  content
48
48
  })
49
- // Group metadata carries authoritative LID<->PN pairs for free (per-participant
50
- // jid + phone_number/lid attrs). Persist them so the rest of the app can resolve
51
- // PN<->LID without a separate usync round trip.
52
- const persistParticipantLidMappings = async participantLists => {
53
- const pairs = []
54
- for (const participants of participantLists) {
55
- for (const p of participants || []) {
56
- if (p.phoneNumber) pairs.push({ lid: p.id, pn: p.phoneNumber })
57
- else if (p.lid) pairs.push({ lid: p.lid, pn: p.id })
58
- }
59
- }
60
- if (!pairs.length) return
61
- try {
62
- await sock.signalRepository.lidMapping.storeLIDPNMappings(pairs)
63
- } catch (error) {
64
- sock.logger?.warn?.({ error }, 'failed to store LID/PN mappings from group metadata')
65
- }
66
- }
67
49
 
68
50
  const mexQuery = (variables, queryId, dataPath) =>
69
51
  (0, mex_1.executeWMexQuery)(variables, queryId, dataPath, query, generateMessageTag)
70
52
  const groupMetadata = async jid => {
71
53
  const result = await groupQuery(jid, 'get', [{ tag: 'query', attrs: { request: 'interactive' } }])
72
- const metadata = (0, exports.extractGroupMetadata)(result)
73
- persistParticipantLidMappings([metadata.participants]).catch(() => {})
74
- return metadata
54
+ return (0, exports.extractGroupMetadata)(result)
75
55
  }
76
56
  /**
77
57
  * Acknowledge a group. Ported from WhatsApp Web's WASmaxGroupsAcknowledgeGroupRPC
@@ -139,29 +119,21 @@ const makeGroupsSocket = config => {
139
119
  await groupQuery(parentJid, 'set', [{ tag: 'sub_group_suggestion', attrs: {}, content: suggestion }])
140
120
  }
141
121
  /**
142
- * Approve, reject, or cancel sub-group suggestions for a community. Ported from
143
- * WhatsApp Web's WASmaxGroupsSubGroupSuggestionsActionRPC.
144
- * approve/reject address suggestions by creator jid; cancel addresses them by
145
- * the suggested group's jid (WASmaxOutGroupsSubGroupSuggestionsActionRequest).
122
+ * Approve or reject sub-group suggestions for a community. Ported from WhatsApp
123
+ * Web's WASmaxGroupsSubGroupSuggestionsActionRPC. NOTE: untested against live WhatsApp.
146
124
  * @param {string} parentJid community/parent group to address
147
- * @param {'approve' | 'reject' | 'cancel'} action
148
- * @param {Array<{ creator?: string, jid?: string }>} suggestions
125
+ * @param {'approve' | 'reject'} action
126
+ * @param {Array<{ creator: string, jid?: string }>} suggestions
149
127
  */
150
128
  const groupSubGroupSuggestionsAction = async (parentJid, action, suggestions) => {
151
129
  await groupQuery(parentJid, 'set', [
152
130
  {
153
- tag: 'sub_group_suggestions_action',
131
+ tag: action,
154
132
  attrs: {},
155
- content: [
156
- {
157
- tag: action,
158
- attrs: {},
159
- content: suggestions.map(s => ({
160
- tag: 'sub_group_suggestion',
161
- attrs: action === 'cancel' ? { jid: s.jid } : { creator: s.creator }
162
- }))
163
- }
164
- ]
133
+ content: suggestions.map(s => ({
134
+ tag: 'sub_group_suggestion',
135
+ attrs: { creator: s.creator, ...(s.jid ? { jid: s.jid } : {}) }
136
+ }))
165
137
  }
166
138
  ])
167
139
  }
@@ -197,9 +169,8 @@ const makeGroupsSocket = config => {
197
169
  data[meta.id] = meta
198
170
  }
199
171
  }
200
- const allGroups = Object.values(data)
201
- persistParticipantLidMappings(allGroups.map(g => g.participants)).catch(() => {})
202
- sock.ev.emit('groups.update', allGroups)
172
+ // TODO: properly parse LID / PN DATA
173
+ sock.ev.emit('groups.update', Object.values(data))
203
174
  return data
204
175
  }
205
176
  sock.ws.on('CB:ib,,dirty', async node => {
@@ -443,11 +414,8 @@ const makeGroupsSocket = config => {
443
414
  const result = await groupQuery('@g.us', 'set', [
444
415
  {
445
416
  tag: 'create',
446
- attrs: { subject, key },
447
- content: [
448
- ...participants.map(jid => ({ tag: 'participant', attrs: { jid } })),
449
- { tag: 'linked_parent', attrs: { jid: communityJid } }
450
- ]
417
+ attrs: { subject, key, parent_group_id: communityJid },
418
+ content: participants.map(jid => ({ tag: 'participant', attrs: { jid } }))
451
419
  }
452
420
  ])
453
421
  return (0, exports.extractGroupMetadata)(result)
@@ -522,18 +490,15 @@ const makeGroupsSocket = config => {
522
490
  * Fetch group info via MEX (richer than IQ — includes invite link, LID addressing, etc.)
523
491
  * @param {string} jid - Group JID
524
492
  */
525
- groupQueryInfo: jid => mexQuery({ group_id: jid }, GROUP_MEX_QUERY_IDS.QUERY_INFO, 'xwa2_group_query_by_id'),
493
+ groupQueryInfo: jid =>
494
+ mexQuery({ group_id: jid }, GROUP_MEX_QUERY_IDS.QUERY_INFO, 'xwa2_group_query_by_id'),
526
495
 
527
496
  /**
528
497
  * Fetch group info by invite code via MEX.
529
498
  * @param {string} code - Group invite code (without the link prefix)
530
499
  */
531
500
  groupQueryInfoByCode: code =>
532
- mexQuery(
533
- { group_input: { invite_code: code } },
534
- GROUP_MEX_QUERY_IDS.QUERY_INFO_BY_CODE,
535
- 'xwa2_group_query_by_id'
536
- ),
501
+ mexQuery({ group_input: { invite_code: code } }, GROUP_MEX_QUERY_IDS.QUERY_INFO_BY_CODE, 'xwa2_group_query_by_id'),
537
502
 
538
503
  /**
539
504
  * Fetch multiple groups at once via MEX.
@@ -610,7 +575,7 @@ const makeGroupsSocket = config => {
610
575
  * @param {*} value - Property value
611
576
  */
612
577
  groupSetProperty: (jid, property, value) =>
613
- mexQuery({ group_id: jid, [property]: value }, GROUP_MEX_QUERY_IDS.SET_PROPERTY, 'xwa2_group_update_property'),
578
+ mexQuery({ group_id: jid, [property]: value }, GROUP_MEX_QUERY_IDS.SET_PROPERTY, 'xwa2_group_set_property'),
614
579
 
615
580
  /**
616
581
  * Reset a group's invite link via MEX (generates new code, invalidates old one).
@@ -693,7 +658,8 @@ const makeGroupsSocket = config => {
693
658
  * Query online status of users from PDP.
694
659
  * @param {string[]} jids - User JIDs
695
660
  */
696
- queryOnlineStatus: jids => mexQuery({ jids }, GROUP_MEX_QUERY_IDS.QUERY_ONLINE_STATUS, 'xwa2_query_online_status'),
661
+ queryOnlineStatus: jids =>
662
+ mexQuery({ jids }, GROUP_MEX_QUERY_IDS.QUERY_ONLINE_STATUS, 'xwa2_query_online_status'),
697
663
 
698
664
  /**
699
665
  * Query online status and last seen of users from PDP.
@@ -732,11 +698,6 @@ const extractGroupMetadata = result => {
732
698
  const communityMemberAddGroupNode = (0, WABinary_1.getBinaryNodeChild)(group, 'allow_non_admin_sub_group_creation')
733
699
  const subGroupVisibilityNode = (0, WABinary_1.getBinaryNodeChild)(group, 'sub_groups_list')
734
700
  const membershipApprovalNode = (0, WABinary_1.getBinaryNodeChild)(group, 'membership_approval_mode')
735
- const capiNode = (0, WABinary_1.getBinaryNodeChild)(group, 'capi')
736
- const appealStatusNode = (0, WABinary_1.getBinaryNodeChild)(group, 'appeal_status')
737
- const defaultSubGroupNode = (0, WABinary_1.getBinaryNodeChild)(group, 'default_sub_group')
738
- const generalChatNode = (0, WABinary_1.getBinaryNodeChild)(group, 'general_chat')
739
- const hiddenGroupNode = (0, WABinary_1.getBinaryNodeChild)(group, 'hidden_group')
740
701
  const metadata = {
741
702
  id: groupId,
742
703
  notify: group.attrs.notify,
@@ -766,23 +727,15 @@ const extractGroupMetadata = result => {
766
727
  isCommunityAnnounce: !!(0, WABinary_1.getBinaryNodeChild)(group, 'default_sub_group'),
767
728
  joinApprovalMode: !!membershipApprovalNode,
768
729
  memberAddMode,
769
- memberShareHistoryMode:
770
- (0, WABinary_1.getBinaryNodeChildString)(group, 'member_share_group_history_mode') || undefined,
771
- memberLinkMode: (0, WABinary_1.getBinaryNodeChildString)(group, 'member_link_mode') || undefined,
772
- limitSharing: !!(0, WABinary_1.getBinaryNodeChild)(group, 'limit_sharing_enabled'),
773
- communityMemberAddGroupMode: communityMemberAddGroupNode?.attrs.state || undefined,
774
- capiCreatedGroup: !!capiNode || undefined,
775
- appealStatus: appealStatusNode?.attrs.type || undefined,
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,
776
736
  isSubGroupHidden: group.attrs.sub_group_visibility === 'hidden' || undefined,
777
- membershipApprovalMode: group.attrs.membership_approval_mode || undefined,
778
- joinPermissions: group.attrs.join_permissions || undefined,
779
- isDefaultSubgroup: !!defaultSubGroupNode || undefined,
780
- isGeneralSubgroup: !!generalChatNode || undefined,
781
- isHiddenSubgroup: !!hiddenGroupNode || undefined,
782
737
  participants: (0, WABinary_1.getBinaryNodeChildren)(group, 'participant').map(({ attrs }) => {
783
- // extractGroupMetadata is sync and has no socket in scope to persist with;
784
- // callers (groupMetadata, groupFetchAllParticipating) persist the LID/PN
785
- // pairs surfaced here via persistParticipantLidMappings.
738
+ // TODO: Store LID MAPPINGS
786
739
  return {
787
740
  id: attrs.jid,
788
741
  phoneNumber:
@@ -794,12 +747,11 @@ const extractGroupMetadata = result => {
794
747
  admin: attrs.type || null,
795
748
  memberLabel: attrs.label || undefined,
796
749
  memberLabelTimestamp: attrs.label_ts ? +attrs.label_ts : undefined,
797
- isBanned: attrs.error === '402' || attrs.ban === 'true' || undefined,
798
- uuid: attrs.uuid || attrs.participant_uuid || undefined
750
+ isBanned: attrs.error === '403' || attrs.ban === 'true' || undefined
799
751
  }
800
752
  }),
801
753
  bannedParticipants: (0, WABinary_1.getBinaryNodeChildren)(group, 'participant')
802
- .filter(({ attrs }) => attrs.error === '402' || attrs.ban === 'true')
754
+ .filter(({ attrs }) => attrs.error === '403' || attrs.ban === 'true')
803
755
  .map(({ attrs }) => ({
804
756
  id: attrs.jid,
805
757
  phoneNumber: attrs.phone_number || undefined,
@@ -7,9 +7,11 @@ const { makePrivacySocket } = require('./privacy')
7
7
  const { makeRegistrationSocket } = require('./registration')
8
8
  const { makeManagedAccountSocket } = require('./managed-account')
9
9
  const { makeGraphQLSocket } = require('./graphql')
10
- const { attachTextRouter } = require('./text-router')
10
+ // Antiban protection — bundled directly into this package
11
11
  const { wrapSocket: _wrapSocket } = require('../antiban')
12
+ const { attachTextRouter } = require('./text-router')
12
13
 
14
+ // export the last socket layer
13
15
  const makeWASocket = config => {
14
16
  const userExplicitSyncFlag = typeof config?.syncFullHistory === 'boolean'
15
17
  const initialFullSyncDone = !!config?.auth?.creds?.initialFullSyncDone
@@ -29,9 +31,9 @@ const makeWASocket = config => {
29
31
  const registrationSock = makeRegistrationSocket(privacySock)
30
32
  const managedSock = makeManagedAccountSocket(registrationSock)
31
33
  const sock = makeGraphQLSocket(managedSock)
34
+ // Auto-wrap with antiban if available (config.antiban = false to opt-out)
32
35
  const finalSock =
33
36
  _wrapSocket && config?.antiban !== false ? _wrapSocket(sock, config?.antiban || 'aggressive') : sock
34
-
35
37
  return attachTextRouter(finalSock)
36
38
  }
37
- exports.default = makeWASocket
39
+ exports.default = makeWASocket
@@ -14,7 +14,7 @@ const {
14
14
  } = require('../Utils/index.js')
15
15
  const { isJidGroup, isPnUser, jidNormalizedUser, STORIES_JID } = require('../WABinary/index.js')
16
16
 
17
- class Badzz88Handler {
17
+ class InteractiveMessageHandler {
18
18
  constructor(waUploadToServer, relayMessageFn, config, sock) {
19
19
  this.relayMessage = relayMessageFn
20
20
  this.waUploadToServer = waUploadToServer
@@ -24,12 +24,13 @@ class Badzz88Handler {
24
24
  detectType(content) {
25
25
  if (content.requestPaymentMessage) return 'PAYMENT'
26
26
  if (content.productMessage) return 'PRODUCT'
27
- if (content.interactiveButtons) return 'INTERACTIVE_BUTTONS'
28
27
  if (content.interactiveMessage) return 'INTERACTIVE'
29
28
  if (content.albumMessage || content.album) return 'ALBUM'
30
29
  if (content.eventMessage) return 'EVENT'
31
30
  if (content.pollResultMessage) return 'POLL_RESULT'
32
31
  if (content.groupStatusMessage) return 'GROUP_STORY'
32
+ if (content.orderMessage) return 'ORDER'
33
+ if (content.groupLabel) return 'GROUP_LABEL'
33
34
  return null
34
35
  }
35
36
  async handlePayment(content, quoted) {
@@ -222,114 +223,6 @@ class Badzz88Handler {
222
223
  }
223
224
  return { interactiveMessage }
224
225
  }
225
- async handleInteractiveButtons(content, _jid, _quoted) {
226
- const {
227
- text,
228
- caption,
229
- title,
230
- subtitle,
231
- footer,
232
- interactiveButtons,
233
- hasMediaAttachment,
234
- image,
235
- video,
236
- document,
237
- mimetype,
238
- jpegThumbnail,
239
- location,
240
- product,
241
- businessOwnerJid
242
- } = content
243
- const bodyText = text || caption || ''
244
- const buttons = interactiveButtons.map(btn => ({
245
- name: btn.name,
246
- buttonParamsJson:
247
- typeof btn.buttonParamsJson === 'string' ? btn.buttonParamsJson : JSON.stringify(btn.buttonParamsJson)
248
- }))
249
- let headerContent = {}
250
- let mediaAttached = typeof hasMediaAttachment === 'boolean' ? hasMediaAttachment : false
251
- if (image) {
252
- const src = typeof image === 'object' && image.url ? { image: { url: image.url } } : { image }
253
- const uploaded = await prepareWAMessageMedia(src, { upload: this.waUploadToServer })
254
- headerContent = { ...uploaded }
255
- mediaAttached = typeof hasMediaAttachment === 'boolean' ? hasMediaAttachment : true
256
- } else if (video) {
257
- const src = typeof video === 'object' && video.url ? { video: { url: video.url } } : { video }
258
- const uploaded = await prepareWAMessageMedia(src, { upload: this.waUploadToServer })
259
- headerContent = { ...uploaded }
260
- mediaAttached = typeof hasMediaAttachment === 'boolean' ? hasMediaAttachment : true
261
- } else if (document) {
262
- const docPayload =
263
- typeof document === 'object' && document.url ? { document: { url: document.url } } : { document }
264
- if (mimetype) docPayload.mimetype = mimetype
265
- const uploaded = await prepareWAMessageMedia(docPayload, { upload: this.waUploadToServer })
266
- if (jpegThumbnail) {
267
- uploaded.documentMessage.jpegThumbnail =
268
- typeof jpegThumbnail === 'string' ? Buffer.from(jpegThumbnail, 'base64') : jpegThumbnail
269
- }
270
- headerContent = { ...uploaded }
271
- mediaAttached = typeof hasMediaAttachment === 'boolean' ? hasMediaAttachment : true
272
- } else if (location) {
273
- headerContent = {
274
- locationMessage: {
275
- degreesLatitude: location.degressLatitude || location.degreesLatitude || 0,
276
- degreesLongitude: location.degressLongitude || location.degreesLongitude || 0,
277
- name: location.name || ''
278
- }
279
- }
280
- mediaAttached = typeof hasMediaAttachment === 'boolean' ? hasMediaAttachment : true
281
- } else if (product) {
282
- let productImage
283
- if (product.productImage) {
284
- const imgSrc =
285
- typeof product.productImage === 'object' && product.productImage.url
286
- ? { image: { url: product.productImage.url } }
287
- : { image: product.productImage }
288
- const uploaded = await prepareWAMessageMedia(imgSrc, { upload: this.waUploadToServer })
289
- productImage = uploaded.imageMessage
290
- }
291
- headerContent = {
292
- productMessage: {
293
- product: {
294
- productImage,
295
- productId: product.productId,
296
- title: product.title,
297
- description: product.description,
298
- currencyCode: product.currencyCode || 'IDR',
299
- priceAmount1000: product.priceAmount1000,
300
- retailerId: product.retailerId,
301
- url: product.url,
302
- productImageCount: product.productImageCount || 1
303
- },
304
- businessOwnerJid: businessOwnerJid || '0@s.whatsapp.net'
305
- }
306
- }
307
- mediaAttached = typeof hasMediaAttachment === 'boolean' ? hasMediaAttachment : true
308
- }
309
- const interactiveMessage = {
310
- body: { text: bodyText },
311
- footer: { text: footer || '' },
312
- header: {
313
- title: title || '',
314
- subtitle: subtitle || '',
315
- hasMediaAttachment: mediaAttached,
316
- ...headerContent
317
- },
318
- nativeFlowMessage: { buttons }
319
- }
320
- return {
321
- viewOnceMessage: {
322
- message: {
323
- messageContextInfo: {
324
- deviceListMetadata: {},
325
- deviceListMetadataVersion: 2,
326
- messageSecret: crypto.randomBytes(32)
327
- },
328
- interactiveMessage
329
- }
330
- }
331
- }
332
- }
333
226
  async handleAlbum(content, jid, quoted) {
334
227
  const array = content.albumMessage || content.album
335
228
  const ctxInfo = content.contextInfo || {}
@@ -344,7 +237,7 @@ class Badzz88Handler {
344
237
  expectedVideoCount: array.filter(a => 'video' in a).length
345
238
  }
346
239
  },
347
- { userJid: jidNormalizedUser(this.sock.authState?.creds?.me?.id || '') }
240
+ { userJid: jidNormalizedUser(this.sock.authState?.creds?.me?.id || ''), browser: this.config?.browser }
348
241
  )
349
242
  await this.relayMessage(jid, album.message, {
350
243
  messageId: album.key.id
@@ -394,18 +287,18 @@ class Badzz88Handler {
394
287
  joinLink: eventData.joinLink || '',
395
288
  startTime:
396
289
  typeof eventData.startTime === 'string'
397
- ? parseInt(eventData.startTime, 10)
290
+ ? parseInt(eventData.startTime)
398
291
  : eventData.startTime || Date.now(),
399
292
  endTime:
400
293
  typeof eventData.endTime === 'string'
401
- ? parseInt(eventData.endTime, 10)
294
+ ? parseInt(eventData.endTime)
402
295
  : eventData.endTime || Date.now() + 3600000,
403
296
  extraGuestsAllowed: eventData.extraGuestsAllowed !== false
404
297
  }
405
298
  }
406
299
  }
407
300
  },
408
- { quoted, userJid: jidNormalizedUser(this.sock.authState?.creds?.me?.id || '') }
301
+ { quoted, userJid: jidNormalizedUser(this.sock.authState?.creds?.me?.id || ''), browser: this.config?.browser }
409
302
  )
410
303
  await this.relayMessage(jid, msg.message, {
411
304
  messageId: msg.key.id
@@ -426,7 +319,7 @@ class Badzz88Handler {
426
319
  }))
427
320
  }
428
321
  },
429
- { quoted, userJid: jidNormalizedUser(this.sock.authState?.creds?.me?.id || '') }
322
+ { quoted, userJid: jidNormalizedUser(this.sock.authState?.creds?.me?.id || ''), browser: this.config?.browser }
430
323
  )
431
324
  await this.relayMessage(jid, msg.message, {
432
325
  messageId: msg.key.id
@@ -454,6 +347,55 @@ class Badzz88Handler {
454
347
  messageId: generateMessageID()
455
348
  })
456
349
  }
350
+ async handleOrderMessage(content, jid, quoted) {
351
+ const orderData = content.orderMessage
352
+ const orderMsg = await generateWAMessageFromContent(jid, {
353
+ orderMessage: {
354
+ orderId: orderData.orderId || 'ORDER' + generateMessageID(),
355
+ thumbnail: orderData.thumbnail || null,
356
+ itemCount: orderData.itemCount || 0,
357
+ status: orderData.status || 'ACCEPTED',
358
+ surface: orderData.surface || 'CATALOG',
359
+ message: orderData.message,
360
+ orderTitle: orderData.orderTitle,
361
+ sellerJid: orderData.sellerJid || jid,
362
+ token: orderData.token || generateMessageID(),
363
+ totalAmount1000: orderData.totalAmount1000 || 0,
364
+ totalCurrencyCode: orderData.totalCurrencyCode || 'IDR',
365
+ messageVersion: 2
366
+ }
367
+ }, { quoted, browser: this.config?.browser })
368
+ await this.relayMessage(jid, orderMsg.message, {
369
+ messageId: orderMsg.key.id
370
+ })
371
+ return orderMsg
372
+ }
373
+ async handleGbLabel(content, jid) {
374
+ const labelData = content.groupLabel
375
+ if (!isJidGroup(jid)) {
376
+ throw new Error('handleGbLabel requires a group jid')
377
+ }
378
+ const msg = await generateWAMessageFromContent(jid, {
379
+ protocolMessage: {
380
+ type: 'GROUP_MEMBER_LABEL_CHANGE',
381
+ memberLabel: {
382
+ label: labelData.labelText.slice(0, 30)
383
+ }
384
+ }
385
+ }, { browser: this.config?.browser })
386
+ return await this.relayMessage(jid, msg.message, {
387
+ additionalNodes: [
388
+ {
389
+ tag: 'meta',
390
+ attrs: {
391
+ tag_reason: 'user_update',
392
+ appdata: 'member_tag'
393
+ },
394
+ content: undefined
395
+ }
396
+ ]
397
+ })
398
+ }
457
399
  async sendStatusWhatsApp(content, jids = []) {
458
400
  const userJid = jidNormalizedUser(this.sock.authState.creds.me.id)
459
401
  const allUsers = new Set()
@@ -557,7 +499,8 @@ class Badzz88Handler {
557
499
  }
558
500
  }
559
501
  const statusMsg = await generateWAMessageFromContent(normalizedId, protocolMessage, {
560
- userJid: jidNormalizedUser(this.sock.authState?.creds?.me?.id || '')
502
+ userJid: jidNormalizedUser(this.sock.authState?.creds?.me?.id || ''),
503
+ browser: this.config?.browser
561
504
  })
562
505
  await this.relayMessage(normalizedId, statusMsg.message, {
563
506
  additionalNodes: [
@@ -576,4 +519,4 @@ class Badzz88Handler {
576
519
  }
577
520
  }
578
521
 
579
- module.exports = { Badzz88Handler }
522
+ module.exports = { InteractiveMessageHandler }
@@ -5,19 +5,14 @@ exports.makeInteropSocket = void 0
5
5
  const { getBinaryNodeChild, getBinaryNodeChildren, S_WHATSAPP_NET } = require('../WABinary')
6
6
  const { executeWMexQuery } = require('./mex')
7
7
 
8
- /**
9
- * w:mex query IDs for interop group and privacy operations.
10
- *
11
- * Source: whatsapp-android-mex_client_persist_ids.json (WA 2.26.26.4 APK assets)
12
- */
13
8
  const INTEROP_MEX_QUERY_IDS = {
14
- CREATE_GROUP: '25726817620301611', // GroupsCreateInteropGroup
15
- LEAVE_GROUP: '25346167795013271', // LeaveInteropGroup
16
- ADD_PARTICIPANTS: '25732168276369451', // AddParticipantsToInteropGroup
17
- QUERY_GROUP_INFO: '32734144032867938', // QueryInteropGroupInfo
18
- PRIVACY_SETTINGS_QUERY: '24849123668112654', // InteropPrivacySettingsQuery
19
- PRIVACY_SETTINGS_UPDATE: '25421856497452763', // InteropPrivacySettingsUpdate
20
- PRIVACY_SETTINGS_WITH_CONTACT_LIST: '24913399124998598' // InteropPrivacySettingWithContactListUpdate
9
+ CREATE_GROUP: '25726817620301612', // GroupsCreateInteropGroup
10
+ LEAVE_GROUP: '25346167795013270', // LeaveInteropGroup
11
+ ADD_PARTICIPANTS: '25732168276369452', // AddParticipantsToInteropGroup
12
+ QUERY_GROUP_INFO: '32734144032867936', // QueryInteropGroupInfo
13
+ PRIVACY_SETTINGS_QUERY: '24849123668112656', // InteropPrivacySettingsQuery
14
+ PRIVACY_SETTINGS_UPDATE: '25421856497452764', // InteropPrivacySettingsUpdate
15
+ PRIVACY_SETTINGS_WITH_CONTACT_LIST: '24913399124998600' // InteropPrivacySettingWithContactListUpdate
21
16
  }
22
17
 
23
18
  /**
@@ -40,7 +35,7 @@ const TOS_RESULT_ACCEPTED = '160'
40
35
  const INTEROP_BATCH_MAX = 256
41
36
 
42
37
  const makeInteropSocket = sock => {
43
- const { query, generateMessageTag, logger, signalRepository, masqueradeAsPrimary } = sock
38
+ const { query, generateMessageTag, logger, signalRepository } = sock
44
39
 
45
40
  const mexQuery = (variables, queryId, dataPath) =>
46
41
  executeWMexQuery(variables, queryId, dataPath, query, generateMessageTag)
@@ -67,7 +62,7 @@ const makeInteropSocket = sock => {
67
62
  return getBinaryNodeChildren(listNode, 'integrator').map(node => {
68
63
  const featuresNode = getBinaryNodeChild(node, 'features')
69
64
  return {
70
- id: parseInt(node.attrs.id, 10),
65
+ id: parseInt(node.attrs.id),
71
66
  name: node.attrs.name,
72
67
  // "active" | "onboarding" | "removed"
73
68
  status: node.attrs.status,
@@ -197,9 +192,9 @@ const makeInteropSocket = sock => {
197
192
  if (errorNode) {
198
193
  return {
199
194
  externalId: userNode.attrs.external_id,
200
- integratorId: parseInt(userNode.attrs.integrator_id, 10),
195
+ integratorId: parseInt(userNode.attrs.integrator_id),
201
196
  error: {
202
- code: parseInt(errorNode.attrs.code, 10),
197
+ code: parseInt(errorNode.attrs.code),
203
198
  text: errorNode.attrs.text
204
199
  }
205
200
  }
@@ -208,7 +203,7 @@ const makeInteropSocket = sock => {
208
203
  jid: userNode.attrs.jid,
209
204
  externalId: userNode.attrs.external_id,
210
205
  normalizedExternalId: userNode.attrs.normalized_external_id,
211
- integratorId: parseInt(userNode.attrs.integrator_id, 10)
206
+ integratorId: parseInt(userNode.attrs.integrator_id)
212
207
  }
213
208
  })
214
209
  }
@@ -239,7 +234,7 @@ const makeInteropSocket = sock => {
239
234
  enabled: settingsNode.attrs?.enabled,
240
235
  users: getBinaryNodeChildren(settingsNode, 'user').map(n => ({
241
236
  externalId: n.attrs.external_id,
242
- integratorId: parseInt(n.attrs.integrator_id, 10),
237
+ integratorId: parseInt(n.attrs.integrator_id),
243
238
  jid: n.attrs.jid
244
239
  }))
245
240
  }
@@ -351,13 +346,7 @@ const makeInteropSocket = sock => {
351
346
  } catch (err) {
352
347
  logger.warn({ err }, 'interop: failed to opt-in integrators')
353
348
  }
354
- logger.info({ integrators: toOptIn.map(i => i.name) }, 'interop: opted in')
355
- logger.warn(
356
- { integrators: toOptIn.map(i => i.name) },
357
- 'interop: receiving messages from interop contacts (BirdyChat/Haiket) is NOT YET SUPPORTED. ' +
358
- 'The interop bridge only delivers to device 0 (primary phone) via a single Signal session — ' +
359
- 'no fan-out to companion devices. Opt-in and sending may work, but inbound messages will not arrive.'
360
- )
349
+ logger.info({ integrators: toOptIn.map(i => i.name) }, 'interop: initialized')
361
350
  return integrators
362
351
  }
363
352
 
@@ -439,7 +428,11 @@ const makeInteropSocket = sock => {
439
428
  */
440
429
  const queryInteropGroupInfo = async groupJid => {
441
430
  const gid = groupJid.split('@')[0]
442
- return mexQuery({ group_input: { gid } }, INTEROP_MEX_QUERY_IDS.QUERY_GROUP_INFO, 'xwa2_interop_group_query_by_id')
431
+ return mexQuery(
432
+ { group_input: { gid } },
433
+ INTEROP_MEX_QUERY_IDS.QUERY_GROUP_INFO,
434
+ 'xwa2_interop_group_query_by_id'
435
+ )
443
436
  }
444
437
 
445
438
  /**
@@ -490,15 +483,6 @@ const makeInteropSocket = sock => {
490
483
  )
491
484
  }
492
485
 
493
- /**
494
- * Query all interop privacy settings via MEX.
495
- * Uses InteropPrivacySettingsQuery (doc_id: 24849123668112654).
496
- * Returns the current value for each privacy feature (e.g. GROUPADD).
497
- * dataPath: xwa2_interop_privacy_settings
498
- */
499
- const queryInteropPrivacySettings = () =>
500
- mexQuery({}, INTEROP_MEX_QUERY_IDS.PRIVACY_SETTINGS_QUERY, 'xwa2_interop_privacy_settings')
501
-
502
486
  /**
503
487
  * Check whether an interop user allows being added to groups (GROUPADD privacy).
504
488
  * Returns true if the user can be added, false if blocked by their privacy settings.
@@ -553,7 +537,6 @@ const makeInteropSocket = sock => {
553
537
  leaveInteropGroup,
554
538
  addParticipantsToInteropGroup,
555
539
  queryInteropGroupInfo,
556
- queryInteropPrivacySettings,
557
540
  updateInteropPrivacySetting,
558
541
  updateInteropPrivacySettingWithContactList,
559
542
  getInteropGroupAddPrivacy,