@mtkruto/node 0.0.835 → 0.0.900

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 (65) hide show
  1. package/esm/client/client.d.ts +23 -3
  2. package/esm/client/client.js +495 -75
  3. package/esm/constants.d.ts +2 -0
  4. package/esm/constants.js +2 -0
  5. package/esm/deps/deno.land/std@0.190.0/encoding/base64.d.ts +11 -0
  6. package/esm/deps/deno.land/std@0.190.0/encoding/base64.js +140 -0
  7. package/esm/deps/deno.land/x/q@v0.0.1/mod.d.ts +6 -0
  8. package/esm/deps/deno.land/x/q@v0.0.1/mod.js +71 -0
  9. package/esm/deps.d.ts +2 -0
  10. package/esm/deps.js +2 -0
  11. package/esm/mod.d.ts +3 -3
  12. package/esm/mod.js +3 -3
  13. package/esm/storage/storage.d.ts +18 -0
  14. package/esm/storage/storage.js +103 -0
  15. package/esm/tl/1_tl_object.d.ts +0 -1
  16. package/esm/tl/1_tl_object.js +1 -1
  17. package/esm/tl/4_tl_writer.d.ts +5 -0
  18. package/esm/tl/5_rpc_result.d.ts +9 -0
  19. package/esm/tl/6_message.d.ts +10 -0
  20. package/esm/tl/{5_message.js → 6_message.js} +2 -2
  21. package/esm/tl/{6_message_container.d.ts → 7_message_container.d.ts} +1 -1
  22. package/esm/tl/{6_message_container.js → 7_message_container.js} +2 -2
  23. package/esm/types/3_message.d.ts +5 -1
  24. package/esm/types/3_message.js +26 -22
  25. package/esm/utilities/1_message.d.ts +2 -2
  26. package/esm/utilities/1_message.js +3 -3
  27. package/esm/utilities/1_password.js +1 -1
  28. package/package.json +1 -1
  29. package/script/client/client.d.ts +23 -3
  30. package/script/client/client.js +495 -75
  31. package/script/constants.d.ts +2 -0
  32. package/script/constants.js +3 -1
  33. package/script/deps/deno.land/std@0.190.0/encoding/base64.d.ts +11 -0
  34. package/script/deps/deno.land/std@0.190.0/encoding/base64.js +145 -0
  35. package/script/deps/deno.land/x/q@v0.0.1/mod.d.ts +6 -0
  36. package/script/deps/deno.land/x/q@v0.0.1/mod.js +75 -0
  37. package/script/deps.d.ts +2 -0
  38. package/script/deps.js +6 -1
  39. package/script/mod.d.ts +3 -3
  40. package/script/mod.js +3 -3
  41. package/script/storage/storage.d.ts +18 -0
  42. package/script/storage/storage.js +126 -0
  43. package/script/tl/1_tl_object.d.ts +0 -1
  44. package/script/tl/1_tl_object.js +1 -1
  45. package/script/tl/4_tl_writer.d.ts +5 -0
  46. package/script/tl/5_rpc_result.d.ts +9 -0
  47. package/script/tl/6_message.d.ts +10 -0
  48. package/script/tl/{5_message.js → 6_message.js} +6 -6
  49. package/script/tl/{6_message_container.d.ts → 7_message_container.d.ts} +1 -1
  50. package/script/tl/{6_message_container.js → 7_message_container.js} +4 -4
  51. package/script/types/3_message.d.ts +5 -1
  52. package/script/types/3_message.js +26 -22
  53. package/script/utilities/1_message.d.ts +2 -2
  54. package/script/utilities/1_message.js +9 -9
  55. package/script/utilities/1_password.js +1 -1
  56. package/esm/tl/3_tl_writer.d.ts +0 -5
  57. package/esm/tl/4_rpc_result.d.ts +0 -8
  58. package/esm/tl/5_message.d.ts +0 -11
  59. package/script/tl/3_tl_writer.d.ts +0 -5
  60. package/script/tl/4_rpc_result.d.ts +0 -8
  61. package/script/tl/5_message.d.ts +0 -11
  62. /package/esm/tl/{3_tl_writer.js → 4_tl_writer.js} +0 -0
  63. /package/esm/tl/{4_rpc_result.js → 5_rpc_result.js} +0 -0
  64. /package/script/tl/{3_tl_writer.js → 4_tl_writer.js} +0 -0
  65. /package/script/tl/{4_rpc_result.js → 5_rpc_result.js} +0 -0
@@ -23,7 +23,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
23
23
  return result;
24
24
  };
25
25
  Object.defineProperty(exports, "__esModule", { value: true });
26
- exports.Client = exports.ParseMode = exports.restartAuth = void 0;
26
+ exports.Client = exports.ParseMode = exports.restartAuth = exports.getEntity = void 0;
27
27
  const deps_js_1 = require("../deps.js");
28
28
  const constants_js_1 = require("../constants.js");
29
29
  const _0_bigint_js_1 = require("../utilities/0_bigint.js");
@@ -36,9 +36,9 @@ const _1_tl_object_js_1 = require("../tl/1_tl_object.js");
36
36
  const types = __importStar(require("../tl/2_types.js"));
37
37
  const functions = __importStar(require("../tl/3_functions.js"));
38
38
  const _3_tl_reader_js_1 = require("../tl/3_tl_reader.js");
39
- const _4_rpc_result_js_1 = require("../tl/4_rpc_result.js");
40
- const _5_message_js_1 = require("../tl/5_message.js");
41
- const _6_message_container_js_1 = require("../tl/6_message_container.js");
39
+ const _5_rpc_result_js_1 = require("../tl/5_rpc_result.js");
40
+ const _6_message_js_1 = require("../tl/6_message.js"); // MTProto API message
41
+ const _7_message_container_js_1 = require("../tl/7_message_container.js");
42
42
  const client_abstract_js_1 = require("./client_abstract.js");
43
43
  const client_plain_js_1 = require("./client_plain.js");
44
44
  const storage_memory_js_1 = require("../storage/storage_memory.js");
@@ -47,8 +47,12 @@ const _0_reply_keyboard_remove_js_1 = require("../types/0_reply_keyboard_remove.
47
47
  const _0_force_reply_js_1 = require("../types/0_force_reply.js");
48
48
  const _2_reply_keyboard_markup_js_1 = require("../types/2_reply_keyboard_markup.js");
49
49
  const _2_inline_keyboard_markup_js_1 = require("../types/2_inline_keyboard_markup.js");
50
- const _3_message_js_1 = require("../types/3_message.js");
50
+ const _3_message_js_1 = require("../types/3_message.js"); // high-level wrapper for Telegram API's message
51
51
  const d = (0, deps_js_1.debug)("client");
52
+ const dRecoverUpdateGap = (0, deps_js_1.debug)("client_recoverUpdateGap");
53
+ const dRecoverChannelUpdateGap = (0, deps_js_1.debug)("client_recoverChannelUpdateGap");
54
+ const UPDATE_GAP = Symbol();
55
+ exports.getEntity = Symbol();
52
56
  exports.restartAuth = Symbol();
53
57
  var ParseMode;
54
58
  (function (ParseMode) {
@@ -114,7 +118,13 @@ class Client extends client_abstract_js_1.ClientAbstract {
114
118
  writable: true,
115
119
  value: new Set()
116
120
  });
117
- Object.defineProperty(this, "updatesHandler", {
121
+ Object.defineProperty(this, "updateState", {
122
+ enumerable: true,
123
+ configurable: true,
124
+ writable: true,
125
+ value: void 0
126
+ });
127
+ Object.defineProperty(this, "updateHandler", {
118
128
  enumerable: true,
119
129
  configurable: true,
120
130
  writable: true,
@@ -168,6 +178,79 @@ class Client extends client_abstract_js_1.ClientAbstract {
168
178
  writable: true,
169
179
  value: false
170
180
  });
181
+ Object.defineProperty(this, "messageProcessQueue", {
182
+ enumerable: true,
183
+ configurable: true,
184
+ writable: true,
185
+ value: (0, deps_js_1.queue)(async (message) => {
186
+ let body = message.body;
187
+ if (body instanceof types.GZIPPacked) {
188
+ body = new _3_tl_reader_js_1.TLReader((0, deps_js_1.gunzip)(body.packedData)).readObject();
189
+ }
190
+ d("received %s", body.constructor.name);
191
+ if (body instanceof types.Updates || body instanceof types.TypeUpdate) {
192
+ await this.processUpdates(body);
193
+ }
194
+ else if (message.body instanceof _5_rpc_result_js_1.RPCResult) {
195
+ let result = message.body.result;
196
+ if (result instanceof types.GZIPPacked) {
197
+ result = new _3_tl_reader_js_1.TLReader((0, deps_js_1.gunzip)(result.packedData)).readObject();
198
+ }
199
+ if (result instanceof types.RPCError) {
200
+ d("RPCResult: %d %s", result.errorCode, result.errorMessage);
201
+ }
202
+ else {
203
+ d("RPCResult: %s", result.constructor.name);
204
+ }
205
+ if (result instanceof types.Updates || result instanceof types.TypeUpdate) {
206
+ await this.processUpdates(result);
207
+ }
208
+ else {
209
+ await this.processResult(result);
210
+ }
211
+ const promise = this.promises.get(message.body.messageId);
212
+ if (promise) {
213
+ if (result instanceof types.RPCError) {
214
+ promise.reject(result);
215
+ }
216
+ else {
217
+ promise.resolve(result);
218
+ }
219
+ this.promises.delete(message.body.messageId);
220
+ }
221
+ }
222
+ else if (message.body instanceof types.Pong) {
223
+ const promise = this.promises.get(message.body.msgId);
224
+ if (promise) {
225
+ promise.resolve(message.body);
226
+ this.promises.delete(message.body.msgId);
227
+ }
228
+ }
229
+ else if (message.body instanceof types.BadMsgNotification || message.body instanceof types.BadServerSalt) {
230
+ if (message.body instanceof types.BadServerSalt) {
231
+ this.state.salt = message.body.newServerSalt;
232
+ }
233
+ const promise = this.promises.get(message.body.badMsgId);
234
+ if (promise) {
235
+ promise.resolve(message.body);
236
+ this.promises.delete(message.body.badMsgId);
237
+ }
238
+ }
239
+ this.toAcknowledge.add(message.id);
240
+ }, 2)
241
+ });
242
+ Object.defineProperty(this, "updateApplicationMutex", {
243
+ enumerable: true,
244
+ configurable: true,
245
+ writable: true,
246
+ value: new deps_js_1.Mutex()
247
+ });
248
+ Object.defineProperty(this, "updateGapRecoveryMutex", {
249
+ enumerable: true,
250
+ configurable: true,
251
+ writable: true,
252
+ value: new deps_js_1.Mutex()
253
+ });
171
254
  this.parseMode = params?.parseMode ?? ParseMode.None;
172
255
  this.appVersion = params?.appVersion ?? constants_js_1.DEFAULT_APP_VERSION;
173
256
  this.deviceModel = params?.deviceModel ?? constants_js_1.DEFAULT_DEVICE_MODEL;
@@ -237,6 +320,11 @@ class Client extends client_abstract_js_1.ClientAbstract {
237
320
  this.receiveLoop();
238
321
  this.pingLoop();
239
322
  }
323
+ async fetchState(source) {
324
+ const state = await this.invoke(new functions.UpdatesGetState());
325
+ this.updateState = state;
326
+ d("state fetched [%s]", source);
327
+ }
240
328
  /**
241
329
  * Calls [initConnection](1) and authorizes the client with one of the following:
242
330
  *
@@ -286,6 +374,7 @@ class Client extends client_abstract_js_1.ClientAbstract {
286
374
  const password = typeof params.password === "string" ? params.password : await params.password();
287
375
  const input = await (0, _1_password_js_1.checkPassword)(password, ap);
288
376
  await this.invoke(new functions.AuthCheckPassword({ password: input }));
377
+ await this.storage.setAccountType("user");
289
378
  d("authorized as user");
290
379
  break;
291
380
  }
@@ -308,7 +397,7 @@ class Client extends client_abstract_js_1.ClientAbstract {
308
397
  }
309
398
  };
310
399
  try {
311
- await this.invoke(new functions.UpdatesGetState());
400
+ await this.fetchState("authorize");
312
401
  d("already authorized");
313
402
  return;
314
403
  }
@@ -349,6 +438,7 @@ class Client extends client_abstract_js_1.ClientAbstract {
349
438
  }
350
439
  else {
351
440
  signedIn = true;
441
+ await this.storage.setAccountType("user");
352
442
  d("authorized as user");
353
443
  break;
354
444
  }
@@ -383,6 +473,7 @@ class Client extends client_abstract_js_1.ClientAbstract {
383
473
  }
384
474
  else {
385
475
  await this.invoke(new functions.AuthImportBotAuthorization({ apiId: this.apiId, apiHash: this.apiHash, botAuthToken: params, flags: 0 }));
476
+ await this.storage.setAccountType("bot");
386
477
  d("authorized as bot");
387
478
  }
388
479
  }
@@ -410,6 +501,14 @@ class Client extends client_abstract_js_1.ClientAbstract {
410
501
  throw err;
411
502
  }
412
503
  }
504
+ finally {
505
+ try {
506
+ await this.fetchState("authorize");
507
+ }
508
+ catch (_err) {
509
+ //
510
+ }
511
+ }
413
512
  }
414
513
  async receiveLoop() {
415
514
  if (!this.auth) {
@@ -440,60 +539,9 @@ class Client extends client_abstract_js_1.ClientAbstract {
440
539
  d("failed to decrypt message: %o", err);
441
540
  continue;
442
541
  }
443
- const messages = decrypted instanceof _6_message_container_js_1.MessageContainer ? decrypted.messages : [decrypted];
542
+ const messages = decrypted instanceof _7_message_container_js_1.MessageContainer ? decrypted.messages : [decrypted];
444
543
  for (const message of messages) {
445
- let body = message.body;
446
- if (body instanceof types.GZIPPacked) {
447
- body = new _3_tl_reader_js_1.TLReader((0, deps_js_1.gunzip)(body.packedData)).readObject();
448
- }
449
- d("received %s", body.constructor.name);
450
- if (body instanceof types.Updates) {
451
- this.processUpdates(body);
452
- }
453
- else if (message.body instanceof _4_rpc_result_js_1.RPCResult) {
454
- let result = message.body.result;
455
- if (result instanceof types.GZIPPacked) {
456
- result = new _3_tl_reader_js_1.TLReader((0, deps_js_1.gunzip)(result.packedData)).readObject();
457
- }
458
- if (result instanceof types.RPCError) {
459
- d("RPCResult: %d %s", result.errorCode, result.errorMessage);
460
- }
461
- else {
462
- d("RPCResult: %s", result.constructor.name);
463
- }
464
- const promise = this.promises.get(message.body.messageId);
465
- if (promise) {
466
- if (result instanceof types.RPCError) {
467
- promise.reject(result);
468
- }
469
- else {
470
- if (result instanceof types.Updates) {
471
- await this.processChats(result.chats);
472
- await this.processUsers(result.users);
473
- }
474
- promise.resolve(result);
475
- }
476
- this.promises.delete(message.body.messageId);
477
- }
478
- }
479
- else if (message.body instanceof types.Pong) {
480
- const promise = this.promises.get(message.body.msgId);
481
- if (promise) {
482
- promise.resolve(message.body);
483
- this.promises.delete(message.body.msgId);
484
- }
485
- }
486
- else if (message.body instanceof types.BadMsgNotification || message.body instanceof types.BadServerSalt) {
487
- if (message.body instanceof types.BadServerSalt) {
488
- this.state.salt = message.body.newServerSalt;
489
- }
490
- const promise = this.promises.get(message.body.badMsgId);
491
- if (promise) {
492
- promise.resolve(message.body);
493
- this.promises.delete(message.body.badMsgId);
494
- }
495
- }
496
- this.toAcknowledge.add(message.id);
544
+ this.messageProcessQueue.push(message);
497
545
  }
498
546
  }
499
547
  }
@@ -517,7 +565,7 @@ class Client extends client_abstract_js_1.ClientAbstract {
517
565
  seqNo++;
518
566
  this.state.seqNo++;
519
567
  }
520
- const message = new _5_message_js_1.Message((0, _1_message_js_1.getMessageId)(), seqNo, function_);
568
+ const message = new _6_message_js_1.Message((0, _1_message_js_1.getMessageId)(), seqNo, function_);
521
569
  await this.transport.send(await (0, _1_message_js_1.encryptMessage)(message, this.auth.key, this.auth.id, this.state.salt, this.sessionId));
522
570
  d("invoked %s", function_.constructor.name);
523
571
  if (noWait) {
@@ -542,6 +590,7 @@ class Client extends client_abstract_js_1.ClientAbstract {
542
590
  async processChats(chats) {
543
591
  for (const chat of chats) {
544
592
  if (chat instanceof types.Channel && chat.accessHash) {
593
+ await this.storage.setEntity(chat);
545
594
  await this.storage.setChannelAccessHash(chat.id, chat.accessHash);
546
595
  if (chat.username) {
547
596
  await this.storage.updateUsernames("channel", chat.id, [chat.username]);
@@ -550,11 +599,15 @@ class Client extends client_abstract_js_1.ClientAbstract {
550
599
  await this.storage.updateUsernames("channel", chat.id, chat.usernames.map((v) => v[_1_tl_object_js_1.as](types.Username)).map((v) => v.username));
551
600
  }
552
601
  }
602
+ else if (chat instanceof types.Chat) {
603
+ await this.storage.setEntity(chat);
604
+ }
553
605
  }
554
606
  }
555
607
  async processUsers(users) {
556
608
  for (const user of users) {
557
609
  if (user instanceof types.User && user.accessHash) {
610
+ await this.storage.setEntity(user);
558
611
  await this.storage.setUserAccessHash(user.id, user.accessHash);
559
612
  if (user.username) {
560
613
  await this.storage.updateUsernames("user", user.id, [user.username]);
@@ -565,19 +618,310 @@ class Client extends client_abstract_js_1.ClientAbstract {
565
618
  }
566
619
  }
567
620
  }
621
+ async applyUpdateNoGap(update, usePts = true) {
622
+ const release = await this.updateApplicationMutex.acquire();
623
+ try {
624
+ if ((update instanceof types.UpdateNewMessage) ||
625
+ (update instanceof types.UpdateDeleteMessages) ||
626
+ (update instanceof types.UpdateReadHistoryInbox) ||
627
+ (update instanceof types.UpdateReadHistoryOutbox) ||
628
+ (update instanceof types.UpdateWebPage) ||
629
+ (update instanceof types.UpdateReadMessagesContents) ||
630
+ (update instanceof types.UpdateEditMessage) ||
631
+ (update instanceof types.UpdateFolderPeers) ||
632
+ (update instanceof types.UpdatePinnedMessages) ||
633
+ (update instanceof types.UpdatePinnedChannelMessages) ||
634
+ (update instanceof types.UpdateShortMessage) ||
635
+ (update instanceof types.UpdateShortChatMessage) ||
636
+ (update instanceof types.UpdateShortSentMessage)) {
637
+ const localState = await this.getLocalState();
638
+ if (localState.pts + update.ptsCount > update.pts) {
639
+ // the update is already applied
640
+ return;
641
+ }
642
+ else if (localState.pts + update.ptsCount < update.pts) {
643
+ // there is an update gap that needs to be filled
644
+ throw UPDATE_GAP;
645
+ }
646
+ localState.pts = update.pts;
647
+ d("applied update with pts %d", update.pts);
648
+ await this.storage.setState(localState);
649
+ }
650
+ else if (usePts &&
651
+ ((update instanceof types.UpdateNewChannelMessage) ||
652
+ (update instanceof types.UpdateDeleteChannelMessages) ||
653
+ (update instanceof types.UpdateEditChannelMessage) ||
654
+ (update instanceof types.UpdateChannelWebPage))) {
655
+ const channelId = update instanceof types.UpdateNewChannelMessage || update instanceof types.UpdateEditChannelMessage ? update.message[_1_tl_object_js_1.as](types.Message).peerId[_1_tl_object_js_1.as](types.PeerChannel).channelId : update.channelId;
656
+ let localPts = await this.storage.getChannelPts(channelId);
657
+ if (!localPts) {
658
+ localPts = update.pts - update.ptsCount;
659
+ }
660
+ if (localPts + update.ptsCount > update.pts) {
661
+ // already applied
662
+ return;
663
+ }
664
+ else if (localPts + update.ptsCount < update.pts) {
665
+ // should call channelGetDifference
666
+ throw UPDATE_GAP;
667
+ }
668
+ d("applied update with pts %d", update.pts);
669
+ await this.storage.setChannelPts(channelId, update.pts);
670
+ }
671
+ // apply update (call listeners)
672
+ this.updateHandler?.(this, update);
673
+ }
674
+ finally {
675
+ release();
676
+ }
677
+ }
678
+ async applyUpdate(update) {
679
+ if (update instanceof types.TypeUpdates &&
680
+ !(update instanceof types.UpdateShortMessage) &&
681
+ !(update instanceof types.UpdateShortChatMessage) &&
682
+ !(update instanceof types.UpdateShortSentMessage)) {
683
+ // other constructors inheriting Updates are not applicable
684
+ (0, _0_control_js_1.UNREACHABLE)();
685
+ }
686
+ if (update instanceof types.TypeUpdate && update instanceof types.UpdateChannelTooLong) {
687
+ // updateChannelTooLong is not applicable
688
+ (0, _0_control_js_1.UNREACHABLE)();
689
+ }
690
+ // can't apply updates when filling gap
691
+ const release = await this.updateGapRecoveryMutex.acquire();
692
+ try {
693
+ await this.applyUpdateNoGap(update);
694
+ release();
695
+ }
696
+ catch (err) {
697
+ release();
698
+ if (err == UPDATE_GAP) {
699
+ if ((update instanceof types.UpdateNewChannelMessage) ||
700
+ (update instanceof types.UpdateDeleteChannelMessages) ||
701
+ (update instanceof types.UpdateEditChannelMessage) ||
702
+ (update instanceof types.UpdateChannelWebPage)) {
703
+ const channelId = update instanceof types.UpdateNewChannelMessage || update instanceof types.UpdateEditChannelMessage ? update.message[_1_tl_object_js_1.as](types.Message).peerId[_1_tl_object_js_1.as](types.PeerChannel).channelId : update.channelId;
704
+ await this.recoverChannelUpdateGap(channelId, "applyUpdate");
705
+ }
706
+ else if ((update instanceof types.UpdateNewMessage) ||
707
+ (update instanceof types.UpdateDeleteMessages) ||
708
+ (update instanceof types.UpdateReadHistoryInbox) ||
709
+ (update instanceof types.UpdateReadHistoryOutbox) ||
710
+ (update instanceof types.UpdateWebPage) ||
711
+ (update instanceof types.UpdateReadMessagesContents) ||
712
+ (update instanceof types.UpdateEditMessage) ||
713
+ (update instanceof types.UpdateFolderPeers) ||
714
+ (update instanceof types.UpdatePinnedMessages) ||
715
+ (update instanceof types.UpdatePinnedChannelMessages) ||
716
+ (update instanceof types.UpdateShortMessage) ||
717
+ (update instanceof types.UpdateShortChatMessage) ||
718
+ (update instanceof types.UpdateShortSentMessage)) {
719
+ await this.recoverUpdateGap("applyUpdate");
720
+ }
721
+ else {
722
+ // can't detect update gap from other types of updates
723
+ (0, _0_control_js_1.UNREACHABLE)();
724
+ }
725
+ // just for integrity
726
+ const release = await this.updateGapRecoveryMutex.acquire();
727
+ try {
728
+ await this.applyUpdateNoGap(update);
729
+ }
730
+ catch (err) {
731
+ if (err == UPDATE_GAP) {
732
+ // the gap must have been filled until now
733
+ (0, _0_control_js_1.UNREACHABLE)();
734
+ }
735
+ else {
736
+ throw err;
737
+ }
738
+ }
739
+ finally {
740
+ release();
741
+ }
742
+ }
743
+ else {
744
+ throw err;
745
+ }
746
+ }
747
+ }
568
748
  async processUpdates(updates) {
569
749
  try {
570
- await this.processChats(updates.chats);
571
- await this.processUsers(updates.users);
572
- for (const update of updates.updates) {
573
- if (update instanceof types.UpdateUserName) {
574
- await this.storage.updateUsernames("user", update.userId, update.usernames.map((v) => v[_1_tl_object_js_1.as](types.Username)).map((v) => v.username));
750
+ if (updates instanceof types.TypeUpdates) {
751
+ if (updates instanceof types.Updates) {
752
+ await this.processChats(updates.chats);
753
+ await this.processUsers(updates.users);
754
+ await this.setUpdateStateDate(updates.date);
755
+ for (const update of updates.updates) {
756
+ await this.processUpdates(update);
757
+ }
758
+ }
759
+ else if (updates instanceof types.UpdateShortMessage ||
760
+ updates instanceof types.UpdateShortChatMessage ||
761
+ updates instanceof types.UpdateShortSentMessage) {
762
+ await this.setUpdateStateDate(updates.date);
763
+ await this.applyUpdate(updates);
764
+ }
765
+ else if (updates instanceof types.UpdatesTooLong) {
766
+ await this.recoverUpdateGap("updatesTooLong");
767
+ }
768
+ else if (updates instanceof types.UpdatesCombined) {
769
+ await this.setUpdateStateDate(updates.date);
770
+ await this.processChats(updates.chats);
771
+ await this.processUsers(updates.users);
772
+ for (const update of updates.updates) {
773
+ await this.processUpdates(update);
774
+ }
575
775
  }
576
776
  }
577
- await this.updatesHandler?.(this, updates);
777
+ else if (updates instanceof types.TypeUpdate && updates instanceof types.UpdateChannelTooLong) {
778
+ if (updates.pts != undefined) {
779
+ await this.storage.setChannelPts(updates.channelId, updates.pts);
780
+ }
781
+ await this.recoverChannelUpdateGap(updates.channelId, "updateChannelTooLong");
782
+ }
783
+ else {
784
+ if (updates instanceof types.UpdateUserName) {
785
+ await this.storage.updateUsernames("user", updates.userId, updates.usernames.map((v) => v[_1_tl_object_js_1.as](types.Username)).map((v) => v.username));
786
+ }
787
+ else if (updates instanceof types.UpdatePtsChanged) {
788
+ await this.fetchState("updatePtsChanged");
789
+ if (this.updateState) {
790
+ await this.storage.setState(this.updateState);
791
+ }
792
+ else {
793
+ (0, _0_control_js_1.UNREACHABLE)();
794
+ }
795
+ }
796
+ await this.applyUpdate(updates);
797
+ }
578
798
  }
579
799
  catch (err) {
580
- console.error("Error processing updates:", err);
800
+ d("error processing updates: %O", err);
801
+ }
802
+ }
803
+ async setUpdateStateDate(date) {
804
+ const release = await this.updateApplicationMutex.acquire();
805
+ try {
806
+ const localState = await this.getLocalState();
807
+ localState.date = date;
808
+ await this.storage.setState(localState);
809
+ }
810
+ finally {
811
+ release();
812
+ }
813
+ }
814
+ async getLocalState() {
815
+ let localState = await this.storage.getState();
816
+ if (!localState) {
817
+ if (this.updateState) {
818
+ localState = this.updateState;
819
+ await this.storage.setState(localState);
820
+ }
821
+ else {
822
+ (0, _0_control_js_1.UNREACHABLE)();
823
+ }
824
+ }
825
+ return localState;
826
+ }
827
+ async recoverUpdateGap(source) {
828
+ dRecoverUpdateGap("recovering from update gap [%s]", source);
829
+ const release = await this.updateGapRecoveryMutex.acquire();
830
+ try {
831
+ let state = await this.getLocalState();
832
+ while (true) {
833
+ const difference = await this.invoke(new functions.UpdatesGetDifference({ pts: state.pts, date: state.date, qts: state.qts }));
834
+ if (difference instanceof types.UpdatesDifference || difference instanceof types.UpdatesDifferenceSlice) {
835
+ await this.processChats(difference.chats);
836
+ await this.processUsers(difference.users);
837
+ for (const message of difference.newMessages) {
838
+ await this.applyUpdateNoGap(new types.UpdateNewMessage({ message, pts: 0, ptsCount: 0 }));
839
+ }
840
+ for (const update of difference.otherUpdates) {
841
+ await this.applyUpdateNoGap(update);
842
+ }
843
+ if (difference instanceof types.UpdatesDifference) {
844
+ dRecoverUpdateGap("recovered from update gap");
845
+ break;
846
+ }
847
+ else if (difference instanceof types.UpdatesDifferenceSlice) {
848
+ state = difference.intermediateState[_1_tl_object_js_1.as](types.UpdatesState);
849
+ }
850
+ else {
851
+ (0, _0_control_js_1.UNREACHABLE)();
852
+ }
853
+ }
854
+ else if (difference instanceof types.UpdatesDifferenceTooLong) {
855
+ // stored messages should be invalidated in case we store messages in the future
856
+ state.pts = difference.pts;
857
+ dRecoverUpdateGap("received differenceTooLong");
858
+ }
859
+ else if (difference instanceof types.UpdatesDifferenceEmpty) {
860
+ await this.setUpdateStateDate(difference.date);
861
+ dRecoverUpdateGap("there was no update gap");
862
+ break;
863
+ }
864
+ else {
865
+ (0, _0_control_js_1.UNREACHABLE)();
866
+ }
867
+ }
868
+ }
869
+ finally {
870
+ release();
871
+ }
872
+ }
873
+ async recoverChannelUpdateGap(channelId, source) {
874
+ dRecoverChannelUpdateGap("recovering channel update gap [%o, %s]", channelId, source);
875
+ const release = await this.updateGapRecoveryMutex.acquire();
876
+ try {
877
+ const pts_ = await this.storage.getChannelPts(channelId);
878
+ let pts = pts_ == null ? 1 : pts_;
879
+ while (true) {
880
+ const { accessHash } = await this.getInputPeer(constants_js_1.ZERO_CHANNEL_ID + -Number(channelId)).then((v) => v[_1_tl_object_js_1.as](types.InputPeerChannel));
881
+ const difference = await this.invoke(new functions.UpdatesGetChannelDifference({
882
+ pts,
883
+ channel: new types.InputChannel({ channelId, accessHash: accessHash }),
884
+ filter: new types.ChannelMessagesFilterEmpty(),
885
+ limit: await this.storage.getAccountType() == "user" ? constants_js_1.CHANNEL_DIFFERENCE_LIMIT_USER : constants_js_1.CHANNEL_DIFFERENCE_LIMIT_BOT,
886
+ }));
887
+ if (difference instanceof types.UpdatesChannelDifference) {
888
+ await this.processChats(difference.chats);
889
+ await this.processUsers(difference.users);
890
+ for (const message of difference.newMessages) {
891
+ await this.applyUpdateNoGap(new types.UpdateNewChannelMessage({ message, pts: 0, ptsCount: 0 }), false);
892
+ }
893
+ for (const update of difference.otherUpdates) {
894
+ await this.applyUpdateNoGap(update, false);
895
+ }
896
+ await this.storage.setChannelPts(channelId, difference.pts);
897
+ dRecoverChannelUpdateGap("recovered from update gap");
898
+ break;
899
+ }
900
+ else if (difference instanceof types.UpdatesChannelDifferenceTooLong) {
901
+ // invalidate messages
902
+ dRecoverChannelUpdateGap("received channelDifferenceTooLong");
903
+ await this.processChats(difference.chats);
904
+ await this.processUsers(difference.users);
905
+ for (const message of difference.messages) {
906
+ await this.applyUpdateNoGap(new types.UpdateNewChannelMessage({ message, pts: 0, ptsCount: 0 }), false);
907
+ }
908
+ const pts_ = difference.dialog[_1_tl_object_js_1.as](types.Dialog).pts;
909
+ if (pts_ != undefined) {
910
+ pts = pts_;
911
+ }
912
+ else {
913
+ (0, _0_control_js_1.UNREACHABLE)();
914
+ }
915
+ dRecoverChannelUpdateGap("processed channelDifferenceTooLong");
916
+ }
917
+ else if (difference instanceof types.UpdatesChannelDifferenceEmpty) {
918
+ dRecoverChannelUpdateGap("there was no update gap");
919
+ break;
920
+ }
921
+ }
922
+ }
923
+ finally {
924
+ release();
581
925
  }
582
926
  }
583
927
  async getInputPeer(id) {
@@ -646,6 +990,50 @@ class Client extends client_abstract_js_1.ClientAbstract {
646
990
  throw new Error("ID format unknown or not implemented");
647
991
  }
648
992
  }
993
+ [exports.getEntity](peer) {
994
+ const type = peer instanceof types.PeerUser ? "user" : peer instanceof types.PeerChat ? "chat" : peer instanceof types.PeerChannel ? "channel" : (0, _0_control_js_1.UNREACHABLE)();
995
+ const id = peer instanceof types.PeerUser ? peer.userId : peer instanceof types.PeerChat ? peer.chatId : peer instanceof types.PeerChannel ? peer.channelId : (0, _0_control_js_1.UNREACHABLE)();
996
+ return this.storage.getEntity(type, id);
997
+ }
998
+ async processResult(result) {
999
+ if (result instanceof types.MessagesDialogs ||
1000
+ result instanceof types.MessagesDialogsSlice ||
1001
+ result instanceof types.MessagesMessages ||
1002
+ result instanceof types.MessagesMessagesSlice ||
1003
+ result instanceof types.MessagesChannelMessages ||
1004
+ result instanceof types.MessagesChatFull ||
1005
+ result instanceof types.ContactsFound ||
1006
+ result instanceof types.AccountPrivacyRules ||
1007
+ result instanceof types.ContactsResolvedPeer ||
1008
+ result instanceof types.ChannelsChannelParticipants ||
1009
+ result instanceof types.ChannelsChannelParticipant ||
1010
+ result instanceof types.MessagesPeerDialogs ||
1011
+ result instanceof types.ContactsTopPeers ||
1012
+ result instanceof types.ChannelsAdminLogResults ||
1013
+ result instanceof types.HelpRecentMeURLs ||
1014
+ result instanceof types.MessagesInactiveChats ||
1015
+ result instanceof types.HelpPromoData ||
1016
+ result instanceof types.MessagesMessageViews ||
1017
+ result instanceof types.MessagesDiscussionMessage ||
1018
+ result instanceof types.PhoneGroupCall ||
1019
+ result instanceof types.PhoneGroupParticipants ||
1020
+ result instanceof types.PhoneJoinAsPeers ||
1021
+ result instanceof types.MessagesSponsoredMessages ||
1022
+ result instanceof types.MessagesSearchResultsCalendar ||
1023
+ result instanceof types.ChannelsSendAsPeers ||
1024
+ result instanceof types.UsersUserFull ||
1025
+ result instanceof types.MessagesPeerSettings ||
1026
+ result instanceof types.MessagesMessageReactionsList ||
1027
+ result instanceof types.MessagesForumTopics ||
1028
+ result instanceof types.AccountAutoSaveSettings ||
1029
+ result instanceof types.ChatlistsExportedInvites ||
1030
+ result instanceof types.ChatlistsChatlistInviteAlready ||
1031
+ result instanceof types.ChatlistsChatlistInvite ||
1032
+ result instanceof types.ChatlistsChatlistUpdates) {
1033
+ await this.processChats(result.chats);
1034
+ await this.processUsers(result.users);
1035
+ }
1036
+ }
649
1037
  async sendMessage(chatId, text, params) {
650
1038
  const entities_ = params?.entities ?? [];
651
1039
  const parseMode = params?.parseMode ?? this.parseMode;
@@ -691,7 +1079,7 @@ class Client extends client_abstract_js_1.ClientAbstract {
691
1079
  const topMsgId = params?.messageThreadId;
692
1080
  const sendAs = params?.sendAs ? await this.getInputPeer(params.sendAs) : undefined;
693
1081
  const entities = entities_?.length > 0 ? entities_.map((v) => (0, _0_message_entity_js_1.messageEntityToTlObject)(v)) : undefined;
694
- const updates = await this.invoke(new functions.MessagesSendMessage({
1082
+ const result = await this.invoke(new functions.MessagesSendMessage({
695
1083
  peer,
696
1084
  randomId,
697
1085
  message,
@@ -703,16 +1091,48 @@ class Client extends client_abstract_js_1.ClientAbstract {
703
1091
  sendAs,
704
1092
  entities,
705
1093
  replyMarkup,
706
- })).then((v) => v[_1_tl_object_js_1.as](types.Updates));
707
- for (const update of updates.updates) {
708
- if (update instanceof types.UpdateNewMessage) {
709
- return (0, _3_message_js_1.constructMessage)(update.message[_1_tl_object_js_1.as](types.Message), updates.users, updates.chats);
1094
+ }));
1095
+ if (result instanceof types.Updates) {
1096
+ for (const update of result.updates) {
1097
+ if (update instanceof types.UpdateNewMessage) {
1098
+ return (0, _3_message_js_1.constructMessage)(update.message[_1_tl_object_js_1.as](types.Message), this[exports.getEntity].bind(this));
1099
+ }
1100
+ else if (update instanceof types.UpdateNewChannelMessage) {
1101
+ return (0, _3_message_js_1.constructMessage)(update.message[_1_tl_object_js_1.as](types.Message), this[exports.getEntity].bind(this));
1102
+ }
710
1103
  }
711
- else if (update instanceof types.UpdateNewChannelMessage) {
712
- return (0, _3_message_js_1.constructMessage)(update.message[_1_tl_object_js_1.as](types.Message), updates.users, updates.chats);
1104
+ }
1105
+ else if (result instanceof types.UpdateShortSentMessage || result instanceof types.UpdateShortSentMessage) {
1106
+ const message = await this.getMessage(chatId, result.id);
1107
+ if (message != null) {
1108
+ return message;
713
1109
  }
714
1110
  }
715
1111
  (0, _0_control_js_1.UNREACHABLE)();
716
1112
  }
1113
+ async getMessages(chatId, messageIds) {
1114
+ const peer = await this.getInputPeer(chatId);
1115
+ let messages_;
1116
+ if (peer instanceof types.InputPeerChannel) {
1117
+ messages_ = await this.invoke(new functions.ChannelsGetMessages({
1118
+ channel: new types.InputChannel({ channelId: peer.channelId, accessHash: peer.accessHash }),
1119
+ id: messageIds.map((v) => new types.InputMessageID({ id: v })),
1120
+ })).then((v) => v[_1_tl_object_js_1.as](types.MessagesMessages));
1121
+ }
1122
+ else {
1123
+ messages_ = await this.invoke(new functions.MessagesGetMessages({
1124
+ id: messageIds.map((v) => new types.InputMessageID({ id: v })),
1125
+ })).then((v) => v[_1_tl_object_js_1.as](types.MessagesMessages));
1126
+ }
1127
+ const messages = new Array();
1128
+ for (const message_ of messages_.messages) {
1129
+ messages.push(await (0, _3_message_js_1.constructMessage)(message_[_1_tl_object_js_1.as](types.Message), this[exports.getEntity].bind(this)));
1130
+ }
1131
+ return messages;
1132
+ }
1133
+ async getMessage(chatId, messageId) {
1134
+ const messages = await this.getMessages(chatId, [messageId]);
1135
+ return messages[0] ?? null;
1136
+ }
717
1137
  }
718
1138
  exports.Client = Client;