@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.
- package/README.MD +1062 -282
- package/WAProto/WAProto.proto +1073 -244
- package/WAProto/index.d.ts +16282 -8183
- package/WAProto/index.js +76605 -50628
- package/engine-requirements.js +10 -10
- package/lib/Defaults/baileys-version.json +1 -1
- package/lib/Defaults/index.d.ts +4 -2
- package/lib/Defaults/index.js +8 -6
- package/lib/Signal/Group/ciphertext-message.d.ts +1 -1
- package/lib/Signal/Group/ciphertext-message.js +1 -1
- package/lib/Signal/Group/sender-message-key.d.ts +1 -1
- package/lib/Signal/Group/sender-message-key.js +1 -1
- package/lib/Signal/libsignal.d.ts +1 -1
- package/lib/Socket/business.d.ts +1 -1
- package/lib/Socket/business.js +1 -1
- package/lib/Socket/chats.d.ts +4 -1
- package/lib/Socket/chats.js +213 -36
- package/lib/Socket/groups.js +87 -15
- package/lib/Socket/index.js +9 -0
- package/lib/Socket/messages-interactive.js +259 -0
- package/lib/Socket/messages-recv.js +1473 -1228
- package/lib/Socket/messages-send.js +437 -469
- package/lib/Socket/socket.js +143 -26
- package/lib/Socket/usync.js +57 -4
- package/lib/Store/make-in-memory-store.js +28 -15
- package/lib/Types/Auth.d.ts +4 -0
- package/lib/Types/Message.d.ts +316 -6
- package/lib/Types/Message.js +1 -1
- package/lib/Types/Socket.d.ts +2 -0
- package/lib/Utils/cache-manager.d.ts +16 -0
- package/lib/Utils/cache-manager.js +22 -5
- package/lib/Utils/chat-utils.js +17 -13
- package/lib/Utils/decode-wa-message.js +1 -11
- package/lib/Utils/event-buffer.js +103 -2
- package/lib/Utils/generics.js +5 -6
- package/lib/Utils/index.d.ts +5 -0
- package/lib/Utils/index.js +3 -0
- package/lib/Utils/jid-validation.d.ts +2 -0
- package/lib/Utils/jid-validation.js +43 -10
- package/lib/Utils/link-preview.js +38 -28
- package/lib/Utils/messages-media.d.ts +1 -1
- package/lib/Utils/messages-media.js +22 -53
- package/lib/Utils/messages.js +653 -65
- package/lib/Utils/performance-config.d.ts +2 -0
- package/lib/Utils/performance-config.js +16 -7
- package/lib/Utils/process-message.js +124 -12
- package/lib/Utils/rate-limiter.js +15 -20
- package/lib/WABinary/generic-utils.js +5 -1
- package/lib/WABinary/jid-utils.d.ts +1 -0
- package/lib/WABinary/jid-utils.js +265 -5
- package/lib/WAUSync/Protocols/USyncContactProtocol.js +75 -5
- package/lib/WAUSync/Protocols/USyncDeviceProtocol.js +59 -6
- package/lib/WAUSync/USyncQuery.js +64 -6
- package/lib/index.d.ts +1 -0
- package/lib/index.js +5 -4
- package/package.json +10 -15
- 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
|
-
|
|
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
|
|
152
|
-
.
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
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
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
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
|
-
|
|
167
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
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
|
-
|
|
211
|
-
|
|
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
|
|
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:
|
|
553
|
-
baseMs:
|
|
554
|
-
maxMs:
|
|
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
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
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
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
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
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
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
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
},
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
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
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
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
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
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,
|
|
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
|
|
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
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
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
|
-
|
|
887
|
-
|
|
888
|
-
|
|
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 = '
|
|
1029
|
+
else if (isEditMsg) {
|
|
1030
|
+
additionalAttributes.edit = (0, WABinary_1.isJidNewsletter)(jid) ? '3' : '1';
|
|
1031
|
+
// required for pin message
|
|
936
1032
|
}
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
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
|
-
|
|
1011
|
-
|
|
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;
|