@fazzcode/baileys 0.1.7 → 2.4.4

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 (209) hide show
  1. package/LICENSE +21 -0
  2. package/README.MD +1420 -103
  3. package/WAProto/WAProto.proto +5311 -0
  4. package/WAProto/index.js +83385 -119575
  5. package/lib/Defaults/index.js +117 -124
  6. package/lib/KeyDB/BinarySearch.js +20 -0
  7. package/lib/KeyDB/KeyedDB.js +167 -0
  8. package/lib/KeyDB/index.js +4 -0
  9. package/lib/Signal/Group/ciphertext-message.js +12 -14
  10. package/lib/Signal/Group/group-session-builder.js +10 -42
  11. package/lib/Signal/Group/group_cipher.js +75 -87
  12. package/lib/Signal/Group/index.js +13 -57
  13. package/lib/Signal/Group/keyhelper.js +17 -52
  14. package/lib/Signal/Group/sender-chain-key.js +27 -33
  15. package/lib/Signal/Group/sender-key-distribution-message.js +62 -63
  16. package/lib/Signal/Group/sender-key-message.js +65 -66
  17. package/lib/Signal/Group/sender-key-name.js +45 -44
  18. package/lib/Signal/Group/sender-key-record.js +39 -49
  19. package/lib/Signal/Group/sender-key-state.js +80 -93
  20. package/lib/Signal/Group/sender-message-key.js +27 -28
  21. package/lib/Signal/libsignal.js +313 -163
  22. package/lib/Signal/lid-mapping.js +155 -0
  23. package/lib/Socket/Client/index.js +4 -19
  24. package/lib/Socket/Client/types.js +13 -0
  25. package/lib/Socket/Client/websocket.js +52 -0
  26. package/lib/Socket/business.js +359 -242
  27. package/lib/Socket/chats.js +851 -830
  28. package/lib/Socket/communities.js +413 -0
  29. package/lib/Socket/groups.js +304 -309
  30. package/lib/Socket/index.js +15 -9
  31. package/lib/Socket/messages-recv.js +1107 -1054
  32. package/lib/Socket/messages-send.js +709 -414
  33. package/lib/Socket/mex.js +45 -0
  34. package/lib/Socket/newsletter.js +232 -318
  35. package/lib/Socket/socket.js +789 -599
  36. package/lib/Store/index.js +6 -10
  37. package/lib/Store/make-cache-manager-store.js +73 -81
  38. package/lib/Store/make-in-memory-store.js +286 -423
  39. package/lib/Store/make-ordered-dictionary.js +77 -79
  40. package/lib/Store/object-repository.js +24 -26
  41. package/lib/Types/Auth.js +3 -2
  42. package/lib/Types/Bussines.js +3 -0
  43. package/lib/Types/Call.js +3 -2
  44. package/lib/Types/Chat.js +9 -4
  45. package/lib/Types/Contact.js +3 -2
  46. package/lib/Types/Events.js +3 -2
  47. package/lib/Types/GroupMetadata.js +3 -2
  48. package/lib/Types/Label.js +24 -26
  49. package/lib/Types/LabelAssociation.js +6 -8
  50. package/lib/Types/Message.js +12 -9
  51. package/lib/Types/Newsletter.js +31 -30
  52. package/lib/Types/Newsletter.js.bak +33 -0
  53. package/lib/Types/Product.js +3 -2
  54. package/lib/Types/Signal.js +3 -2
  55. package/lib/Types/Socket.js +4 -2
  56. package/lib/Types/State.js +11 -2
  57. package/lib/Types/USync.js +3 -2
  58. package/lib/Types/index.js +27 -41
  59. package/lib/Utils/auth-utils.js +211 -198
  60. package/lib/Utils/baileys-event-stream.js +42 -61
  61. package/lib/Utils/browser-utils.js +25 -0
  62. package/lib/Utils/business.js +213 -214
  63. package/lib/Utils/chat-utils.js +710 -687
  64. package/lib/Utils/crypto.js +112 -133
  65. package/lib/Utils/decode-wa-message.js +252 -183
  66. package/lib/Utils/event-buffer.js +510 -496
  67. package/lib/Utils/generics.js +328 -356
  68. package/lib/Utils/history.js +83 -92
  69. package/lib/Utils/index.js +21 -33
  70. package/lib/Utils/link-preview.js +71 -83
  71. package/lib/Utils/logger.js +5 -7
  72. package/lib/Utils/lt-hash.js +40 -46
  73. package/lib/Utils/make-mutex.js +34 -41
  74. package/lib/Utils/message-retry-manager.js +113 -0
  75. package/lib/Utils/messages-media.js +548 -678
  76. package/lib/Utils/messages.js +352 -249
  77. package/lib/Utils/noise-handler.js +138 -149
  78. package/lib/Utils/pre-key-manager.js +85 -0
  79. package/lib/Utils/process-message.js +323 -303
  80. package/lib/Utils/signal.js +148 -138
  81. package/lib/Utils/use-multi-file-auth-state.js +98 -67
  82. package/lib/Utils/validate-connection.js +183 -188
  83. package/lib/WABinary/constants.js +1298 -35
  84. package/lib/WABinary/decode.js +237 -249
  85. package/lib/WABinary/encode.js +208 -218
  86. package/lib/WABinary/generic-utils.js +53 -57
  87. package/lib/WABinary/index.js +7 -21
  88. package/lib/WABinary/jid-utils.js +89 -58
  89. package/lib/WABinary/types.js +3 -2
  90. package/lib/WAM/BinaryInfo.js +10 -12
  91. package/lib/WAM/constants.js +22851 -15348
  92. package/lib/WAM/encode.js +135 -136
  93. package/lib/WAM/index.js +5 -19
  94. package/lib/WAUSync/Protocols/USyncContactProtocol.js +28 -30
  95. package/lib/WAUSync/Protocols/USyncDeviceProtocol.js +49 -53
  96. package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.js +27 -28
  97. package/lib/WAUSync/Protocols/USyncStatusProtocol.js +36 -39
  98. package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.js +50 -50
  99. package/lib/WAUSync/Protocols/UsyncLIDProtocol.js +26 -20
  100. package/lib/WAUSync/Protocols/index.js +6 -20
  101. package/lib/WAUSync/USyncQuery.js +86 -85
  102. package/lib/WAUSync/USyncUser.js +23 -25
  103. package/lib/WAUSync/index.js +5 -19
  104. package/lib/index.js +32 -34
  105. package/package.json +99 -105
  106. package/engine-requirements.js +0 -10
  107. package/lib/Defaults/baileys-version.json +0 -3
  108. package/lib/Defaults/index.d.ts +0 -53
  109. package/lib/Defaults/phonenumber-mcc.json +0 -223
  110. package/lib/Signal/Group/ciphertext-message.d.ts +0 -9
  111. package/lib/Signal/Group/group-session-builder.d.ts +0 -14
  112. package/lib/Signal/Group/group_cipher.d.ts +0 -17
  113. package/lib/Signal/Group/index.d.ts +0 -11
  114. package/lib/Signal/Group/keyhelper.d.ts +0 -10
  115. package/lib/Signal/Group/queue-job.d.ts +0 -1
  116. package/lib/Signal/Group/queue-job.js +0 -57
  117. package/lib/Signal/Group/sender-chain-key.d.ts +0 -13
  118. package/lib/Signal/Group/sender-key-distribution-message.d.ts +0 -16
  119. package/lib/Signal/Group/sender-key-message.d.ts +0 -18
  120. package/lib/Signal/Group/sender-key-name.d.ts +0 -17
  121. package/lib/Signal/Group/sender-key-record.d.ts +0 -30
  122. package/lib/Signal/Group/sender-key-state.d.ts +0 -38
  123. package/lib/Signal/Group/sender-message-key.d.ts +0 -11
  124. package/lib/Signal/libsignal.d.ts +0 -3
  125. package/lib/Socket/Client/abstract-socket-client.d.ts +0 -17
  126. package/lib/Socket/Client/abstract-socket-client.js +0 -13
  127. package/lib/Socket/Client/index.d.ts +0 -3
  128. package/lib/Socket/Client/mobile-socket-client.d.ts +0 -13
  129. package/lib/Socket/Client/mobile-socket-client.js +0 -65
  130. package/lib/Socket/Client/web-socket-client.d.ts +0 -12
  131. package/lib/Socket/Client/web-socket-client.js +0 -62
  132. package/lib/Socket/business.d.ts +0 -171
  133. package/lib/Socket/chats.d.ts +0 -80
  134. package/lib/Socket/dugong.d.ts +0 -219
  135. package/lib/Socket/dugong.js +0 -441
  136. package/lib/Socket/groups.d.ts +0 -115
  137. package/lib/Socket/index.d.ts +0 -173
  138. package/lib/Socket/messages-recv.d.ts +0 -161
  139. package/lib/Socket/messages-send.d.ts +0 -149
  140. package/lib/Socket/newsletter.d.ts +0 -134
  141. package/lib/Socket/registration.d.ts +0 -267
  142. package/lib/Socket/registration.js +0 -166
  143. package/lib/Socket/socket.d.ts +0 -43
  144. package/lib/Socket/usync.d.ts +0 -36
  145. package/lib/Socket/usync.js +0 -70
  146. package/lib/Store/index.d.ts +0 -3
  147. package/lib/Store/make-cache-manager-store.d.ts +0 -13
  148. package/lib/Store/make-in-memory-store.d.ts +0 -118
  149. package/lib/Store/make-ordered-dictionary.d.ts +0 -13
  150. package/lib/Store/object-repository.d.ts +0 -10
  151. package/lib/Types/Auth.d.ts +0 -110
  152. package/lib/Types/Call.d.ts +0 -13
  153. package/lib/Types/Chat.d.ts +0 -102
  154. package/lib/Types/Contact.d.ts +0 -19
  155. package/lib/Types/Events.d.ts +0 -157
  156. package/lib/Types/GroupMetadata.d.ts +0 -55
  157. package/lib/Types/Label.d.ts +0 -35
  158. package/lib/Types/LabelAssociation.d.ts +0 -29
  159. package/lib/Types/Message.d.ts +0 -273
  160. package/lib/Types/Newsletter.d.ts +0 -92
  161. package/lib/Types/Product.d.ts +0 -78
  162. package/lib/Types/Signal.d.ts +0 -57
  163. package/lib/Types/Socket.d.ts +0 -111
  164. package/lib/Types/State.d.ts +0 -27
  165. package/lib/Types/USync.d.ts +0 -25
  166. package/lib/Types/index.d.ts +0 -57
  167. package/lib/Utils/auth-utils.d.ts +0 -18
  168. package/lib/Utils/baileys-event-stream.d.ts +0 -16
  169. package/lib/Utils/business.d.ts +0 -22
  170. package/lib/Utils/chat-utils.d.ts +0 -71
  171. package/lib/Utils/crypto.d.ts +0 -41
  172. package/lib/Utils/decode-wa-message.d.ts +0 -19
  173. package/lib/Utils/event-buffer.d.ts +0 -35
  174. package/lib/Utils/generics.d.ts +0 -92
  175. package/lib/Utils/history.d.ts +0 -15
  176. package/lib/Utils/index.d.ts +0 -17
  177. package/lib/Utils/link-preview.d.ts +0 -21
  178. package/lib/Utils/logger.d.ts +0 -4
  179. package/lib/Utils/lt-hash.d.ts +0 -12
  180. package/lib/Utils/make-mutex.d.ts +0 -7
  181. package/lib/Utils/messages-media.d.ts +0 -116
  182. package/lib/Utils/messages.d.ts +0 -77
  183. package/lib/Utils/noise-handler.d.ts +0 -21
  184. package/lib/Utils/process-message.d.ts +0 -41
  185. package/lib/Utils/signal.d.ts +0 -32
  186. package/lib/Utils/use-multi-file-auth-state.d.ts +0 -13
  187. package/lib/Utils/validate-connection.d.ts +0 -11
  188. package/lib/WABinary/constants.d.ts +0 -27
  189. package/lib/WABinary/decode.d.ts +0 -7
  190. package/lib/WABinary/encode.d.ts +0 -3
  191. package/lib/WABinary/generic-utils.d.ts +0 -16
  192. package/lib/WABinary/index.d.ts +0 -5
  193. package/lib/WABinary/jid-utils.d.ts +0 -31
  194. package/lib/WABinary/types.d.ts +0 -18
  195. package/lib/WAM/BinaryInfo.d.ts +0 -17
  196. package/lib/WAM/constants.d.ts +0 -38
  197. package/lib/WAM/encode.d.ts +0 -3
  198. package/lib/WAM/index.d.ts +0 -3
  199. package/lib/WAUSync/Protocols/USyncContactProtocol.d.ts +0 -9
  200. package/lib/WAUSync/Protocols/USyncDeviceProtocol.d.ts +0 -22
  201. package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.d.ts +0 -12
  202. package/lib/WAUSync/Protocols/USyncStatusProtocol.d.ts +0 -12
  203. package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.d.ts +0 -25
  204. package/lib/WAUSync/Protocols/UsyncLIDProtocol.d.ts +0 -8
  205. package/lib/WAUSync/Protocols/index.d.ts +0 -4
  206. package/lib/WAUSync/USyncQuery.d.ts +0 -28
  207. package/lib/WAUSync/USyncUser.d.ts +0 -12
  208. package/lib/WAUSync/index.d.ts +0 -3
  209. package/lib/index.d.ts +0 -12
@@ -1,65 +1,89 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.makeMessagesSocket = void 0;
7
- const boom_1 = require("@hapi/boom");
8
- const node_cache_1 = __importDefault(require("node-cache"));
9
- const WAProto_1 = require("../../WAProto");
10
- const Defaults_1 = require("../Defaults");
11
- const axios_1 = require("axios")
12
- const Utils_1 = require("../Utils");
13
- const link_preview_1 = require("../Utils/link-preview");
14
- const WABinary_1 = require("../WABinary");
15
- const newsletter_1 = require("./newsletter");
16
- const kikyy = require('./dugong');
17
- var ListType = WAProto_1.proto.Message.ListMessage.ListType;
18
- const makeMessagesSocket = (config) => {
19
- const {
20
- logger,
21
- linkPreviewImageThumbnailWidth,
22
- generateHighQualityLinkPreview,
23
- options: axiosOptions,
24
- patchMessageBeforeSending
25
- } = config;
26
- const sock = (0, newsletter_1.makeNewsletterSocket)(config);
27
- const {
28
- ev,
29
- authState,
30
- processingMutex,
31
- signalRepository,
32
- upsertMessage,
33
- query,
34
- fetchPrivacySettings,
35
- generateMessageTag,
36
- sendNode,
37
- groupMetadata,
38
- groupToggleEphemeral
39
- } = sock;
40
- const userDevicesCache = config.userDevicesCache || new node_cache_1.default({
41
- stdTTL: Defaults_1.DEFAULT_CACHE_TTLS.USER_DEVICES,
1
+ import NodeCache from '@cacheable/node-cache';
2
+ import { Boom } from '@hapi/boom';
3
+ import { proto } from '../../WAProto/index.js';
4
+ import {
5
+ DEFAULT_CACHE_TTLS,
6
+ WA_DEFAULT_EPHEMERAL
7
+ } from '../Defaults/index.js';
8
+ import {
9
+ aggregateMessageKeysNotFromMe,
10
+ assertMediaContent,
11
+ bindWaitForEvent,
12
+ decryptMediaRetryData,
13
+ encodeNewsletterMessage,
14
+ encodeSignedDeviceIdentity,
15
+ encodeWAMessage,
16
+ encryptMediaRetryRequest,
17
+ extractDeviceJids,
18
+ generateMessageIDV2,
19
+ generateParticipantHashV2,
20
+ generateWAMessage,
21
+ getStatusCodeForMediaRetry,
22
+ getUrlFromDirectPath,
23
+ getWAUploadToServer,
24
+ MessageRetryManager,
25
+ normalizeMessageContent,
26
+ parseAndInjectE2ESessions,
27
+ unixTimestampSeconds
28
+ } from '../Utils/index.js';
29
+ import {
30
+ areJidsSameUser,
31
+ getBinaryNodeChild,
32
+ getBinaryNodeChildren,
33
+ getAdditionalNode,
34
+ getBinaryNodeFilter,
35
+ isHostedLidUser,
36
+ isHostedPnUser,
37
+ isJidGroup,
38
+ isLidUser,
39
+ isPnUser,
40
+ jidDecode,
41
+ jidEncode,
42
+ isJidNewsletter,
43
+ jidNormalizedUser,
44
+ S_WHATSAPP_NET
45
+ } from '../WABinary/index.js';
46
+ import { getUrlInfo } from '../Utils/link-preview.js';
47
+ import { makeKeyedMutex } from '../Utils/make-mutex.js';
48
+ import { USyncQuery, USyncUser } from '../WAUSync/index.js';
49
+ import { makeNewsletterSocket } from './newsletter.js';
50
+ export const makeMessagesSocket = (config) => {
51
+ const { logger, linkPreviewImageThumbnailWidth, generateHighQualityLinkPreview, options: httpRequestOptions, patchMessageBeforeSending, cachedGroupMetadata, enableRecentMessageCache, maxMsgRetryCount } = config;
52
+ const sock = makeNewsletterSocket(config);
53
+ const { ev, authState, processingMutex, signalRepository, upsertMessage, query, fetchPrivacySettings, sendNode, groupMetadata, groupToggleEphemeral } = sock;
54
+ const userDevicesCache = config.userDevicesCache ||
55
+ new NodeCache({
56
+ stdTTL: DEFAULT_CACHE_TTLS.USER_DEVICES, // 5 minutes
57
+ useClones: false
58
+ });
59
+ const peerSessionsCache = new NodeCache({
60
+ stdTTL: DEFAULT_CACHE_TTLS.USER_DEVICES,
42
61
  useClones: false
43
62
  });
63
+ // Initialize message retry manager if enabled
64
+ const messageRetryManager = enableRecentMessageCache ? new MessageRetryManager(logger, maxMsgRetryCount) : null;
65
+ // Prevent race conditions in Signal session encryption by user
66
+ const encryptionMutex = makeKeyedMutex();
44
67
  let mediaConn;
45
68
  const refreshMediaConn = async (forceGet = false) => {
46
69
  const media = await mediaConn;
47
- if (!media || forceGet || (new Date().getTime() - media.fetchDate.getTime()) > media.ttl * 1000) {
70
+ if (!media || forceGet || new Date().getTime() - media.fetchDate.getTime() > media.ttl * 1000) {
48
71
  mediaConn = (async () => {
49
72
  const result = await query({
50
73
  tag: 'iq',
51
74
  attrs: {
52
75
  type: 'set',
53
76
  xmlns: 'w:m',
54
- to: WABinary_1.S_WHATSAPP_NET,
77
+ to: S_WHATSAPP_NET
55
78
  },
56
79
  content: [{ tag: 'media_conn', attrs: {} }]
57
80
  });
58
- const mediaConnNode = (0, WABinary_1.getBinaryNodeChild)(result, 'media_conn');
81
+ const mediaConnNode = getBinaryNodeChild(result, 'media_conn');
82
+ // TODO: explore full length of data that whatsapp provides
59
83
  const node = {
60
- hosts: (0, WABinary_1.getBinaryNodeChildren)(mediaConnNode, 'host').map(({ attrs }) => ({
84
+ hosts: getBinaryNodeChildren(mediaConnNode, 'host').map(({ attrs }) => ({
61
85
  hostname: attrs.hostname,
62
- maxContentLengthBytes: +attrs.maxContentLengthBytes,
86
+ maxContentLengthBytes: +attrs.maxContentLengthBytes
63
87
  })),
64
88
  auth: mediaConnNode.attrs.auth,
65
89
  ttl: +mediaConnNode.attrs.ttl,
@@ -76,17 +100,20 @@ const makeMessagesSocket = (config) => {
76
100
  * used for receipts of phone call, read, delivery etc.
77
101
  * */
78
102
  const sendReceipt = async (jid, participant, messageIds, type) => {
103
+ if (!messageIds || messageIds.length === 0) {
104
+ throw new Boom('missing ids in receipt');
105
+ }
79
106
  const node = {
80
107
  tag: 'receipt',
81
108
  attrs: {
82
- id: messageIds[0],
83
- },
109
+ id: messageIds[0]
110
+ }
84
111
  };
85
112
  const isReadReceipt = type === 'read' || type === 'read-self';
86
113
  if (isReadReceipt) {
87
- node.attrs.t = (0, Utils_1.unixTimestampSeconds)().toString();
114
+ node.attrs.t = unixTimestampSeconds().toString();
88
115
  }
89
- if (type === 'sender' && (0, WABinary_1.isJidUser)(jid)) {
116
+ if (type === 'sender' && (isPnUser(jid) || isLidUser(jid))) {
90
117
  node.attrs.recipient = jid;
91
118
  node.attrs.to = participant;
92
119
  }
@@ -97,7 +124,7 @@ const makeMessagesSocket = (config) => {
97
124
  }
98
125
  }
99
126
  if (type) {
100
- node.attrs.type = (0, WABinary_1.isJidNewsLetter)(jid) ? 'read-self' : type;
127
+ node.attrs.type = type;
101
128
  }
102
129
  const remainingMessageIds = messageIds.slice(1);
103
130
  if (remainingMessageIds.length) {
@@ -117,7 +144,7 @@ const makeMessagesSocket = (config) => {
117
144
  };
118
145
  /** Correctly bulk send receipts to multiple chats, participants */
119
146
  const sendReceipts = async (keys, type) => {
120
- const recps = (0, Utils_1.aggregateMessageKeysNotFromMe)(keys);
147
+ const recps = aggregateMessageKeysNotFromMe(keys);
121
148
  for (const { jid, participant, messageIds } of recps) {
122
149
  await sendReceipt(jid, participant, messageIds, type);
123
150
  }
@@ -131,312 +158,569 @@ const makeMessagesSocket = (config) => {
131
158
  };
132
159
  /** Fetch all the devices we've to send a message to */
133
160
  const getUSyncDevices = async (jids, useCache, ignoreZeroDevices) => {
134
- var _a;
135
161
  const deviceResults = [];
136
162
  if (!useCache) {
137
163
  logger.debug('not using cache for devices');
138
164
  }
139
- const users = [];
140
- jids = Array.from(new Set(jids));
141
- for (let jid of jids) {
142
- const user = (_a = (0, WABinary_1.jidDecode)(jid)) === null || _a === void 0 ? void 0 : _a.user;
143
- jid = (0, WABinary_1.jidNormalizedUser)(jid);
144
- const devices = userDevicesCache.get(user);
145
- if (devices && useCache) {
146
- deviceResults.push(...devices);
147
- logger.trace({ user }, 'using cache for devices');
165
+ const toFetch = [];
166
+ const jidsWithUser = jids
167
+ .map(jid => {
168
+ const decoded = jidDecode(jid);
169
+ const user = decoded?.user;
170
+ const device = decoded?.device;
171
+ const isExplicitDevice = typeof device === 'number' && device >= 0;
172
+ if (isExplicitDevice && user) {
173
+ deviceResults.push({
174
+ user,
175
+ device,
176
+ jid
177
+ });
178
+ return null;
179
+ }
180
+ jid = jidNormalizedUser(jid);
181
+ return { jid, user };
182
+ })
183
+ .filter(jid => jid !== null);
184
+ let mgetDevices;
185
+ if (useCache && userDevicesCache.mget) {
186
+ const usersToFetch = jidsWithUser.map(j => j?.user).filter(Boolean);
187
+ mgetDevices = await userDevicesCache.mget(usersToFetch);
188
+ }
189
+ for (const { jid, user } of jidsWithUser) {
190
+ if (useCache) {
191
+ const devices = mgetDevices?.[user] ||
192
+ (userDevicesCache.mget ? undefined : (await userDevicesCache.get(user)));
193
+ if (devices) {
194
+ const devicesWithJid = devices.map(d => ({
195
+ ...d,
196
+ jid: jidEncode(d.user, d.server, d.device)
197
+ }));
198
+ deviceResults.push(...devicesWithJid);
199
+ logger.trace({ user }, 'using cache for devices');
200
+ }
201
+ else {
202
+ toFetch.push(jid);
203
+ }
148
204
  }
149
205
  else {
150
- users.push({ tag: 'user', attrs: { jid } });
206
+ toFetch.push(jid);
151
207
  }
152
208
  }
153
- if (!users.length) {
209
+ if (!toFetch.length) {
154
210
  return deviceResults;
155
211
  }
156
- const iq = {
157
- tag: 'iq',
158
- attrs: {
159
- to: WABinary_1.S_WHATSAPP_NET,
160
- type: 'get',
161
- xmlns: 'usync',
162
- },
163
- content: [
164
- {
165
- tag: 'usync',
166
- attrs: {
167
- sid: generateMessageTag(),
168
- mode: 'query',
169
- last: 'true',
170
- index: '0',
171
- context: 'message',
172
- },
173
- content: [
174
- {
175
- tag: 'query',
176
- attrs: {},
177
- content: [
178
- {
179
- tag: 'devices',
180
- attrs: { version: '2' }
181
- }
182
- ]
183
- },
184
- { tag: 'list', attrs: {}, content: users }
185
- ]
186
- },
187
- ],
188
- };
189
- const result = await query(iq);
190
- const extracted = (0, Utils_1.extractDeviceJids)(result, authState.creds.me.id, ignoreZeroDevices);
191
- const deviceMap = {};
192
- for (const item of extracted) {
193
- deviceMap[item.user] = deviceMap[item.user] || [];
194
- deviceMap[item.user].push(item);
195
- deviceResults.push(item);
212
+ const requestedLidUsers = new Set();
213
+ for (const jid of toFetch) {
214
+ if (isLidUser(jid) || isHostedLidUser(jid)) {
215
+ const user = jidDecode(jid)?.user;
216
+ if (user)
217
+ requestedLidUsers.add(user);
218
+ }
196
219
  }
197
- for (const key in deviceMap) {
198
- userDevicesCache.set(key, deviceMap[key]);
220
+ const query = new USyncQuery().withContext('message').withDeviceProtocol().withLIDProtocol();
221
+ for (const jid of toFetch) {
222
+ query.withUser(new USyncUser().withId(jid)); // todo: investigate - the idea here is that <user> should have an inline lid field with the lid being the pn equivalent
223
+ }
224
+ const result = await sock.executeUSyncQuery(query);
225
+ if (result) {
226
+ // TODO: LID MAP this stuff (lid protocol will now return lid with devices)
227
+ const lidResults = result.list.filter(a => !!a.lid);
228
+ if (lidResults.length > 0) {
229
+ logger.trace('Storing LID maps from device call');
230
+ await signalRepository.lidMapping.storeLIDPNMappings(lidResults.map(a => ({ lid: a.lid, pn: a.id })));
231
+ }
232
+ const extracted = extractDeviceJids(result?.list, authState.creds.me.id, authState.creds.me.lid, ignoreZeroDevices);
233
+ const deviceMap = {};
234
+ for (const item of extracted) {
235
+ deviceMap[item.user] = deviceMap[item.user] || [];
236
+ deviceMap[item.user]?.push(item);
237
+ }
238
+ // Process each user's devices as a group for bulk LID migration
239
+ for (const [user, userDevices] of Object.entries(deviceMap)) {
240
+ const isLidUser = requestedLidUsers.has(user);
241
+ // Process all devices for this user
242
+ for (const item of userDevices) {
243
+ const finalJid = isLidUser
244
+ ? jidEncode(user, item.server, item.device)
245
+ : jidEncode(item.user, item.server, item.device);
246
+ deviceResults.push({
247
+ ...item,
248
+ jid: finalJid
249
+ });
250
+ logger.debug({
251
+ user: item.user,
252
+ device: item.device,
253
+ finalJid,
254
+ usedLid: isLidUser
255
+ }, 'Processed device with LID priority');
256
+ }
257
+ }
258
+ if (userDevicesCache.mset) {
259
+ // if the cache supports mset, we can set all devices in one go
260
+ await userDevicesCache.mset(Object.entries(deviceMap).map(([key, value]) => ({ key, value })));
261
+ }
262
+ else {
263
+ for (const key in deviceMap) {
264
+ if (deviceMap[key])
265
+ await userDevicesCache.set(key, deviceMap[key]);
266
+ }
267
+ }
268
+ const userDeviceUpdates = {};
269
+ for (const [userId, devices] of Object.entries(deviceMap)) {
270
+ if (devices && devices.length > 0) {
271
+ userDeviceUpdates[userId] = devices.map(d => d.device?.toString() || '0');
272
+ }
273
+ }
274
+ if (Object.keys(userDeviceUpdates).length > 0) {
275
+ try {
276
+ await authState.keys.set({ 'device-list': userDeviceUpdates });
277
+ logger.debug({ userCount: Object.keys(userDeviceUpdates).length }, 'stored user device lists for bulk migration');
278
+ }
279
+ catch (error) {
280
+ logger.warn({ error }, 'failed to store user device lists');
281
+ }
282
+ }
199
283
  }
200
284
  return deviceResults;
201
285
  };
202
- const assertSessions = async (jids, force) => {
286
+ const assertSessions = async (jids) => {
203
287
  let didFetchNewSession = false;
204
- let jidsRequiringFetch = [];
205
- if (force) {
206
- jidsRequiringFetch = jids;
207
- }
208
- else {
209
- const addrs = jids.map(jid => (signalRepository
210
- .jidToSignalProtocolAddress(jid)));
211
- const sessions = await authState.keys.get('session', addrs);
212
- for (const jid of jids) {
213
- const signalId = signalRepository
214
- .jidToSignalProtocolAddress(jid);
215
- if (!sessions[signalId]) {
216
- jidsRequiringFetch.push(jid);
288
+ const uniqueJids = [...new Set(jids)]; // Deduplicate JIDs
289
+ const jidsRequiringFetch = [];
290
+ logger.debug({ jids }, 'assertSessions call with jids');
291
+ // Check peerSessionsCache and validate sessions using libsignal loadSession
292
+ for (const jid of uniqueJids) {
293
+ const signalId = signalRepository.jidToSignalProtocolAddress(jid);
294
+ const cachedSession = peerSessionsCache.get(signalId);
295
+ if (cachedSession !== undefined) {
296
+ if (cachedSession) {
297
+ continue; // Session exists in cache
217
298
  }
218
299
  }
300
+ else {
301
+ const sessionValidation = await signalRepository.validateSession(jid);
302
+ const hasSession = sessionValidation.exists;
303
+ peerSessionsCache.set(signalId, hasSession);
304
+ if (hasSession) {
305
+ continue;
306
+ }
307
+ }
308
+ jidsRequiringFetch.push(jid);
219
309
  }
220
310
  if (jidsRequiringFetch.length) {
221
- logger.debug({ jidsRequiringFetch }, 'fetching sessions');
311
+ // LID if mapped, otherwise original
312
+ const wireJids = [
313
+ ...jidsRequiringFetch.filter(jid => !!isLidUser(jid) || !!isHostedLidUser(jid)),
314
+ ...((await signalRepository.lidMapping.getLIDsForPNs(jidsRequiringFetch.filter(jid => !!isPnUser(jid) || !!isHostedPnUser(jid)))) || []).map(a => a.lid)
315
+ ];
316
+ logger.debug({ jidsRequiringFetch, wireJids }, 'fetching sessions');
222
317
  const result = await query({
223
318
  tag: 'iq',
224
319
  attrs: {
225
320
  xmlns: 'encrypt',
226
321
  type: 'get',
227
- to: WABinary_1.S_WHATSAPP_NET,
322
+ to: S_WHATSAPP_NET
228
323
  },
229
324
  content: [
230
325
  {
231
326
  tag: 'key',
232
327
  attrs: {},
233
- content: jidsRequiringFetch.map(jid => ({
328
+ content: wireJids.map(jid => ({
234
329
  tag: 'user',
235
- attrs: { jid },
330
+ attrs: { jid }
236
331
  }))
237
332
  }
238
333
  ]
239
334
  });
240
- await (0, Utils_1.parseAndInjectE2ESessions)(result, signalRepository);
335
+ await parseAndInjectE2ESessions(result, signalRepository);
241
336
  didFetchNewSession = true;
337
+ // Cache fetched sessions using wire JIDs
338
+ for (const wireJid of wireJids) {
339
+ const signalId = signalRepository.jidToSignalProtocolAddress(wireJid);
340
+ peerSessionsCache.set(signalId, true);
341
+ }
242
342
  }
243
343
  return didFetchNewSession;
244
344
  };
245
- const createParticipantNodes = async (jids, message, extraAttrs) => {
246
- const patched = await patchMessageBeforeSending(message, jids);
247
- const bytes = (0, Utils_1.encodeWAMessage)(patched);
345
+ const sendPeerDataOperationMessage = async (pdoMessage) => {
346
+ //TODO: for later, abstract the logic to send a Peer Message instead of just PDO - useful for App State Key Resync with phone
347
+ if (!authState.creds.me?.id) {
348
+ throw new Boom('Not authenticated');
349
+ }
350
+ const protocolMessage = {
351
+ protocolMessage: {
352
+ peerDataOperationRequestMessage: pdoMessage,
353
+ type: proto.Message.ProtocolMessage.Type.PEER_DATA_OPERATION_REQUEST_MESSAGE
354
+ }
355
+ };
356
+ const meJid = jidNormalizedUser(authState.creds.me.id);
357
+ const msgId = await relayMessage(meJid, protocolMessage, {
358
+ additionalAttributes: {
359
+ category: 'peer',
360
+ push_priority: 'high_force'
361
+ },
362
+ additionalNodes: [
363
+ {
364
+ tag: 'meta',
365
+ attrs: { appdata: 'default' }
366
+ }
367
+ ]
368
+ });
369
+ return msgId;
370
+ };
371
+ const createParticipantNodes = async (recipientJids, message, extraAttrs, dsmMessage) => {
372
+ if (!recipientJids.length) {
373
+ return { nodes: [], shouldIncludeDeviceIdentity: false };
374
+ }
375
+ const patched = await patchMessageBeforeSending(message, recipientJids);
376
+ const patchedMessages = Array.isArray(patched)
377
+ ? patched
378
+ : recipientJids.map(jid => ({ recipientJid: jid, message: patched }));
248
379
  let shouldIncludeDeviceIdentity = false;
249
- const nodes = await Promise.all(jids.map(async (jid) => {
250
- const { type, ciphertext } = await signalRepository
251
- .encryptMessage({ jid, data: bytes });
252
- if (type === 'pkmsg') {
253
- shouldIncludeDeviceIdentity = true;
254
- }
255
- const node = {
256
- tag: 'to',
257
- attrs: { jid },
258
- content: [{
259
- tag: 'enc',
260
- attrs: {
261
- v: '2',
262
- type,
263
- ...extraAttrs || {}
264
- },
265
- content: ciphertext
266
- }]
267
- };
380
+ const meId = authState.creds.me.id;
381
+ const meLid = authState.creds.me?.lid;
382
+ const meLidUser = meLid ? jidDecode(meLid)?.user : null;
383
+ const encryptionPromises = patchedMessages.map(async ({ recipientJid: jid, message: patchedMessage }) => {
384
+ if (!jid)
385
+ return null;
386
+ let msgToEncrypt = patchedMessage;
387
+ if (dsmMessage) {
388
+ const { user: targetUser } = jidDecode(jid);
389
+ const { user: ownPnUser } = jidDecode(meId);
390
+ const ownLidUser = meLidUser;
391
+ const isOwnUser = targetUser === ownPnUser || (ownLidUser && targetUser === ownLidUser);
392
+ const isExactSenderDevice = jid === meId || (meLid && jid === meLid);
393
+ if (isOwnUser && !isExactSenderDevice) {
394
+ msgToEncrypt = dsmMessage;
395
+ logger.debug({ jid, targetUser }, 'Using DSM for own device');
396
+ }
397
+ }
398
+ const bytes = encodeWAMessage(msgToEncrypt);
399
+ const mutexKey = jid;
400
+ const node = await encryptionMutex.mutex(mutexKey, async () => {
401
+ const { type, ciphertext } = await signalRepository.encryptMessage({
402
+ jid,
403
+ data: bytes
404
+ });
405
+ if (type === 'pkmsg') {
406
+ shouldIncludeDeviceIdentity = true;
407
+ }
408
+ return {
409
+ tag: 'to',
410
+ attrs: { jid },
411
+ content: [
412
+ {
413
+ tag: 'enc',
414
+ attrs: {
415
+ v: '2',
416
+ type,
417
+ ...(extraAttrs || {})
418
+ },
419
+ content: ciphertext
420
+ }
421
+ ]
422
+ };
423
+ });
268
424
  return node;
269
- }));
425
+ });
426
+ const nodes = (await Promise.all(encryptionPromises)).filter(node => node !== null);
270
427
  return { nodes, shouldIncludeDeviceIdentity };
271
- }; //apela
272
- const relayMessage = async (jid, message, { messageId: msgId, participant, additionalAttributes, additionalNodes, useUserDevicesCache, cachedGroupMetadata, statusJidList, AI = true }) => {
273
- const meId = authState.creds.me.id;
274
- let shouldIncludeDeviceIdentity = false;
428
+ };
429
+ const relayMessage = async (jid, message, { messageId: msgId, participant, additionalAttributes, additionalNodes, useUserDevicesCache, useCachedGroupMetadata, statusJidList, AI = false }) => {
430
+ // let shouldIncludeDeviceIdentity = false;
275
431
  let didPushAdditional = false
276
- const { user, server } = (0, WABinary_1.jidDecode)(jid);
432
+ const meId = authState.creds.me.id;
433
+ const meLid = authState.creds.me?.lid;
434
+ const isRetryResend = Boolean(participant?.jid);
435
+ let shouldIncludeDeviceIdentity = isRetryResend;
277
436
  const statusJid = 'status@broadcast';
437
+ const { user, server } = jidDecode(jid);
278
438
  const isGroup = server === 'g.us';
279
439
  const isStatus = jid === statusJid;
280
440
  const isLid = server === 'lid';
281
- const isPrivate = server === 's.whatsapp.net'
282
441
  const isNewsletter = server === 'newsletter';
283
- msgId = msgId || (0, Utils_1.generateMessageID)();
442
+ const isPrivate = server === 's.whatsapp.net'
443
+ const finalJid = jid;
444
+ msgId = msgId || generateMessageIDV2(meId);
284
445
  useUserDevicesCache = useUserDevicesCache !== false;
446
+ useCachedGroupMetadata = useCachedGroupMetadata !== false && !isStatus;
285
447
  const participants = [];
286
- const destinationJid = (!isStatus) ? (0, WABinary_1.jidEncode)(user, isLid ? 'lid' : isGroup ? 'g.us' : isNewsletter ? 'newsletter' : 's.whatsapp.net') : statusJid;
448
+ const destinationJid = !isStatus ? finalJid : statusJid;
287
449
  const binaryNodeContent = [];
288
450
  const devices = [];
289
451
  const meMsg = {
290
452
  deviceSentMessage: {
291
453
  destinationJid,
292
454
  message
293
- }
455
+ },
456
+ messageContextInfo: message.messageContextInfo
294
457
  };
458
+ const extraAttrs = {};
459
+ const messages = normalizeMessageContent(message)
460
+ const buttonType = getButtonType(messages);
295
461
  if (participant) {
296
- // when the retry request is not for a group
297
- // only send to the specific device that asked for a retry
298
- // otherwise the message is sent out to every device that should be a recipient
299
462
  if (!isGroup && !isStatus) {
300
- additionalAttributes = { ...additionalAttributes, 'device_fanout': 'false' };
463
+ additionalAttributes = {
464
+ ...additionalAttributes,
465
+ device_fanout: 'false'
466
+ };
301
467
  }
302
- const { user, device } = (0, WABinary_1.jidDecode)(participant.jid);
303
- devices.push({ user, device });
468
+ const { user, device } = jidDecode(participant.jid);
469
+ devices.push({
470
+ user,
471
+ device,
472
+ jid: participant.jid
473
+ });
304
474
  }
305
475
  await authState.keys.transaction(async () => {
306
- var _a, _b, _c, _d, _e, _f;
307
476
  const mediaType = getMediaType(message);
477
+ if (mediaType) {
478
+ extraAttrs['mediatype'] = mediaType;
479
+ }
480
+
481
+ if (isNewsletter) {
482
+ const patched = patchMessageBeforeSending ? await patchMessageBeforeSending(message, []) : message;
483
+ const bytes = encodeNewsletterMessage(patched);
484
+ binaryNodeContent.push({
485
+ tag: "plaintext",
486
+ attrs: mediaType ? { mediatype: mediaType } : {},
487
+ content: bytes
488
+ });
489
+ const stanza = {
490
+ tag: "message",
491
+ attrs: {
492
+ to: jid,
493
+ id: msgId,
494
+ type: getTypeMessage(message),
495
+ ...(additionalAttributes || {})
496
+ },
497
+ content: binaryNodeContent
498
+ };
499
+ logger.debug({ msgId }, `sending newsletter message to ${jid}`);
500
+ await sendNode(stanza);
501
+ return;
502
+ }
503
+
504
+ if (messages.pinInChatMessage || messages.keepInChatMessage || message.reactionMessage || message.protocolMessage?.editedMessage) {
505
+ extraAttrs['decrypt-fail'] = 'hide'
506
+ }
507
+
508
+ if (messages.interactiveResponseMessage?.nativeFlowResponseMessage) {
509
+ extraAttrs['native_flow_name'] = messages.interactiveResponseMessage?.nativeFlowResponseMessage.name
510
+ }
511
+
308
512
  if (isGroup || isStatus) {
309
513
  const [groupData, senderKeyMap] = await Promise.all([
310
514
  (async () => {
311
- let groupData = cachedGroupMetadata ? await cachedGroupMetadata(jid) : undefined;
312
- if (groupData) {
313
- logger.trace({ jid, participants: groupData.participants.length }, 'using cached group metadata');
515
+ let groupData = useCachedGroupMetadata && cachedGroupMetadata ? await cachedGroupMetadata(jid) : undefined; // todo: should we rely on the cache specially if the cache is outdated and the metadata has new fields?
516
+ if (groupData && Array.isArray(groupData?.participants)) {
517
+ logger.trace({
518
+ jid,
519
+ participants: groupData.participants.length
520
+ }, 'using cached group metadata');
314
521
  }
315
- if (!groupData && !isStatus) {
316
- groupData = await groupMetadata(jid);
522
+ else if (!isStatus) {
523
+ groupData = await groupMetadata(jid); // TODO: start storing group participant list + addr mode in Signal & stop relying on this
317
524
  }
318
525
  return groupData;
319
526
  })(),
320
527
  (async () => {
321
528
  if (!participant && !isStatus) {
322
- const result = await authState.keys.get('sender-key-memory', [jid]);
529
+ // what if sender memory is less accurate than the cached metadata
530
+ // on participant change in group, we should do sender memory manipulation
531
+ const result = await authState.keys.get('sender-key-memory', [jid]); // TODO: check out what if the sender key memory doesn't include the LID stuff now?
323
532
  return result[jid] || {};
324
533
  }
325
534
  return {};
326
535
  })()
327
536
  ]);
328
537
  if (!participant) {
329
- const participantsList = (groupData && !isStatus) ? groupData.participants.map(p => p.id) : [];
538
+ const participantsList = groupData && !isStatus ? groupData.participants.map(p => p.id) : [];
330
539
  if (isStatus && statusJidList) {
331
540
  participantsList.push(...statusJidList);
332
541
  }
542
+ // if (!isStatus) {
543
+ // additionalAttributes = {
544
+ // ...additionalAttributes,
545
+ // addressing_mode: groupData?.addressingMode || 'pn'
546
+ // };
547
+ // }
333
548
  const additionalDevices = await getUSyncDevices(participantsList, !!useUserDevicesCache, false);
334
549
  devices.push(...additionalDevices);
335
550
  }
336
- const patched = await patchMessageBeforeSending(message, devices.map(d => (0, WABinary_1.jidEncode)(d.user, isLid ? 'lid' : 's.whatsapp.net', d.device)));
337
- const bytes = (0, Utils_1.encodeWAMessage)(patched);
551
+ if (groupData?.ephemeralDuration && groupData.ephemeralDuration > 0) {
552
+ additionalAttributes = {
553
+ ...additionalAttributes,
554
+ expiration: groupData.ephemeralDuration.toString()
555
+ };
556
+ }
557
+ const patched = await patchMessageBeforeSending(message);
558
+ if (Array.isArray(patched)) {
559
+ throw new Boom('Per-jid patching is not supported in groups');
560
+ }
561
+ const bytes = encodeWAMessage(patched);
562
+ const groupAddressingMode = additionalAttributes?.['addressing_mode'] || groupData?.addressingMode || 'lid';
563
+ const groupSenderIdentity = groupAddressingMode === 'lid' && meLid ? meLid : meId;
338
564
  const { ciphertext, senderKeyDistributionMessage } = await signalRepository.encryptGroupMessage({
339
565
  group: destinationJid,
340
566
  data: bytes,
341
- meId,
567
+ meId: groupSenderIdentity
342
568
  });
343
- const senderKeyJids = [];
344
- // ensure a connection is established with every device
345
- for (const { user, device } of devices) {
346
- const jid = (0, WABinary_1.jidEncode)(user, (groupData === null || groupData === void 0 ? void 0 : groupData.addressingMode) === 'lid' ? 'lid' : 's.whatsapp.net', device);
347
- if (!senderKeyMap[jid] || !!participant) {
348
- senderKeyJids.push(jid);
349
- // store that this person has had the sender keys sent to them
350
- senderKeyMap[jid] = true;
569
+ const senderKeyRecipients = [];
570
+ for (const device of devices) {
571
+ const deviceJid = device.jid;
572
+ const hasKey = !!senderKeyMap[deviceJid];
573
+ if ((!hasKey || !!participant) &&
574
+ !isHostedLidUser(deviceJid) &&
575
+ !isHostedPnUser(deviceJid) &&
576
+ device.device !== 99) {
577
+ //todo: revamp all this logic
578
+ // the goal is to follow with what I said above for each group, and instead of a true false map of ids, we can set an array full of those the app has already sent pkmsgs
579
+ senderKeyRecipients.push(deviceJid);
580
+ senderKeyMap[deviceJid] = true;
351
581
  }
352
582
  }
353
- // if there are some participants with whom the session has not been established
354
- // if there are, we re-send the senderkey
355
- if (senderKeyJids.length) {
356
- logger.debug({ senderKeyJids }, 'sending new sender key');
583
+ if (senderKeyRecipients.length) {
584
+ logger.debug({ senderKeyJids: senderKeyRecipients }, 'sending new sender key');
357
585
  const senderKeyMsg = {
358
586
  senderKeyDistributionMessage: {
359
587
  axolotlSenderKeyDistributionMessage: senderKeyDistributionMessage,
360
588
  groupId: destinationJid
361
589
  }
362
590
  };
363
- await assertSessions(senderKeyJids, false);
364
- const result = await createParticipantNodes(senderKeyJids, senderKeyMsg, mediaType ? { mediatype: mediaType } : undefined);
591
+ const senderKeySessionTargets = senderKeyRecipients;
592
+ await assertSessions(senderKeySessionTargets);
593
+ const result = await createParticipantNodes(senderKeyRecipients, senderKeyMsg, extraAttrs);
365
594
  shouldIncludeDeviceIdentity = shouldIncludeDeviceIdentity || result.shouldIncludeDeviceIdentity;
366
595
  participants.push(...result.nodes);
367
596
  }
368
- binaryNodeContent.push({
369
- tag: 'enc',
370
- attrs: { v: '2', type: 'skmsg' },
371
- content: ciphertext
372
- });
373
- await authState.keys.set({ 'sender-key-memory': { [jid]: senderKeyMap } });
374
- }
375
- else if (isNewsletter) {
376
- // Message edit
377
- if ((_a = message.protocolMessage) === null || _a === void 0 ? void 0 : _a.editedMessage) {
378
- msgId = (_b = message.protocolMessage.key) === null || _b === void 0 ? void 0 : _b.id;
379
- message = message.protocolMessage.editedMessage;
380
- }
381
- // Message delete
382
- if (((_c = message.protocolMessage) === null || _c === void 0 ? void 0 : _c.type) === WAProto_1.proto.Message.ProtocolMessage.Type.REVOKE) {
383
- msgId = (_d = message.protocolMessage.key) === null || _d === void 0 ? void 0 : _d.id;
384
- message = {};
385
- }
386
- const patched = await patchMessageBeforeSending(message, []);
387
- const bytes = WAProto_1.proto.Message.encode(patched).finish();
388
- binaryNodeContent.push({
389
- tag: 'plaintext',
390
- attrs: mediaType ? { mediatype: mediaType } : {},
391
- content: bytes
392
- });
597
+ if (isRetryResend) {
598
+ const { type, ciphertext: encryptedContent } = await signalRepository.encryptMessage({
599
+ data: bytes,
600
+ jid: participant?.jid
601
+ });
602
+ binaryNodeContent.push({
603
+ tag: 'enc',
604
+ attrs: {
605
+ v: '2',
606
+ type,
607
+ count: participant.count.toString()
608
+ },
609
+ content: encryptedContent
610
+ });
611
+ }
612
+ else {
613
+ binaryNodeContent.push({
614
+ tag: 'enc',
615
+ attrs: {
616
+ v: '2',
617
+ type: 'skmsg',
618
+ ...extraAttrs
619
+ },
620
+ content: ciphertext
621
+ });
622
+ await authState.keys.set({ 'sender-key-memory': { [jid]: senderKeyMap } });
623
+ }
393
624
  }
394
625
  else {
395
- const { user: meUser, device: meDevice } = (0, WABinary_1.jidDecode)(meId);
626
+ // ADDRESSING CONSISTENCY: Match own identity to conversation context
627
+ // TODO: investigate if this is true
628
+ let ownId = meId;
629
+ if (isLid && meLid) {
630
+ ownId = meLid;
631
+ logger.debug({ to: jid, ownId }, 'Using LID identity for @lid conversation');
632
+ }
633
+ else {
634
+ logger.debug({ to: jid, ownId }, 'Using PN identity for @s.whatsapp.net conversation');
635
+ }
636
+ const { user: ownUser } = jidDecode(ownId);
396
637
  if (!participant) {
397
- devices.push({ user });
398
- // do not send message to self if the device is 0 (mobile)
399
- if (meDevice !== undefined && meDevice !== 0) {
400
- devices.push({ user: meUser });
638
+ const targetUserServer = isLid ? 'lid' : 's.whatsapp.net';
639
+ devices.push({
640
+ user,
641
+ device: 0,
642
+ jid: jidEncode(user, targetUserServer, 0) // rajeh, todo: this entire logic is convoluted and weird.
643
+ });
644
+ if (user !== ownUser) {
645
+ const ownUserServer = isLid ? 'lid' : 's.whatsapp.net';
646
+ const ownUserForAddressing = isLid && meLid ? jidDecode(meLid).user : jidDecode(meId).user;
647
+ devices.push({
648
+ user: ownUserForAddressing,
649
+ device: 0,
650
+ jid: jidEncode(ownUserForAddressing, ownUserServer, 0)
651
+ });
652
+ }
653
+ if (additionalAttributes?.['category'] !== 'peer') {
654
+ // Clear placeholders and enumerate actual devices
655
+ devices.length = 0;
656
+ // Use conversation-appropriate sender identity
657
+ const senderIdentity = isLid && meLid
658
+ ? jidEncode(jidDecode(meLid)?.user, 'lid', undefined)
659
+ : jidEncode(jidDecode(meId)?.user, 's.whatsapp.net', undefined);
660
+ // Enumerate devices for sender and target with consistent addressing
661
+ const sessionDevices = await getUSyncDevices([senderIdentity, jid], true, false);
662
+ devices.push(...sessionDevices);
663
+ logger.debug({
664
+ deviceCount: devices.length,
665
+ devices: devices.map(d => `${d.user}:${d.device}@${jidDecode(d.jid)?.server}`)
666
+ }, 'Device enumeration complete with unified addressing');
401
667
  }
402
- const additionalDevices = await getUSyncDevices([meId, jid], !!useUserDevicesCache, true);
403
- devices.push(...additionalDevices);
404
668
  }
405
- const allJids = [];
406
- const meJids = [];
407
- const otherJids = [];
408
- for (const { user, device } of devices) {
409
- const isMe = user === meUser;
410
- const jid = (0, WABinary_1.jidEncode)(isMe && isLid ? ((_f = (_e = authState.creds) === null || _e === void 0 ? void 0 : _e.me) === null || _f === void 0 ? void 0 : _f.lid.split(':')[0]) || user : user, isLid ? 'lid' : 's.whatsapp.net', device);
669
+ const allRecipients = [];
670
+ const meRecipients = [];
671
+ const otherRecipients = [];
672
+ const { user: mePnUser } = jidDecode(meId);
673
+ const { user: meLidUser } = meLid ? jidDecode(meLid) : { user: null };
674
+ for (const { user, jid } of devices) {
675
+ const isExactSenderDevice = jid === meId || (meLid && jid === meLid);
676
+ if (isExactSenderDevice) {
677
+ logger.debug({ jid, meId, meLid }, 'Skipping exact sender device (whatsmeow pattern)');
678
+ continue;
679
+ }
680
+ // Check if this is our device (could match either PN or LID user)
681
+ const isMe = user === mePnUser || user === meLidUser;
411
682
  if (isMe) {
412
- meJids.push(jid);
683
+ meRecipients.push(jid);
413
684
  }
414
685
  else {
415
- otherJids.push(jid);
686
+ otherRecipients.push(jid);
416
687
  }
417
- allJids.push(jid);
688
+ allRecipients.push(jid);
418
689
  }
419
- await assertSessions(allJids, false);
690
+ await assertSessions(allRecipients);
420
691
  const [{ nodes: meNodes, shouldIncludeDeviceIdentity: s1 }, { nodes: otherNodes, shouldIncludeDeviceIdentity: s2 }] = await Promise.all([
421
- createParticipantNodes(meJids, meMsg, mediaType ? { mediatype: mediaType } : undefined),
422
- createParticipantNodes(otherJids, message, mediaType ? { mediatype: mediaType } : undefined)
692
+ // For own devices: use DSM if available (1:1 chats only)
693
+ createParticipantNodes(meRecipients, meMsg || message, extraAttrs),
694
+ createParticipantNodes(otherRecipients, message, extraAttrs, meMsg)
423
695
  ]);
424
696
  participants.push(...meNodes);
425
697
  participants.push(...otherNodes);
698
+ /* if (meRecipients.length > 0 || otherRecipients.length > 0) {
699
+ extraAttrs['phash'] = generateParticipantHashV2([...meRecipients, ...otherRecipients]);
700
+ }*/
426
701
  shouldIncludeDeviceIdentity = shouldIncludeDeviceIdentity || s1 || s2;
427
702
  }
428
703
  if (participants.length) {
429
- binaryNodeContent.push({
430
- tag: 'participants',
431
- attrs: {},
432
- content: participants
433
- });
704
+ if (additionalAttributes?.['category'] === 'peer') {
705
+ const peerNode = participants[0]?.content?.[0];
706
+ if (peerNode) {
707
+ binaryNodeContent.push(peerNode); // push only enc
708
+ }
709
+ }
710
+ else {
711
+ binaryNodeContent.push({
712
+ tag: 'participants',
713
+ attrs: {},
714
+ content: participants
715
+ });
716
+ }
434
717
  }
435
718
  const stanza = {
436
719
  tag: 'message',
437
720
  attrs: {
438
721
  id: msgId,
439
- type: isNewsletter ? getTypeMessage(message) : 'text',
722
+ to: destinationJid,
723
+ type: getTypeMessage(messages),
440
724
  ...(additionalAttributes || {})
441
725
  },
442
726
  content: binaryNodeContent
@@ -445,11 +729,11 @@ const makeMessagesSocket = (config) => {
445
729
  // ensure the message is only sent to that person
446
730
  // if a retry receipt is sent to everyone -- it'll fail decryption for everyone else who received the msg
447
731
  if (participant) {
448
- if ((0, WABinary_1.isJidGroup)(destinationJid)) {
732
+ if (isJidGroup(destinationJid)) {
449
733
  stanza.attrs.to = destinationJid;
450
734
  stanza.attrs.participant = participant.jid;
451
735
  }
452
- else if ((0, WABinary_1.areJidsSameUser)(participant.jid, meId)) {
736
+ else if (areJidsSameUser(participant.jid, meId)) {
453
737
  stanza.attrs.to = participant.jid;
454
738
  stanza.attrs.recipient = destinationJid;
455
739
  }
@@ -461,34 +745,14 @@ const makeMessagesSocket = (config) => {
461
745
  stanza.attrs.to = destinationJid;
462
746
  }
463
747
  if (shouldIncludeDeviceIdentity) {
748
+ ;
464
749
  stanza.content.push({
465
750
  tag: 'device-identity',
466
751
  attrs: {},
467
- content: (0, Utils_1.encodeSignedDeviceIdentity)(authState.creds.account, true)
752
+ content: encodeSignedDeviceIdentity(authState.creds.account, true)
468
753
  });
469
754
  logger.debug({ jid }, 'adding device identity');
470
755
  }
471
-
472
- const messages = Utils_1.normalizeMessageContent(message)
473
- const buttonType = getButtonType(messages);
474
- if(!isNewsletter && buttonType) {
475
- const content = WABinary_1.getAdditionalNode(buttonType)
476
- const filteredNode = WABinary_1.getBinaryNodeFilter(additionalNodes)
477
-
478
- if (filteredNode) {
479
- didPushAdditional = true
480
- stanza.content.push(...additionalNodes)
481
- }
482
- else {
483
- stanza.content.push(...content)
484
- }
485
- logger.debug({ jid }, 'adding business node')
486
- }
487
-
488
- if (additionalNodes && additionalNodes.length > 0) {
489
- stanza.content.push(...additionalNodes);
490
- }
491
-
492
756
  if (AI && isPrivate) {
493
757
  const botNode = {
494
758
  tag: 'bot',
@@ -497,7 +761,7 @@ const makeMessagesSocket = (config) => {
497
761
  }
498
762
  }
499
763
 
500
- const filteredBizBot = WABinary_1.getBinaryFilteredBizBot(additionalNodes ? additionalNodes : [])
764
+ const filteredBizBot = getBinaryNodeFilter(additionalNodes ? additionalNodes : [])
501
765
 
502
766
  if (filteredBizBot) {
503
767
  stanza.content.push(...additionalNodes)
@@ -507,25 +771,63 @@ const makeMessagesSocket = (config) => {
507
771
  else {
508
772
  stanza.content.push(botNode)
509
773
  }
510
- }
774
+ }
775
+
776
+ if(buttonType && !isStatus) {
777
+ const content = getAdditionalNode(buttonType)
778
+ const filteredNode = getBinaryNodeFilter(additionalNodes)
779
+
780
+ if (filteredNode) {
781
+ didPushAdditional = true
782
+ stanza.content.push(...additionalNodes)
783
+ }
784
+ else {
785
+ stanza.content.push(...content)
786
+ }
787
+ logger.debug({ jid }, 'adding business node')
788
+ }
789
+
790
+ if (!didPushAdditional && additionalNodes && additionalNodes.length > 0) {
791
+ stanza.content.push(...additionalNodes);
792
+ }
511
793
  logger.debug({ msgId }, `sending message to ${participants.length} devices`);
512
794
  await sendNode(stanza);
513
- });
795
+ // Add message to retry cache if enabled
796
+ if (messageRetryManager && !participant) {
797
+ messageRetryManager.addRecentMessage(destinationJid, msgId, message);
798
+ }
799
+ }, meId);
514
800
  return msgId;
515
801
  };
516
802
  const getTypeMessage = (msg) => {
517
- const message = Utils_1.normalizeMessageContent(msg)
518
- if (message.reactionMessage) {
519
- return 'reaction'
520
- }
521
- else if (getMediaType(message)) {
522
- return 'media'
523
- }
803
+ if (msg.viewOnceMessage) {
804
+ return getTypeMessage(msg.viewOnceMessage.message);
805
+ }
806
+ else if (msg.viewOnceMessageV2) {
807
+ return getTypeMessage(msg.viewOnceMessageV2.message);
808
+ }
809
+ else if (msg.viewOnceMessageV2Extension) {
810
+ return getTypeMessage(msg.viewOnceMessageV2Extension.message);
811
+ }
812
+ else if (msg.ephemeralMessage) {
813
+ return getTypeMessage(msg.ephemeralMessage.message);
814
+ }
815
+ else if (msg.documentWithCaptionMessage) {
816
+ return getTypeMessage(msg.documentWithCaptionMessage.message);
817
+ }
818
+ else if (msg.reactionMessage) {
819
+ return 'reaction';
820
+ }
821
+ else if (msg.pollCreationMessage || msg.pollCreationMessageV2 || msg.pollCreationMessageV3 || msg.pollUpdateMessage) {
822
+ return 'poll';
823
+ }
824
+ else if (getMediaType(msg)) {
825
+ return 'media';
826
+ }
524
827
  else {
525
- return 'text'
828
+ return 'text';
526
829
  }
527
- }
528
-
830
+ };
529
831
  const getMediaType = (message) => {
530
832
  if (message.imageMessage) {
531
833
  return 'image'
@@ -575,7 +877,7 @@ const makeMessagesSocket = (config) => {
575
877
  else if (/https:\/\/wa\.me\/p\/\d+\/\d+/.test(message.extendedTextMessage?.text)) {
576
878
  return 'productlink'
577
879
  }
578
- }
880
+ }
579
881
  const getButtonType = (message) => {
580
882
  if (message.listMessage) {
581
883
  return 'list'
@@ -583,6 +885,21 @@ const makeMessagesSocket = (config) => {
583
885
  else if (message.buttonsMessage) {
584
886
  return 'buttons'
585
887
  }
888
+ else if (message.interactiveMessage?.nativeFlowMessage?.buttons?.[0]?.name === 'review_and_pay') {
889
+ return 'review_and_pay'
890
+ }
891
+ else if (message.interactiveMessage?.nativeFlowMessage?.buttons?.[0]?.name === 'review_order') {
892
+ return 'review_order'
893
+ }
894
+ else if (message.interactiveMessage?.nativeFlowMessage?.buttons?.[0]?.name === 'payment_info') {
895
+ return 'payment_info'
896
+ }
897
+ else if (message.interactiveMessage?.nativeFlowMessage?.buttons?.[0]?.name === 'payment_status') {
898
+ return 'payment_status'
899
+ }
900
+ else if (message.interactiveMessage?.nativeFlowMessage?.buttons?.[0]?.name === 'payment_method') {
901
+ return 'payment_method'
902
+ }
586
903
  else if (message.interactiveMessage && message.interactiveMessage?.nativeFlowMessage) {
587
904
  return 'interactive'
588
905
  }
@@ -591,11 +908,11 @@ const makeMessagesSocket = (config) => {
591
908
  }
592
909
  }
593
910
  const getPrivacyTokens = async (jids) => {
594
- const t = (0, Utils_1.unixTimestampSeconds)().toString();
911
+ const t = unixTimestampSeconds().toString();
595
912
  const result = await query({
596
913
  tag: 'iq',
597
914
  attrs: {
598
- to: WABinary_1.S_WHATSAPP_NET,
915
+ to: S_WHATSAPP_NET,
599
916
  type: 'set',
600
917
  xmlns: 'privacy'
601
918
  },
@@ -606,7 +923,7 @@ const makeMessagesSocket = (config) => {
606
923
  content: jids.map(jid => ({
607
924
  tag: 'token',
608
925
  attrs: {
609
- jid: (0, WABinary_1.jidNormalizedUser)(jid),
926
+ jid: jidNormalizedUser(jid),
610
927
  t,
611
928
  type: 'trusted_contact'
612
929
  }
@@ -615,33 +932,9 @@ const makeMessagesSocket = (config) => {
615
932
  ]
616
933
  });
617
934
  return result;
618
- }
619
-
620
- const sendPeerDataOperationMessage = async (pdoMessage) => {
621
- var _a;
622
- //TODO: for later, abstract the logic to send a Peer Message instead of just PDO - useful for App State Key Resync with phone
623
- if (!((_a = authState.creds.me) === null || _a === void 0 ? void 0 : _a.id)) {
624
- throw new boom_1.Boom('Not authenticated');
625
- }
626
- const protocolMessage = {
627
- protocolMessage: {
628
- peerDataOperationRequestMessage: pdoMessage,
629
- type: WAProto_1.proto.Message.ProtocolMessage.Type.PEER_DATA_OPERATION_REQUEST_MESSAGE
630
- }
631
- };
632
- const meJid = (0, WABinary_1.jidNormalizedUser)(authState.creds.me.id);
633
- const msgId = await relayMessage(meJid, protocolMessage, {
634
- additionalAttributes: {
635
- category: 'peer',
636
- // eslint-disable-next-line camelcase
637
- push_priority: 'high_force',
638
- },
639
- });
640
- return msgId;
641
935
  };
642
- const waUploadToServer = (0, Utils_1.getWAUploadToServer)(config, refreshMediaConn);
643
- const rahmi = new kikyy(Utils_1, waUploadToServer, relayMessage);
644
- const waitForMsgMediaUpdate = (0, Utils_1.bindWaitForEvent)(ev, 'messages.media-update');
936
+ const waUploadToServer = getWAUploadToServer(config, refreshMediaConn);
937
+ const waitForMsgMediaUpdate = bindWaitForEvent(ev, 'messages.media-update');
645
938
  return {
646
939
  ...sock,
647
940
  getPrivacyTokens,
@@ -649,23 +942,23 @@ const makeMessagesSocket = (config) => {
649
942
  relayMessage,
650
943
  sendReceipt,
651
944
  sendReceipts,
652
- rahmi,
653
945
  readMessages,
654
946
  refreshMediaConn,
655
- getUSyncDevices,
656
- createParticipantNodes,
657
947
  waUploadToServer,
658
- sendPeerDataOperationMessage,
659
948
  fetchPrivacySettings,
949
+ sendPeerDataOperationMessage,
950
+ createParticipantNodes,
951
+ getUSyncDevices,
952
+ messageRetryManager,
660
953
  updateMediaMessage: async (message) => {
661
- const content = (0, Utils_1.assertMediaContent)(message.message);
954
+ const content = assertMediaContent(message.message);
662
955
  const mediaKey = content.mediaKey;
663
956
  const meId = authState.creds.me.id;
664
- const node = (0, Utils_1.encryptMediaRetryRequest)(message.key, mediaKey, meId);
957
+ const node = await encryptMediaRetryRequest(message.key, mediaKey, meId);
665
958
  let error = undefined;
666
959
  await Promise.all([
667
960
  sendNode(node),
668
- waitForMsgMediaUpdate(update => {
961
+ waitForMsgMediaUpdate(async (update) => {
669
962
  const result = update.find(c => c.key.id === message.key.id);
670
963
  if (result) {
671
964
  if (result.error) {
@@ -673,13 +966,16 @@ const makeMessagesSocket = (config) => {
673
966
  }
674
967
  else {
675
968
  try {
676
- const media = (0, Utils_1.decryptMediaRetryData)(result.media, mediaKey, result.key.id);
677
- if (media.result !== WAProto_1.proto.MediaRetryNotification.ResultType.SUCCESS) {
678
- const resultStr = WAProto_1.proto.MediaRetryNotification.ResultType[media.result];
679
- throw new boom_1.Boom(`Media re-upload failed by device (${resultStr})`, { data: media, statusCode: (0, Utils_1.getStatusCodeForMediaRetry)(media.result) || 404 });
969
+ const media = await decryptMediaRetryData(result.media, mediaKey, result.key.id);
970
+ if (media.result !== proto.MediaRetryNotification.ResultType.SUCCESS) {
971
+ const resultStr = proto.MediaRetryNotification.ResultType[media.result];
972
+ throw new Boom(`Media re-upload failed by device (${resultStr})`, {
973
+ data: media,
974
+ statusCode: getStatusCodeForMediaRetry(media.result) || 404
975
+ });
680
976
  }
681
977
  content.directPath = media.directPath;
682
- content.url = (0, Utils_1.getUrlFromDirectPath)(content.directPath);
978
+ content.url = getUrlFromDirectPath(content.directPath);
683
979
  logger.debug({ directPath: media.directPath, key: result.key }, 'media update successful');
684
980
  }
685
981
  catch (err) {
@@ -693,113 +989,112 @@ const makeMessagesSocket = (config) => {
693
989
  if (error) {
694
990
  throw error;
695
991
  }
696
- ev.emit('messages.update', [
697
- { key: message.key, update: { message: message.message } }
698
- ]);
992
+ ev.emit('messages.update', [{ key: message.key, update: { message: message.message } }]);
699
993
  return message;
700
994
  },
701
995
  sendMessage: async (jid, content, options = {}) => {
702
996
  const userJid = authState.creds.me.id;
703
- const { filter = false, quoted } = options;
704
- const getParticipantAttr = () => filter ? { participant: { jid } } : {};
705
- const messageType = rahmi.detectType(content);
706
-
707
- if (messageType) {
708
- switch(messageType) {
709
- case 'PAYMENT':
710
- const paymentContent = await rahmi.handlePayment(content, quoted);
711
- return await relayMessage(jid, paymentContent, {
712
- messageId: Utils_1.generateMessageID(),
713
- ...getParticipantAttr()
714
- });
715
-
716
- case 'PRODUCT':
717
- const productContent = await rahmi.handleProduct(content, jid, quoted);
718
- const productMsg = await Utils_1.generateWAMessageFromContent(jid, productContent, { quoted });
719
- return await relayMessage(jid, productMsg.message, {
720
- messageId: productMsg.key.id,
721
- ...getParticipantAttr()
722
- });
723
-
724
- case 'INTERACTIVE':
725
- const interactiveContent = await rahmi.handleInteractive(content, jid, quoted);
726
- const interactiveMsg = await Utils_1.generateWAMessageFromContent(jid, interactiveContent, { quoted });
727
- return await relayMessage(jid, interactiveMsg.message, {
728
- messageId: interactiveMsg.key.id,
729
- ...getParticipantAttr()
997
+ if (typeof content === 'object' &&
998
+ 'disappearingMessagesInChat' in content &&
999
+ typeof content['disappearingMessagesInChat'] !== 'undefined' &&
1000
+ isJidGroup(jid)) {
1001
+ const { disappearingMessagesInChat } = content;
1002
+ const value = typeof disappearingMessagesInChat === 'boolean'
1003
+ ? disappearingMessagesInChat
1004
+ ? WA_DEFAULT_EPHEMERAL
1005
+ : 0
1006
+ : disappearingMessagesInChat;
1007
+ await groupToggleEphemeral(jid, value);
1008
+ }
1009
+ else {
1010
+ const fullMsg = await generateWAMessage(jid, content, {
1011
+ logger,
1012
+ userJid,
1013
+ getUrlInfo: text => getUrlInfo(text, {
1014
+ thumbnailWidth: linkPreviewImageThumbnailWidth,
1015
+ fetchOpts: {
1016
+ timeout: 3000,
1017
+ ...(httpRequestOptions || {})
1018
+ },
1019
+ logger,
1020
+ uploadImage: generateHighQualityLinkPreview ? waUploadToServer : undefined
1021
+ }),
1022
+ //TODO: CACHE
1023
+ getProfilePicUrl: sock.profilePictureUrl,
1024
+ getCallLink: sock.createCallLink,
1025
+ upload: async (readStream, opts) => {
1026
+ const up = await waUploadToServer(readStream, {
1027
+ ...opts,
1028
+ newsletter: isJidNewsletter(jid)
730
1029
  });
731
- case 'ALBUM':
732
- const albumContent = await rahmi.handleAlbum(content, jid, quoted)
733
- return albumContent;
734
-
735
- case 'EVENT':
736
- return await rahmi.handleEvent(content, jid, quoted)
737
-
738
- case 'POLL_RESULT':
739
- return await rahmi.handlePollResult(content, jid, quoted)
740
- }
741
- }
742
- const fullMsg = await Utils_1.generateWAMessage(jid, content, {
743
- logger,
744
- userJid,
745
- quoted,
746
- getUrlInfo: text => link_preview_1.getUrlInfo(text, {
747
- thumbnailWidth: linkPreviewImageThumbnailWidth,
748
- fetchOpts: {
749
- timeout: 3000,
750
- ...axiosOptions || {}
1030
+ return up;
751
1031
  },
752
- logger,
753
- uploadImage: generateHighQualityLinkPreview ? waUploadToServer : undefined
754
- }),
755
- upload: async (readStream, opts) => {
756
- const up = await waUploadToServer(readStream, {
757
- ...opts,
758
- newsletter: WABinary_1.isJidNewsLetter(jid)
759
- });
760
- return up;
761
- },
762
- mediaCache: config.mediaCache,
763
- options: config.options,
764
- ...options
765
- });
766
-
767
- const isDeleteMsg = 'delete' in content && !!content.delete;
768
- const isEditMsg = 'edit' in content && !!content.edit;
769
- const isAiMsg = 'ai' in content && !!content.ai;
770
-
771
- const additionalAttributes = {};
772
- const additionalNodes = [];
773
-
774
- if (isDeleteMsg) {
775
- const fromMe = content.delete?.fromMe;
776
- const isGroup = WABinary_1.isJidGroup(content.delete?.remoteJid);
777
- additionalAttributes.edit = (isGroup && !fromMe) || WABinary_1.isJidNewsLetter(jid) ? '8' : '7';
778
- } else if (isEditMsg) {
779
- additionalAttributes.edit = WABinary_1.isJidNewsLetter(jid) ? '3' : '1';
780
- } else if (isAiMsg) {
781
- additionalNodes.push({
1032
+ mediaCache: config.mediaCache,
1033
+ options: config.options,
1034
+ messageId: generateMessageIDV2(sock.user?.id),
1035
+ ...options
1036
+ });
1037
+ const isAiMsg = 'ai' in content && !!content.ai;
1038
+ const isEventMsg = 'event' in content && !!content.event;
1039
+ const isDeleteMsg = 'delete' in content && !!content.delete;
1040
+ const isEditMsg = 'edit' in content && !!content.edit;
1041
+ const isPinMsg = 'pin' in content && !!content.pin;
1042
+ const isPollMessage = 'poll' in content && !!content.poll;
1043
+ const additionalAttributes = {};
1044
+ const additionalNodes = [];
1045
+ // required for delete
1046
+ if (isDeleteMsg) {
1047
+ // if the chat is a group, and I am not the author, then delete the message as an admin
1048
+ if (isJidGroup(content.delete?.remoteJid) && !content.delete?.fromMe) {
1049
+ additionalAttributes.edit = '8';
1050
+ }
1051
+ else {
1052
+ additionalAttributes.edit = '7';
1053
+ }
1054
+ }
1055
+ else if (isEditMsg) {
1056
+ additionalAttributes.edit = '1';
1057
+ }
1058
+ else if (isAiMsg) {
1059
+ additionalNodes.push({
782
1060
  attrs: {
783
1061
  biz_bot: '1'
784
1062
  }, tag: "bot"
785
1063
  });
786
- }
787
-
788
- await relayMessage(jid, fullMsg.message, {
789
- messageId: fullMsg.key.id,
790
- cachedGroupMetadata: options.cachedGroupMetadata,
791
- additionalNodes: isAiMsg ? additionalNodes : options.additionalNodes,
792
- additionalAttributes,
793
- statusJidList: options.statusJidList
794
- });
795
-
796
- if (config.emitOwnEvents) {
797
- process.nextTick(() => {
798
- processingMutex.mutex(() => upsertMessage(fullMsg, 'append'));
1064
+ }
1065
+ else if (isPinMsg) {
1066
+ additionalAttributes.edit = '2';
1067
+ }
1068
+ else if (isPollMessage) {
1069
+ additionalNodes.push({
1070
+ tag: 'meta',
1071
+ attrs: {
1072
+ polltype: 'creation'
1073
+ }
1074
+ });
1075
+ }
1076
+ else if (isEventMsg) {
1077
+ additionalNodes.push({
1078
+ tag: 'meta',
1079
+ attrs: {
1080
+ event_type: 'creation'
1081
+ }
1082
+ });
1083
+ }
1084
+ await relayMessage(jid, fullMsg.message, {
1085
+ messageId: fullMsg.key.id,
1086
+ useCachedGroupMetadata: options.useCachedGroupMetadata,
1087
+ additionalAttributes,
1088
+ statusJidList: options.statusJidList,
1089
+ additionalNodes: isAiMsg ? additionalNodes : options.additionalNodes
799
1090
  });
1091
+ if (config.emitOwnEvents) {
1092
+ process.nextTick(() => {
1093
+ processingMutex.mutex(() => upsertMessage(fullMsg, 'append'));
1094
+ });
1095
+ }
1096
+ return fullMsg;
800
1097
  }
801
- return fullMsg;
802
1098
  }
803
- }
804
- };
805
- exports.makeMessagesSocket = makeMessagesSocket;
1099
+ };
1100
+ };