@mtcute/core 0.22.3 → 0.23.1

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 (111) hide show
  1. package/client.cjs +1 -1
  2. package/client.js +1 -1
  3. package/highlevel/base.cjs +1 -0
  4. package/highlevel/base.js +1 -0
  5. package/highlevel/client.d.cts +7 -3
  6. package/highlevel/client.d.ts +7 -3
  7. package/highlevel/methods/auth/send-code.cjs +8 -2
  8. package/highlevel/methods/auth/send-code.d.cts +4 -2
  9. package/highlevel/methods/auth/send-code.d.ts +4 -2
  10. package/highlevel/methods/auth/send-code.js +8 -2
  11. package/highlevel/methods/auth/start.cjs +6 -1
  12. package/highlevel/methods/auth/start.d.cts +1 -1
  13. package/highlevel/methods/auth/start.d.ts +1 -1
  14. package/highlevel/methods/auth/start.js +6 -1
  15. package/highlevel/methods/chats/open-chat.cjs +1 -1
  16. package/highlevel/methods/chats/open-chat.js +1 -1
  17. package/highlevel/methods/dialogs/find-dialogs.cjs +3 -1
  18. package/highlevel/methods/dialogs/find-dialogs.js +3 -1
  19. package/highlevel/methods/dialogs/get-peer-dialogs.cjs +49 -11
  20. package/highlevel/methods/dialogs/get-peer-dialogs.d.cts +1 -1
  21. package/highlevel/methods/dialogs/get-peer-dialogs.d.ts +1 -1
  22. package/highlevel/methods/dialogs/get-peer-dialogs.js +49 -11
  23. package/highlevel/methods/files/normalize-input-file.d.cts +1 -0
  24. package/highlevel/methods/files/normalize-input-file.d.ts +1 -0
  25. package/highlevel/methods/files/normalize-input-media.cjs +13 -6
  26. package/highlevel/methods/files/normalize-input-media.d.cts +1 -0
  27. package/highlevel/methods/files/normalize-input-media.d.ts +1 -0
  28. package/highlevel/methods/files/normalize-input-media.js +13 -6
  29. package/highlevel/methods/files/upload-file.cjs +6 -3
  30. package/highlevel/methods/files/upload-file.d.cts +1 -0
  31. package/highlevel/methods/files/upload-file.d.ts +1 -0
  32. package/highlevel/methods/files/upload-file.js +6 -3
  33. package/highlevel/methods/messages/send-common.d.cts +1 -0
  34. package/highlevel/methods/messages/send-common.d.ts +1 -0
  35. package/highlevel/methods/messages/send-media-group.cjs +3 -2
  36. package/highlevel/methods/messages/send-media-group.js +3 -2
  37. package/highlevel/methods/messages/send-media.cjs +3 -2
  38. package/highlevel/methods/messages/send-media.js +3 -2
  39. package/highlevel/methods/messages/send-text.cjs +1 -1
  40. package/highlevel/methods/messages/send-text.js +1 -1
  41. package/highlevel/methods/users/resolve-peer-many.cjs +8 -43
  42. package/highlevel/methods/users/resolve-peer-many.js +9 -44
  43. package/highlevel/storage/service/peers.cjs +37 -9
  44. package/highlevel/storage/service/peers.d.cts +4 -0
  45. package/highlevel/storage/service/peers.d.ts +4 -0
  46. package/highlevel/storage/service/peers.js +38 -10
  47. package/highlevel/storage/storage.cjs +3 -0
  48. package/highlevel/storage/storage.d.cts +1 -0
  49. package/highlevel/storage/storage.d.ts +1 -0
  50. package/highlevel/storage/storage.js +3 -0
  51. package/highlevel/types/conversation.cjs +3 -4
  52. package/highlevel/types/conversation.js +3 -4
  53. package/highlevel/types/messages/message-action.cjs +11 -0
  54. package/highlevel/types/messages/message-action.d.cts +15 -1
  55. package/highlevel/types/messages/message-action.d.ts +15 -1
  56. package/highlevel/types/messages/message-action.js +11 -0
  57. package/highlevel/types/peers/full-user.cjs +8 -0
  58. package/highlevel/types/peers/full-user.d.cts +4 -0
  59. package/highlevel/types/peers/full-user.d.ts +4 -0
  60. package/highlevel/types/peers/full-user.js +8 -0
  61. package/highlevel/types/peers/peers-index.cjs +10 -0
  62. package/highlevel/types/peers/peers-index.d.cts +1 -0
  63. package/highlevel/types/peers/peers-index.d.ts +1 -0
  64. package/highlevel/types/peers/peers-index.js +10 -0
  65. package/highlevel/types/premium/business-connection.cjs +3 -3
  66. package/highlevel/types/premium/business-connection.d.cts +2 -2
  67. package/highlevel/types/premium/business-connection.d.ts +2 -2
  68. package/highlevel/types/premium/business-connection.js +3 -3
  69. package/highlevel/types/premium/saved-star-gift.cjs +2 -2
  70. package/highlevel/types/premium/saved-star-gift.d.cts +2 -2
  71. package/highlevel/types/premium/saved-star-gift.d.ts +2 -2
  72. package/highlevel/types/premium/saved-star-gift.js +2 -2
  73. package/highlevel/types/premium/stars-gift-unique.cjs +35 -5
  74. package/highlevel/types/premium/stars-gift-unique.d.cts +23 -3
  75. package/highlevel/types/premium/stars-gift-unique.d.ts +23 -3
  76. package/highlevel/types/premium/stars-gift-unique.js +35 -5
  77. package/highlevel/types/premium/stars-transaction.cjs +4 -0
  78. package/highlevel/types/premium/stars-transaction.d.cts +2 -0
  79. package/highlevel/types/premium/stars-transaction.d.ts +2 -0
  80. package/highlevel/types/premium/stars-transaction.js +4 -0
  81. package/highlevel/updates/manager.cjs +4 -4
  82. package/highlevel/updates/manager.js +4 -4
  83. package/highlevel/worker/storage.cjs +4 -0
  84. package/highlevel/worker/storage.d.cts +2 -0
  85. package/highlevel/worker/storage.d.ts +2 -0
  86. package/highlevel/worker/storage.js +4 -0
  87. package/network/authorization.cjs +1 -1
  88. package/network/authorization.js +1 -1
  89. package/network/middlewares/flood-waiter.cjs +20 -4
  90. package/network/middlewares/flood-waiter.d.cts +9 -2
  91. package/network/middlewares/flood-waiter.d.ts +9 -2
  92. package/network/middlewares/flood-waiter.js +20 -4
  93. package/network/mtproto-session.cjs +3 -4
  94. package/network/mtproto-session.d.cts +1 -1
  95. package/network/mtproto-session.d.ts +1 -1
  96. package/network/mtproto-session.js +3 -4
  97. package/network/network-manager.cjs +3 -3
  98. package/network/network-manager.d.cts +1 -1
  99. package/network/network-manager.d.ts +1 -1
  100. package/network/network-manager.js +3 -3
  101. package/network/persistent-connection.cjs +1 -0
  102. package/network/persistent-connection.js +1 -0
  103. package/network/session-connection.cjs +7 -5
  104. package/network/session-connection.js +7 -5
  105. package/package.json +7 -7
  106. package/utils/binary/compat.cjs +2 -0
  107. package/utils/binary/compat.js +2 -0
  108. package/utils/early-timer.cjs +12 -7
  109. package/utils/early-timer.d.cts +3 -3
  110. package/utils/early-timer.d.ts +3 -3
  111. package/utils/early-timer.js +12 -7
@@ -1218,7 +1218,7 @@ class UpdatesManager {
1218
1218
  pending.ptsBefore,
1219
1219
  diff
1220
1220
  );
1221
- pending.timeout = Date.now() + 500;
1221
+ pending.timeout = performance.now() + 500;
1222
1222
  pendingPtsUpdatesPostponed.add(pending);
1223
1223
  postponedTimer.emitBefore(pending.timeout);
1224
1224
  } else if (diff > -1e6) {
@@ -1287,7 +1287,7 @@ class UpdatesManager {
1287
1287
  continue;
1288
1288
  }
1289
1289
  if (localPts < pending.ptsBefore) {
1290
- const now = Date.now();
1290
+ const now = performance.now();
1291
1291
  if (now < pending.timeout) {
1292
1292
  log.debug(
1293
1293
  "postponed %s (cid = %d) is still waiting (%dms left) (current pts %d, need %d)",
@@ -1341,7 +1341,7 @@ class UpdatesManager {
1341
1341
  pending.qtsBefore,
1342
1342
  diff
1343
1343
  );
1344
- pending.timeout = Date.now() + 500;
1344
+ pending.timeout = performance.now() + 500;
1345
1345
  pendingQtsUpdatesPostponed.add(pending);
1346
1346
  postponedTimer.emitBefore(pending.timeout);
1347
1347
  } else {
@@ -1375,7 +1375,7 @@ class UpdatesManager {
1375
1375
  continue;
1376
1376
  }
1377
1377
  if (this.qts < pending.qtsBefore) {
1378
- const now = Date.now();
1378
+ const now = performance.now();
1379
1379
  if (now < pending.timeout) {
1380
1380
  log.debug(
1381
1381
  "postponed %s is still waiting (%dms left) (current qts %d, need %d)",
@@ -55,6 +55,7 @@ class PeersServiceProxy {
55
55
  this.getByUsername = bind("getByUsername");
56
56
  this.getCompleteById = bind("getCompleteById");
57
57
  this.getMinAccessHash = bind("getMinAccessHash");
58
+ this.close = bind("close");
58
59
  }
59
60
  updatePeersFrom;
60
61
  store;
@@ -63,6 +64,7 @@ class PeersServiceProxy {
63
64
  getByUsername;
64
65
  getCompleteById;
65
66
  getMinAccessHash;
67
+ close;
66
68
  }
67
69
  class TelegramStorageProxy {
68
70
  constructor(_invoker) {
@@ -71,10 +73,12 @@ class TelegramStorageProxy {
71
73
  this.self = new CurrentUserServiceProxy(this._invoker);
72
74
  this.peers = new PeersServiceProxy(this._invoker);
73
75
  this.clear = bind("clear");
76
+ this.close = bind("close");
74
77
  }
75
78
  self;
76
79
  peers;
77
80
  clear;
81
+ close;
78
82
  // todo - remove once we move these to updates manager
79
83
  updates = null;
80
84
  refMsgs = null;
@@ -26,6 +26,7 @@ declare class PeersServiceProxy implements PublicPart<PeersService> {
26
26
  readonly getByUsername: PeersService['getByUsername'];
27
27
  readonly getCompleteById: PeersService['getCompleteById'];
28
28
  readonly getMinAccessHash: PeersService['getMinAccessHash'];
29
+ readonly close: PeersService['close'];
29
30
  constructor(_invoker: WorkerInvoker);
30
31
  }
31
32
  export declare class TelegramStorageProxy implements PublicPart<TelegramStorageManager> {
@@ -33,6 +34,7 @@ export declare class TelegramStorageProxy implements PublicPart<TelegramStorageM
33
34
  readonly self: CurrentUserServiceProxy;
34
35
  readonly peers: PeersServiceProxy;
35
36
  readonly clear: TelegramStorageManager['clear'];
37
+ readonly close: TelegramStorageManager['close'];
36
38
  constructor(_invoker: WorkerInvoker);
37
39
  readonly updates: never;
38
40
  readonly refMsgs: never;
@@ -26,6 +26,7 @@ declare class PeersServiceProxy implements PublicPart<PeersService> {
26
26
  readonly getByUsername: PeersService['getByUsername'];
27
27
  readonly getCompleteById: PeersService['getCompleteById'];
28
28
  readonly getMinAccessHash: PeersService['getMinAccessHash'];
29
+ readonly close: PeersService['close'];
29
30
  constructor(_invoker: WorkerInvoker);
30
31
  }
31
32
  export declare class TelegramStorageProxy implements PublicPart<TelegramStorageManager> {
@@ -33,6 +34,7 @@ export declare class TelegramStorageProxy implements PublicPart<TelegramStorageM
33
34
  readonly self: CurrentUserServiceProxy;
34
35
  readonly peers: PeersServiceProxy;
35
36
  readonly clear: TelegramStorageManager['clear'];
37
+ readonly close: TelegramStorageManager['close'];
36
38
  constructor(_invoker: WorkerInvoker);
37
39
  readonly updates: never;
38
40
  readonly refMsgs: never;
@@ -48,6 +48,7 @@ class PeersServiceProxy {
48
48
  this.getByUsername = bind("getByUsername");
49
49
  this.getCompleteById = bind("getCompleteById");
50
50
  this.getMinAccessHash = bind("getMinAccessHash");
51
+ this.close = bind("close");
51
52
  }
52
53
  updatePeersFrom;
53
54
  store;
@@ -56,6 +57,7 @@ class PeersServiceProxy {
56
57
  getByUsername;
57
58
  getCompleteById;
58
59
  getMinAccessHash;
60
+ close;
59
61
  }
60
62
  class TelegramStorageProxy {
61
63
  constructor(_invoker) {
@@ -64,10 +66,12 @@ class TelegramStorageProxy {
64
66
  this.self = new CurrentUserServiceProxy(this._invoker);
65
67
  this.peers = new PeersServiceProxy(this._invoker);
66
68
  this.clear = bind("clear");
69
+ this.close = bind("close");
67
70
  }
68
71
  self;
69
72
  peers;
70
73
  clear;
74
+ close;
71
75
  // todo - remove once we move these to updates manager
72
76
  updates = null;
73
77
  refMsgs = null;
@@ -239,7 +239,7 @@ async function doAuthorization(connection, crypto, expiresIn) {
239
239
  throw new Error("Step 3: invalid server nonce from server");
240
240
  }
241
241
  const dhPrime = utils.bigint.fromBytes(serverDhInner.dhPrime);
242
- const timeOffset = Math.floor(Date.now() / 1e3) - serverDhInner.serverTime;
242
+ const timeOffset = serverDhInner.serverTime - Math.floor(performance.now() / 1e3);
243
243
  session.updateTimeOffset(timeOffset);
244
244
  const g = BigInt(serverDhInner.g);
245
245
  const gA = utils.bigint.fromBytes(serverDhInner.gA);
@@ -232,7 +232,7 @@ async function doAuthorization(connection, crypto, expiresIn) {
232
232
  throw new Error("Step 3: invalid server nonce from server");
233
233
  }
234
234
  const dhPrime = bigint.fromBytes(serverDhInner.dhPrime);
235
- const timeOffset = Math.floor(Date.now() / 1e3) - serverDhInner.serverTime;
235
+ const timeOffset = serverDhInner.serverTime - Math.floor(performance.now() / 1e3);
236
236
  session.updateTimeOffset(timeOffset);
237
237
  const g = BigInt(serverDhInner.g);
238
238
  const gA = bigint.fromBytes(serverDhInner.gA);
@@ -8,15 +8,29 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
8
8
  const abortSignal = require("../../utils/abort-signal.cjs");
9
9
  const miscUtils = require("../../utils/misc-utils.cjs");
10
10
  const typeAssertions = require("../../utils/type-assertions.cjs");
11
+ const SILENTLY_SLEEP_METHODS = /* @__PURE__ */ new Set([
12
+ "upload.getFile",
13
+ "upload.saveFilePart",
14
+ "upload.saveBigFilePart",
15
+ "updates.getDifference",
16
+ "updates.getChannelDifference"
17
+ ]);
18
+ const SILENTLY_SLEEP_THRESHOLD = 5;
11
19
  function floodWaiter(options) {
12
- const { maxWait = 1e4, maxRetries = 5, store = true, minStoredWait = 3e3 } = options;
20
+ const {
21
+ maxWait = 1e4,
22
+ maxRetries = 5,
23
+ store = true,
24
+ minStoredWait = 2e3,
25
+ onBeforeWait
26
+ } = options;
13
27
  const storage = /* @__PURE__ */ new Map();
14
28
  return async (ctx, next) => {
15
29
  const method = ctx.request._;
16
30
  const storedWaitUntil = store ? storage.get(method) : void 0;
17
31
  const floodSleepThreshold = ctx.params?.floodSleepThreshold ?? maxWait;
18
32
  if (storedWaitUntil !== void 0) {
19
- const delta = storedWaitUntil - Date.now();
33
+ const delta = storedWaitUntil - performance.now();
20
34
  if (delta <= minStoredWait) {
21
35
  storage.delete(method);
22
36
  } else if (delta <= floodSleepThreshold) {
@@ -45,14 +59,16 @@ function floodWaiter(options) {
45
59
  return res;
46
60
  }
47
61
  if (store && !err.startsWith("SLOWMODE_WAIT_")) {
48
- storage.set(method, Date.now() + seconds * 1e3);
62
+ storage.set(method, performance.now() + seconds * 1e3);
49
63
  }
50
64
  if (seconds === 0) {
51
65
  seconds = 1;
52
66
  }
53
67
  const ms = seconds * 1e3;
54
68
  if (ms <= floodSleepThreshold) {
55
- if (ctx.request._ !== "upload.getFile") {
69
+ if (onBeforeWait) {
70
+ onBeforeWait(ctx, seconds);
71
+ } else if (!(seconds < SILENTLY_SLEEP_THRESHOLD && SILENTLY_SLEEP_METHODS.has(method))) {
56
72
  ctx.manager._log.warn("%s resulted in a flood wait, will retry in %d seconds", method, seconds);
57
73
  }
58
74
  await miscUtils.sleepWithAbort(
@@ -1,4 +1,4 @@
1
- import { RpcCallMiddleware } from '../network-manager.js';
1
+ import { RpcCallMiddleware, RpcCallMiddlewareContext } from '../network-manager.js';
2
2
  export interface FloodWaiterOptions {
3
3
  /**
4
4
  * Maximum number of ms to wait when a FLOOD_WAIT_X
@@ -30,8 +30,15 @@ export interface FloodWaiterOptions {
30
30
  * If the stored wait time is less than this value,
31
31
  * the request will not be delayed
32
32
  *
33
- * @default 3_000
33
+ * @default 2_000
34
34
  */
35
35
  minStoredWait?: number;
36
+ /**
37
+ * Function that will be called before we are about to wait for `seconds`
38
+ * seconds before retrying the request.
39
+ *
40
+ * @default print a warning to the console, except some methods that often result in flood waits
41
+ */
42
+ onBeforeWait?: (ctx: RpcCallMiddlewareContext, seconds: number) => void;
36
43
  }
37
44
  export declare function floodWaiter(options: FloodWaiterOptions): RpcCallMiddleware;
@@ -1,4 +1,4 @@
1
- import { RpcCallMiddleware } from '../network-manager.js';
1
+ import { RpcCallMiddleware, RpcCallMiddlewareContext } from '../network-manager.js';
2
2
  export interface FloodWaiterOptions {
3
3
  /**
4
4
  * Maximum number of ms to wait when a FLOOD_WAIT_X
@@ -30,8 +30,15 @@ export interface FloodWaiterOptions {
30
30
  * If the stored wait time is less than this value,
31
31
  * the request will not be delayed
32
32
  *
33
- * @default 3_000
33
+ * @default 2_000
34
34
  */
35
35
  minStoredWait?: number;
36
+ /**
37
+ * Function that will be called before we are about to wait for `seconds`
38
+ * seconds before retrying the request.
39
+ *
40
+ * @default print a warning to the console, except some methods that often result in flood waits
41
+ */
42
+ onBeforeWait?: (ctx: RpcCallMiddlewareContext, seconds: number) => void;
36
43
  }
37
44
  export declare function floodWaiter(options: FloodWaiterOptions): RpcCallMiddleware;
@@ -1,15 +1,29 @@
1
1
  import { combineAbortSignals } from "../../utils/abort-signal.js";
2
2
  import { sleepWithAbort } from "../../utils/misc-utils.js";
3
3
  import { isTlRpcError } from "../../utils/type-assertions.js";
4
+ const SILENTLY_SLEEP_METHODS = /* @__PURE__ */ new Set([
5
+ "upload.getFile",
6
+ "upload.saveFilePart",
7
+ "upload.saveBigFilePart",
8
+ "updates.getDifference",
9
+ "updates.getChannelDifference"
10
+ ]);
11
+ const SILENTLY_SLEEP_THRESHOLD = 5;
4
12
  function floodWaiter(options) {
5
- const { maxWait = 1e4, maxRetries = 5, store = true, minStoredWait = 3e3 } = options;
13
+ const {
14
+ maxWait = 1e4,
15
+ maxRetries = 5,
16
+ store = true,
17
+ minStoredWait = 2e3,
18
+ onBeforeWait
19
+ } = options;
6
20
  const storage = /* @__PURE__ */ new Map();
7
21
  return async (ctx, next) => {
8
22
  const method = ctx.request._;
9
23
  const storedWaitUntil = store ? storage.get(method) : void 0;
10
24
  const floodSleepThreshold = ctx.params?.floodSleepThreshold ?? maxWait;
11
25
  if (storedWaitUntil !== void 0) {
12
- const delta = storedWaitUntil - Date.now();
26
+ const delta = storedWaitUntil - performance.now();
13
27
  if (delta <= minStoredWait) {
14
28
  storage.delete(method);
15
29
  } else if (delta <= floodSleepThreshold) {
@@ -38,14 +52,16 @@ function floodWaiter(options) {
38
52
  return res;
39
53
  }
40
54
  if (store && !err.startsWith("SLOWMODE_WAIT_")) {
41
- storage.set(method, Date.now() + seconds * 1e3);
55
+ storage.set(method, performance.now() + seconds * 1e3);
42
56
  }
43
57
  if (seconds === 0) {
44
58
  seconds = 1;
45
59
  }
46
60
  const ms = seconds * 1e3;
47
61
  if (ms <= floodSleepThreshold) {
48
- if (ctx.request._ !== "upload.getFile") {
62
+ if (onBeforeWait) {
63
+ onBeforeWait(ctx, seconds);
64
+ } else if (!(seconds < SILENTLY_SLEEP_THRESHOLD && SILENTLY_SLEEP_METHODS.has(method))) {
49
65
  ctx.manager._log.warn("%s resulted in a flood wait, will retry in %d seconds", method, seconds);
50
66
  }
51
67
  await sleepWithAbort(
@@ -29,7 +29,7 @@ class MtprotoSession {
29
29
  _authKey;
30
30
  _authKeyTemp;
31
31
  _authKeyTempSecondary;
32
- _timeOffset = 0;
32
+ _timeOffset = performance.timeOrigin;
33
33
  _lastMessageId = Long.ZERO;
34
34
  _seqNo = 0;
35
35
  /// state ///
@@ -132,8 +132,8 @@ class MtprotoSession {
132
132
  return true;
133
133
  }
134
134
  getMessageId() {
135
- const timeTicks = Date.now();
136
- const timeSec = Math.floor(timeTicks / 1e3) - this._timeOffset;
135
+ const timeTicks = performance.now();
136
+ const timeSec = Math.floor(timeTicks / 1e3) + this._timeOffset;
137
137
  const timeMSec = timeTicks % 1e3;
138
138
  const random = miscUtils.getRandomInt(65535);
139
139
  let messageId = new Long(timeMSec << 21 | random << 3 | 4, timeSec);
@@ -206,7 +206,6 @@ class MtprotoSession {
206
206
  this.next429Timeout = 1e3;
207
207
  }, 6e4);
208
208
  this.log.debug("transport flood, waiting for %d ms before proceeding", timeout);
209
- return Date.now() + timeout;
210
209
  }
211
210
  resetLastPing(withTime = false) {
212
211
  if (withTime) this.lastPingTime = 0;
@@ -119,7 +119,7 @@ export declare class MtprotoSession {
119
119
  /** Decrypt a single MTProto message using session's keys */
120
120
  decryptMessage(data: Uint8Array, callback: Parameters<AuthKey['decryptMessage']>[2]): void;
121
121
  writeMessage(writer: TlBinaryWriter, content: tl.TlObject | mtp.TlObject | Uint8Array, isContentRelated?: boolean): Long;
122
- onTransportFlood(callback: () => void): number | undefined;
122
+ onTransportFlood(callback: () => void): void;
123
123
  resetLastPing(withTime?: boolean): void;
124
124
  addToChain(chainId: string | number, msgId: Long): Long | undefined;
125
125
  removeFromChain(chainId: string | number, msgId: Long): void;
@@ -119,7 +119,7 @@ export declare class MtprotoSession {
119
119
  /** Decrypt a single MTProto message using session's keys */
120
120
  decryptMessage(data: Uint8Array, callback: Parameters<AuthKey['decryptMessage']>[2]): void;
121
121
  writeMessage(writer: TlBinaryWriter, content: tl.TlObject | mtp.TlObject | Uint8Array, isContentRelated?: boolean): Long;
122
- onTransportFlood(callback: () => void): number | undefined;
122
+ onTransportFlood(callback: () => void): void;
123
123
  resetLastPing(withTime?: boolean): void;
124
124
  addToChain(chainId: string | number, msgId: Long): Long | undefined;
125
125
  removeFromChain(chainId: string | number, msgId: Long): void;
@@ -22,7 +22,7 @@ class MtprotoSession {
22
22
  _authKey;
23
23
  _authKeyTemp;
24
24
  _authKeyTempSecondary;
25
- _timeOffset = 0;
25
+ _timeOffset = performance.timeOrigin;
26
26
  _lastMessageId = Long.ZERO;
27
27
  _seqNo = 0;
28
28
  /// state ///
@@ -125,8 +125,8 @@ class MtprotoSession {
125
125
  return true;
126
126
  }
127
127
  getMessageId() {
128
- const timeTicks = Date.now();
129
- const timeSec = Math.floor(timeTicks / 1e3) - this._timeOffset;
128
+ const timeTicks = performance.now();
129
+ const timeSec = Math.floor(timeTicks / 1e3) + this._timeOffset;
130
130
  const timeMSec = timeTicks % 1e3;
131
131
  const random = getRandomInt(65535);
132
132
  let messageId = new Long(timeMSec << 21 | random << 3 | 4, timeSec);
@@ -199,7 +199,6 @@ class MtprotoSession {
199
199
  this.next429Timeout = 1e3;
200
200
  }, 6e4);
201
201
  this.log.debug("transport flood, waiting for %d ms before proceeding", timeout);
202
- return Date.now() + timeout;
203
202
  }
204
203
  resetLastPing(withTime = false) {
205
204
  if (withTime) this.lastPingTime = 0;
@@ -189,7 +189,7 @@ class DcConnectionManager {
189
189
  return false;
190
190
  }
191
191
  if (this.manager.params.usePfs || forcePfs) {
192
- const now = Date.now();
192
+ const now = performance.now();
193
193
  await Promise.all(
194
194
  Array.from({ length: this.main.getCount() }, async (_, i) => {
195
195
  const temp = await this.manager._storage.provider.authKeys.getTemp(this.dcId, i, now);
@@ -220,7 +220,7 @@ class NetworkManager {
220
220
  _: "initConnection",
221
221
  deviceModel,
222
222
  systemVersion: "1.0",
223
- appVersion: "0.22.3",
223
+ appVersion: "0.23.1",
224
224
  systemLangCode: "en",
225
225
  langPack: "",
226
226
  // "langPacks are for official apps only"
@@ -501,7 +501,7 @@ class NetworkManager {
501
501
  res = await multi.sendRpc(message, params?.timeout, params?.abortSignal, params?.chainId);
502
502
  }
503
503
  } else if (err === "AUTH_KEY_UNREGISTERED") {
504
- this._log.warn("exported auth key error, trying re-exporting..");
504
+ this._log.debug("exported auth key error, trying re-exporting..");
505
505
  await this._exportAuthTo(manager);
506
506
  res = await multi.sendRpc(message, params?.timeout, params?.abortSignal, params?.chainId);
507
507
  }
@@ -32,7 +32,7 @@ export interface NetworkManagerParams {
32
32
  writerMap: TlWriterMap;
33
33
  isPremium: boolean;
34
34
  emitError: (err: Error) => void;
35
- onUpdate: (upd: tl.TypeUpdates) => void;
35
+ onUpdate: (upd: tl.TypeUpdates, fromClient: boolean) => void;
36
36
  onUsable: () => void;
37
37
  onConnecting: () => void;
38
38
  onNetworkChanged: (connected: boolean) => void;
@@ -32,7 +32,7 @@ export interface NetworkManagerParams {
32
32
  writerMap: TlWriterMap;
33
33
  isPremium: boolean;
34
34
  emitError: (err: Error) => void;
35
- onUpdate: (upd: tl.TypeUpdates) => void;
35
+ onUpdate: (upd: tl.TypeUpdates, fromClient: boolean) => void;
36
36
  onUsable: () => void;
37
37
  onConnecting: () => void;
38
38
  onNetworkChanged: (connected: boolean) => void;
@@ -182,7 +182,7 @@ class DcConnectionManager {
182
182
  return false;
183
183
  }
184
184
  if (this.manager.params.usePfs || forcePfs) {
185
- const now = Date.now();
185
+ const now = performance.now();
186
186
  await Promise.all(
187
187
  Array.from({ length: this.main.getCount() }, async (_, i) => {
188
188
  const temp = await this.manager._storage.provider.authKeys.getTemp(this.dcId, i, now);
@@ -213,7 +213,7 @@ class NetworkManager {
213
213
  _: "initConnection",
214
214
  deviceModel,
215
215
  systemVersion: "1.0",
216
- appVersion: "0.22.3",
216
+ appVersion: "0.23.1",
217
217
  systemLangCode: "en",
218
218
  langPack: "",
219
219
  // "langPacks are for official apps only"
@@ -494,7 +494,7 @@ class NetworkManager {
494
494
  res = await multi.sendRpc(message, params?.timeout, params?.abortSignal, params?.chainId);
495
495
  }
496
496
  } else if (err === "AUTH_KEY_UNREGISTERED") {
497
- this._log.warn("exported auth key error, trying re-exporting..");
497
+ this._log.debug("exported auth key error, trying re-exporting..");
498
498
  await this._exportAuthTo(manager);
499
499
  res = await multi.sendRpc(message, params?.timeout, params?.abortSignal, params?.chainId);
500
500
  }
@@ -23,6 +23,7 @@ class PersistentConnection {
23
23
  this.log.debug("connecting to %j", dc);
24
24
  return params.transport.connect(dc);
25
25
  },
26
+ strategy: params.reconnectionStrategy,
26
27
  onOpen: this._onOpen.bind(this),
27
28
  onClose: this._onClose.bind(this),
28
29
  onError: this._onError.bind(this),
@@ -16,6 +16,7 @@ class PersistentConnection {
16
16
  this.log.debug("connecting to %j", dc);
17
17
  return params.transport.connect(dc);
18
18
  },
19
+ strategy: params.reconnectionStrategy,
19
20
  onOpen: this._onOpen.bind(this),
20
21
  onClose: this._onClose.bind(this),
21
22
  onError: this._onError.bind(this),
@@ -762,7 +762,7 @@ class SessionConnection extends persistentConnection.PersistentConnection {
762
762
  if (info.pingId.neq(pingId)) {
763
763
  this.log.warn("received pong to %l, but expected ping_id = %l (got %l)", msgId, info.pingId, pingId);
764
764
  }
765
- const rtt = Date.now() - this._session.lastPingTime;
765
+ const rtt = performance.now() - this._session.lastPingTime;
766
766
  this._session.lastPingRtt = rtt;
767
767
  if (info.containerId.neq(msgId)) {
768
768
  this._onMessageAcked(info.containerId);
@@ -781,7 +781,7 @@ class SessionConnection extends persistentConnection.PersistentConnection {
781
781
  case 20: {
782
782
  if (msg.errorCode !== 20) {
783
783
  const serverTime = msgId.high >>> 0;
784
- const timeOffset = Math.floor(Date.now() / 1e3) - serverTime;
784
+ const timeOffset = serverTime - Math.floor(performance.now() / 1e3);
785
785
  this._session.updateTimeOffset(timeOffset);
786
786
  this.log.debug("server time: %d, corrected offset to %d", serverTime, timeOffset);
787
787
  }
@@ -1130,7 +1130,7 @@ class SessionConnection extends persistentConnection.PersistentConnection {
1130
1130
  let cancelRpcs = null;
1131
1131
  let destroySessions = null;
1132
1132
  let rootMsgId = null;
1133
- const now = Date.now();
1133
+ const now = performance.now();
1134
1134
  if (this._session.queuedAcks.length) {
1135
1135
  let acks = this._session.queuedAcks;
1136
1136
  if (acks.length > 8192) {
@@ -1151,7 +1151,9 @@ class SessionConnection extends persistentConnection.PersistentConnection {
1151
1151
  if (now - this._session.lastPingTime > this._pingInterval) {
1152
1152
  if (!this._session.lastPingMsgId.isZero()) {
1153
1153
  this.log.warn("didn't receive pong for previous ping (msg_id = %l). are we offline?", this._session.lastPingMsgId);
1154
- this._resetSession("ping timeout");
1154
+ if (!this._disconnectedManually) {
1155
+ this._resetSession("ping timeout");
1156
+ }
1155
1157
  return;
1156
1158
  }
1157
1159
  pingId = longUtils.randomLong();
@@ -1161,7 +1163,7 @@ class SessionConnection extends persistentConnection.PersistentConnection {
1161
1163
  // ÷ 1000 * 1.25
1162
1164
  disconnectDelay: Math.round(this._pingInterval * 125e-5)
1163
1165
  };
1164
- this._session.lastPingTime = Date.now();
1166
+ this._session.lastPingTime = now;
1165
1167
  pingRequest = tlRuntime.TlBinaryWriter.serializeObject(this._writerMap, obj);
1166
1168
  containerSize += pingRequest.length + 16;
1167
1169
  containerMessageCount += 1;
@@ -755,7 +755,7 @@ class SessionConnection extends PersistentConnection {
755
755
  if (info.pingId.neq(pingId)) {
756
756
  this.log.warn("received pong to %l, but expected ping_id = %l (got %l)", msgId, info.pingId, pingId);
757
757
  }
758
- const rtt = Date.now() - this._session.lastPingTime;
758
+ const rtt = performance.now() - this._session.lastPingTime;
759
759
  this._session.lastPingRtt = rtt;
760
760
  if (info.containerId.neq(msgId)) {
761
761
  this._onMessageAcked(info.containerId);
@@ -774,7 +774,7 @@ class SessionConnection extends PersistentConnection {
774
774
  case 20: {
775
775
  if (msg.errorCode !== 20) {
776
776
  const serverTime = msgId.high >>> 0;
777
- const timeOffset = Math.floor(Date.now() / 1e3) - serverTime;
777
+ const timeOffset = serverTime - Math.floor(performance.now() / 1e3);
778
778
  this._session.updateTimeOffset(timeOffset);
779
779
  this.log.debug("server time: %d, corrected offset to %d", serverTime, timeOffset);
780
780
  }
@@ -1123,7 +1123,7 @@ class SessionConnection extends PersistentConnection {
1123
1123
  let cancelRpcs = null;
1124
1124
  let destroySessions = null;
1125
1125
  let rootMsgId = null;
1126
- const now = Date.now();
1126
+ const now = performance.now();
1127
1127
  if (this._session.queuedAcks.length) {
1128
1128
  let acks = this._session.queuedAcks;
1129
1129
  if (acks.length > 8192) {
@@ -1144,7 +1144,9 @@ class SessionConnection extends PersistentConnection {
1144
1144
  if (now - this._session.lastPingTime > this._pingInterval) {
1145
1145
  if (!this._session.lastPingMsgId.isZero()) {
1146
1146
  this.log.warn("didn't receive pong for previous ping (msg_id = %l). are we offline?", this._session.lastPingMsgId);
1147
- this._resetSession("ping timeout");
1147
+ if (!this._disconnectedManually) {
1148
+ this._resetSession("ping timeout");
1149
+ }
1148
1150
  return;
1149
1151
  }
1150
1152
  pingId = randomLong();
@@ -1154,7 +1156,7 @@ class SessionConnection extends PersistentConnection {
1154
1156
  // ÷ 1000 * 1.25
1155
1157
  disconnectDelay: Math.round(this._pingInterval * 125e-5)
1156
1158
  };
1157
- this._session.lastPingTime = Date.now();
1159
+ this._session.lastPingTime = now;
1158
1160
  pingRequest = TlBinaryWriter.serializeObject(this._writerMap, obj);
1159
1161
  containerSize += pingRequest.length + 16;
1160
1162
  containerMessageCount += 1;
package/package.json CHANGED
@@ -1,17 +1,17 @@
1
1
  {
2
2
  "name": "@mtcute/core",
3
3
  "type": "module",
4
- "version": "0.22.3",
4
+ "version": "0.23.1",
5
5
  "description": "Type-safe library for MTProto (Telegram API)",
6
6
  "license": "MIT",
7
7
  "scripts": {},
8
8
  "dependencies": {
9
- "@fuman/io": "0.0.8",
10
- "@fuman/net": "0.0.9",
11
- "@fuman/utils": "0.0.4",
12
- "@mtcute/file-id": "^0.22.0",
13
- "@mtcute/tl": "^200.0.0",
14
- "@mtcute/tl-runtime": "^0.22.0",
9
+ "@fuman/io": "0.0.14",
10
+ "@fuman/net": "0.0.14",
11
+ "@fuman/utils": "0.0.14",
12
+ "@mtcute/file-id": "^0.23.0",
13
+ "@mtcute/tl": "^202.0.0",
14
+ "@mtcute/tl-runtime": "^0.23.0",
15
15
  "@types/events": "3.0.0",
16
16
  "long": "5.2.3"
17
17
  },
@@ -89,6 +89,8 @@ function mapCompatObject(obj) {
89
89
  return mapCompatMessageAction(obj);
90
90
  case "userFull_layer199":
91
91
  return replaceType(dropFields(obj, ["premiumGifts"]), "userFull");
92
+ case "userFull_layer200":
93
+ return replaceType(obj, "userFull");
92
94
  case "user_layer199":
93
95
  return {
94
96
  ...obj,
@@ -82,6 +82,8 @@ function mapCompatObject(obj) {
82
82
  return mapCompatMessageAction(obj);
83
83
  case "userFull_layer199":
84
84
  return replaceType(dropFields(obj, ["premiumGifts"]), "userFull");
85
+ case "userFull_layer200":
86
+ return replaceType(obj, "userFull");
85
87
  case "user_layer199":
86
88
  return {
87
89
  ...obj,
@@ -16,11 +16,11 @@ class EarlyTimer {
16
16
  }
17
17
  /**
18
18
  * Emit the timer when the event loop is idle
19
- * (basically `setImmediate()`)
19
+ * (basically `queueMicrotask()`)
20
20
  */
21
21
  emitWhenIdle() {
22
22
  utils.timers.clearTimeout(this._timeout);
23
- this._timeoutTs = Date.now();
23
+ this._timeoutTs = performance.now();
24
24
  if (typeof queueMicrotask !== "undefined") {
25
25
  queueMicrotask(this.emitNow);
26
26
  } else {
@@ -30,23 +30,28 @@ class EarlyTimer {
30
30
  /**
31
31
  * Emit the timer before the next given milliseconds
32
32
  *
33
- * Shorthand for `emitBefore(Date.now() + ms)`
33
+ * Shorthand for `emitBefore(performance.now() + ms)`
34
34
  *
35
35
  * @param ms Milliseconds to schedule for
36
36
  */
37
37
  emitBeforeNext(ms) {
38
- return this.emitBefore(Date.now() + ms);
38
+ return this.emitBefore(performance.now() + ms);
39
39
  }
40
40
  /**
41
41
  * Emit the timer before the given time
42
42
  *
43
- * @param ts Unix time in MS
43
+ * @param ts timestamp in ms relative to `performance.timeOrigin`
44
44
  */
45
45
  emitBefore(ts) {
46
46
  if (!this._timeoutTs || ts < this._timeoutTs) {
47
47
  this.reset();
48
- this._timeout = utils.timers.setTimeout(this.emitNow, ts - Date.now());
49
- this._timeoutTs = ts;
48
+ const diff = ts - performance.now();
49
+ if (diff > 0) {
50
+ this._timeout = utils.timers.setTimeout(this.emitNow, diff);
51
+ this._timeoutTs = ts;
52
+ } else {
53
+ this._handler();
54
+ }
50
55
  }
51
56
  }
52
57
  /**