@pontalabs/baileys 1.0.10 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (119) hide show
  1. package/README.md +96 -85
  2. package/lib/Defaults/connection.js +39 -0
  3. package/lib/Defaults/constants.js +50 -0
  4. package/lib/Defaults/history.js +13 -0
  5. package/lib/Defaults/index.js +36 -151
  6. package/lib/Defaults/media.js +43 -0
  7. package/lib/Defaults/phonenumber-mcc.json +221 -221
  8. package/lib/Defaults/prefix.js +12 -0
  9. package/lib/Defaults/vialeys-version.json +7 -0
  10. package/lib/Signal/Group/ciphertext-message.js +10 -15
  11. package/lib/Signal/Group/group-session-builder.js +34 -60
  12. package/lib/Signal/Group/group_cipher.js +69 -76
  13. package/lib/Signal/Group/index.js +41 -60
  14. package/lib/Signal/Group/keyhelper.js +12 -57
  15. package/lib/Signal/Group/sender-chain-key.js +20 -33
  16. package/lib/Signal/Group/sender-key-distribution-message.js +43 -48
  17. package/lib/Signal/Group/sender-key-message.js +58 -53
  18. package/lib/Signal/Group/sender-key-name.js +21 -31
  19. package/lib/Signal/Group/sender-key-record.js +21 -34
  20. package/lib/Signal/Group/sender-key-state.js +59 -106
  21. package/lib/Signal/Group/sender-message-key.js +16 -21
  22. package/lib/Signal/libsignal.js +282 -203
  23. package/lib/Signal/lid-mapping.js +164 -184
  24. package/lib/Socket/Client/index.js +31 -22
  25. package/lib/Socket/Client/types.js +9 -15
  26. package/lib/Socket/Client/websocket.js +42 -37
  27. package/lib/Socket/business.js +212 -336
  28. package/lib/Socket/chats.js +696 -940
  29. package/lib/Socket/community.js +454 -369
  30. package/lib/Socket/groups.js +278 -280
  31. package/lib/Socket/index.js +9 -21
  32. package/lib/Socket/messages-recv.js +1027 -1570
  33. package/lib/Socket/messages-send.js +1180 -1136
  34. package/lib/Socket/mex.js +59 -0
  35. package/lib/Socket/newsletter.js +193 -251
  36. package/lib/Socket/socket.js +758 -898
  37. package/lib/Store/index.js +35 -24
  38. package/lib/Store/make-cache-manager-store.js +53 -66
  39. package/lib/Store/make-in-memory-store.js +319 -325
  40. package/lib/Store/make-ordered-dictionary.js +49 -57
  41. package/lib/Store/object-repository.js +10 -15
  42. package/lib/Types/Auth.js +2 -3
  43. package/lib/Types/Bussines.js +2 -3
  44. package/lib/Types/Call.js +2 -3
  45. package/lib/Types/Chat.js +10 -9
  46. package/lib/Types/Contact.js +2 -3
  47. package/lib/Types/Events.js +2 -3
  48. package/lib/Types/GroupMetadata.js +2 -3
  49. package/lib/Types/Label.js +6 -12
  50. package/lib/Types/LabelAssociation.js +4 -13
  51. package/lib/Types/Message.js +10 -18
  52. package/lib/Types/MexUpdates.js +15 -18
  53. package/lib/Types/Newsletter.js +26 -34
  54. package/lib/Types/Product.js +2 -3
  55. package/lib/Types/Signal.js +2 -3
  56. package/lib/Types/Socket.js +2 -3
  57. package/lib/Types/State.js +8 -13
  58. package/lib/Types/USync.js +2 -3
  59. package/lib/Types/index.js +49 -40
  60. package/lib/Utils/auth-utils.js +190 -495
  61. package/lib/Utils/browser-utils.js +29 -0
  62. package/lib/Utils/business.js +177 -199
  63. package/lib/Utils/chat-utils.js +711 -624
  64. package/lib/Utils/crypto.js +116 -161
  65. package/lib/Utils/decode-wa-message.js +225 -321
  66. package/lib/Utils/event-buffer.js +363 -405
  67. package/lib/Utils/generics.js +318 -472
  68. package/lib/Utils/history.js +72 -76
  69. package/lib/Utils/index.js +49 -41
  70. package/lib/Utils/link-preview.js +59 -103
  71. package/lib/Utils/logger.js +4 -7
  72. package/lib/Utils/lt-hash.js +29 -42
  73. package/lib/Utils/make-mutex.js +26 -42
  74. package/lib/Utils/message-retry-manager.js +134 -160
  75. package/lib/Utils/messages-media.js +665 -731
  76. package/lib/Utils/messages.js +518 -1
  77. package/lib/Utils/noise-handler.js +127 -125
  78. package/lib/Utils/pre-key-manager.js +86 -0
  79. package/lib/Utils/process-message.js +739 -351
  80. package/lib/Utils/signal.js +146 -129
  81. package/lib/Utils/use-multi-file-auth-state.js +68 -135
  82. package/lib/Utils/validate-connection.js +183 -142
  83. package/lib/Utils/vialeys-event-stream.js +41 -0
  84. package/lib/WABinary/constants.js +1281 -1289
  85. package/lib/WABinary/decode.js +145 -200
  86. package/lib/WABinary/encode.js +149 -202
  87. package/lib/WABinary/generic-utils.js +79 -97
  88. package/lib/WABinary/index.js +36 -25
  89. package/lib/WABinary/jid-utils.js +91 -123
  90. package/lib/WABinary/types.js +2 -3
  91. package/lib/WAM/BinaryInfo.js +8 -13
  92. package/lib/WAM/constants.js +16584 -11464
  93. package/lib/WAM/encode.js +117 -133
  94. package/lib/WAM/index.js +34 -23
  95. package/lib/WAUSync/Protocols/USyncBotProfileProtocol.js +62 -69
  96. package/lib/WAUSync/Protocols/USyncContactProtocol.js +11 -25
  97. package/lib/WAUSync/Protocols/USyncDeviceProtocol.js +32 -44
  98. package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.js +13 -23
  99. package/lib/WAUSync/Protocols/USyncLIDProtocol.js +24 -38
  100. package/lib/WAUSync/Protocols/USyncStatusProtocol.js +17 -31
  101. package/lib/WAUSync/Protocols/index.js +37 -26
  102. package/lib/WAUSync/USyncQuery.js +66 -66
  103. package/lib/WAUSync/USyncUser.js +13 -18
  104. package/lib/WAUSync/index.js +34 -23
  105. package/lib/index.js +95 -28
  106. package/package.json +4 -3
  107. package/lib/Defaults/baileys-version.json +0 -3
  108. package/lib/Signal/Group/queue-job.d.ts +0 -1
  109. package/lib/Signal/Group/queue-job.js +0 -57
  110. package/lib/Socket/usync.d.ts +0 -37
  111. package/lib/Socket/usync.js +0 -83
  112. package/lib/Utils/baileys-event-stream.d.ts +0 -18
  113. package/lib/Utils/baileys-event-stream.js +0 -70
  114. package/lib/Utils/signal-housekeeping.d.ts +0 -19
  115. package/lib/Utils/signal-housekeeping.js +0 -73
  116. package/lib/Utils/use-mongo-file-auth-state.d.ts +0 -6
  117. package/lib/Utils/use-mongo-file-auth-state.js +0 -84
  118. package/lib/Utils/use-single-file-auth-state.d.ts +0 -13
  119. package/lib/Utils/use-single-file-auth-state.js +0 -80
@@ -1,1339 +1,1378 @@
1
- "use strict"
2
-
3
- var __importDefault = (this && this.__importDefault) || function(mod) {
4
- return (mod && mod.__esModule) ? mod : {
5
- "default": mod
6
- }
7
- }
8
-
9
- Object.defineProperty(exports, "__esModule", {
10
- value: true
11
- })
12
-
13
- const node_cache_1 = __importDefault(require("@cacheable/node-cache"))
14
- const boom_1 = require("@hapi/boom")
15
- const crypto_1 = require("crypto")
16
- const WAProto_1 = require("../../WAProto")
17
- const Defaults_1 = require("../Defaults")
18
- const Utils_1 = require("../Utils")
19
- const Types_1 = require("../Types")
20
- const WABinary_1 = require("../WABinary")
21
- const WAUSync_1 = require("../WAUSync")
22
- const newsletter_1 = require("./newsletter")
23
- const link_preview_1 = require("../Utils/link-preview")
24
- const make_keyed_mutex_1 = require("../Utils/make-mutex")
25
-
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const { default: NodeCache } = require("@cacheable/node-cache");
4
+ const { Boom: Boom } = require("@hapi/boom");
5
+ const { randomBytes: randomBytes } = require("crypto");
6
+ const { proto: proto } = require("../../WAProto");
7
+ const {
8
+ DEFAULT_CACHE_TTLS: DEFAULT_CACHE_TTLS,
9
+ WA_DEFAULT_EPHEMERAL: WA_DEFAULT_EPHEMERAL,
10
+ } = require("../Defaults/constants");
11
+ const {
12
+ delay: delay,
13
+ assertMediaContent: assertMediaContent,
14
+ bindWaitForEvent: bindWaitForEvent,
15
+ decryptMediaRetryData: decryptMediaRetryData,
16
+ encodeNewsletterMessage: encodeNewsletterMessage,
17
+ encodeSignedDeviceIdentity: encodeSignedDeviceIdentity,
18
+ encodeWAMessage: encodeWAMessage,
19
+ encryptMediaRetryRequest: encryptMediaRetryRequest,
20
+ extractDeviceJids: extractDeviceJids,
21
+ generateMessageID: generateMessageID,
22
+ generateParticipantHashV2: generateParticipantHashV2,
23
+ generateWAMessage: generateWAMessage,
24
+ generateWAMessageFromContent: generateWAMessageFromContent,
25
+ getStatusCodeForMediaRetry: getStatusCodeForMediaRetry,
26
+ getUrlFromDirectPath: getUrlFromDirectPath,
27
+ getWAUploadToServer: getWAUploadToServer,
28
+ MessageRetryManager: MessageRetryManager,
29
+ normalizeMessageContent: normalizeMessageContent,
30
+ parseAndInjectE2ESessions: parseAndInjectE2ESessions,
31
+ unixTimestampSeconds: unixTimestampSeconds,
32
+ prepareAlbumMessageContent: prepareAlbumMessageContent,
33
+ aggregateMessageKeysNotFromMe: aggregateMessageKeysNotFromMe,
34
+ } = require("../Utils");
35
+ const { WAMessageAddressingMode: WAMessageAddressingMode } = require("../Types");
36
+ const {
37
+ areJidsSameUser: areJidsSameUser,
38
+ getBinaryNodeChild: getBinaryNodeChild,
39
+ getBinaryNodeChildren: getBinaryNodeChildren,
40
+ getBinaryFilteredBizBot: getBinaryFilteredBizBot,
41
+ getBinaryFilteredButtons: getBinaryFilteredButtons,
42
+ isHostedLidUser: isHostedLidUser,
43
+ isHostedPnUser: isHostedPnUser,
44
+ isJidNewsletter: isJidNewsletter,
45
+ isJidGroup: isJidGroup,
46
+ isLidUser: isLidUser,
47
+ isPnUser: isPnUser,
48
+ jidDecode: jidDecode,
49
+ jidEncode: jidEncode,
50
+ jidNormalizedUser: jidNormalizedUser,
51
+ STORIES_JID: STORIES_JID,
52
+ S_WHATSAPP_NET: S_WHATSAPP_NET,
53
+ } = require("../WABinary");
54
+ const { USyncUser: USyncUser, USyncQuery: USyncQuery } = require("../WAUSync");
55
+ const { makeNewsletterSocket: makeNewsletterSocket } = require("./newsletter");
56
+ const { getUrlInfo: getUrlInfo } = require("../Utils/link-preview");
57
+ const { makeKeyedMutex: makeKeyedMutex } = require("../Utils/make-mutex");
26
58
  const makeMessagesSocket = (config) => {
27
59
  const {
28
- logger,
29
- maxMsgRetryCount,
30
- linkPreviewImageThumbnailWidth,
31
- generateHighQualityLinkPreview,
32
- options: axiosOptions,
33
- patchMessageBeforeSending,
34
- cachedGroupMetadata,
35
- enableRecentMessageCache
36
- } = config
37
- const sock = newsletter_1.makeNewsletterSocket(config)
60
+ logger: logger,
61
+ linkPreviewImageThumbnailWidth: linkPreviewImageThumbnailWidth,
62
+ generateHighQualityLinkPreview: generateHighQualityLinkPreview,
63
+ options: httpRequestOptions,
64
+ patchMessageBeforeSending: patchMessageBeforeSending,
65
+ cachedGroupMetadata: cachedGroupMetadata,
66
+ enableRecentMessageCache: enableRecentMessageCache,
67
+ maxMsgRetryCount: maxMsgRetryCount,
68
+ } = config;
69
+ const conn = makeNewsletterSocket(config);
38
70
  const {
39
- ev,
40
- authState,
41
- processingMutex,
42
- signalRepository,
43
- upsertMessage,
44
- createCallLink,
45
- query,
46
- fetchPrivacySettings,
47
- sendNode,
48
- groupQuery,
49
- groupMetadata,
50
- groupToggleEphemeral,
51
- newsletterWMexQuery,
52
- executeUSyncQuery
53
- } = sock
54
-
55
- const userDevicesCache = config.userDevicesCache || new node_cache_1.default({
56
- stdTTL: Defaults_1.DEFAULT_CACHE_TTLS.USER_DEVICES,
57
- useClones: false
58
- })
59
-
60
- const messageRetryManager = enableRecentMessageCache ? new Utils_1.MessageRetryManager(logger, maxMsgRetryCount) : null
61
- const encryptionMutex = make_keyed_mutex_1.makeKeyedMutex()
62
- const devicesMutex = make_keyed_mutex_1.makeMutex()
63
- let mediaConn
64
-
71
+ ev: ev,
72
+ authState: authState,
73
+ messageMutex: messageMutex,
74
+ signalRepository: signalRepository,
75
+ upsertMessage: upsertMessage,
76
+ createCallLink: createCallLink,
77
+ query: query,
78
+ fetchPrivacySettings: fetchPrivacySettings,
79
+ sendNode: sendNode,
80
+ groupQuery: groupQuery,
81
+ groupMetadata: groupMetadata,
82
+ groupToggleEphemeral: groupToggleEphemeral,
83
+ executeUSyncQuery: executeUSyncQuery,
84
+ newsletterMetadata: newsletterMetadata,
85
+ } = conn;
86
+ const userDevicesCache =
87
+ config.userDevicesCache ||
88
+ new NodeCache({
89
+ stdTTL: DEFAULT_CACHE_TTLS.USER_DEVICES,
90
+ useClones: false,
91
+ });
92
+ const peerSessionsCache = new NodeCache({
93
+ stdTTL: DEFAULT_CACHE_TTLS.USER_DEVICES,
94
+ useClones: false,
95
+ });
96
+ const messageRetryManager = enableRecentMessageCache
97
+ ? new MessageRetryManager(logger, maxMsgRetryCount)
98
+ : null;
99
+ const encryptionMutex = makeKeyedMutex();
100
+ let mediaConn;
65
101
  const refreshMediaConn = async (forceGet = false) => {
66
- const media = await mediaConn
67
- if (!media || forceGet || (new Date().getTime() - media.fetchDate.getTime()) > media.ttl * 1000) {
102
+ const media = await mediaConn;
103
+ if (
104
+ !media ||
105
+ forceGet ||
106
+ new Date().getTime() - media.fetchDate.getTime() > media.ttl * 1e3
107
+ ) {
68
108
  mediaConn = (async () => {
69
109
  const result = await query({
70
- tag: 'iq',
71
- attrs: {
72
- type: 'set',
73
- xmlns: 'w:m',
74
- to: WABinary_1.S_WHATSAPP_NET,
75
- },
76
- content: [{
77
- tag: 'media_conn',
78
- attrs: {}
79
- }]
80
- })
81
- const mediaConnNode = WABinary_1.getBinaryNodeChild(result, 'media_conn')
110
+ tag: "iq",
111
+ attrs: { type: "set", xmlns: "w:m", to: S_WHATSAPP_NET },
112
+ content: [{ tag: "media_conn", attrs: {} }],
113
+ });
114
+ const mediaConnNode = getBinaryNodeChild(result, "media_conn");
82
115
  const node = {
83
- hosts: WABinary_1.getBinaryNodeChildren(mediaConnNode, 'host').map(({
84
- attrs
85
- }) => ({
116
+ hosts: getBinaryNodeChildren(mediaConnNode, "host").map(({ attrs: attrs }) => ({
86
117
  hostname: attrs.hostname,
87
118
  maxContentLengthBytes: +attrs.maxContentLengthBytes,
88
119
  })),
89
120
  auth: mediaConnNode.attrs.auth,
90
121
  ttl: +mediaConnNode.attrs.ttl,
91
- fetchDate: new Date()
92
- }
93
- logger.debug('fetched media conn')
94
- return node
95
- })()
122
+ fetchDate: new Date(),
123
+ };
124
+ logger.debug("fetched media conn");
125
+ return node;
126
+ })();
96
127
  }
97
- return mediaConn
98
- }
99
-
128
+ return mediaConn;
129
+ };
100
130
  const sendReceipt = async (jid, participant, messageIds, type) => {
101
- const node = {
102
- tag: 'receipt',
103
- attrs: {
104
- id: messageIds[0],
105
- },
131
+ if (!messageIds || messageIds.length === 0) {
132
+ throw new Boom("missing ids in receipt");
106
133
  }
107
- const isReadReceipt = type === 'read' || type === 'read-self'
134
+ const node = { tag: "receipt", attrs: { id: messageIds[0] } };
135
+ const isReadReceipt = type === "read" || type === "read-self";
108
136
  if (isReadReceipt) {
109
- node.attrs.t = Utils_1.unixTimestampSeconds().toString()
137
+ node.attrs.t = unixTimestampSeconds().toString();
110
138
  }
111
- if (type === 'sender' && WABinary_1.isJidUser(jid)) {
112
- node.attrs.recipient = jid
113
- node.attrs.to = participant
139
+ if (type === "sender" && (isPnUser(jid) || isLidUser(jid))) {
140
+ node.attrs.recipient = jid;
141
+ node.attrs.to = participant;
114
142
  } else {
115
- node.attrs.to = jid
143
+ node.attrs.to = jid;
116
144
  if (participant) {
117
- node.attrs.participant = participant
145
+ node.attrs.participant = participant;
118
146
  }
119
147
  }
120
148
  if (type) {
121
- node.attrs.type = WABinary_1.isJidNewsletter(jid) ? 'read-self' : type
149
+ node.attrs.type = type;
122
150
  }
123
- const remainingMessageIds = messageIds.slice(1)
151
+ const remainingMessageIds = messageIds.slice(1);
124
152
  if (remainingMessageIds.length) {
125
- node.content = [{
126
- tag: 'list',
127
- attrs: {},
128
- content: remainingMessageIds.map(id => ({
129
- tag: 'item',
130
- attrs: {
131
- id
132
- }
133
- }))
134
- }]
153
+ node.content = [
154
+ {
155
+ tag: "list",
156
+ attrs: {},
157
+ content: remainingMessageIds.map((id) => ({
158
+ tag: "item",
159
+ attrs: { id: id },
160
+ })),
161
+ },
162
+ ];
135
163
  }
136
- logger.debug({
137
- attrs: node.attrs,
138
- messageIds
139
- }, 'sending receipt for messages')
140
- await sendNode(node)
141
- }
142
-
164
+ logger.debug({ attrs: node.attrs, messageIds: messageIds }, "sending receipt for messages");
165
+ await sendNode(node);
166
+ };
143
167
  const sendReceipts = async (keys, type) => {
144
- const recps = Utils_1.aggregateMessageKeysNotFromMe(keys)
145
- for (const { jid, participant, messageIds } of recps) {
146
- await sendReceipt(jid, participant, messageIds, type)
168
+ const recps = aggregateMessageKeysNotFromMe(keys);
169
+ for (const { jid: jid, participant: participant, messageIds: messageIds } of recps) {
170
+ await sendReceipt(jid, participant, messageIds, type);
147
171
  }
148
- }
149
-
172
+ };
150
173
  const readMessages = async (keys) => {
151
- const privacySettings = await fetchPrivacySettings()
152
- const readType = privacySettings.readreceipts === 'all' ? 'read' : 'read-self'
153
- await sendReceipts(keys, readType)
154
- }
155
-
156
- const deduplicateLidPnJids = (jids) => {
157
- const lidUsers = new Set()
158
- const filteredJids = []
159
-
160
- for (const jid of jids) {
161
- if (WABinary_1.isLidUser(jid)) {
162
- const user = WABinary_1.jidDecode(jid)?.user
163
- if (user) lidUsers.add(user)
164
- }
165
- }
166
-
167
- for (const jid of jids) {
168
- if (WABinary_1.isJidUser(jid)) {
169
- const user = WABinary_1.jidDecode(jid)?.user
170
- if (user && lidUsers.has(user)) {
171
- logger.debug({
172
- jid
173
- }, 'Skipping PN - LID version exists')
174
- continue
175
- }
176
- }
177
- filteredJids.push(jid)
178
- }
179
- return filteredJids
180
- }
181
-
182
- const profilePictureUrl = async (jid) => {
183
- if (WABinary_1.isJidNewsletter(jid)) {
184
- let node = await newsletterWMexQuery(undefined, Types_1.QueryIds.METADATA, {
185
- input: {
186
- key: jid,
187
- type: 'JID',
188
- view_role: 'GUEST'
189
- },
190
- fetch_viewer_metadata: true,
191
- fetch_full_image: true,
192
- fetch_creation_time: true
193
- })
194
- let result = WABinary_1.getBinaryNodeChild(node, 'result')?.content?.toString()
195
- let metadata = JSON.parse(result).data[Types_1.XWAPaths.NEWSLETTER]
196
- return Utils_1.getUrlFromDirectPath(metadata.thread_metadata.picture?.direct_path || '')
197
- } else {
198
- const result = await query({
199
- tag: 'iq',
200
- attrs: {
201
- target: WABinary_1.jidNormalizedUser(jid),
202
- to: WABinary_1.S_WHATSAPP_NET,
203
- type: 'get',
204
- xmlns: 'w:profile:picture'
205
- },
206
- content: [{
207
- tag: 'picture',
208
- attrs: {
209
- type: 'image',
210
- query: 'url'
211
- }
212
- }]
213
- })
214
- const child = WABinary_1.getBinaryNodeChild(result, 'picture')
215
- return child?.attrs?.url || null
216
- }
217
- }
218
-
174
+ const privacySettings = await fetchPrivacySettings();
175
+ const readType = privacySettings.readreceipts === "all" ? "read" : "read-self";
176
+ await sendReceipts(keys, readType);
177
+ };
219
178
  const getUSyncDevices = async (jids, useCache, ignoreZeroDevices) => {
220
- const deviceResults = []
221
-
179
+ const deviceResults = [];
222
180
  if (!useCache) {
223
- logger.debug('not using cache for devices')
181
+ logger.debug("not using cache for devices");
224
182
  }
225
-
226
- const toFetch = []
227
-
228
- jids = deduplicateLidPnJids(Array.from(new Set(jids)))
183
+ const toFetch = [];
229
184
  const jidsWithUser = jids
230
- .map(jid => {
231
- const decoded = WABinary_1.jidDecode(jid)
232
- const user = decoded?.user
233
- const device = decoded?.device
234
- const isExplicitDevice = typeof device === 'number' && device >= 0
235
-
185
+ .map((jid) => {
186
+ const decoded = jidDecode(jid);
187
+ const user = decoded?.user;
188
+ const device = decoded?.device;
189
+ const isExplicitDevice = typeof device === "number" && device >= 0;
236
190
  if (isExplicitDevice && user) {
237
- deviceResults.push({
238
- user,
239
- device,
240
- wireJid: jid
241
- });
242
- return null
243
- }
244
-
245
- jid = WABinary_1.jidNormalizedUser(jid)
246
- return {
247
- jid,
248
- user
191
+ deviceResults.push({ user: user, device: device, jid: jid });
192
+ return null;
249
193
  }
194
+ jid = jidNormalizedUser(jid);
195
+ return { jid: jid, user: user };
250
196
  })
251
- .filter(jid => jid !== null)
252
-
253
- let mgetDevices
197
+ .filter((jid) => jid !== null);
198
+ let mgetDevices;
254
199
  if (useCache && userDevicesCache.mget) {
255
- const usersToFetch = jidsWithUser.map(j => j?.user).filter(Boolean)
256
- mgetDevices = await userDevicesCache.mget(usersToFetch)
200
+ const usersToFetch = jidsWithUser.map((j) => j?.user).filter(Boolean);
201
+ mgetDevices = await userDevicesCache.mget(usersToFetch);
257
202
  }
258
-
259
- for (const { jid, user } of jidsWithUser) {
203
+ for (const { jid: jid, user: user } of jidsWithUser) {
260
204
  if (useCache) {
261
- const devices = mgetDevices?.[user] || (userDevicesCache.mget ? undefined : (await userDevicesCache.get(user)))
205
+ const devices =
206
+ mgetDevices?.[user] ||
207
+ (userDevicesCache.mget ? undefined : await userDevicesCache.get(user));
262
208
  if (devices) {
263
- const isLidJid = WABinary_1.isLidUser(jid)
264
- const devicesWithWire = devices.map(d => ({
209
+ const devicesWithJid = devices.map((d) => ({
265
210
  ...d,
266
- wireJid: isLidJid ? WABinary_1.jidEncode(d.user, 'lid', d.device) : WABinary_1.jidEncode(d.user, 's.whatsapp.net', d.device)
267
- }))
268
- deviceResults.push(...devicesWithWire)
269
- logger.trace({
270
- user
271
- }, 'using cache for devices')
211
+ jid: jidEncode(d.user, d.server, d.device),
212
+ }));
213
+ deviceResults.push(...devicesWithJid);
214
+ logger.trace({ user: user }, "using cache for devices");
272
215
  } else {
273
- toFetch.push(jid)
216
+ toFetch.push(jid);
274
217
  }
275
218
  } else {
276
- toFetch.push(jid)
219
+ toFetch.push(jid);
277
220
  }
278
221
  }
279
-
280
222
  if (!toFetch.length) {
281
- return deviceResults
223
+ return deviceResults;
282
224
  }
283
-
284
- const requestedLidUsers = new Set()
225
+ const requestedLidUsers = new Set();
285
226
  for (const jid of toFetch) {
286
- if (WABinary_1.isLidUser(jid)) {
287
- const user = WABinary_1.jidDecode(jid)?.user
288
- if (user) requestedLidUsers.add(user)
227
+ if (isLidUser(jid) || isHostedLidUser(jid)) {
228
+ const user = jidDecode(jid)?.user;
229
+ if (user) requestedLidUsers.add(user);
289
230
  }
290
231
  }
291
-
292
- const query = new WAUSync_1.USyncQuery().withContext('message').withDeviceProtocol()
232
+ const query = new USyncQuery()
233
+ .withContext("message")
234
+ .withDeviceProtocol()
235
+ .withLIDProtocol();
293
236
  for (const jid of toFetch) {
294
- query.withUser(new WAUSync_1.USyncUser().withId(jid))
237
+ query.withUser(new USyncUser().withId(jid));
295
238
  }
296
-
297
- const result = await executeUSyncQuery(query)
239
+ const result = await executeUSyncQuery(query);
298
240
  if (result) {
299
- // FIX: pontalabs sebelumnya gak pernah nyimpen mapping LID<->PN
300
- // dari hasil USync device query ini (nuiisweety nyimpen + langsung
301
- // force-refresh session buat LID yang baru ketemu). Tanpa ini,
302
- // pengiriman ke kontak yang butuh LID addressing bisa tetep pakai
303
- // address PN yang salah/basi -> penerima gak bisa decrypt balasan
304
- // bot ("Menunggu pesan ini...").
305
- const lidResults = (result.list || []).filter(item => !!item.lid)
241
+ const lidResults = result.list.filter((a) => !!a.lid);
306
242
  if (lidResults.length > 0) {
243
+ logger.trace("Storing LID maps from device call");
244
+ await signalRepository.lidMapping.storeLIDPNMappings(
245
+ lidResults.map((a) => ({ lid: a.lid, pn: a.id }))
246
+ );
307
247
  try {
308
- await signalRepository.lidMapping.storeLIDPNMappings(
309
- lidResults.map(item => ({ lid: item.lid, pn: item.id }))
310
- )
311
- const lids = lidResults.map(item => item.lid)
312
- await assertSessions(lids, true)
313
- } catch (error) {
314
- logger.warn({ error, count: lidResults.length }, 'failed to store/refresh LID mappings from device sync')
248
+ const lids = lidResults.map((a) => a.lid);
249
+ if (lids.length) {
250
+ await assertSessions(lids, true);
251
+ }
252
+ } catch (e) {
253
+ logger.warn(
254
+ { e: e, count: lidResults.length },
255
+ "failed to assert sessions for newly mapped LIDs"
256
+ );
315
257
  }
316
258
  }
317
- const extracted = Utils_1.extractDeviceJids(result?.list, authState.creds.me.id, ignoreZeroDevices)
318
- const deviceMap = {}
259
+ const extracted = extractDeviceJids(
260
+ result?.list,
261
+ authState.creds.me.id,
262
+ authState.creds.me.lid,
263
+ ignoreZeroDevices
264
+ );
265
+ const deviceMap = {};
319
266
  for (const item of extracted) {
320
- deviceMap[item.user] = deviceMap[item.user] || []
321
- deviceMap[item.user]?.push(item)
267
+ deviceMap[item.user] = deviceMap[item.user] || [];
268
+ deviceMap[item.user]?.push(item);
322
269
  }
323
270
  for (const [user, userDevices] of Object.entries(deviceMap)) {
324
- const isLidUser = requestedLidUsers.has(user)
271
+ const isLidUser = requestedLidUsers.has(user);
325
272
  for (const item of userDevices) {
326
- const finalWireJid = isLidUser ? WABinary_1.jidEncode(user, 'lid', item.device) : WABinary_1.jidEncode(item.user, 's.whatsapp.net', item.device)
327
- deviceResults.push({
328
- ...item,
329
- wireJid: finalWireJid
330
- });
331
- logger.debug({
332
- user: item.user,
333
- device: item.device,
334
- finalWireJid,
335
- usedLid: isLidUser
336
- }, 'Processed device with LID priority')
273
+ const finalJid = isLidUser
274
+ ? jidEncode(user, item.server, item.device)
275
+ : jidEncode(item.user, item.server, item.device);
276
+ deviceResults.push({ ...item, jid: finalJid });
277
+ logger.debug(
278
+ {
279
+ user: item.user,
280
+ device: item.device,
281
+ finalJid: finalJid,
282
+ usedLid: isLidUser,
283
+ },
284
+ "Processed device with LID priority"
285
+ );
337
286
  }
338
287
  }
339
-
340
- await devicesMutex.mutex(async () => {
341
- if (userDevicesCache.mset) {
342
- await userDevicesCache.mset(Object.entries(deviceMap).map(([key, value]) => ({
343
- key,
344
- value
345
- })))
346
- } else {
347
- for (const key in deviceMap) {
348
- if (deviceMap[key]) await userDevicesCache.set(key, deviceMap[key])
349
- }
288
+ if (userDevicesCache.mset) {
289
+ await userDevicesCache.mset(
290
+ Object.entries(deviceMap).map(([key, value]) => ({
291
+ key: key,
292
+ value: value,
293
+ }))
294
+ );
295
+ } else {
296
+ for (const key in deviceMap) {
297
+ if (deviceMap[key]) await userDevicesCache.set(key, deviceMap[key]);
350
298
  }
351
- })
299
+ }
300
+ const userDeviceUpdates = {};
301
+ for (const [userId, devices] of Object.entries(deviceMap)) {
302
+ if (devices && devices.length > 0) {
303
+ userDeviceUpdates[userId] = devices.map((d) => d.device?.toString() || "0");
304
+ }
305
+ }
306
+ if (Object.keys(userDeviceUpdates).length > 0) {
307
+ try {
308
+ await authState.keys.set({ "device-list": userDeviceUpdates });
309
+ logger.debug(
310
+ { userCount: Object.keys(userDeviceUpdates).length },
311
+ "stored user device lists for bulk migration"
312
+ );
313
+ } catch (error) {
314
+ logger.warn({ error: error }, "failed to store user device lists");
315
+ }
316
+ }
352
317
  }
353
- return deviceResults
354
- }
355
-
318
+ return deviceResults;
319
+ };
320
+ const updateMemberLabel = (jid, memberLabel) => {
321
+ if (!isJidGroup(jid)) {
322
+ throw new Error("Jid must a group!");
323
+ }
324
+ const protocolMessage = {
325
+ protocolMessage: {
326
+ type: proto.Message.ProtocolMessage.Type.GROUP_MEMBER_LABEL_CHANGE,
327
+ memberLabel: {
328
+ label: memberLabel?.slice(0, 30),
329
+ labelTimestamp: unixTimestampSeconds(),
330
+ },
331
+ },
332
+ };
333
+ return relayMessage(jid, protocolMessage, {
334
+ additionalNodes: [
335
+ {
336
+ tag: "meta",
337
+ attrs: { tag_reason: "user_update", appdata: "member_tag" },
338
+ },
339
+ ],
340
+ });
341
+ };
356
342
  const assertSessions = async (jids, force) => {
357
343
  let didFetchNewSession = false;
358
- let jidsRequiringFetch = [];
359
-
360
- if (force) {
361
- jidsRequiringFetch = jids;
362
- } else {
363
- // FIX: sebelumnya cuma ngecek "ada record tersimpan atau enggak"
364
- // (truthy check di authState.keys.get('session', ...)). Record
365
- // yang kosong/stale/rusak (misal device grup yang session-nya
366
- // kebentuk tapi gak pernah kepakai/keisi ratchet) tetep truthy,
367
- // jadi dianggap "udah punya sesi" padahal libsignal-nya beneran
368
- // kosong -> pas encrypt muncul "SessionError: No sessions".
369
- // validateSession ngecek session-nya beneran ada & "open" enggak,
370
- // bukan cuma record-nya ada.
371
- for (const jid of jids) {
344
+ const uniqueJids = [...new Set(jids)];
345
+ const jidsRequiringFetch = [];
346
+ logger.debug({ jids: jids }, "assertSessions call with jids");
347
+ for (const jid of uniqueJids) {
348
+ const signalId = signalRepository.jidToSignalProtocolAddress(jid);
349
+ const cachedSession = peerSessionsCache.get(signalId);
350
+ if (cachedSession !== undefined) {
351
+ if (cachedSession && !force) {
352
+ continue;
353
+ }
354
+ } else {
372
355
  const sessionValidation = await signalRepository.validateSession(jid);
373
- if (!sessionValidation.exists) {
374
- jidsRequiringFetch.push(jid);
356
+ const hasSession = sessionValidation.exists;
357
+ peerSessionsCache.set(signalId, hasSession);
358
+ if (hasSession && !force) {
359
+ continue;
375
360
  }
376
361
  }
362
+ jidsRequiringFetch.push(jid);
377
363
  }
378
-
379
364
  if (jidsRequiringFetch.length) {
380
- logger.debug({ jidsRequiringFetch }, 'fetching sessions');
381
-
365
+ const wireJids = [
366
+ ...jidsRequiringFetch.filter((jid) => !!isLidUser(jid) || !!isHostedLidUser(jid)),
367
+ ...(
368
+ (await signalRepository.lidMapping.getLIDsForPNs(
369
+ jidsRequiringFetch.filter((jid) => !!isPnUser(jid) || !!isHostedPnUser(jid))
370
+ )) || []
371
+ ).map((a) => a.lid),
372
+ ];
373
+ logger.debug(
374
+ { jidsRequiringFetch: jidsRequiringFetch, wireJids: wireJids },
375
+ "fetching sessions"
376
+ );
382
377
  const result = await query({
383
- tag: 'iq',
384
- attrs: {
385
- xmlns: 'encrypt',
386
- type: 'get',
387
- to: WABinary_1.S_WHATSAPP_NET,
388
- },
378
+ tag: "iq",
379
+ attrs: { xmlns: "encrypt", type: "get", to: S_WHATSAPP_NET },
389
380
  content: [
390
381
  {
391
- tag: 'key',
382
+ tag: "key",
392
383
  attrs: {},
393
- content: jidsRequiringFetch.map(jid => ({
394
- tag: 'user',
395
- attrs: { jid },
396
- }))
397
- }
398
- ]
384
+ content: wireJids.map((jid) => {
385
+ const attrs = { jid: jid };
386
+ if (force) attrs.reason = "identity";
387
+ return { tag: "user", attrs: attrs };
388
+ }),
389
+ },
390
+ ],
399
391
  });
400
- await (0, Utils_1.parseAndInjectE2ESessions)(result, signalRepository);
392
+ await parseAndInjectE2ESessions(result, signalRepository);
401
393
  didFetchNewSession = true;
394
+ for (const wireJid of wireJids) {
395
+ const signalId = signalRepository.jidToSignalProtocolAddress(wireJid);
396
+ peerSessionsCache.set(signalId, true);
397
+ }
402
398
  }
403
399
  return didFetchNewSession;
404
400
  };
405
-
406
401
  const sendPeerDataOperationMessage = async (pdoMessage) => {
407
402
  if (!authState.creds.me?.id) {
408
- throw new boom_1.Boom('Not authenticated')
403
+ throw new Boom("Not authenticated");
409
404
  }
410
-
411
405
  const protocolMessage = {
412
406
  protocolMessage: {
413
407
  peerDataOperationRequestMessage: pdoMessage,
414
- type: WAProto_1.proto.Message.ProtocolMessage.Type.PEER_DATA_OPERATION_REQUEST_MESSAGE
415
- }
416
- }
417
-
418
- const meJid = WABinary_1.jidNormalizedUser(authState.creds.me.id)
419
- const msgId = await relayMessage(meJid, protocolMessage, {
420
- additionalAttributes: {
421
- category: 'peer',
422
- push_priority: 'high_force',
408
+ type: proto.Message.ProtocolMessage.Type.PEER_DATA_OPERATION_REQUEST_MESSAGE,
423
409
  },
424
- })
425
- return msgId
426
- }
427
-
428
- const createParticipantNodes = async (jids, message, extraAttrs) => {
429
- let patched = await patchMessageBeforeSending(message, jids);
430
-
431
- if (!Array.isArray(patched)) {
432
- patched = jids ? jids.map(jid => ({ recipientJid: jid, ...patched })) : [patched];
410
+ };
411
+ const meJid = jidNormalizedUser(authState.creds.me.id);
412
+ const msgId = await relayMessage(meJid, protocolMessage, {
413
+ additionalAttributes: { category: "peer", push_priority: "high_force" },
414
+ additionalNodes: [{ tag: "meta", attrs: { appdata: "default" } }],
415
+ });
416
+ return msgId;
417
+ };
418
+ const createParticipantNodes = async (recipientJids, message, extraAttrs, dsmMessage) => {
419
+ if (!recipientJids.length) {
420
+ return { nodes: [], shouldIncludeDeviceIdentity: false };
433
421
  }
434
-
422
+ const patched = await patchMessageBeforeSending(message, recipientJids);
423
+ const patchedMessages = Array.isArray(patched)
424
+ ? patched
425
+ : recipientJids.map((jid) => ({ recipientJid: jid, message: patched }));
435
426
  let shouldIncludeDeviceIdentity = false;
436
- const nodes = await Promise.all(patched.map(async (patchedMessageWithJid) => {
437
- const { recipientJid: jid, ...patchedMessage } = patchedMessageWithJid;
438
- if (!jid) {
439
- return {};
440
- }
441
-
442
- const bytes = (0, Utils_1.encodeWAMessage)(patchedMessage);
443
- // FIX: encryptMessage sebelumnya dipanggil tanpa mutex, padahal
444
- // encryptionMutex sudah ada tapi gak dipakai. Kalau ada 2 pesan
445
- // dikirim hampir bersamaan ke jid yang sama (misal "processing..."
446
- // lalu hasil), encryptMessage bisa race saat baca-ubah-tulis session
447
- // Signal, merusak ratchet -> salah satu pesan jadi gak bisa
448
- // didekripsi penerima ("Menunggu pesan ini..." nyangkut selamanya).
449
- const node = await encryptionMutex.mutex(jid, async () => {
450
- const { type, ciphertext } = await signalRepository.encryptMessage({ jid, data: bytes });
451
- if (type === 'pkmsg') {
452
- shouldIncludeDeviceIdentity = true;
427
+ const meId = authState.creds.me.id;
428
+ const meLid = authState.creds.me?.lid;
429
+ const meLidUser = meLid ? jidDecode(meLid)?.user : null;
430
+ const encryptionPromises = patchedMessages.map(
431
+ async ({ recipientJid: jid, message: patchedMessage }) => {
432
+ if (!jid) return null;
433
+ let msgToEncrypt = patchedMessage;
434
+ if (dsmMessage) {
435
+ const { user: targetUser } = jidDecode(jid);
436
+ const { user: ownPnUser } = jidDecode(meId);
437
+ const ownLidUser = meLidUser;
438
+ const isOwnUser =
439
+ targetUser === ownPnUser || (ownLidUser && targetUser === ownLidUser);
440
+ const isExactSenderDevice = jid === meId || (meLid && jid === meLid);
441
+ if (isOwnUser && !isExactSenderDevice) {
442
+ msgToEncrypt = dsmMessage;
443
+ logger.debug(
444
+ { jid: jid, targetUser: targetUser },
445
+ "Using DSM for own device"
446
+ );
447
+ }
453
448
  }
454
- return {
455
- tag: 'to',
456
- attrs: { jid },
457
- content: [{
458
- tag: 'enc',
459
- attrs: {
460
- v: '2',
461
- type,
462
- ...extraAttrs || {}
463
- },
464
- content: ciphertext
465
- }]
466
- };
467
- });
468
- return node;
469
- }));
470
- return { nodes, shouldIncludeDeviceIdentity };
449
+ const bytes = encodeWAMessage(msgToEncrypt);
450
+ const mutexKey = jid;
451
+ const node = await encryptionMutex.mutex(mutexKey, async () => {
452
+ const { type: type, ciphertext: ciphertext } =
453
+ await signalRepository.encryptMessage({ jid: jid, data: bytes });
454
+ if (type === "pkmsg") {
455
+ shouldIncludeDeviceIdentity = true;
456
+ }
457
+ return {
458
+ tag: "to",
459
+ attrs: { jid: jid },
460
+ content: [
461
+ {
462
+ tag: "enc",
463
+ attrs: { v: "2", type: type, ...(extraAttrs || {}) },
464
+ content: ciphertext,
465
+ },
466
+ ],
467
+ };
468
+ });
469
+ return node;
470
+ }
471
+ );
472
+ const nodes = (await Promise.all(encryptionPromises)).filter((node) => node !== null);
473
+ return {
474
+ nodes: nodes,
475
+ shouldIncludeDeviceIdentity: shouldIncludeDeviceIdentity,
476
+ };
471
477
  };
472
-
473
- const relayMessage = async (jid, message, {
474
- messageId: msgId,
475
- participant,
476
- additionalAttributes,
477
- useUserDevicesCache,
478
- useCachedGroupMetadata,
479
- statusJidList,
480
- additionalNodes,
481
- ai = false
482
- }) => {
483
- const meId = authState.creds.me.id
484
- const meLid = authState.creds.me?.lid
485
-
486
- let additionalAlready = false
487
- let shouldIncludeDeviceIdentity = false
488
-
489
- const {
490
- user,
491
- server
492
- } = WABinary_1.jidDecode(jid)
493
-
494
- const statusJid = 'status@broadcast'
495
- const isGroup = server === 'g.us'
496
- const isPrivate = server === 's.whatsapp.net'
497
- const isNewsletter = server == 'newsletter'
498
- const isStatus = jid === statusJid
499
- const isLid = server === 'lid'
500
-
501
- const finalJid = jid
502
-
503
- let ownId = meId
504
-
505
- if (isLid && meLid) {
506
- ownId = meLid
507
- logger.debug({
508
- to: jid,
509
- ownId
510
- }, 'Using LID identity for @lid conversation')
478
+ const profilePictureUrl = async (jid) => {
479
+ if (isJidNewsletter(jid)) {
480
+ const metadata = await conn.newsletterMetadata("JID", jid);
481
+ return getUrlFromDirectPath(metadata.thread_metadata.picture?.direct_path || "");
511
482
  } else {
512
- logger.debug({
513
- to: jid,
514
- ownId
515
- }, 'Using PN identity for @s.whatsapp.net conversation')
483
+ const result = await query({
484
+ tag: "iq",
485
+ attrs: {
486
+ target: jidNormalizedUser(jid),
487
+ to: S_WHATSAPP_NET,
488
+ type: "get",
489
+ xmlns: "w:profile:picture",
490
+ },
491
+ content: [{ tag: "picture", attrs: { type: "image", query: "url" } }],
492
+ });
493
+ const child = getBinaryNodeChild(result, "picture");
494
+ return child?.attrs?.url || null;
516
495
  }
517
-
518
- msgId = msgId || Utils_1.generateMessageID(authState.creds.me.id)
519
- useUserDevicesCache = useUserDevicesCache !== false
520
- useCachedGroupMetadata = useCachedGroupMetadata !== false && !isStatus
521
-
522
- const participants = []
523
- const destinationJid = !isStatus ? finalJid : statusJid
524
- const binaryNodeContent = []
525
- const devices = []
526
-
527
- const meMsg = {
528
- deviceSentMessage: {
529
- destinationJid,
530
- message
531
- },
532
- messageContextInfo: message.messageContextInfo || {}
496
+ };
497
+ const relayMessage = async (
498
+ jid,
499
+ message,
500
+ {
501
+ messageId: msgId,
502
+ participant: participant,
503
+ additionalAttributes: additionalAttributes,
504
+ useUserDevicesCache: useUserDevicesCache,
505
+ useCachedGroupMetadata: useCachedGroupMetadata,
506
+ statusJidList: statusJidList,
507
+ additionalNodes: additionalNodes,
508
+ AI: AI = false,
509
+ onTarget = false,
533
510
  }
534
-
535
- const extraAttrs = {}
536
- const regexGroupOld = /^(\d{1,15})-(\d+)@g\.us$/
537
- const messages = Utils_1.normalizeMessageContent(message)
538
- const buttonType = getButtonType(messages)
539
- const pollMessage = messages.pollCreationMessage || messages.pollCreationMessageV2 || messages.pollCreationMessageV3
540
-
511
+ ) => {
512
+ const meId = authState.creds.me.id;
513
+ const meLid = authState.creds.me?.lid;
514
+ const isRetryResend = Boolean(participant?.jid);
515
+ let shouldIncludeDeviceIdentity = isRetryResend;
516
+ let didPushAdditional = false;
517
+ const statusJid = "status@broadcast";
518
+ const { user: user, server: server } = jidDecode(jid);
519
+ const isGroup = server === "g.us";
520
+ const isStatus = jid === statusJid;
521
+ const isLid = server === "lid";
522
+ const isNewsletter = server === "newsletter";
523
+ const isGroupOrStatus = isGroup || isStatus;
524
+ const finalJid = jid;
525
+ msgId = msgId || generateMessageID(meId);
526
+ useUserDevicesCache = useUserDevicesCache !== false;
527
+ useCachedGroupMetadata = useCachedGroupMetadata !== false && !isStatus;
528
+ const participants = [];
529
+ const destinationJid = !isStatus ? finalJid : statusJid;
530
+ const binaryNodeContent = [];
531
+ const devices = [];
532
+ const meMsg = {
533
+ deviceSentMessage: { destinationJid: destinationJid, message: message },
534
+ messageContextInfo: message.messageContextInfo,
535
+ };
536
+ const extraAttrs = {};
537
+ const regexGroupOld = /^(\d{1,15})-(\d+)@g\.us$/;
538
+ const messages = normalizeMessageContent(message);
539
+ const buttonType = getButtonType(messages);
540
+ const pollMessage =
541
+ messages.pollCreationMessage ||
542
+ messages.pollCreationMessageV2 ||
543
+ messages.pollCreationMessageV3;
541
544
  if (participant) {
542
545
  if (!isGroup && !isStatus) {
543
546
  additionalAttributes = {
544
547
  ...additionalAttributes,
545
- 'device_fanout': 'false'
546
- }
548
+ device_fanout: "false",
549
+ };
547
550
  }
548
-
549
- const {
550
- user,
551
- device
552
- } = WABinary_1.jidDecode(participant.jid)
553
-
554
- devices.push({
555
- user,
556
- device,
557
- wireJid: participant.jid
558
- })
551
+ const { user: user, device: device } = jidDecode(participant.jid);
552
+ devices.push({ user: user, device: device, jid: participant.jid });
559
553
  }
560
-
561
554
  await authState.keys.transaction(async () => {
562
- const mediaType = getMediaType(messages)
555
+ const mediaType = getMediaType(message);
563
556
  if (mediaType) {
564
- extraAttrs['mediatype'] = mediaType
557
+ extraAttrs["mediatype"] = mediaType;
565
558
  }
559
+ if (isNewsletter) {
566
560
 
567
- if (messages.pinInChatMessage || messages.keepInChatMessage || message.reactionMessage || message.protocolMessage?.editedMessage) {
568
- extraAttrs['decrypt-fail'] = 'hide'
569
- }
561
+ const patched = patchMessageBeforeSending
562
+ ? await patchMessageBeforeSending(message, [])
563
+ : message
564
+
565
+ const mediaType = getMediaType(patched)
566
+
567
+ if (mediaType) {
568
+ extraAttrs["mediatype"] = mediaType
569
+ }
570
+
571
+ if (
572
+ patched.interactiveMessage &&
573
+ !extraAttrs["mediatype"]
574
+ ) {
575
+ extraAttrs["mediatype"] = "interactive"
576
+ }
570
577
 
578
+ const bytes = encodeNewsletterMessage(patched)
579
+
580
+ binaryNodeContent.push({
581
+ tag: "plaintext",
582
+ attrs: extraAttrs,
583
+ content: bytes
584
+ })
585
+
586
+ const stanza = {
587
+ tag: "message",
588
+ attrs: {
589
+ to: jid,
590
+ id: msgId,
591
+ type: getTypeMessage(patched),
592
+ ...(additionalAttributes || {}),
593
+ },
594
+ content: binaryNodeContent,
595
+ }
596
+
597
+ logger.debug(
598
+ {
599
+ msgId,
600
+ mediaType,
601
+ extraAttrs
602
+ },
603
+ `sending newsletter message to ${jid}`
604
+ )
605
+
606
+ await sendNode(stanza)
607
+
608
+ return
609
+ }
610
+ if (
611
+ messages.pinInChatMessage ||
612
+ messages.keepInChatMessage ||
613
+ message.reactionMessage ||
614
+ message.protocolMessage?.editedMessage
615
+ ) {
616
+ extraAttrs["decrypt-fail"] = "hide";
617
+ }
571
618
  if (messages.interactiveResponseMessage?.nativeFlowResponseMessage) {
572
- extraAttrs['native_flow_name'] = messages.interactiveResponseMessage.nativeFlowResponseMessage?.name || 'menu_options'
619
+ extraAttrs["native_flow_name"] =
620
+ messages.interactiveResponseMessage.nativeFlowResponseMessage?.name ||
621
+ "menu_options";
573
622
  }
574
-
575
- if (isGroup || isStatus) {
623
+ if (isGroupOrStatus && !isRetryResend) {
576
624
  const [groupData, senderKeyMap] = await Promise.all([
577
625
  (async () => {
578
- let groupData = useCachedGroupMetadata && cachedGroupMetadata ? await cachedGroupMetadata(jid) : undefined
626
+ let groupData =
627
+ useCachedGroupMetadata && cachedGroupMetadata
628
+ ? await cachedGroupMetadata(jid)
629
+ : undefined;
579
630
  if (groupData && Array.isArray(groupData?.participants)) {
580
- logger.trace({
581
- jid,
582
- participants: groupData.participants.length
583
- }, 'using cached group metadata')
631
+ logger.trace(
632
+ { jid: jid, participants: groupData.participants.length },
633
+ "using cached group metadata"
634
+ );
584
635
  } else if (!isStatus) {
585
- groupData = await global.groupMetadataCache(jid)
636
+ groupData = await groupMetadata(jid);
586
637
  }
587
- return groupData
638
+ return groupData;
588
639
  })(),
589
640
  (async () => {
590
641
  if (!participant && !isStatus) {
591
- const result = await authState.keys.get('sender-key-memory', [jid])
592
- return result[jid] || {}
642
+ const result = await authState.keys.get("sender-key-memory", [jid]);
643
+ return result[jid] || {};
593
644
  }
594
- return {}
595
- })()
596
- ])
597
-
598
- if (!participant) {
599
- const participantsList = (groupData && !isStatus) ? groupData.participants.map(p => p.id) : []
600
- if (isStatus && statusJidList) {
601
- participantsList.push(...statusJidList)
602
- }
603
- if (!isStatus) {
604
- const groupAddressingMode = groupData?.addressingMode || (isLid ? Types_1.WAMessageAddressingMode.LID : Types_1.WAMessageAddressingMode.PN)
605
- additionalAttributes = {
606
- ...additionalAttributes,
607
- addressing_mode: groupAddressingMode
608
- }
609
- }
610
- const additionalDevices = await getUSyncDevices(participantsList, !!useUserDevicesCache, false)
611
- devices.push(...additionalDevices)
645
+ return {};
646
+ })(),
647
+ ]);
648
+ const participantsList = groupData ? groupData.participants.map((p) => p.id) : [];
649
+ if (groupData?.ephemeralDuration && groupData.ephemeralDuration > 0) {
650
+ additionalAttributes = {
651
+ ...additionalAttributes,
652
+ expiration: groupData.ephemeralDuration.toString(),
653
+ };
612
654
  }
613
-
614
- const patched = await patchMessageBeforeSending(message, devices.map(d => WABinary_1.jidEncode(d.user, isLid ? 'lid' : 's.whatsapp.net', d.device)))
615
- const bytes = Utils_1.encodeWAMessage(patched)
616
-
617
- const groupAddressingMode = groupData?.addressingMode || (isLid ? 'lid' : 'pn')
618
- const groupSenderIdentity = groupAddressingMode === 'lid' && meLid ? meLid : meId
619
-
655
+ if (isStatus && statusJidList) {
656
+ participantsList.push(...statusJidList);
657
+ }
658
+ const additionalDevices = await getUSyncDevices(
659
+ participantsList,
660
+ !!useUserDevicesCache,
661
+ false
662
+ );
663
+ devices.push(...additionalDevices);
664
+ if (isGroup) {
665
+ additionalAttributes = {
666
+ ...additionalAttributes,
667
+ addressing_mode: groupData?.addressingMode || "lid",
668
+ };
669
+ }
670
+ const patched = await patchMessageBeforeSending(message);
671
+ if (Array.isArray(patched)) {
672
+ throw new Boom("Per-jid patching is not supported in groups");
673
+ }
674
+ const bytes = encodeWAMessage(patched);
675
+ const groupAddressingMode =
676
+ additionalAttributes?.["addressing_mode"] || groupData?.addressingMode || "lid";
677
+ const groupSenderIdentity = groupAddressingMode === "lid" && meLid ? meLid : meId;
620
678
  const {
621
- ciphertext,
622
- senderKeyDistributionMessage
679
+ ciphertext: ciphertext,
680
+ senderKeyDistributionMessage: senderKeyDistributionMessage,
623
681
  } = await signalRepository.encryptGroupMessage({
624
682
  group: destinationJid,
625
683
  data: bytes,
626
- meId: groupSenderIdentity
627
- })
628
-
629
- const senderKeyJids = []
630
-
684
+ meId: groupSenderIdentity,
685
+ });
686
+ const senderKeyRecipients = [];
631
687
  for (const device of devices) {
632
- const deviceJid = device.wireJid
633
- const hasKey = !!senderKeyMap[deviceJid]
634
- if (!hasKey || !!participant) {
635
- senderKeyJids.push(deviceJid)
636
- senderKeyMap[deviceJid] = true
688
+ const deviceJid = device.jid;
689
+ const hasKey = !!senderKeyMap[deviceJid];
690
+ if (
691
+ (!hasKey || !!participant) &&
692
+ !isHostedLidUser(deviceJid) &&
693
+ !isHostedPnUser(deviceJid) &&
694
+ device.device !== 99
695
+ ) {
696
+ senderKeyRecipients.push(deviceJid);
697
+ senderKeyMap[deviceJid] = true;
637
698
  }
638
699
  }
639
-
640
- if (senderKeyJids.length) {
641
- logger.debug({
642
- senderKeyJids
643
- }, 'sending new sender key')
700
+ if (senderKeyRecipients.length) {
701
+ logger.debug({ senderKeyJids: senderKeyRecipients }, "sending new sender key");
644
702
  const senderKeyMsg = {
645
703
  senderKeyDistributionMessage: {
646
704
  axolotlSenderKeyDistributionMessage: senderKeyDistributionMessage,
647
- groupId: destinationJid
648
- }
649
- }
650
-
651
- await assertSessions(senderKeyJids, false)
652
- const result = await createParticipantNodes(senderKeyJids, senderKeyMsg, extraAttrs)
653
- shouldIncludeDeviceIdentity = shouldIncludeDeviceIdentity || result.shouldIncludeDeviceIdentity
654
- participants.push(...result.nodes)
705
+ groupId: destinationJid,
706
+ },
707
+ };
708
+ const senderKeySessionTargets = senderKeyRecipients;
709
+ await assertSessions(senderKeySessionTargets);
710
+ const result = await createParticipantNodes(
711
+ senderKeyRecipients,
712
+ senderKeyMsg,
713
+ extraAttrs
714
+ );
715
+ shouldIncludeDeviceIdentity =
716
+ shouldIncludeDeviceIdentity || result.shouldIncludeDeviceIdentity;
717
+ participants.push(...result.nodes);
655
718
  }
656
-
657
719
  binaryNodeContent.push({
658
- tag: 'enc',
659
- attrs: {
660
- v: '2',
661
- type: 'skmsg',
662
- ...extraAttrs
663
- },
664
- content: ciphertext
665
- })
666
-
720
+ tag: "enc",
721
+ attrs: { v: "2", type: "skmsg", ...extraAttrs },
722
+ content: ciphertext,
723
+ });
667
724
  await authState.keys.set({
668
- 'sender-key-memory': {
669
- [jid]: senderKeyMap
670
- }
671
- })
672
- } else if (isNewsletter) {
673
- if (message.protocolMessage?.editedMessage) {
674
- msgId = message.protocolMessage.key?.id
675
- message = message.protocolMessage.editedMessage
676
- }
677
-
678
- if (message.protocolMessage?.type === WAProto_1.proto.Message.ProtocolMessage.Type.REVOKE) {
679
- msgId = message.protocolMessage.key?.id
680
- message = {}
681
- }
682
-
683
- const patched = await patchMessageBeforeSending(message, [])
684
- const bytes = Utils_1.encodeNewsletterMessage(patched)
685
-
686
- binaryNodeContent.push({
687
- tag: 'plaintext',
688
- attrs: extraAttrs,
689
- content: bytes
690
- })
725
+ "sender-key-memory": { [jid]: senderKeyMap },
726
+ });
691
727
  } else {
692
- const {
693
- user: ownUser
694
- } = WABinary_1.jidDecode(ownId)
695
-
696
- if (!participant) {
697
- const targetUserServer = isLid ? 'lid' : 's.whatsapp.net'
728
+ let ownId = meId;
729
+ if (isLid && meLid) {
730
+ ownId = meLid;
731
+ logger.debug(
732
+ { to: jid, ownId: ownId },
733
+ "Using LID identity for @lid conversation"
734
+ );
735
+ } else {
736
+ logger.debug(
737
+ { to: jid, ownId: ownId },
738
+ "Using PN identity for @s.whatsapp.net conversation"
739
+ );
740
+ }
741
+ const { user: ownUser } = jidDecode(ownId);
742
+ if (!isRetryResend) {
743
+ const targetUserServer = isLid ? "lid" : "s.whatsapp.net";
698
744
  devices.push({
699
- user,
745
+ user: user,
700
746
  device: 0,
701
- wireJid: WABinary_1.jidEncode(user, targetUserServer, 0)
702
- })
703
-
747
+ jid: jidEncode(user, targetUserServer, 0),
748
+ });
704
749
  if (user !== ownUser) {
705
- const ownUserServer = isLid ? 'lid' : 's.whatsapp.net';
706
- const ownUserForAddressing = isLid && meLid ? WABinary_1.jidDecode(meLid).user : WABinary_1.jidDecode(meId).user
750
+ const ownUserServer = isLid ? "lid" : "s.whatsapp.net";
751
+ const ownUserForAddressing =
752
+ isLid && meLid ? jidDecode(meLid).user : jidDecode(meId).user;
707
753
  devices.push({
708
754
  user: ownUserForAddressing,
709
755
  device: 0,
710
- wireJid: WABinary_1.jidEncode(ownUserForAddressing, ownUserServer, 0)
711
- })
756
+ jid: jidEncode(ownUserForAddressing, ownUserServer, 0),
757
+ });
712
758
  }
713
-
714
- if (additionalAttributes?.['category'] !== 'peer') {
715
- devices.length = 0
716
- const senderIdentity = isLid && meLid ? WABinary_1.jidEncode(WABinary_1.jidDecode(meLid)?.user, 'lid', undefined) : WABinary_1.jidEncode(WABinary_1.jidDecode(meId)?.user, 's.whatsapp.net', undefined)
717
- const sessionDevices = await getUSyncDevices([senderIdentity, jid], false, false)
718
- devices.push(...sessionDevices)
719
- logger.debug({
720
- deviceCount: devices.length,
721
- devices: devices.map(d => `${d.user}:${d.device}@${WABinary_1.jidDecode(d.wireJid)?.server}`)
722
- }, 'Device enumeration complete with unified addressing')
759
+ if (additionalAttributes?.["category"] !== "peer") {
760
+ devices.length = 0;
761
+ const senderIdentity =
762
+ isLid && meLid
763
+ ? jidEncode(jidDecode(meLid)?.user, "lid", undefined)
764
+ : jidEncode(jidDecode(meId)?.user, "s.whatsapp.net", undefined);
765
+ const sessionDevices = await getUSyncDevices(
766
+ [senderIdentity, jid],
767
+ true,
768
+ false
769
+ );
770
+ devices.push(...sessionDevices);
771
+ logger.debug(
772
+ {
773
+ deviceCount: devices.length,
774
+ devices: devices.map(
775
+ (d) => `${d.user}:${d.device}@${jidDecode(d.jid)?.server}`
776
+ ),
777
+ },
778
+ "Device enumeration complete with unified addressing"
779
+ );
723
780
  }
724
781
  }
782
+ const allRecipients = []
783
+ const meRecipients = []
784
+ const otherRecipients = []
785
+
786
+ const { user: mePnUser } = jidDecode(meId)
787
+ const { user: meLidUser } = meLid ? jidDecode(meLid) : { user: null }
788
+
789
+ for (const { user, jid } of devices) {
790
+ const isExactSenderDevice =
791
+ jid === meId || (meLid && jid === meLid)
792
+
793
+ if (isExactSenderDevice) {
794
+ logger.debug(
795
+ { jid, meId, meLid },
796
+ 'Skipping exact sender device (whatsmeow pattern)'
797
+ )
798
+ continue
799
+ }
725
800
 
726
- const allJids = []
727
- const meJids = []
728
- const otherJids = []
729
-
730
- const {
731
- user: mePnUser
732
- } = WABinary_1.jidDecode(meId)
733
- const {
734
- user: meLidUser
735
- } = meLid ? WABinary_1.jidDecode(meLid) : {
736
- user: null
737
- }
801
+ const isMe =
802
+ user === mePnUser ||
803
+ user === meLidUser
738
804
 
739
- for (const { user, wireJid } of devices) {
740
- const isExactSenderDevice = wireJid === meId || (meLid && wireJid === meLid)
741
- if (isExactSenderDevice) {
742
- logger.debug({
743
- wireJid,
744
- meId,
745
- meLid
746
- }, 'Skipping exact sender device (whatsmeow pattern)')
747
- continue
748
- }
749
- const isMe = user === mePnUser || (meLidUser && user === meLidUser)
750
- const jid = wireJid
751
- if (isMe) {
752
- meJids.push(jid)
753
- } else {
754
- otherJids.push(jid)
755
- }
756
- allJids.push(jid)
757
- }
805
+ const skipSender = onTarget === true
758
806
 
759
- await assertSessions([...otherJids, ...meJids], false)
760
- const [{
761
- nodes: meNodes,
762
- shouldIncludeDeviceIdentity: s1
763
- }, {
764
- nodes: otherNodes,
765
- shouldIncludeDeviceIdentity: s2
766
- }] = await Promise.all([
767
- createParticipantNodes(meJids, meMsg || message, extraAttrs),
768
- createParticipantNodes(otherJids, message, extraAttrs, meMsg)
769
- ])
807
+ if (isMe) {
808
+ if (!skipSender) {
809
+ meRecipients.push(jid)
810
+ allRecipients.push(jid)
811
+ }
812
+ continue
813
+ }
770
814
 
771
- participants.push(...meNodes)
772
- participants.push(...otherNodes)
773
- if (meJids.length > 0 || otherJids.length > 0) {
774
- extraAttrs['phash'] = Utils_1.generateParticipantHashV2([...meJids, ...otherJids])
815
+ otherRecipients.push(jid)
816
+ allRecipients.push(jid)
817
+ }
818
+ await assertSessions(allRecipients);
819
+ const [
820
+ { nodes: meNodes, shouldIncludeDeviceIdentity: s1 },
821
+ { nodes: otherNodes, shouldIncludeDeviceIdentity: s2 },
822
+ ] = await Promise.all([
823
+ createParticipantNodes(meRecipients, meMsg || message, extraAttrs),
824
+ createParticipantNodes(otherRecipients, message, extraAttrs, meMsg),
825
+ ]);
826
+ participants.push(...meNodes);
827
+ participants.push(...otherNodes);
828
+ if (meRecipients.length > 0 || otherRecipients.length > 0) {
829
+ extraAttrs["phash"] = generateParticipantHashV2([
830
+ ...meRecipients,
831
+ ...otherRecipients,
832
+ ]);
775
833
  }
776
- shouldIncludeDeviceIdentity = shouldIncludeDeviceIdentity || s1 || s2
834
+ shouldIncludeDeviceIdentity = shouldIncludeDeviceIdentity || s1 || s2;
835
+ }
836
+ if (isRetryResend) {
837
+ const isParticipantLid = isLidUser(participant.jid);
838
+ const isMe = areJidsSameUser(participant.jid, isParticipantLid ? meLid : meId);
839
+ const encodedMessageToSend = isMe
840
+ ? encodeWAMessage({
841
+ deviceSentMessage: {
842
+ destinationJid: destinationJid,
843
+ message: message,
844
+ },
845
+ })
846
+ : encodeWAMessage(message);
847
+ const { type: type, ciphertext: encryptedContent } =
848
+ await signalRepository.encryptMessage({
849
+ data: encodedMessageToSend,
850
+ jid: participant.jid,
851
+ });
852
+ binaryNodeContent.push({
853
+ tag: "enc",
854
+ attrs: { v: "2", type: type, count: participant.count.toString() },
855
+ content: encryptedContent,
856
+ });
777
857
  }
778
-
779
858
  if (participants.length) {
780
- if (additionalAttributes?.['category'] === 'peer') {
781
- const peerNode = participants[0]?.content?.[0]
859
+ if (additionalAttributes?.["category"] === "peer") {
860
+ const peerNode = participants[0]?.content?.[0];
782
861
  if (peerNode) {
783
- binaryNodeContent.push(peerNode)
862
+ binaryNodeContent.push(peerNode);
784
863
  }
785
864
  } else {
786
865
  binaryNodeContent.push({
787
- tag: 'participants',
866
+ tag: "participants",
788
867
  attrs: {},
789
- content: participants
790
- })
868
+ content: participants,
869
+ });
791
870
  }
792
871
  }
793
-
794
872
  const stanza = {
795
- tag: 'message',
873
+ tag: "message",
796
874
  attrs: {
797
- to: destinationJid,
798
875
  id: msgId,
876
+ to: destinationJid,
799
877
  type: getTypeMessage(message),
800
- ...(additionalAttributes || {})
878
+ ...(additionalAttributes || {}),
801
879
  },
802
- content: binaryNodeContent
803
- }
804
-
880
+ content: binaryNodeContent,
881
+ };
805
882
  if (participant) {
806
- if (WABinary_1.isJidGroup(destinationJid)) {
807
- stanza.attrs.to = destinationJid
808
- stanza.attrs.participant = participant.jid
809
- } else if (WABinary_1.areJidsSameUser(participant.jid, meId)) {
810
- stanza.attrs.to = participant.jid
811
- stanza.attrs.recipient = destinationJid
883
+ if (isJidGroup(destinationJid)) {
884
+ stanza.attrs.to = destinationJid;
885
+ stanza.attrs.participant = participant.jid;
886
+ } else if (areJidsSameUser(participant.jid, meId)) {
887
+ stanza.attrs.to = participant.jid;
888
+ stanza.attrs.recipient = destinationJid;
812
889
  } else {
813
- stanza.attrs.to = participant.jid
890
+ stanza.attrs.to = participant.jid;
814
891
  }
815
892
  } else {
816
- stanza.attrs.to = destinationJid
893
+ stanza.attrs.to = destinationJid;
817
894
  }
818
-
819
895
  if (shouldIncludeDeviceIdentity) {
820
896
  stanza.content.push({
821
- tag: 'device-identity',
897
+ tag: "device-identity",
822
898
  attrs: {},
823
- content: Utils_1.encodeSignedDeviceIdentity(authState.creds.account, true)
824
- })
825
- logger.debug({
826
- jid
827
- }, 'adding device identity')
899
+ content: encodeSignedDeviceIdentity(authState.creds.account, true),
900
+ });
901
+ logger.debug({ jid: jid }, "adding device identity");
828
902
  }
829
-
830
- if (isGroup && regexGroupOld.test(jid) && !message.reactionMessage) {
903
+ const contactTcTokenData =
904
+ !isGroup && !isRetryResend && !isStatus
905
+ ? await authState.keys.get("tctoken", [destinationJid])
906
+ : {};
907
+ const tcTokenBuffer = contactTcTokenData[destinationJid]?.token;
908
+ if (tcTokenBuffer) {
831
909
  stanza.content.push({
832
- tag: 'multicast',
833
- attrs: {}
834
- })
910
+ tag: "tctoken",
911
+ attrs: {},
912
+ content: tcTokenBuffer,
913
+ });
914
+ }
915
+ if (isGroup && regexGroupOld.test(jid) && !message.reactionMessage) {
916
+ stanza.content.push({ tag: "multicast", attrs: {} });
835
917
  }
836
-
837
918
  if (pollMessage || messages.eventMessage) {
838
- let attrs = {};
839
- if (messages.eventMessage) {
840
- attrs.event_type = 'creation';
841
- } else {
842
- attrs.polltype = 'creation';
843
- if (isNewsletter) {
844
- attrs.contenttype = (pollMessage && pollMessage.pollContentType === 2) ? 'image' : 'text';
845
- }
846
- }
847
919
  stanza.content.push({
848
- tag: 'meta',
849
- attrs: attrs
920
+ tag: "meta",
921
+ attrs: messages.eventMessage
922
+ ? { event_type: "creation" }
923
+ : isNewsletter
924
+ ? {
925
+ polltype: "creation",
926
+ contenttype: pollMessage?.pollContentType === 2 ? "image" : "text",
927
+ }
928
+ : { polltype: "creation" },
850
929
  });
851
930
  }
852
-
853
931
  if (!isNewsletter && buttonType) {
854
- const buttonsNode = getButtonArgs(messages)
855
- const filteredButtons = WABinary_1.getBinaryFilteredButtons(additionalNodes ? additionalNodes : [])
932
+ const buttonsNode = getButtonArgs(messages);
933
+ const filteredButtons = getBinaryFilteredButtons(
934
+ additionalNodes ? additionalNodes : []
935
+ );
856
936
  if (filteredButtons) {
857
- stanza.content.push(...additionalNodes)
858
- additionalAlready = true
937
+ stanza.content.push(...additionalNodes);
938
+ didPushAdditional = true;
859
939
  } else {
860
- stanza.content.push(buttonsNode)
940
+ stanza.content.push(buttonsNode);
861
941
  }
862
942
  }
863
-
864
- if (ai && isPrivate) {
865
- const botNode = {
866
- tag: 'bot',
867
- attrs: {
868
- biz_bot: '1'
869
- }
870
- }
871
- const filteredBizBot = WABinary_1.getBinaryFilteredBizBot(additionalNodes ? additionalNodes : [])
943
+ if (AI && isPrivate) {
944
+ const botNode = { tag: "bot", attrs: { biz_bot: "1" } };
945
+ const filteredBizBot = getBinaryFilteredBizBot(
946
+ additionalNodes ? additionalNodes : []
947
+ );
872
948
  if (filteredBizBot) {
873
- stanza.content.push(...additionalNodes)
874
- additionalAlready = true
949
+ stanza.content.push(...additionalNodes);
950
+ didPushAdditional = true;
875
951
  } else {
876
- stanza.content.push(botNode)
952
+ stanza.content.push(botNode);
877
953
  }
878
954
  }
879
-
880
- if (!additionalAlready && additionalNodes && additionalNodes.length > 0) {
881
- stanza.content.push(...additionalNodes)
955
+ if (!didPushAdditional && additionalNodes && additionalNodes.length > 0) {
956
+ stanza.content.push(...additionalNodes);
882
957
  }
883
-
884
- logger.debug({
885
- msgId
886
- }, `sending message to ${participants.length} devices`)
887
-
888
- await sendNode(stanza)
958
+ logger.debug({ msgId: msgId }, `sending message to ${participants.length} devices`);
959
+ await sendNode(stanza);
889
960
  if (messageRetryManager && !participant) {
890
- messageRetryManager.addRecentMessage(destinationJid, msgId, message)
961
+ messageRetryManager.addRecentMessage(destinationJid, msgId, message);
891
962
  }
892
- }, meId)
893
- return msgId
894
- }
895
-
963
+ }, meId);
964
+ return msgId;
965
+ };
896
966
  const getTypeMessage = (msg) => {
897
- const message = Utils_1.normalizeMessageContent(msg)
898
- if (message.pollCreationMessage || message.pollCreationMessageV2 || message.pollCreationMessageV3) {
899
- return 'poll'
967
+ const message = normalizeMessageContent(msg);
968
+ if (
969
+ message.pollCreationMessage ||
970
+ message.pollCreationMessageV2 ||
971
+ message.pollCreationMessageV3
972
+ ) {
973
+ return "poll";
900
974
  } else if (message.reactionMessage) {
901
- return 'reaction'
975
+ return "reaction";
902
976
  } else if (message.eventMessage) {
903
- return 'event'
977
+ return "event";
904
978
  } else if (getMediaType(message)) {
905
- return 'media'
979
+ return "media";
906
980
  } else {
907
- return 'text'
981
+ return "text";
908
982
  }
909
- }
910
-
983
+ };
911
984
  const getMediaType = (message) => {
912
985
  if (message.imageMessage) {
913
- return 'image'
986
+ return "image";
914
987
  } else if (message.stickerMessage) {
915
- return message.stickerMessage.isLottie ? '1p_sticker' : message.stickerMessage.isAvatar ? 'avatar_sticker' : 'sticker'
988
+ return message.stickerMessage.isLottie
989
+ ? "1p_sticker"
990
+ : message.stickerMessage.isAvatar
991
+ ? "avatar_sticker"
992
+ : "sticker";
916
993
  } else if (message.videoMessage) {
917
- return message.videoMessage.gifPlayback ? 'gif' : 'video'
994
+ return message.videoMessage.gifPlayback ? "gif" : "video";
918
995
  } else if (message.audioMessage) {
919
- return message.audioMessage.ptt ? 'ptt' : 'audio'
996
+ return message.audioMessage.ptt ? "ptt" : "audio";
920
997
  } else if (message.ptvMessage) {
921
- return 'ptv'
998
+ return "ptv";
922
999
  } else if (message.albumMessage) {
923
- return 'collection'
1000
+ return "collection";
924
1001
  } else if (message.contactMessage) {
925
- return 'vcard'
1002
+ return "vcard";
926
1003
  } else if (message.documentMessage) {
927
- return 'document'
1004
+ return "document";
928
1005
  } else if (message.stickerPackMessage) {
929
- return 'sticker_pack'
1006
+ return "sticker_pack";
930
1007
  } else if (message.contactsArrayMessage) {
931
- return 'contact_array'
1008
+ return "contact_array";
932
1009
  } else if (message.locationMessage) {
933
- return 'location'
1010
+ return "location";
934
1011
  } else if (message.liveLocationMessage) {
935
- return 'livelocation'
1012
+ return "livelocation";
936
1013
  } else if (message.listMessage) {
937
- return 'list'
1014
+ return "list";
938
1015
  } else if (message.listResponseMessage) {
939
- return 'list_response'
1016
+ return "list_response";
940
1017
  } else if (message.buttonsResponseMessage) {
941
- return 'buttons_response'
1018
+ return "buttons_response";
942
1019
  } else if (message.orderMessage) {
943
- return 'order'
1020
+ return "order";
944
1021
  } else if (message.productMessage) {
945
- return 'product'
1022
+ return "product";
946
1023
  } else if (message.interactiveResponseMessage) {
947
- return 'native_flow_response'
1024
+ return "native_flow_response";
948
1025
  } else if (/https:\/\/wa\.me\/c\/\d+/.test(message.extendedTextMessage?.text)) {
949
- return 'cataloglink'
1026
+ return "cataloglink";
950
1027
  } else if (/https:\/\/wa\.me\/p\/\d+\/\d+/.test(message.extendedTextMessage?.text)) {
951
- return 'productlink'
1028
+ return "productlink";
952
1029
  } else if (message.extendedTextMessage?.matchedText || message.groupInviteMessage) {
953
- return 'url'
1030
+ return "url";
954
1031
  }
955
- }
956
-
1032
+ };
957
1033
  const getButtonType = (message) => {
958
- const message_content = message.viewOnceMessage?.message || message;
959
- if (message_content.listMessage) {
960
- return 'list';
961
- } else if (message_content.buttonsMessage) {
962
- return 'buttons';
963
- } else if (message_content.interactiveMessage?.nativeFlowMessage) {
964
- return 'native_flow';
1034
+ if (message.listMessage) {
1035
+ return "list";
1036
+ } else if (message.buttonsMessage) {
1037
+ return "buttons";
1038
+ } else if (message.interactiveMessage?.nativeFlowMessage) {
1039
+ return "native_flow";
965
1040
  }
966
1041
  };
967
-
968
1042
  const getButtonArgs = (message) => {
969
- const message_content = message.viewOnceMessage?.message || message;
970
- const message_flow = message_content.interactiveMessage?.nativeFlowMessage;
971
- const flow_buttons_first = message_flow?.buttons?.[0]?.name;
972
- const flow_buttons_special = [ 'mpm', 'cta_catalog', 'send_location', 'call_permission_request', 'wa_payment_transaction_details', 'automated_greeting_message_view_catalog' ];
973
- const baseArgs = {
974
- tag: 'biz',
975
- attrs: {
976
- actual_actors: '2',
977
- host_storage: '2',
978
- privacy_mode_ts: Utils_1.unixTimestampSeconds().toString()
979
- }
980
- };
981
- if (message_flow && (flow_buttons_first === 'review_and_pay' || flow_buttons_first === 'payment_info')) {
1043
+ const nativeFlow = message.interactiveMessage?.nativeFlowMessage;
1044
+ const firstButtonName = nativeFlow?.buttons?.[0]?.name;
1045
+ const nativeFlowSpecials = [
1046
+ "mpm",
1047
+ "cta_catalog",
1048
+ "send_location",
1049
+ "call_permission_request",
1050
+ "wa_payment_transaction_details",
1051
+ "automated_greeting_message_view_catalog",
1052
+ ];
1053
+ if (
1054
+ nativeFlow &&
1055
+ (firstButtonName === "review_and_pay" || firstButtonName === "payment_info")
1056
+ ) {
982
1057
  return {
983
- tag: 'biz',
1058
+ tag: "biz",
984
1059
  attrs: {
985
- native_flow_name: flow_buttons_first === 'review_and_pay' ? 'order_details' : flow_buttons_first
986
- }
1060
+ native_flow_name:
1061
+ firstButtonName === "review_and_pay" ? "order_details" : firstButtonName,
1062
+ },
987
1063
  };
988
- }
989
- if (message_flow && flow_buttons_special.includes(flow_buttons_first)) {
1064
+ } else if (nativeFlow && nativeFlowSpecials.includes(firstButtonName)) {
990
1065
  return {
991
- ...baseArgs,
1066
+ tag: "biz",
1067
+ attrs: {
1068
+ actual_actors: "2",
1069
+ host_storage: "2",
1070
+ privacy_mode_ts: unixTimestampSeconds().toString(),
1071
+ },
992
1072
  content: [
993
1073
  {
994
- tag: 'interactive',
995
- attrs: { type: 'native_flow', v: '1' },
996
- content: [{
997
- tag: 'native_flow',
998
- attrs: { v: '2', name: flow_buttons_first }
999
- }]
1074
+ tag: "interactive",
1075
+ attrs: { type: "native_flow", v: "1" },
1076
+ content: [{ tag: "native_flow", attrs: { v: "2", name: firstButtonName } }],
1000
1077
  },
1001
- {
1002
- tag: 'quality_control',
1003
- attrs: { source_type: 'third_party' }
1004
- }
1005
- ]
1078
+ { tag: "quality_control", attrs: { source_type: "third_party" } },
1079
+ ],
1006
1080
  };
1007
- }
1008
- if (message_flow || message_content.buttonsMessage) {
1081
+ } else if (nativeFlow || message.buttonsMessage) {
1009
1082
  return {
1010
- ...baseArgs,
1083
+ tag: "biz",
1084
+ attrs: {
1085
+ actual_actors: "2",
1086
+ host_storage: "2",
1087
+ privacy_mode_ts: unixTimestampSeconds().toString(),
1088
+ },
1011
1089
  content: [
1012
1090
  {
1013
- tag: 'interactive',
1014
- attrs: { type: 'native_flow', v: '1' },
1015
- content: [{
1016
- tag: 'native_flow',
1017
- attrs: { v: '9', name: 'mixed' }
1018
- }]
1091
+ tag: "interactive",
1092
+ attrs: { type: "native_flow", v: "1" },
1093
+ content: [{ tag: "native_flow", attrs: { v: "9", name: "mixed" } }],
1019
1094
  },
1020
- {
1021
- tag: 'quality_control',
1022
- attrs: { source_type: 'third_party' }
1023
- }
1024
- ]
1095
+ { tag: "quality_control", attrs: { source_type: "third_party" } },
1096
+ ],
1025
1097
  };
1026
- }
1027
- if (message_content.listMessage) {
1098
+ } else if (message.listMessage) {
1028
1099
  return {
1029
- ...baseArgs,
1100
+ tag: "biz",
1101
+ attrs: {
1102
+ actual_actors: "2",
1103
+ host_storage: "2",
1104
+ privacy_mode_ts: unixTimestampSeconds().toString(),
1105
+ },
1030
1106
  content: [
1031
- {
1032
- tag: 'list',
1033
- attrs: { v: '2', type: 'product_list' }
1034
- },
1035
- {
1036
- tag: 'quality_control',
1037
- attrs: { source_type: 'third_party' }
1038
- }
1039
- ]
1107
+ { tag: "list", attrs: { v: "2", type: "product_list" } },
1108
+ { tag: "quality_control", attrs: { source_type: "third_party" } },
1109
+ ],
1110
+ };
1111
+ } else {
1112
+ return {
1113
+ tag: "biz",
1114
+ attrs: {
1115
+ actual_actors: "2",
1116
+ host_storage: "2",
1117
+ privacy_mode_ts: unixTimestampSeconds().toString(),
1118
+ },
1040
1119
  };
1041
1120
  }
1042
- return baseArgs;
1043
1121
  };
1044
-
1045
1122
  const getPrivacyTokens = async (jids) => {
1046
- const t = Utils_1.unixTimestampSeconds().toString()
1047
-
1123
+ const t = unixTimestampSeconds().toString();
1048
1124
  const result = await query({
1049
- tag: 'iq',
1050
- attrs: {
1051
- to: WABinary_1.S_WHATSAPP_NET,
1052
- type: 'set',
1053
- xmlns: 'privacy'
1054
- },
1055
- content: [{
1056
- tag: 'tokens',
1057
- attrs: {},
1058
- content: jids.map(jid => ({
1059
- tag: 'token',
1060
- attrs: {
1061
- jid: WABinary_1.jidNormalizedUser(jid),
1062
- t,
1063
- type: 'trusted_contact'
1064
- }
1065
- }))
1066
- }]
1067
- })
1068
-
1069
- return result
1070
- }
1071
-
1125
+ tag: "iq",
1126
+ attrs: { to: S_WHATSAPP_NET, type: "set", xmlns: "privacy" },
1127
+ content: [
1128
+ {
1129
+ tag: "tokens",
1130
+ attrs: {},
1131
+ content: jids.map((jid) => ({
1132
+ tag: "token",
1133
+ attrs: {
1134
+ jid: jidNormalizedUser(jid),
1135
+ t: t,
1136
+ type: "trusted_contact",
1137
+ },
1138
+ })),
1139
+ },
1140
+ ],
1141
+ });
1142
+ return result;
1143
+ };
1072
1144
  const getEphemeralGroup = (jid) => {
1073
- if (!WABinary_1.isJidGroup(jid)) throw new TypeError("Jid should originate from a group!")
1074
-
1075
- return groupQuery(jid, 'get', [{
1076
- tag: 'query',
1077
- attrs: {
1078
- request: 'interactive'
1079
- }
1080
- }])
1081
- .then((groups) => WABinary_1.getBinaryNodeChild(groups, 'group'))
1082
- .then((metadata) => WABinary_1.getBinaryNodeChild(metadata, 'ephemeral')?.attrs?.expiration || 0)
1083
- }
1084
-
1085
- const waUploadToServer = Utils_1.getWAUploadToServer(config, refreshMediaConn)
1086
-
1087
- const waitForMsgMediaUpdate = Utils_1.bindWaitForEvent(ev, 'messages.media-update')
1088
-
1145
+ if (!isJidGroup(jid)) throw new TypeError("Jid should originate from a group!");
1146
+ return groupQuery(jid, "get", [{ tag: "query", attrs: { request: "interactive" } }])
1147
+ .then((groups) => getBinaryNodeChild(groups, "group"))
1148
+ .then((metadata) => getBinaryNodeChild(metadata, "ephemeral")?.attrs?.expiration || 0);
1149
+ };
1150
+ const waUploadToServer = getWAUploadToServer(config, refreshMediaConn);
1151
+ const waitForMsgMediaUpdate = bindWaitForEvent(ev, "messages.media-update");
1089
1152
  return {
1090
- ...sock,
1091
- getPrivacyTokens,
1092
- assertSessions,
1093
- relayMessage,
1094
- sendReceipt,
1095
- sendReceipts,
1096
- readMessages,
1097
- profilePictureUrl,
1098
- getUSyncDevices,
1099
- refreshMediaConn,
1100
- waUploadToServer,
1101
- getEphemeralGroup,
1102
- fetchPrivacySettings,
1103
- messageRetryManager,
1104
- createParticipantNodes,
1105
- sendPeerDataOperationMessage,
1153
+ ...conn,
1154
+ getPrivacyTokens: getPrivacyTokens,
1155
+ assertSessions: assertSessions,
1156
+ profilePictureUrl: profilePictureUrl,
1157
+ relayMessage: relayMessage,
1158
+ sendReceipt: sendReceipt,
1159
+ sendReceipts: sendReceipts,
1160
+ readMessages: readMessages,
1161
+ getUSyncDevices: getUSyncDevices,
1162
+ refreshMediaConn: refreshMediaConn,
1163
+ waUploadToServer: waUploadToServer,
1164
+ getEphemeralGroup: getEphemeralGroup,
1165
+ fetchPrivacySettings: fetchPrivacySettings,
1166
+ messageRetryManager: messageRetryManager,
1167
+ createParticipantNodes: createParticipantNodes,
1168
+ sendPeerDataOperationMessage: sendPeerDataOperationMessage,
1169
+ updateMemberLabel: updateMemberLabel,
1106
1170
  updateMediaMessage: async (message) => {
1107
- const content = Utils_1.assertMediaContent(message.message)
1108
- const mediaKey = content.mediaKey
1109
- const meId = authState.creds.me.id
1110
- const node = await Utils_1.encryptMediaRetryRequest(message.key, mediaKey, meId)
1111
- let error = undefined
1112
-
1171
+ const content = assertMediaContent(message.message);
1172
+ const mediaKey = content.mediaKey;
1173
+ const meId = authState.creds.me.id;
1174
+ const node = await encryptMediaRetryRequest(message.key, mediaKey, meId);
1175
+ let error = undefined;
1113
1176
  await Promise.all([
1114
1177
  sendNode(node),
1115
1178
  waitForMsgMediaUpdate(async (update) => {
1116
- const result = update.find(c => c.key.id === message.key.id)
1179
+ const result = update.find((c) => c.key.id === message.key.id);
1117
1180
  if (result) {
1118
1181
  if (result.error) {
1119
- error = result.error
1182
+ error = result.error;
1120
1183
  } else {
1121
1184
  try {
1122
- const media = await Utils_1.decryptMediaRetryData(result.media, mediaKey, result.key.id)
1123
-
1124
- if (media.result !== WAProto_1.proto.MediaRetryNotification.ResultType.SUCCESS) {
1125
- const resultStr = WAProto_1.proto.MediaRetryNotification.ResultType[media.result]
1126
-
1127
- throw new boom_1.Boom(`Media re-upload failed by device (${resultStr})`, {
1128
- data: media,
1129
- statusCode: Utils_1.getStatusCodeForMediaRetry(media.result) || 404
1130
- })
1185
+ const media = await decryptMediaRetryData(
1186
+ result.media,
1187
+ mediaKey,
1188
+ result.key.id
1189
+ );
1190
+ if (
1191
+ media.result !== proto.MediaRetryNotification.ResultType.SUCCESS
1192
+ ) {
1193
+ const resultStr =
1194
+ proto.MediaRetryNotification.ResultType[media.result];
1195
+ throw new Boom(
1196
+ `Media re-upload failed by device (${resultStr})`,
1197
+ {
1198
+ data: media,
1199
+ statusCode:
1200
+ getStatusCodeForMediaRetry(media.result) || 404,
1201
+ }
1202
+ );
1131
1203
  }
1132
-
1133
- content.directPath = media.directPath
1134
-
1135
- content.url = Utils_1.getUrlFromDirectPath(content.directPath)
1136
-
1137
- logger.debug({
1138
- directPath: media.directPath,
1139
- key: result.key
1140
- }, 'media update successful')
1204
+ content.directPath = media.directPath;
1205
+ content.url = getUrlFromDirectPath(content.directPath);
1206
+ logger.debug(
1207
+ { directPath: media.directPath, key: result.key },
1208
+ "media update successful"
1209
+ );
1141
1210
  } catch (err) {
1142
- error = err
1211
+ error = err;
1143
1212
  }
1144
1213
  }
1145
-
1146
- return true
1214
+ return true;
1147
1215
  }
1148
- })
1149
- ])
1150
-
1216
+ }),
1217
+ ]);
1151
1218
  if (error) {
1152
- throw error
1219
+ throw error;
1153
1220
  }
1154
-
1155
- ev.emit('messages.update', [{
1156
- key: message.key,
1157
- update: {
1158
- message: message.message
1159
- }
1160
- }])
1161
-
1162
- return message
1221
+ ev.emit("messages.update", [
1222
+ { key: message.key, update: { message: message.message } },
1223
+ ]);
1224
+ return message;
1163
1225
  },
1164
1226
  sendStatusMentions: async (content, jids = []) => {
1165
- const MAX_STATUS_MENTIONS = 5
1166
- if (jids.length > MAX_STATUS_MENTIONS) {
1167
- logger.warn(
1168
- { requested: jids.length, max: MAX_STATUS_MENTIONS },
1169
- `sendStatusMentions: max ${MAX_STATUS_MENTIONS} mentions per status, truncating`
1170
- )
1171
- jids = jids.slice(0, MAX_STATUS_MENTIONS)
1172
- }
1173
- const userJid = WABinary_1.jidNormalizedUser(authState.creds.me.id)
1174
- let allUsers = new Set()
1175
- allUsers.add(userJid)
1176
-
1227
+ const userJid = jidNormalizedUser(authState.creds.me.id);
1228
+ let allUsers = new Set();
1229
+ allUsers.add(userJid);
1177
1230
  for (const id of jids) {
1178
- const isGroup = WABinary_1.isJidGroup(id)
1179
- const isPrivate = WABinary_1.isJidUser(id)
1180
-
1231
+ const isGroup = isJidGroup(id);
1232
+ const isPrivate = isPnUser(id);
1181
1233
  if (isGroup) {
1182
1234
  try {
1183
- const metadata = await cachedGroupMetadata(id) || await global.groupMetadataCache(id)
1184
- const participants = metadata.participants.map(p => WABinary_1.jidNormalizedUser(p.id))
1185
- participants.forEach(jid => allUsers.add(jid))
1235
+ const metadata =
1236
+ (await cachedGroupMetadata(id)) || (await groupMetadata(id));
1237
+ const participants = metadata.participants.map((p) =>
1238
+ jidNormalizedUser(p.id)
1239
+ );
1240
+ participants.forEach((jid) => allUsers.add(jid));
1186
1241
  } catch (error) {
1187
- logger.error(`Error getting metadata for group ${id}: ${error}`)
1242
+ logger.error(`Error getting metadata for group ${id}: ${error}`);
1188
1243
  }
1189
1244
  } else if (isPrivate) {
1190
- allUsers.add(WABinary_1.jidNormalizedUser(id))
1245
+ allUsers.add(jidNormalizedUser(id));
1191
1246
  }
1192
1247
  }
1193
-
1194
- const uniqueUsers = Array.from(allUsers)
1195
- const getRandomHexColor = () => "#" + Math.floor(Math.random() * 16777215).toString(16).padStart(6, "0")
1196
-
1197
- const isMedia = content.image || content.video || content.audio
1198
- const isAudio = !!content.audio
1199
-
1200
- const messageContent = {
1201
- ...content
1202
- }
1203
-
1248
+ const uniqueUsers = Array.from(allUsers);
1249
+ const getRandomHexColor = () =>
1250
+ "#" +
1251
+ Math.floor(Math.random() * 16777215)
1252
+ .toString(16)
1253
+ .padStart(6, "0");
1254
+ const isMedia = content.image || content.video || content.audio;
1255
+ const isAudio = !!content.audio;
1256
+ const messageContent = { ...content };
1204
1257
  if (isMedia && !isAudio) {
1205
1258
  if (messageContent.text) {
1206
- messageContent.caption = messageContent.text
1207
-
1208
- delete messageContent.text
1259
+ messageContent.caption = messageContent.text;
1260
+ delete messageContent.text;
1209
1261
  }
1210
-
1211
- delete messageContent.ptt
1212
- delete messageContent.font
1213
- delete messageContent.backgroundColor
1214
- delete messageContent.textColor
1262
+ delete messageContent.ptt;
1263
+ delete messageContent.font;
1264
+ delete messageContent.backgroundColor;
1265
+ delete messageContent.textColor;
1215
1266
  }
1216
-
1217
1267
  if (isAudio) {
1218
- delete messageContent.text
1219
- delete messageContent.caption
1220
- delete messageContent.font
1221
- delete messageContent.textColor
1268
+ delete messageContent.text;
1269
+ delete messageContent.caption;
1270
+ delete messageContent.font;
1271
+ delete messageContent.textColor;
1222
1272
  }
1223
-
1224
- const font = !isMedia ? (content.font || Math.floor(Math.random() * 9)) : undefined
1225
- const textColor = !isMedia ? (content.textColor || getRandomHexColor()) : undefined
1226
- const backgroundColor = (!isMedia || isAudio) ? (content.backgroundColor || getRandomHexColor()) : undefined
1227
- const ptt = isAudio ? (typeof content.ptt === 'boolean' ? content.ptt : true) : undefined
1228
-
1229
- let msg
1230
- let mediaHandle
1273
+ const font = !isMedia ? content.font || Math.floor(Math.random() * 9) : undefined;
1274
+ const textColor = !isMedia ? content.textColor || getRandomHexColor() : undefined;
1275
+ const backgroundColor =
1276
+ !isMedia || isAudio ? content.backgroundColor || getRandomHexColor() : undefined;
1277
+ const ptt = isAudio
1278
+ ? typeof content.ptt === "boolean"
1279
+ ? content.ptt
1280
+ : true
1281
+ : undefined;
1282
+ let msg;
1283
+ let mediaHandle;
1231
1284
  try {
1232
- msg = await Utils_1.generateWAMessage(WABinary_1.STORIES_JID, messageContent, {
1233
- logger,
1234
- userJid,
1235
- getUrlInfo: text => link_preview_1.getUrlInfo(text, {
1236
- thumbnailWidth: linkPreviewImageThumbnailWidth,
1237
- fetchOpts: {
1238
- timeout: 3000,
1239
- ...axiosOptions || {}
1240
- },
1241
- logger,
1242
- uploadImage: generateHighQualityLinkPreview ? waUploadToServer : undefined
1243
- }),
1285
+ msg = await generateWAMessage(STORIES_JID, messageContent, {
1286
+ logger: logger,
1287
+ userJid: userJid,
1288
+ getUrlInfo: (text) =>
1289
+ getUrlInfo(text, {
1290
+ thumbnailWidth: linkPreviewImageThumbnailWidth,
1291
+ fetchOpts: { timeout: 3e3, ...(httpRequestOptions || {}) },
1292
+ logger: logger,
1293
+ uploadImage: generateHighQualityLinkPreview
1294
+ ? waUploadToServer
1295
+ : undefined,
1296
+ }),
1244
1297
  upload: async (encFilePath, opts) => {
1245
- const up = await waUploadToServer(encFilePath, {
1246
- ...opts
1247
- })
1248
- mediaHandle = up.handle
1249
- return up
1298
+ const up = await waUploadToServer(encFilePath, { ...opts });
1299
+ mediaHandle = up.handle;
1300
+ return up;
1250
1301
  },
1251
1302
  mediaCache: config.mediaCache,
1252
1303
  options: config.options,
1253
- font,
1254
- textColor,
1255
- backgroundColor,
1256
- ptt
1257
- })
1304
+ font: font,
1305
+ textColor: textColor,
1306
+ backgroundColor: backgroundColor,
1307
+ ptt: ptt,
1308
+ });
1258
1309
  } catch (error) {
1259
- logger.error(`Error generating message: ${error}`)
1260
- throw error
1310
+ logger.error(`Error generating message: ${error}`);
1311
+ throw error;
1261
1312
  }
1262
-
1263
- await relayMessage(WABinary_1.STORIES_JID, msg.message, {
1313
+ await relayMessage(STORIES_JID, msg.message, {
1264
1314
  messageId: msg.key.id,
1265
1315
  statusJidList: uniqueUsers,
1266
- additionalNodes: [{
1267
- tag: 'meta',
1268
- attrs: {},
1269
- content: [{
1270
- tag: 'mentioned_users',
1316
+ additionalNodes: [
1317
+ {
1318
+ tag: "meta",
1271
1319
  attrs: {},
1272
- content: jids.map(jid => ({
1273
- tag: 'to',
1274
- attrs: {
1275
- jid: WABinary_1.jidNormalizedUser(jid)
1276
- }
1277
- }))
1278
- }]
1279
- }]
1280
- })
1281
-
1320
+ content: [
1321
+ {
1322
+ tag: "mentioned_users",
1323
+ attrs: {},
1324
+ content: jids.map((jid) => ({
1325
+ tag: "to",
1326
+ attrs: { jid: jidNormalizedUser(jid) },
1327
+ })),
1328
+ },
1329
+ ],
1330
+ },
1331
+ ],
1332
+ });
1282
1333
  for (const id of jids) {
1283
1334
  try {
1284
- const normalizedId = WABinary_1.jidNormalizedUser(id)
1285
- const isPrivate = WABinary_1.isJidUser(normalizedId)
1286
- const type = isPrivate ? 'statusMentionMessage' : 'groupStatusMentionMessage'
1287
-
1335
+ const normalizedId = jidNormalizedUser(id);
1336
+ const isPrivate = isPnUser(normalizedId);
1337
+ const type = isPrivate ? "statusMentionMessage" : "groupStatusMentionMessage";
1288
1338
  const protocolMessage = {
1289
1339
  [type]: {
1290
- message: {
1291
- protocolMessage: {
1292
- key: msg.key,
1293
- type: 25
1294
- }
1295
- }
1340
+ message: { protocolMessage: { key: msg.key, type: 25 } },
1296
1341
  },
1297
- messageContextInfo: {
1298
- messageSecret: crypto_1.randomBytes(32)
1299
- }
1300
- }
1301
-
1302
- const statusMsg = await Utils_1.generateWAMessageFromContent(normalizedId,
1303
- protocolMessage, {}
1304
- )
1305
-
1306
- await relayMessage(
1342
+ messageContextInfo: { messageSecret: randomBytes(32) },
1343
+ };
1344
+ const statusMsg = await generateWAMessageFromContent(
1307
1345
  normalizedId,
1308
- statusMsg.message, {
1309
- additionalNodes: [{
1310
- tag: 'meta',
1311
- attrs: isPrivate ? {
1312
- is_status_mention: 'true'
1313
- } : {
1314
- is_group_status_mention: 'true'
1315
- }
1316
- }]
1317
- }
1318
- )
1319
-
1320
- await Utils_1.delay(2000)
1346
+ protocolMessage,
1347
+ {}
1348
+ );
1349
+ await relayMessage(normalizedId, statusMsg.message, {
1350
+ additionalNodes: [
1351
+ {
1352
+ tag: "meta",
1353
+ attrs: isPrivate
1354
+ ? { is_status_mention: "true" }
1355
+ : { is_group_status_mention: "true" },
1356
+ },
1357
+ ],
1358
+ });
1359
+ await delay(2e3);
1321
1360
  } catch (error) {
1322
- logger.error(`Error sending to ${id}: ${error}`)
1361
+ logger.error(`Error sending to ${id}: ${error}`);
1323
1362
  }
1324
1363
  }
1325
-
1326
- return msg
1364
+ return msg;
1327
1365
  },
1366
+ // --- tambahan dari 1.0.11: kirim album (banyak media digabung 1 pesan) ---
1328
1367
  sendAlbumMessage: async (jid, medias, options = {}) => {
1329
- const userJid = authState.creds.me.id
1368
+ const userJid = authState.creds.me.id;
1330
1369
  for (const media of medias) {
1331
- if (!media.image && !media.video) throw new TypeError(`medias[i] must have image or video property`)
1370
+ if (!media.image && !media.video) throw new TypeError(`medias[i] must have image or video property`);
1332
1371
  }
1333
- if (medias.length < 2) throw new RangeError("Minimum 2 media")
1334
- const time = options.delay || 500
1335
- delete options.delay
1336
- const album = await Utils_1.generateWAMessageFromContent(jid, {
1372
+ if (medias.length < 2) throw new RangeError("Minimum 2 media");
1373
+ const time = options.delay || 500;
1374
+ delete options.delay;
1375
+ const album = await generateWAMessageFromContent(jid, {
1337
1376
  albumMessage: {
1338
1377
  expectedImageCount: medias.filter(media => media.image).length,
1339
1378
  expectedVideoCount: medias.filter(media => media.video).length,
@@ -1342,16 +1381,15 @@ const makeMessagesSocket = (config) => {
1342
1381
  }, {
1343
1382
  userJid,
1344
1383
  ...options
1345
- })
1384
+ });
1346
1385
  await relayMessage(jid, album.message, {
1347
1386
  messageId: album.key.id
1348
- })
1349
- let mediaHandle
1350
- let msg
1387
+ });
1388
+ let msg;
1351
1389
  for (const i in medias) {
1352
- const media = medias[i]
1390
+ const media = medias[i];
1353
1391
  if (media.image) {
1354
- msg = await Utils_1.generateWAMessage(jid, {
1392
+ msg = await generateWAMessage(jid, {
1355
1393
  image: media.image,
1356
1394
  ...media,
1357
1395
  ...options
@@ -1360,15 +1398,14 @@ const makeMessagesSocket = (config) => {
1360
1398
  upload: async (readStream, opts) => {
1361
1399
  const up = await waUploadToServer(readStream, {
1362
1400
  ...opts,
1363
- newsletter: WABinary_1.isJidNewsletter(jid)
1364
- })
1365
- mediaHandle = up.handle
1366
- return up
1401
+ newsletter: isJidNewsletter(jid)
1402
+ });
1403
+ return up;
1367
1404
  },
1368
1405
  ...options
1369
- })
1406
+ });
1370
1407
  } else if (media.video) {
1371
- msg = await Utils_1.generateWAMessage(jid, {
1408
+ msg = await generateWAMessage(jid, {
1372
1409
  video: media.video,
1373
1410
  ...media,
1374
1411
  ...options
@@ -1377,138 +1414,145 @@ const makeMessagesSocket = (config) => {
1377
1414
  upload: async (readStream, opts) => {
1378
1415
  const up = await waUploadToServer(readStream, {
1379
1416
  ...opts,
1380
- newsletter: WABinary_1.isJidNewsletter(jid)
1381
- })
1382
- mediaHandle = up.handle
1383
- return up
1417
+ newsletter: isJidNewsletter(jid)
1418
+ });
1419
+ return up;
1384
1420
  },
1385
1421
  ...options,
1386
- })
1422
+ });
1387
1423
  }
1388
1424
  if (msg) {
1389
1425
  msg.message.messageContextInfo = {
1390
- messageSecret: crypto_1.randomBytes(32),
1426
+ messageSecret: randomBytes(32),
1391
1427
  messageAssociation: {
1392
1428
  associationType: 1,
1393
1429
  parentMessageKey: album.key
1394
1430
  }
1395
- }
1431
+ };
1396
1432
  }
1397
1433
  await relayMessage(jid, msg.message, {
1398
1434
  messageId: msg.key.id
1399
- })
1400
- await Utils_1.delay(time)
1435
+ });
1436
+ await delay(time);
1401
1437
  }
1402
- return album
1438
+ return album;
1403
1439
  },
1440
+ // --- akhir tambahan ---
1404
1441
  sendMessage: async (jid, content, options = {}) => {
1405
- const userJid = authState.creds.me.id
1406
- const additionalAttributes = {}
1407
-
1408
- if (typeof content === 'object' && 'disappearingMessagesInChat' in content && typeof content['disappearingMessagesInChat'] !== 'undefined' && WABinary_1.isJidGroup(jid)) {
1409
- const { disappearingMessagesInChat } = content
1410
- const value = typeof disappearingMessagesInChat === 'boolean' ? (disappearingMessagesInChat ? Defaults_1.WA_DEFAULT_EPHEMERAL : 0) : disappearingMessagesInChat
1411
- await groupToggleEphemeral(jid, value)
1412
- } else if (typeof content === 'object' && 'album' in content && content.album) {
1413
- const albumMsg = await Utils_1.prepareAlbumMessageContent(jid, content.album, {
1414
- sock: {
1415
- relayMessage,
1416
- waUploadToServer
1442
+ const userJid = authState.creds.me.id;
1443
+ const additionalAttributes = {};
1444
+ if (!options.ephemeralExpiration) {
1445
+ if (isJidGroup(jid)) {
1446
+ const expiration = await getEphemeralGroup(jid);
1447
+ options.ephemeralExpiration = expiration;
1448
+ }
1449
+ }
1450
+ if (
1451
+ typeof content === "object" &&
1452
+ "disappearingMessagesInChat" in content &&
1453
+ typeof content["disappearingMessagesInChat"] !== "undefined" &&
1454
+ isJidGroup(jid)
1455
+ ) {
1456
+ const { disappearingMessagesInChat: disappearingMessagesInChat } = content;
1457
+ const value =
1458
+ typeof disappearingMessagesInChat === "boolean"
1459
+ ? disappearingMessagesInChat
1460
+ ? WA_DEFAULT_EPHEMERAL
1461
+ : 0
1462
+ : disappearingMessagesInChat;
1463
+ await groupToggleEphemeral(jid, value);
1464
+ } else if (typeof content === "object" && "album" in content && content.album) {
1465
+ const albumMsg = await prepareAlbumMessageContent(jid, content.album, {
1466
+ conn: {
1467
+ relayMessage: relayMessage,
1468
+ waUploadToServer: waUploadToServer,
1417
1469
  },
1418
1470
  userJid: userJid,
1419
- ...options
1420
- })
1421
-
1471
+ ...options,
1472
+ });
1422
1473
  for (const media of albumMsg) {
1423
- await Utils_1.delay(options.delay || 500)
1474
+ await delay(options.delay || 500);
1424
1475
  await relayMessage(jid, media.message, {
1425
1476
  messageId: media.key.id,
1426
1477
  useCachedGroupMetadata: options.useCachedGroupMetadata,
1427
- additionalAttributes,
1478
+ additionalAttributes: additionalAttributes,
1428
1479
  statusJidList: options.statusJidList,
1429
1480
  additionalNodes: options.additionalNodes,
1430
- ai: options.ai
1431
- })
1481
+ AI: options.ai,
1482
+ });
1432
1483
  }
1433
-
1434
- return albumMsg
1484
+ return albumMsg;
1435
1485
  } else {
1436
- let mediaHandle
1437
-
1438
- const fullMsg = await Utils_1.generateWAMessage(jid, content, {
1439
- logger,
1440
- userJid,
1441
- getUrlInfo: text => link_preview_1.getUrlInfo(text, {
1442
- thumbnailWidth: linkPreviewImageThumbnailWidth,
1443
- fetchOpts: {
1444
- timeout: 3000,
1445
- ...axiosOptions || {}
1446
- },
1447
- logger,
1448
- uploadImage: generateHighQualityLinkPreview ? waUploadToServer : undefined
1449
- }),
1486
+ let mediaHandle;
1487
+ const fullMsg = await generateWAMessage(jid, content, {
1488
+ logger: logger,
1489
+ userJid: userJid,
1490
+ getUrlInfo: (text) =>
1491
+ getUrlInfo(text, {
1492
+ thumbnailWidth: linkPreviewImageThumbnailWidth,
1493
+ fetchOpts: { timeout: 3e3, ...(httpRequestOptions || {}) },
1494
+ logger: logger,
1495
+ uploadImage: generateHighQualityLinkPreview
1496
+ ? waUploadToServer
1497
+ : undefined,
1498
+ }),
1450
1499
  getProfilePicUrl: profilePictureUrl,
1451
1500
  getCallLink: createCallLink,
1452
1501
  upload: async (encFilePath, opts) => {
1453
1502
  const up = await waUploadToServer(encFilePath, {
1454
1503
  ...opts,
1455
- newsletter: WABinary_1.isJidNewsletter(jid)
1456
- })
1457
- mediaHandle = up.handle
1458
- return up
1504
+ newsletter: isJidNewsletter(jid),
1505
+ });
1506
+ mediaHandle = up.handle;
1507
+ return up;
1459
1508
  },
1460
1509
  mediaCache: config.mediaCache,
1461
1510
  options: config.options,
1462
- messageId: Utils_1.generateMessageID(userJid),
1511
+ messageId: generateMessageID(userJid),
1463
1512
  ...options,
1464
- })
1465
-
1466
- const isPin = 'pin' in content && !!content.pin
1467
- const isEdit = 'edit' in content && !!content.edit
1468
- const isDelete = 'delete' in content && !!content.delete
1469
- const isKeep = 'keep' in content && !!content.keep && content.keep?.type === 2
1470
-
1513
+ });
1514
+ const isPin = "pin" in content && !!content.pin;
1515
+ const isEdit = "edit" in content && !!content.edit;
1516
+ const isDelete = "delete" in content && !!content.delete;
1517
+ const isKeep = "keep" in content && !!content.keep && content.keep?.type === 2;
1471
1518
  if (isDelete || isKeep) {
1472
- if (WABinary_1.isJidGroup(content.delete?.remoteJid) && !content.delete?.fromMe || WABinary_1.isJidNewsletter(jid)) {
1473
- additionalAttributes.edit = '8'
1519
+ if (
1520
+ (isJidGroup(content.delete?.remoteJid) && !content.delete?.fromMe) ||
1521
+ isJidNewsletter(jid)
1522
+ ) {
1523
+ additionalAttributes.edit = "8";
1474
1524
  } else {
1475
- additionalAttributes.edit = '7'
1525
+ additionalAttributes.edit = "7";
1476
1526
  }
1477
1527
  } else if (isEdit) {
1478
- additionalAttributes.edit = WABinary_1.isJidNewsletter(jid) ? '3' : '1'
1528
+ additionalAttributes.edit = isJidNewsletter(jid) ? "3" : "1";
1479
1529
  } else if (isPin) {
1480
- additionalAttributes.edit = '2'
1530
+ additionalAttributes.edit = "2";
1481
1531
  }
1482
-
1483
1532
  if (mediaHandle) {
1484
- additionalAttributes['media_id'] = mediaHandle
1533
+ additionalAttributes["media_id"] = mediaHandle;
1485
1534
  }
1486
-
1487
- if ('cachedGroupMetadata' in options) {
1488
- console.warn('cachedGroupMetadata in sendMessage are deprecated, now cachedGroupMetadata is part of the socket config.')
1535
+ if ("cachedGroupMetadata" in options) {
1536
+ console.warn(
1537
+ "cachedGroupMetadata in sendMessage are deprecated, now cachedGroupMetadata is part of the socket config."
1538
+ );
1489
1539
  }
1490
-
1491
1540
  await relayMessage(jid, fullMsg.message, {
1492
1541
  messageId: fullMsg.key.id,
1493
1542
  useCachedGroupMetadata: options.useCachedGroupMetadata,
1494
- additionalAttributes,
1543
+ additionalAttributes: additionalAttributes,
1495
1544
  statusJidList: options.statusJidList,
1496
1545
  additionalNodes: options.additionalNodes,
1497
- ai: options.ai
1498
- })
1499
-
1546
+ AI: options.ai,
1547
+ });
1500
1548
  if (config.emitOwnEvents) {
1501
- process.nextTick(() => {
1502
- processingMutex.mutex(() => (upsertMessage(fullMsg, 'append')))
1503
- })
1549
+ process.nextTick(async () => {
1550
+ await messageMutex.mutex(() => upsertMessage(fullMsg, "append"));
1551
+ });
1504
1552
  }
1505
-
1506
- return fullMsg
1553
+ return fullMsg;
1507
1554
  }
1508
- }
1509
- }
1510
- }
1511
-
1512
- module.exports = {
1513
- makeMessagesSocket
1514
- }
1555
+ },
1556
+ };
1557
+ };
1558
+ module.exports = { makeMessagesSocket: makeMessagesSocket };