@realvare/based 2.7.62 → 2.7.71

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 (57) hide show
  1. package/README.MD +1062 -282
  2. package/WAProto/WAProto.proto +1073 -244
  3. package/WAProto/index.d.ts +16282 -8183
  4. package/WAProto/index.js +76605 -50628
  5. package/engine-requirements.js +10 -10
  6. package/lib/Defaults/baileys-version.json +1 -1
  7. package/lib/Defaults/index.d.ts +4 -2
  8. package/lib/Defaults/index.js +8 -6
  9. package/lib/Signal/Group/ciphertext-message.d.ts +1 -1
  10. package/lib/Signal/Group/ciphertext-message.js +1 -1
  11. package/lib/Signal/Group/sender-message-key.d.ts +1 -1
  12. package/lib/Signal/Group/sender-message-key.js +1 -1
  13. package/lib/Signal/libsignal.d.ts +1 -1
  14. package/lib/Socket/business.d.ts +1 -1
  15. package/lib/Socket/business.js +1 -1
  16. package/lib/Socket/chats.d.ts +4 -1
  17. package/lib/Socket/chats.js +213 -36
  18. package/lib/Socket/groups.js +87 -15
  19. package/lib/Socket/index.js +9 -0
  20. package/lib/Socket/messages-interactive.js +259 -0
  21. package/lib/Socket/messages-recv.js +1473 -1228
  22. package/lib/Socket/messages-send.js +437 -469
  23. package/lib/Socket/socket.js +143 -26
  24. package/lib/Socket/usync.js +57 -4
  25. package/lib/Store/make-in-memory-store.js +28 -15
  26. package/lib/Types/Auth.d.ts +4 -0
  27. package/lib/Types/Message.d.ts +316 -6
  28. package/lib/Types/Message.js +1 -1
  29. package/lib/Types/Socket.d.ts +2 -0
  30. package/lib/Utils/cache-manager.d.ts +16 -0
  31. package/lib/Utils/cache-manager.js +22 -5
  32. package/lib/Utils/chat-utils.js +17 -13
  33. package/lib/Utils/decode-wa-message.js +1 -11
  34. package/lib/Utils/event-buffer.js +103 -2
  35. package/lib/Utils/generics.js +5 -6
  36. package/lib/Utils/index.d.ts +5 -0
  37. package/lib/Utils/index.js +3 -0
  38. package/lib/Utils/jid-validation.d.ts +2 -0
  39. package/lib/Utils/jid-validation.js +43 -10
  40. package/lib/Utils/link-preview.js +38 -28
  41. package/lib/Utils/messages-media.d.ts +1 -1
  42. package/lib/Utils/messages-media.js +22 -53
  43. package/lib/Utils/messages.js +653 -65
  44. package/lib/Utils/performance-config.d.ts +2 -0
  45. package/lib/Utils/performance-config.js +16 -7
  46. package/lib/Utils/process-message.js +124 -12
  47. package/lib/Utils/rate-limiter.js +15 -20
  48. package/lib/WABinary/generic-utils.js +5 -1
  49. package/lib/WABinary/jid-utils.d.ts +1 -0
  50. package/lib/WABinary/jid-utils.js +265 -5
  51. package/lib/WAUSync/Protocols/USyncContactProtocol.js +75 -5
  52. package/lib/WAUSync/Protocols/USyncDeviceProtocol.js +59 -6
  53. package/lib/WAUSync/USyncQuery.js +64 -6
  54. package/lib/index.d.ts +1 -0
  55. package/lib/index.js +5 -4
  56. package/package.json +10 -15
  57. package/WAProto/index.ts.ts +0 -53473
@@ -7,6 +7,7 @@ exports.makeMessagesSocket = void 0;
7
7
  const boom_1 = require("@hapi/boom");
8
8
  const node_cache_1 = __importDefault(require("@cacheable/node-cache"));
9
9
  const crypto_1 = require("crypto");
10
+ const AbortController = require("abort-controller");
10
11
  const WAProto_1 = require("../../WAProto");
11
12
  const Defaults_1 = require("../Defaults");
12
13
  const Utils_1 = require("../Utils");
@@ -15,7 +16,6 @@ const link_preview_1 = require("../Utils/link-preview");
15
16
  const WABinary_1 = require("../WABinary");
16
17
  const WAUSync_1 = require("../WAUSync");
17
18
  const newsletter_1 = require("./newsletter");
18
- const rate_limiter_1 = __importDefault(require("../Utils/rate-limiter"));
19
19
  const makeMessagesSocket = (config) => {
20
20
  const { logger, linkPreviewImageThumbnailWidth, generateHighQualityLinkPreview, options: axiosOptions, patchMessageBeforeSending, cachedGroupMetadata, } = config;
21
21
  const sock = (0, newsletter_1.makeNewsletterSocket)(config);
@@ -24,13 +24,7 @@ const makeMessagesSocket = (config) => {
24
24
  stdTTL: Defaults_1.DEFAULT_CACHE_TTLS.USER_DEVICES, // 5 minutes
25
25
  useClones: false
26
26
  });
27
-
28
- // Initialize rate limiter for anti-ban protection
29
- const messagesSendRate = config.messagesSendRate || 1;
30
- if(messagesSendRate > 5) {
31
- logger.warn(`messagesSendRate is set to a high value (${messagesSendRate}), this may increase the risk of getting banned. Recommended value is <= 3`);
32
- }
33
- const rateLimiter = new rate_limiter_1.default(messagesSendRate);
27
+ const inFlightDeviceFetch = new Map();
34
28
  let mediaConn;
35
29
  const refreshMediaConn = async (forceGet = false) => {
36
30
  const media = await mediaConn;
@@ -127,6 +121,8 @@ const makeMessagesSocket = (config) => {
127
121
  logger.debug('not using cache for devices');
128
122
  }
129
123
  const toFetch = [];
124
+ const usersToFetch = new Set();
125
+ const inFlightPromises = [];
130
126
  jids = Array.from(new Set(jids));
131
127
  for (let jid of jids) {
132
128
  const user = (_a = (0, WABinary_1.jidDecode)(jid)) === null || _a === void 0 ? void 0 : _a.user;
@@ -138,42 +134,128 @@ const makeMessagesSocket = (config) => {
138
134
  logger.trace({ user }, 'using cache for devices');
139
135
  }
140
136
  else {
141
- toFetch.push(jid);
137
+ const inFlight = user ? inFlightDeviceFetch.get(user) : undefined;
138
+ if (inFlight) {
139
+ inFlightPromises.push(inFlight.then(devs => {
140
+ if (devs && devs.length) {
141
+ deviceResults.push(...devs);
142
+ }
143
+ }));
144
+ }
145
+ else {
146
+ toFetch.push(jid);
147
+ if (user) {
148
+ usersToFetch.add(user);
149
+ }
150
+ }
142
151
  }
143
152
  }
144
153
  else {
145
154
  toFetch.push(jid);
155
+ if (user) {
156
+ usersToFetch.add(user);
157
+ }
146
158
  }
147
159
  }
160
+ if (inFlightPromises.length) {
161
+ await Promise.all(inFlightPromises);
162
+ }
148
163
  if (!toFetch.length) {
149
164
  return deviceResults;
150
165
  }
151
- const query = new WAUSync_1.USyncQuery()
152
- .withContext('message')
153
- .withDeviceProtocol();
154
- for (const jid of toFetch) {
155
- query.withUser(new WAUSync_1.USyncUser().withId(jid));
156
- }
157
- const result = await sock.executeUSyncQuery(query);
158
- if (result) {
159
- const extracted = (0, Utils_1.extractDeviceJids)(result === null || result === void 0 ? void 0 : result.list, authState.creds.me.id, ignoreZeroDevices);
166
+ const fetchPromise = (async () => {
167
+ const query = new WAUSync_1.USyncQuery()
168
+ .withContext('message')
169
+ .withDeviceProtocol();
170
+ for (const jid of toFetch) {
171
+ query.withUser(new WAUSync_1.USyncUser().withId(jid));
172
+ }
173
+ const result = await sock.executeUSyncQuery(query);
160
174
  const deviceMap = {};
161
- for (const item of extracted) {
162
- deviceMap[item.user] = deviceMap[item.user] || [];
163
- deviceMap[item.user].push(item);
164
- deviceResults.push(item);
175
+ if (result) {
176
+ const extracted = (0, Utils_1.extractDeviceJids)(result === null || result === void 0 ? void 0 : result.list, authState.creds.me.id, ignoreZeroDevices);
177
+ for (const item of extracted) {
178
+ deviceMap[item.user] = deviceMap[item.user] || [];
179
+ deviceMap[item.user].push(item);
180
+ deviceResults.push(item);
181
+ }
182
+ for (const key in deviceMap) {
183
+ userDevicesCache.set(key, deviceMap[key]);
184
+ }
165
185
  }
166
- for (const key in deviceMap) {
167
- userDevicesCache.set(key, deviceMap[key]);
186
+ return deviceMap;
187
+ })();
188
+ for (const user of usersToFetch) {
189
+ inFlightDeviceFetch.set(user, fetchPromise.then(deviceMap => deviceMap[user] || []));
190
+ }
191
+ try {
192
+ await fetchPromise;
193
+ }
194
+ finally {
195
+ for (const user of usersToFetch) {
196
+ const current = inFlightDeviceFetch.get(user);
197
+ if (current) {
198
+ inFlightDeviceFetch.delete(user);
199
+ }
168
200
  }
169
201
  }
170
202
  return deviceResults;
171
203
  };
204
+ // Cache to track JIDs that have failed session fetching to prevent infinite loops
205
+ const failedSessionFetchCache = new Map();
206
+ const FAILED_SESSION_CACHE_TTL = 5 * 60 * 1000; // 5 minutes
207
+ // Cache to track recently sent messages to prevent duplicate sends
208
+ const recentlySentMessagesCache = new node_cache_1.default({
209
+ stdTTL: Defaults_1.DEFAULT_CACHE_TTLS.MSG_RETRY, // 1 hour
210
+ useClones: false,
211
+ maxKeys: 1000 // Limit to prevent memory issues
212
+ });
213
+ const inFlightSessionFetch = new Map();
214
+
215
+ // Cleanup function to remove expired entries from the cache
216
+ const cleanupFailedSessionCache = () => {
217
+ const now = Date.now();
218
+ for (const [jid, failureTime] of failedSessionFetchCache.entries()) {
219
+ if (now - failureTime >= FAILED_SESSION_CACHE_TTL) {
220
+ failedSessionFetchCache.delete(jid);
221
+ }
222
+ }
223
+ };
224
+
225
+ // Run cleanup every 5 minutes
226
+ const cleanupInterval = setInterval(cleanupFailedSessionCache, 5 * 60 * 1000);
227
+
228
+ // Helper function to check if message was recently sent
229
+ const wasMessageRecentlySent = (msgId, jid) => {
230
+ const cacheKey = `${msgId}:${jid}`;
231
+ return recentlySentMessagesCache.has(cacheKey);
232
+ };
233
+
234
+ // Helper function to mark message as recently sent
235
+ const markMessageAsSent = (msgId, jid) => {
236
+ const cacheKey = `${msgId}:${jid}`;
237
+ recentlySentMessagesCache.set(cacheKey, true);
238
+ };
239
+
172
240
  const assertSessions = async (jids, force) => {
173
241
  let didFetchNewSession = false;
174
242
  let jidsRequiringFetch = [];
175
243
  if (force) {
176
- jidsRequiringFetch = jids;
244
+ // Filter out JIDs that have recently failed session fetching
245
+ jidsRequiringFetch = jids.filter(jid => {
246
+ const failureTime = failedSessionFetchCache.get(jid);
247
+ if (failureTime && (Date.now() - failureTime) < FAILED_SESSION_CACHE_TTL) {
248
+ logger.debug({ jid }, 'skipping session fetch for recently failed JID');
249
+ return false;
250
+ }
251
+ return true;
252
+ });
253
+
254
+ // If all JIDs are filtered out, return early without attempting fetch
255
+ if (jidsRequiringFetch.length === 0 && jids.length > 0) {
256
+ logger.debug({ originalJids: jids }, 'all JIDs recently failed, skipping session fetch entirely');
257
+ return didFetchNewSession;
258
+ }
177
259
  }
178
260
  else {
179
261
  const addrs = jids.map(jid => (signalRepository
@@ -183,57 +265,130 @@ const makeMessagesSocket = (config) => {
183
265
  const signalId = signalRepository
184
266
  .jidToSignalProtocolAddress(jid);
185
267
  if (!sessions[signalId]) {
186
- jidsRequiringFetch.push(jid);
268
+ // Also check if this JID recently failed
269
+ const failureTime = failedSessionFetchCache.get(jid);
270
+ if (!failureTime || (Date.now() - failureTime) >= FAILED_SESSION_CACHE_TTL) {
271
+ jidsRequiringFetch.push(jid);
272
+ }
187
273
  }
188
274
  }
189
275
  }
190
276
  if (jidsRequiringFetch.length) {
277
+ const awaitingInflight = [];
278
+ const uniqueJids = Array.from(new Set(jidsRequiringFetch));
279
+ jidsRequiringFetch = [];
280
+ for (const jid of uniqueJids) {
281
+ const inFlight = inFlightSessionFetch.get(jid);
282
+ if (inFlight) {
283
+ awaitingInflight.push(inFlight);
284
+ }
285
+ else {
286
+ jidsRequiringFetch.push(jid);
287
+ }
288
+ }
191
289
  logger.debug({ jidsRequiringFetch }, 'fetching sessions');
192
- const result = await query({
193
- tag: 'iq',
194
- attrs: {
195
- xmlns: 'encrypt',
196
- type: 'get',
197
- to: WABinary_1.S_WHATSAPP_NET,
198
- },
199
- content: [
200
- {
201
- tag: 'key',
202
- attrs: {},
203
- content: jidsRequiringFetch.map(jid => ({
204
- tag: 'user',
205
- attrs: { jid },
206
- }))
290
+ const TOTAL_TIMEOUT_MS = 120000; // 120 seconds
291
+ const abortController = new AbortController();
292
+ const timeout = setTimeout(() => abortController.abort(), TOTAL_TIMEOUT_MS);
293
+ try {
294
+ const BATCH_SIZE = 50;
295
+ for (let i = 0; i < jidsRequiringFetch.length; i += BATCH_SIZE) {
296
+ const batch = jidsRequiringFetch.slice(i, i + BATCH_SIZE);
297
+ try {
298
+ const batchPromise = (0, retry_1.retryWithBackoff)(() => query({
299
+ tag: 'iq',
300
+ attrs: {
301
+ xmlns: 'encrypt',
302
+ type: 'get',
303
+ to: WABinary_1.S_WHATSAPP_NET,
304
+ },
305
+ content: [
306
+ {
307
+ tag: 'key',
308
+ attrs: {},
309
+ content: batch.map(jid => ({
310
+ tag: 'user',
311
+ attrs: { jid },
312
+ }))
313
+ }
314
+ ]
315
+ }), {
316
+ retries: 4,
317
+ baseMs: 2000,
318
+ maxMs: 10000,
319
+ jitter: true,
320
+ timeoutPerAttemptMs: 25000,
321
+ shouldRetry: (err) => {
322
+ var _a;
323
+ const status = ((_a = err.output) === null || _a === void 0 ? void 0 : _a.statusCode) || (err === null || err === void 0 ? void 0 : err.statusCode);
324
+ // Don't retry "not-acceptable" (406) errors as they indicate permission issues
325
+ // Don't retry aborted requests as they were intentionally cancelled
326
+ if (status === 406 || err.message === 'aborted' || err.code === 'ABORT_ERR') {
327
+ return false;
328
+ }
329
+ return !status || (status >= 500 || status === 408 || status === 429) || err.message.includes('WebSocket is not open');
330
+ },
331
+ onRetry: (err, n) => logger === null || logger === void 0 ? void 0 : logger.warn({ err, attempt: n }, 'retrying fetch sessions'),
332
+ signal: abortController.signal
333
+ });
334
+ for (const jid of batch) {
335
+ inFlightSessionFetch.set(jid, batchPromise.then(() => undefined));
336
+ }
337
+ const result = await batchPromise;
338
+ await (0, Utils_1.parseAndInjectE2ESessions)(result, signalRepository);
339
+ didFetchNewSession = true;
340
+ for (const jid of batch) {
341
+ inFlightSessionFetch.delete(jid);
342
+ }
343
+ } catch (err) {
344
+ // Cache failed JIDs to prevent infinite retries
345
+ logger.warn({ err, batch }, 'session fetch failed for batch, caching failed JIDs');
346
+ for (const jid of batch) {
347
+ failedSessionFetchCache.set(jid, Date.now());
348
+ inFlightSessionFetch.delete(jid);
349
+ }
350
+ // Re-throw the error so the caller knows the fetch failed
351
+ throw err;
207
352
  }
208
- ]
209
- });
210
- await (0, Utils_1.parseAndInjectE2ESessions)(result, signalRepository);
211
- didFetchNewSession = true;
353
+ }
354
+ if (awaitingInflight.length) {
355
+ await Promise.all(awaitingInflight);
356
+ }
357
+ } finally {
358
+ clearTimeout(timeout);
359
+ }
212
360
  }
213
361
  return didFetchNewSession;
214
362
  };
215
- const sendPeerDataOperationMessage = async (pdoMessage) => {
363
+ const sendPeerMessage = async (protocolMessageContent, options = {}) => {
216
364
  var _a;
217
- //TODO: for later, abstract the logic to send a Peer Message instead of just PDO - useful for App State Key Resync with phone
218
365
  if (!((_a = authState.creds.me) === null || _a === void 0 ? void 0 : _a.id)) {
219
366
  throw new boom_1.Boom('Not authenticated');
220
367
  }
368
+
221
369
  const protocolMessage = {
222
- protocolMessage: {
223
- peerDataOperationRequestMessage: pdoMessage,
224
- type: WAProto_1.proto.Message.ProtocolMessage.Type.PEER_DATA_OPERATION_REQUEST_MESSAGE
225
- }
370
+ protocolMessage: protocolMessageContent
226
371
  };
372
+
227
373
  const meJid = (0, WABinary_1.jidNormalizedUser)(authState.creds.me.id);
228
374
  const msgId = await relayMessage(meJid, protocolMessage, {
229
375
  additionalAttributes: {
230
376
  category: 'peer',
231
377
  // eslint-disable-next-line camelcase
232
378
  push_priority: 'high_force',
379
+ ...options.additionalAttributes
233
380
  },
381
+ ...options
234
382
  });
235
383
  return msgId;
236
384
  };
385
+
386
+ const sendPeerDataOperationMessage = async (pdoMessage) => {
387
+ return sendPeerMessage({
388
+ peerDataOperationRequestMessage: pdoMessage,
389
+ type: WAProto_1.proto.Message.ProtocolMessage.Type.PEER_DATA_OPERATION_REQUEST_MESSAGE
390
+ });
391
+ };
237
392
  const createParticipantNodes = async (jids, message, extraAttrs) => {
238
393
  let patched = await patchMessageBeforeSending(message, jids);
239
394
  if (!Array.isArray(patched)) {
@@ -279,6 +434,13 @@ const makeMessagesSocket = (config) => {
279
434
  const isStatus = jid === statusJid;
280
435
  const isLid = server === 'lid';
281
436
  msgId = msgId || (0, Utils_1.generateMessageIDV2)((_a = sock.user) === null || _a === void 0 ? void 0 : _a.id);
437
+
438
+ // Check if this message was recently sent to prevent duplicate sends
439
+ if (wasMessageRecentlySent(msgId, jid)) {
440
+ logger.debug({ msgId, jid }, 'message recently sent, skipping duplicate send');
441
+ return msgId;
442
+ }
443
+
282
444
  useUserDevicesCache = useUserDevicesCache !== false;
283
445
  useCachedGroupMetadata = useCachedGroupMetadata !== false && !isStatus;
284
446
  const participants = [];
@@ -549,9 +711,9 @@ const makeMessagesSocket = (config) => {
549
711
  }
550
712
  logger.debug({ msgId }, `sending message to ${participants.length} devices`);
551
713
  await (0, retry_1.retryWithBackoff)(({ signal }) => sendNode(stanza, { signal }), {
552
- retries: 3,
553
- baseMs: 300,
554
- maxMs: 4000,
714
+ retries: 2, // Riduci i tentativi
715
+ baseMs: 100, // Riduci l'attesa iniziale
716
+ maxMs: 2000, // Riduci l'attesa massima
555
717
  jitter: true,
556
718
  timeoutPerAttemptMs: 5000,
557
719
  shouldRetry: (err) => {
@@ -561,6 +723,9 @@ const makeMessagesSocket = (config) => {
561
723
  },
562
724
  onRetry: (err, n) => logger?.warn?.({ err, attempt: n }, 'retrying sendNode')
563
725
  });
726
+
727
+ // Mark message as successfully sent to prevent duplicate sends
728
+ markMessageAsSent(msgId, jid);
564
729
  });
565
730
  return msgId;
566
731
  };
@@ -666,205 +831,171 @@ const makeMessagesSocket = (config) => {
666
831
  });
667
832
  return result;
668
833
  };
669
- const waUploadToServer = (0, Utils_1.getWAUploadToServer)(config, refreshMediaConn);
670
- const waitForMsgMediaUpdate = (0, Utils_1.bindWaitForEvent)(ev, 'messages.media-update');
671
-
672
- // Helper function to send message without admin-only logic
673
- const sendMessageInternal = async (jid, content, options = {}) => {
674
- var _a, _b, _c;
675
- const userJid = authState.creds.me.id;
676
-
677
- if (!options.ephemeralExpiration) {
678
- if ((0, WABinary_1.isJidGroup)(jid)) {
679
- const groups = await sock.groupQuery(jid, 'get', [{
680
- tag: 'query',
681
- attrs: {
682
- request: 'interactive'
683
- }
684
- }]);
685
- const metadata = (0, WABinary_1.getBinaryNodeChild)(groups, 'group');
686
- const expiration = ((_b = (_a = (0, WABinary_1.getBinaryNodeChild)(metadata, 'ephemeral')) === null || _a === void 0 ? void 0 : _a.attrs) === null || _b === void 0 ? void 0 : _b.expiration) || 0;
687
- options.ephemeralExpiration = expiration;
834
+ const waUploadToServer = (0, Utils_1.getWAUploadToServer)(config, refreshMediaConn);
835
+ const waitForMsgMediaUpdate = (0, Utils_1.bindWaitForEvent)(ev, 'messages.media-update');
836
+ return {
837
+ ...sock,
838
+ getPrivacyTokens,
839
+ assertSessions,
840
+ relayMessage,
841
+ sendReceipt,
842
+ sendReceipts,
843
+ readMessages,
844
+ sendPeerDataOperationMessage,
845
+ sendPeerMessage,
846
+ getUSyncDevices,
847
+ getFailedSessionCache: () => failedSessionFetchCache,
848
+ getFailedSessionCacheTTL: () => FAILED_SESSION_CACHE_TTL,
849
+ getRecentlySentMessagesCache: () => recentlySentMessagesCache,
850
+ wasMessageRecentlySent,
851
+ markMessageAsSent,
852
+ sendMessage: async (jid, content, options = {}) => {
853
+ var _a, _b, _c;
854
+ const userJid = authState.creds.me.id;
855
+ if (!options.ephemeralExpiration) {
856
+ if ((0, WABinary_1.isJidGroup)(jid)) {
857
+ const useCache = options.useCachedGroupMetadata !== false;
858
+ const groupData = (useCache && cachedGroupMetadata) ? await cachedGroupMetadata(jid) : await groupMetadata(jid);
859
+ options.ephemeralExpiration = (groupData === null || groupData === void 0 ? void 0 : groupData.ephemeralDuration) || 0;
860
+ }
688
861
  }
689
- }
690
- if (typeof content === 'object' &&
691
- 'disappearingMessagesInChat' in content &&
692
- typeof content['disappearingMessagesInChat'] !== 'undefined' &&
693
- (0, WABinary_1.isJidGroup)(jid)) {
694
- const { disappearingMessagesInChat } = content;
695
- const value = typeof disappearingMessagesInChat === 'boolean' ?
696
- (disappearingMessagesInChat ? Defaults_1.WA_DEFAULT_EPHEMERAL : 0) :
697
- disappearingMessagesInChat;
698
- await groupToggleEphemeral(jid, value);
699
- }
700
- if (typeof content === 'object' && 'album' in content && content.album) {
701
- const { album, caption } = content;
702
- if (caption && !album[0].caption) {
703
- album[0].caption = caption;
862
+ if (typeof content === 'object' &&
863
+ 'disappearingMessagesInChat' in content &&
864
+ typeof content['disappearingMessagesInChat'] !== 'undefined' &&
865
+ (0, WABinary_1.isJidGroup)(jid)) {
866
+ const { disappearingMessagesInChat } = content;
867
+ const value = typeof disappearingMessagesInChat === 'boolean' ?
868
+ (disappearingMessagesInChat ? Defaults_1.WA_DEFAULT_EPHEMERAL : 0) :
869
+ disappearingMessagesInChat;
870
+ await groupToggleEphemeral(jid, value);
704
871
  }
705
- let mediaHandle;
706
- let mediaMsg;
707
- const albumMsg = (0, Utils_1.generateWAMessageFromContent)(jid, {
708
- albumMessage: {
709
- expectedImageCount: album.filter(item => 'image' in item).length,
710
- expectedVideoCount: album.filter(item => 'video' in item).length
711
- }
712
- }, { userJid, ...options });
713
- await relayMessage(jid, albumMsg.message, {
714
- messageId: albumMsg.key.id
715
- });
716
- for (const i in album) {
717
- const media = album[i];
718
- if ('image' in media) {
719
- mediaMsg = await (0, Utils_1.generateWAMessage)(jid, {
720
- image: media.image,
721
- ...(media.caption ? { caption: media.caption } : {}),
722
- ...options
723
- }, {
724
- userJid,
725
- upload: async (readStream, opts) => {
726
- const up = await waUploadToServer(readStream, { ...opts, newsletter: (0, WABinary_1.isJidNewsletter)(jid) });
727
- mediaHandle = up.handle;
728
- return up;
729
- },
730
- ...options,
731
- });
872
+ // Handle pin messages
873
+ if (typeof content === 'object' && 'pin' in content && content.pin) {
874
+ const pinData = typeof content.pin === 'object' ? content.pin : { key: content.pin };
875
+ // Map type: 1 = PIN_FOR_ALL, 2 = UNPIN_FOR_ALL
876
+ const pinType = pinData.type !== undefined ? pinData.type : (content.type !== undefined ? content.type : WAProto_1.proto.Message.PinInChatMessage.Type.PIN_FOR_ALL);
877
+ const msgId = (0, Utils_1.generateMessageIDV2)((_c = sock.user) === null || _c === void 0 ? void 0 : _c.id);
878
+ const pinMessage = {
879
+ pinInChatMessage: {
880
+ key: pinData.key,
881
+ type: pinType,
882
+ senderTimestampMs: Date.now()
883
+ }
884
+ };
885
+ // Add messageContextInfo only for PIN (type 1), not for UNPIN (type 2)
886
+ if (pinType === WAProto_1.proto.Message.PinInChatMessage.Type.PIN_FOR_ALL) {
887
+ pinMessage.messageContextInfo = {
888
+ messageAddOnDurationInSecs: pinData.time || content.time || 86400, // Default 24 hours
889
+ messageAddOnExpiryType: WAProto_1.proto.MessageContextInfo.MessageAddonExpiryType.STATIC
890
+ };
732
891
  }
733
- else if ('video' in media) {
734
- mediaMsg = await (0, Utils_1.generateWAMessage)(jid, {
735
- video: media.video,
736
- ...(media.caption ? { caption: media.caption } : {}),
737
- ...(media.gifPlayback !== undefined ? { gifPlayback: media.gifPlayback } : {}),
738
- ...options
739
- }, {
740
- userJid,
741
- upload: async (readStream, opts) => {
742
- const up = await waUploadToServer(readStream, { ...opts, newsletter: (0, WABinary_1.isJidNewsletter)(jid) });
743
- mediaHandle = up.handle;
744
- return up;
745
- },
746
- ...options,
892
+ const fullMsg = {
893
+ key: {
894
+ remoteJid: jid,
895
+ fromMe: true,
896
+ id: msgId,
897
+ participant: userJid
898
+ },
899
+ message: pinMessage,
900
+ messageTimestamp: (0, Utils_1.unixTimestampSeconds)()
901
+ };
902
+ await relayMessage(jid, fullMsg.message, { //oopsie, questo è il fix per il pin 😿
903
+ messageId: fullMsg.key.id,
904
+ useCachedGroupMetadata: options.useCachedGroupMetadata,
905
+ additionalAttributes: {
906
+ edit: '2',
907
+ ...(options.additionalAttributes || {})
908
+ }
909
+ });
910
+ if (config.emitOwnEvents) {
911
+ process.nextTick(() => {
912
+ processingMutex.mutex(() => (upsertMessage(fullMsg, 'append')));
747
913
  });
748
914
  }
749
- else if ('url' in media) {
750
- // Assume URL is an image if not specified
751
- mediaMsg = await (0, Utils_1.generateWAMessage)(jid, {
752
- image: media.url,
753
- ...(media.caption ? { caption: media.caption } : {}),
754
- ...options
755
- }, {
756
- userJid,
757
- upload: async (readStream, opts) => {
758
- const up = await waUploadToServer(readStream, { ...opts, newsletter: (0, WABinary_1.isJidNewsletter)(jid) });
759
- mediaHandle = up.handle;
760
- return up;
761
- },
762
- ...options,
763
- });
915
+ return fullMsg;
916
+ }
917
+ if (typeof content === 'object' && 'album' in content && content.album) {
918
+ const { album, caption } = content;
919
+ if (caption && !album[0].caption) {
920
+ album[0].caption = caption;
764
921
  }
765
- if (mediaMsg) {
766
- mediaMsg.message.messageContextInfo = {
767
- messageSecret: (0, crypto_1.randomBytes)(32),
768
- messageAssociation: {
769
- associationType: 1,
770
- parentMessageKey: albumMsg.key
771
- }
772
- };
922
+ let mediaHandle;
923
+ let mediaMsg;
924
+ const albumMsg = (0, Utils_1.generateWAMessageFromContent)(jid, {
925
+ albumMessage: {
926
+ expectedImageCount: album.filter(item => 'image' in item).length,
927
+ expectedVideoCount: album.filter(item => 'video' in item).length
928
+ }
929
+ }, { userJid, ...options });
930
+ await relayMessage(jid, albumMsg.message, {
931
+ messageId: albumMsg.key.id
932
+ });
933
+ for (const i in album) {
934
+ const media = album[i];
935
+ if ('image' in media) {
936
+ mediaMsg = await (0, Utils_1.generateWAMessage)(jid, {
937
+ image: media.image,
938
+ ...(media.caption ? { caption: media.caption } : {}),
939
+ ...options
940
+ }, {
941
+ userJid,
942
+ upload: async (readStream, opts) => {
943
+ const up = await waUploadToServer(readStream, { ...opts, newsletter: (0, WABinary_1.isJidNewsletter)(jid) });
944
+ mediaHandle = up.handle;
945
+ return up;
946
+ },
947
+ ...options,
948
+ });
949
+ }
950
+ else if ('video' in media) {
951
+ mediaMsg = await (0, Utils_1.generateWAMessage)(jid, {
952
+ video: media.video,
953
+ ...(media.caption ? { caption: media.caption } : {}),
954
+ ...(media.gifPlayback !== undefined ? { gifPlayback: media.gifPlayback } : {}),
955
+ ...options
956
+ }, {
957
+ userJid,
958
+ upload: async (readStream, opts) => {
959
+ const up = await waUploadToServer(readStream, { ...opts, newsletter: (0, WABinary_1.isJidNewsletter)(jid) });
960
+ mediaHandle = up.handle;
961
+ return up;
962
+ },
963
+ ...options,
964
+ });
965
+ }
966
+ if (mediaMsg) {
967
+ mediaMsg.message.messageContextInfo = {
968
+ messageSecret: (0, crypto_1.randomBytes)(32),
969
+ messageAssociation: {
970
+ associationType: 1,
971
+ parentMessageKey: albumMsg.key
972
+ }
973
+ };
974
+ }
773
975
  await relayMessage(jid, mediaMsg.message, {
774
976
  messageId: mediaMsg.key.id
775
977
  });
776
- await new Promise(resolve => setTimeout(resolve, 800));
777
- }
778
- }
779
- return albumMsg;
780
- }
781
- else if (typeof content === 'object' && 'stickerPack' in content && content.stickerPack) {
782
- // Send sticker pack metadata first, then each sticker associated with it
783
- const { stickerPack } = content;
784
- const stickers = stickerPack.stickers || [];
785
- if (!Array.isArray(stickers) || stickers.length === 0) {
786
- throw new boom_1.Boom('stickerPack requires at least one sticker', { statusCode: 400 });
787
- }
788
-
789
- // Prepare cover thumbnail if provided
790
- let thumbnailDirectPath;
791
- let thumbnailEncSha256;
792
- let thumbnailSha256;
793
- let thumbnailHeight;
794
- let thumbnailWidth;
795
- if (stickerPack.cover) {
796
- try {
797
- const thumbMsg = await (0, Utils_1.prepareWAMessageMedia)({ image: stickerPack.cover }, {
798
- logger,
799
- userJid,
800
- upload: async (readStream, opts) => {
801
- const up = await waUploadToServer(readStream, { ...opts, newsletter: (0, WABinary_1.isJidNewsletter)(jid) });
802
- return up;
803
- },
804
- mediaCache: config.mediaCache,
805
- options: config.options,
806
- messageId: (0, Utils_1.generateMessageIDV2)((_c = sock.user) === null || _c === void 0 ? void 0 : _c.id),
807
- ...options,
808
- });
809
- if (thumbMsg.imageMessage) {
810
- thumbnailDirectPath = thumbMsg.imageMessage.directPath;
811
- thumbnailEncSha256 = thumbMsg.imageMessage.fileEncSha256;
812
- thumbnailSha256 = thumbMsg.imageMessage.fileSha256;
813
- thumbnailHeight = thumbMsg.imageMessage.height;
814
- thumbnailWidth = thumbMsg.imageMessage.width;
815
- }
816
- }
817
- catch (err) {
818
- logger === null || logger === void 0 ? void 0 : logger.warn({ err }, 'failed to prepare stickerPack cover');
978
+ await new Promise(resolve => setTimeout(resolve, 100));
819
979
  }
980
+ return albumMsg;
820
981
  }
821
-
822
- // Map stickers metadata to proto-friendly shape
823
- const protoStickers = stickers.map((s, idx) => ({
824
- fileName: s.fileName || `sticker_${idx}.webp`,
825
- isAnimated: !!s.isAnimated,
826
- emojis: Array.isArray(s.emojis) ? s.emojis : (s.emojis ? [s.emojis] : []),
827
- accessibilityLabel: s.accessibilityLabel,
828
- isLottie: !!s.isLottie,
829
- mimetype: s.mimetype || 'image/webp'
830
- }));
831
-
832
- const stickerPackObj = {
833
- name: stickerPack.name,
834
- publisher: stickerPack.publisher,
835
- packDescription: stickerPack.description,
836
- stickers: protoStickers,
837
- thumbnailDirectPath,
838
- thumbnailEncSha256,
839
- thumbnailSha256,
840
- thumbnailHeight,
841
- thumbnailWidth,
842
- };
843
-
844
- // Create and send the pack metadata message
845
- const contentForSend = { stickerPackMessage: WAProto_1.proto.Message.StickerPackMessage.fromObject(stickerPackObj) };
846
- const packMsg = (0, Utils_1.generateWAMessageFromContent)(jid, contentForSend, {
847
- userJid,
848
- upload: waUploadToServer,
849
- mediaCache: config.mediaCache,
850
- options: config.options,
851
- messageId: (0, Utils_1.generateMessageIDV2)((_c = sock.user) === null || _c === void 0 ? void 0 : _c.id),
852
- ...options,
853
- });
854
- await relayMessage(jid, packMsg.message, { messageId: packMsg.key.id });
855
-
856
- // Send each sticker associated with the pack
857
- let lastMsg = packMsg;
858
- for (const sticker of stickers) {
859
- const stickerData = sticker.sticker || sticker.data || sticker.buffer || sticker.image || sticker.url || sticker;
860
- if (!stickerData) {
861
- throw new boom_1.Boom('Sticker data not found for sticker: ' + JSON.stringify(sticker), { statusCode: 400 });
862
- }
863
- const stickerContent = { sticker: stickerData };
982
+ else {
864
983
  let mediaHandle;
865
- const stickerMsg = await (0, Utils_1.generateWAMessage)(jid, stickerContent, {
984
+ const fullMsg = await (0, Utils_1.generateWAMessage)(jid, content, {
866
985
  logger,
867
986
  userJid,
987
+ getUrlInfo: text => (0, link_preview_1.getUrlInfo)(text, {
988
+ thumbnailWidth: linkPreviewImageThumbnailWidth,
989
+ fetchOpts: {
990
+ timeout: 3000,
991
+ ...axiosOptions || {}
992
+ },
993
+ logger,
994
+ uploadImage: generateHighQualityLinkPreview
995
+ ? waUploadToServer
996
+ : undefined
997
+ }),
998
+ getProfilePicUrl: sock.profilePictureUrl,
868
999
  upload: async (readStream, opts) => {
869
1000
  const up = await waUploadToServer(readStream, { ...opts, newsletter: (0, WABinary_1.isJidNewsletter)(jid) });
870
1001
  mediaHandle = up.handle;
@@ -875,243 +1006,80 @@ const makeMessagesSocket = (config) => {
875
1006
  messageId: (0, Utils_1.generateMessageIDV2)((_c = sock.user) === null || _c === void 0 ? void 0 : _c.id),
876
1007
  ...options,
877
1008
  });
878
- // Associate sticker with the pack message
879
- stickerMsg.message.messageContextInfo = {
880
- messageSecret: (0, crypto_1.randomBytes)(32),
881
- messageAssociation: {
882
- associationType: 1,
883
- parentMessageKey: packMsg.key
1009
+ const isDeleteMsg = 'delete' in content && !!content.delete;
1010
+ const isEditMsg = 'edit' in content && !!content.edit;
1011
+ const isPinMsg = 'pin' in content && !!content.pin;
1012
+ const isKeepMsg = 'keep' in content && content.keep;
1013
+ const isPollMessage = 'poll' in content && !!content.poll;
1014
+ const isAiMsg = 'ai' in content && !!content.ai;
1015
+ const isAiRichResponseMsg = 'richResponse' in content && !!content.richResponse;
1016
+ const additionalAttributes = {};
1017
+ const additionalNodes = [];
1018
+ // required for delete
1019
+ if (isDeleteMsg) {
1020
+ // if the chat is a group, and I am not the author, then delete the message as an admin
1021
+ if (((0, WABinary_1.isJidGroup)(content.delete.remoteJid) && !content.delete.fromMe) || (0, WABinary_1.isJidNewsletter)(jid)) {
1022
+ additionalAttributes.edit = '8';
884
1023
  }
885
- };
886
- await relayMessage(jid, stickerMsg.message, { messageId: stickerMsg.key.id });
887
- lastMsg = stickerMsg;
888
- // Add delay between stickers to avoid rate limiting
889
- await new Promise(resolve => setTimeout(resolve, 800));
890
- }
891
- return lastMsg;
892
- }
893
- else {
894
- let mediaHandle;
895
- const fullMsg = await (0, Utils_1.generateWAMessage)(jid, content, {
896
- logger,
897
- userJid,
898
- getUrlInfo: text => (0, link_preview_1.getUrlInfo)(text, {
899
- thumbnailWidth: linkPreviewImageThumbnailWidth,
900
- fetchOpts: {
901
- timeout: 3000,
902
- ...axiosOptions || {}
903
- },
904
- logger,
905
- uploadImage: generateHighQualityLinkPreview
906
- ? waUploadToServer
907
- : undefined
908
- }),
909
- getProfilePicUrl: sock.profilePictureUrl,
910
- upload: async (readStream, opts) => {
911
- const up = await waUploadToServer(readStream, { ...opts, newsletter: (0, WABinary_1.isJidNewsletter)(jid) });
912
- mediaHandle = up.handle;
913
- return up;
914
- },
915
- mediaCache: config.mediaCache,
916
- options: config.options,
917
- messageId: (0, Utils_1.generateMessageIDV2)((_c = sock.user) === null || _c === void 0 ? void 0 : _c.id),
918
- ...options,
919
- });
920
- const isDeleteMsg = 'delete' in content && !!content.delete;
921
- const isEditMsg = 'edit' in content && !!content.edit;
922
- const isPinMsg = 'pin' in content && !!content.pin;
923
- const isKeepMsg = 'keep' in content && content.keep;
924
- const isPollMessage = 'poll' in content && !!content.poll;
925
- const isAiMsg = options.ai === true;
926
- const additionalAttributes = {};
927
- const additionalNodes = [];
928
- // required for delete
929
- if (isDeleteMsg) {
930
- // if the chat is a group, and I am not the author, then delete the message as an admin
931
- if (((0, WABinary_1.isJidGroup)(content.delete.remoteJid) && !content.delete.fromMe) || (0, WABinary_1.isJidNewsletter)(jid)) {
932
- additionalAttributes.edit = '8';
1024
+ else {
1025
+ additionalAttributes.edit = '7';
1026
+ }
1027
+ // required for edit message
933
1028
  }
934
- else {
935
- additionalAttributes.edit = '7';
1029
+ else if (isEditMsg) {
1030
+ additionalAttributes.edit = (0, WABinary_1.isJidNewsletter)(jid) ? '3' : '1';
1031
+ // required for pin message
936
1032
  }
937
- // required for edit message
938
- }
939
- else if (isEditMsg) {
940
- additionalAttributes.edit = (0, WABinary_1.isJidNewsletter)(jid) ? '3' : '1';
941
- // required for pin message
942
- }
943
- else if (isPinMsg) {
944
- additionalAttributes.edit = '2';
945
- // required for keep message
946
- }
947
- else if (isKeepMsg) {
948
- additionalAttributes.edit = '6';
949
- // required for polling message
950
- }
951
- else if (isPollMessage) {
952
- additionalNodes.push({
953
- tag: 'meta',
954
- attrs: {
955
- polltype: 'creation'
956
- },
957
- });
958
- // required to display AI icon on message
959
- }
960
- else if (isAiMsg) {
961
- additionalNodes.push({
962
- attrs: {
963
- biz_bot: '1'
964
- },
965
- tag: "bot"
966
- });
967
- }
968
- if (mediaHandle) {
969
- additionalAttributes['media_id'] = mediaHandle;
970
- }
971
- if ('cachedGroupMetadata' in options) {
972
- console.warn('cachedGroupMetadata in sendMessage are deprecated, now cachedGroupMetadata is part of the socket config.');
973
- }
974
- // Add AI context if needed
975
- if (isAiMsg) {
976
- fullMsg.message.messageContextInfo = {
977
- ...fullMsg.message.messageContextInfo,
978
- biz_bot: '1'
979
- };
980
- }
981
-
982
-
983
- await relayMessage(jid, fullMsg.message, { messageId: fullMsg.key.id, useCachedGroupMetadata: options.useCachedGroupMetadata, additionalAttributes, additionalNodes: isAiMsg ? additionalNodes : options.additionalNodes, statusJidList: options.statusJidList });
984
- if (config.emitOwnEvents) {
985
- process.nextTick(() => {
986
- processingMutex.mutex(() => (upsertMessage(fullMsg, 'append')));
987
- });
988
- }
989
- return fullMsg;
990
- }
991
- };
992
-
993
- // Helper function to send missed call note
994
- const sendMissedCallNote = async (jid, media, options = {}) => {
995
- const prepared = await prepareWAMessageMedia(media, { upload: sock.waUploadToServer });
996
- return sock.sendMessage(jid, {
997
- ...prepared,
998
- ptt: !!media.audio,
999
- contextInfo: {
1000
- externalAdReply: {
1001
- title: 'Missed Call Note',
1002
- body: options.callInfo?.id ? `From call ${options.callInfo.id}` : 'Recent call'
1033
+ else if (isPinMsg) {
1034
+ additionalAttributes.edit = '2';
1035
+ // required for keep message
1036
+ }
1037
+ else if (isKeepMsg) {
1038
+ additionalAttributes.edit = '6';
1039
+ // required for polling message
1040
+ }
1041
+ else if (isPollMessage) {
1042
+ additionalNodes.push({
1043
+ tag: 'meta',
1044
+ attrs: {
1045
+ polltype: 'creation'
1046
+ },
1047
+ });
1048
+ // required to display AI icon on message
1049
+ }
1050
+ else if (isAiMsg || isAiRichResponseMsg) {
1051
+ additionalNodes.push({
1052
+ attrs: {
1053
+ biz_bot: '1'
1054
+ },
1055
+ tag: "bot"
1056
+ });
1057
+ }
1058
+ if (mediaHandle) {
1059
+ additionalAttributes['media_id'] = mediaHandle;
1060
+ }
1061
+ if ('cachedGroupMetadata' in options) {
1062
+ logger.warn('cachedGroupMetadata in sendMessage are deprecated, now cachedGroupMetadata is part of the socket config.');
1003
1063
  }
1064
+ await relayMessage(jid, fullMsg.message, { messageId: fullMsg.key.id, useCachedGroupMetadata: options.useCachedGroupMetadata, additionalAttributes, additionalNodes: (isAiMsg || isAiRichResponseMsg) ? additionalNodes : options.additionalNodes, statusJidList: options.statusJidList });
1065
+ if (config.emitOwnEvents) {
1066
+ process.nextTick(() => {
1067
+ processingMutex.mutex(() => (upsertMessage(fullMsg, 'append')));
1068
+ });
1069
+ }
1070
+ return fullMsg;
1004
1071
  }
1005
- });
1072
+ }
1006
1073
  };
1007
-
1074
+
1075
+ // Import interactive methods
1076
+ const { makeInteractiveSocket } = require('./messages-interactive');
1077
+ const interactiveSocket = makeInteractiveSocket(config);
1078
+
1008
1079
  return {
1009
1080
  ...sock,
1010
- getPrivacyTokens,
1011
- assertSessions,
1012
- relayMessage,
1013
- sendReceipt,
1014
- sendReceipts,
1015
- readMessages,
1016
- refreshMediaConn,
1017
- waUploadToServer,
1018
- fetchPrivacySettings,
1019
- getUSyncDevices,
1020
- createParticipantNodes,
1021
- sendPeerDataOperationMessage,
1022
- sendMissedCallNote,
1023
- updateMediaMessage: async (message) => {
1024
- const content = (0, Utils_1.assertMediaContent)(message.message);
1025
- const mediaKey = content.mediaKey;
1026
- const meId = authState.creds.me.id;
1027
- const node = await (0, Utils_1.encryptMediaRetryRequest)(message.key, mediaKey, meId);
1028
- let error = undefined;
1029
- await Promise.all([
1030
- sendNode(node),
1031
- waitForMsgMediaUpdate(async (update) => {
1032
- const result = update.find(c => c.key.id === message.key.id);
1033
- if (result) {
1034
- if (result.error) {
1035
- error = result.error;
1036
- }
1037
- else {
1038
- try {
1039
- const media = await (0, Utils_1.decryptMediaRetryData)(result.media, mediaKey, result.key.id);
1040
- if (media.result !== WAProto_1.proto.MediaRetryNotification.ResultType.SUCCESS) {
1041
- const resultStr = WAProto_1.proto.MediaRetryNotification.ResultType[media.result];
1042
- throw new boom_1.Boom(`Media re-upload failed by device (${resultStr})`, { data: media, statusCode: (0, Utils_1.getStatusCodeForMediaRetry)(media.result) || 404 });
1043
- }
1044
- content.directPath = media.directPath;
1045
- content.url = (0, Utils_1.getUrlFromDirectPath)(content.directPath);
1046
- logger.debug({ directPath: media.directPath, key: result.key }, 'media update successful');
1047
- }
1048
- catch (err) {
1049
- error = err;
1050
- }
1051
- }
1052
- return true;
1053
- }
1054
- })
1055
- ]);
1056
- if (error) {
1057
- throw error;
1058
- }
1059
- ev.emit('messages.update', [
1060
- { key: message.key, update: { message: message.message } }
1061
- ]);
1062
- return message;
1063
- },
1064
- sendMessage: async (jid, content, options = {}) => {
1065
- var _a;
1066
- // Handle admin-only messages by sending private messages to each admin
1067
- if (((_a = content.contextInfo) === null || _a === void 0 ? void 0 : _a.isAdminOnly) && (0, WABinary_1.isJidGroup)(jid)) {
1068
- try {
1069
- // Get group metadata to find admins
1070
- const metadata = await sock.groupMetadata(jid);
1071
- const participants = metadata.participants || [];
1072
-
1073
- // Find admin JIDs and ensure they are properly formatted
1074
- const adminJids = participants
1075
- .filter(p => p.admin === 'admin' || p.admin === 'superadmin')
1076
- .map(p => (0, WABinary_1.jidNormalizedUser)(p.id));
1077
-
1078
- if (adminJids.length === 0) {
1079
- throw new boom_1.Boom('No admins found in group', { statusCode: 400 });
1080
- }
1081
-
1082
- // Remove isAdminOnly from content to avoid recursion
1083
- const contentCopy = { ...content };
1084
- if (contentCopy.contextInfo) {
1085
- const { isAdminOnly, ...contextInfoRest } = contentCopy.contextInfo;
1086
- contentCopy.contextInfo = contextInfoRest;
1087
- }
1088
-
1089
- // Add group context to indicate this is from a group
1090
- contentCopy.contextInfo = {
1091
- ...contentCopy.contextInfo,
1092
- groupJid: jid,
1093
- adminOnlyMessage: true
1094
- };
1095
-
1096
- // Send private message to each admin
1097
- const results = [];
1098
- for (const adminJid of adminJids) {
1099
- try {
1100
- const result = await rateLimiter.add(() => sendMessageInternal(adminJid, contentCopy, options));
1101
- results.push(result);
1102
- } catch (error) {
1103
- console.warn(`Failed to send admin-only message to ${adminJid}:`, error);
1104
- }
1105
- }
1106
-
1107
- return results.length > 0 ? results[0] : null; // Return first successful result
1108
- } catch (error) {
1109
- console.error('Failed to send admin-only message:', error);
1110
- throw error;
1111
- }
1112
- }
1113
- return rateLimiter.add(() => sendMessageInternal(jid, content, options));
1114
- }
1081
+ ...interactiveSocket,
1082
+ sendMessage
1115
1083
  };
1116
1084
  };
1117
- exports.makeMessagesSocket = makeMessagesSocket;
1085
+ exports.makeMessagesSocket = makeMessagesSocket;