@mtcute/core 0.30.0 → 0.30.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.
Files changed (148) hide show
  1. package/client.cjs +8 -0
  2. package/client.js +8 -0
  3. package/highlevel/client.d.cts +63 -1
  4. package/highlevel/client.d.ts +63 -1
  5. package/highlevel/methods/files/download-iterable.cjs +80 -45
  6. package/highlevel/methods/files/download-iterable.js +80 -45
  7. package/highlevel/methods/files/normalize-input-media.cjs +9 -1
  8. package/highlevel/methods/files/normalize-input-media.js +10 -2
  9. package/highlevel/methods/files/upload-file.cjs +6 -1
  10. package/highlevel/methods/files/upload-file.js +6 -1
  11. package/highlevel/methods/messages/create-rich-streaming-draft.cjs +39 -0
  12. package/highlevel/methods/messages/create-rich-streaming-draft.d.cts +42 -0
  13. package/highlevel/methods/messages/create-rich-streaming-draft.d.ts +42 -0
  14. package/highlevel/methods/messages/create-rich-streaming-draft.js +34 -0
  15. package/highlevel/methods/messages/normalize-rich-message.cjs +168 -0
  16. package/highlevel/methods/messages/normalize-rich-message.d.cts +10 -0
  17. package/highlevel/methods/messages/normalize-rich-message.d.ts +10 -0
  18. package/highlevel/methods/messages/normalize-rich-message.js +163 -0
  19. package/highlevel/methods/messages/send-common.cjs +3 -2
  20. package/highlevel/methods/messages/send-common.d.cts +4 -1
  21. package/highlevel/methods/messages/send-common.d.ts +4 -1
  22. package/highlevel/methods/messages/send-common.js +3 -2
  23. package/highlevel/methods/messages/send-rich-message.cjs +49 -0
  24. package/highlevel/methods/messages/send-rich-message.d.cts +38 -0
  25. package/highlevel/methods/messages/send-rich-message.d.ts +38 -0
  26. package/highlevel/methods/messages/send-rich-message.js +44 -0
  27. package/highlevel/methods.d.cts +3 -0
  28. package/highlevel/methods.d.ts +3 -0
  29. package/highlevel/types/bots/inline-message/factories.cjs +14 -0
  30. package/highlevel/types/bots/inline-message/factories.d.cts +9 -1
  31. package/highlevel/types/bots/inline-message/factories.d.ts +9 -1
  32. package/highlevel/types/bots/inline-message/factories.js +14 -0
  33. package/highlevel/types/bots/inline-message/types.d.cts +17 -1
  34. package/highlevel/types/bots/inline-message/types.d.ts +17 -1
  35. package/highlevel/types/files/utils.d.cts +9 -0
  36. package/highlevel/types/files/utils.d.ts +9 -0
  37. package/highlevel/types/media/input-media/types.d.cts +1 -1
  38. package/highlevel/types/media/input-media/types.d.ts +1 -1
  39. package/highlevel/types/messages/index.d.cts +1 -1
  40. package/highlevel/types/messages/index.d.ts +1 -1
  41. package/highlevel/types/messages/message.cjs +1 -1
  42. package/highlevel/types/messages/message.d.cts +1 -1
  43. package/highlevel/types/messages/message.d.ts +1 -1
  44. package/highlevel/types/messages/message.js +1 -1
  45. package/highlevel/types/messages/rich/index.d.cts +4 -0
  46. package/highlevel/types/messages/rich/index.d.ts +4 -0
  47. package/highlevel/types/messages/rich/inner.cjs +219 -0
  48. package/highlevel/types/messages/rich/inner.d.cts +127 -0
  49. package/highlevel/types/messages/rich/inner.d.ts +127 -0
  50. package/highlevel/types/messages/rich/inner.js +214 -0
  51. package/highlevel/types/messages/{rich-message.cjs → rich/rich-message.cjs} +6 -6
  52. package/highlevel/types/messages/{rich-message.d.cts → rich/rich-message.d.cts} +5 -5
  53. package/highlevel/types/messages/{rich-message.d.ts → rich/rich-message.d.ts} +5 -5
  54. package/highlevel/types/messages/{rich-message.js → rich/rich-message.js} +6 -6
  55. package/highlevel/types/messages/rich/types.d.cts +76 -0
  56. package/highlevel/types/messages/rich/types.d.ts +76 -0
  57. package/highlevel/updates/manager.cjs +10 -169
  58. package/highlevel/updates/manager.js +10 -169
  59. package/highlevel/utils/entities.cjs +176 -0
  60. package/highlevel/utils/entities.d.cts +18 -0
  61. package/highlevel/utils/entities.d.ts +18 -0
  62. package/highlevel/utils/entities.js +177 -1
  63. package/highlevel/utils/index.d.cts +1 -0
  64. package/highlevel/utils/index.d.ts +1 -0
  65. package/highlevel/utils/walk-page-blocks.cjs +164 -0
  66. package/highlevel/utils/walk-page-blocks.d.cts +9 -0
  67. package/highlevel/utils/walk-page-blocks.d.ts +9 -0
  68. package/highlevel/utils/walk-page-blocks.js +159 -0
  69. package/index.cjs +3 -1
  70. package/index.js +3 -1
  71. package/methods.cjs +4 -0
  72. package/methods.js +4 -0
  73. package/network/authorization.cjs +1 -1
  74. package/network/authorization.js +1 -1
  75. package/network/delay-gate.cjs +29 -0
  76. package/network/delay-gate.d.cts +5 -0
  77. package/network/delay-gate.d.ts +5 -0
  78. package/network/delay-gate.js +24 -0
  79. package/network/delay-gate.test.d.cts +1 -0
  80. package/network/delay-gate.test.d.ts +1 -0
  81. package/network/message-id-store.cjs +30 -0
  82. package/network/message-id-store.d.cts +7 -0
  83. package/network/message-id-store.d.ts +7 -0
  84. package/network/message-id-store.js +25 -0
  85. package/network/message-id-store.test.d.cts +1 -0
  86. package/network/message-id-store.test.d.ts +1 -0
  87. package/network/middlewares/bundle.cjs +2 -0
  88. package/network/middlewares/bundle.d.cts +1 -0
  89. package/network/middlewares/bundle.d.ts +1 -0
  90. package/network/middlewares/bundle.js +2 -0
  91. package/network/middlewares/default.cjs +6 -1
  92. package/network/middlewares/default.js +6 -1
  93. package/network/middlewares/flood-waiter.test.d.cts +1 -0
  94. package/network/middlewares/flood-waiter.test.d.ts +1 -0
  95. package/network/middlewares/internal-errors.test.d.cts +1 -0
  96. package/network/middlewares/internal-errors.test.d.ts +1 -0
  97. package/network/middlewares/media-throttle.cjs +65 -0
  98. package/network/middlewares/media-throttle.d.cts +5 -0
  99. package/network/middlewares/media-throttle.d.ts +5 -0
  100. package/network/middlewares/media-throttle.js +60 -0
  101. package/network/middlewares/media-throttle.test.d.cts +1 -0
  102. package/network/middlewares/media-throttle.test.d.ts +1 -0
  103. package/network/middlewares/on-error.test.d.cts +1 -0
  104. package/network/middlewares/on-error.test.d.ts +1 -0
  105. package/network/middlewares/on-method.test.d.cts +1 -0
  106. package/network/middlewares/on-method.test.d.ts +1 -0
  107. package/network/mtproto-session.cjs +9 -2
  108. package/network/mtproto-session.d.cts +5 -2
  109. package/network/mtproto-session.d.ts +5 -2
  110. package/network/mtproto-session.js +9 -2
  111. package/network/mtproxy/_fake-tls.cjs +169 -107
  112. package/network/mtproxy/_fake-tls.js +169 -107
  113. package/network/mtproxy/_fake-tls.test.d.cts +1 -0
  114. package/network/mtproxy/_fake-tls.test.d.ts +1 -0
  115. package/network/multi-session-connection.cjs +7 -0
  116. package/network/multi-session-connection.d.cts +2 -0
  117. package/network/multi-session-connection.d.ts +2 -0
  118. package/network/multi-session-connection.js +7 -0
  119. package/network/network-manager.cjs +7 -1
  120. package/network/network-manager.js +7 -1
  121. package/network/resource-limiter.cjs +60 -0
  122. package/network/resource-limiter.d.cts +11 -0
  123. package/network/resource-limiter.d.ts +11 -0
  124. package/network/resource-limiter.js +55 -0
  125. package/network/resource-limiter.test.d.cts +1 -0
  126. package/network/resource-limiter.test.d.ts +1 -0
  127. package/network/server-salt.cjs +7 -3
  128. package/network/server-salt.d.cts +2 -0
  129. package/network/server-salt.d.ts +2 -0
  130. package/network/server-salt.js +7 -3
  131. package/network/session-connection.cjs +106 -20
  132. package/network/session-connection.d.cts +11 -0
  133. package/network/session-connection.d.ts +11 -0
  134. package/network/session-connection.js +106 -20
  135. package/package.json +1 -1
  136. package/tl/api-schema.json +1 -1
  137. package/tl/binary/reader.cjs +115 -109
  138. package/tl/binary/reader.js +115 -109
  139. package/tl/binary/writer.cjs +243 -245
  140. package/tl/binary/writer.js +243 -245
  141. package/tl/index.d.cts +227 -216
  142. package/tl/index.d.ts +227 -216
  143. package/tl/inner-tl.cjs +3 -1
  144. package/tl/inner-tl.js +3 -1
  145. package/types/utils.d.cts +4 -0
  146. package/types/utils.d.ts +4 -0
  147. package/utils.cjs +4 -0
  148. package/utils.js +5 -1
@@ -1,6 +1,7 @@
1
1
  import { Bytes, read } from "@fuman/io";
2
2
  import { u8, typed, bigint } from "@fuman/utils";
3
3
  const MAX_TLS_PACKET_LENGTH = 2878;
4
+ const MAX_TLS_HELLO_SIZE = 4096;
4
5
  const KEY_MOD = 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEDn;
5
6
  const QUAD_RES_MOD = 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEDn;
6
7
  const QUAD_RES_POW = 0x3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6n;
@@ -27,7 +28,11 @@ function _isQuadraticResidue(a) {
27
28
  return r === 1n;
28
29
  }
29
30
  function executeTlsOperations(h) {
30
- h.string([22, 3, 1, 2, 0, 1, 0, 1, 252, 3, 3]);
31
+ h.string([22, 3, 1]);
32
+ h.beginScope();
33
+ h.string([1, 0]);
34
+ h.beginScope();
35
+ h.string([3, 3]);
31
36
  h.zero(32);
32
37
  h.string([32]);
33
38
  h.random(32);
@@ -65,67 +70,34 @@ function executeTlsOperations(h) {
65
70
  0,
66
71
  53,
67
72
  1,
68
- 0,
69
- 1,
70
- 147
73
+ 0
71
74
  ]);
72
- h.grease(2);
73
- h.string([0, 0, 0, 0]);
74
- h.beginScope();
75
75
  h.beginScope();
76
- h.string([0]);
77
- h.beginScope();
78
- h.domain();
79
- h.endScope();
80
- h.endScope();
81
- h.endScope();
82
- h.string([0, 23, 0, 0, 255, 1, 0, 1, 0, 0, 10, 0, 10, 0, 8]);
83
- h.grease(4);
84
- h.string(
85
- [
86
- 0,
87
- 29,
88
- 0,
89
- 23,
90
- 0,
91
- 24,
92
- 0,
93
- 11,
94
- 0,
95
- 2,
96
- 1,
97
- 0,
98
- 0,
99
- 35,
100
- 0,
101
- 0,
102
- 0,
103
- 16,
104
- 0,
105
- 14,
106
- 0,
107
- 12,
108
- 2,
109
- 104,
110
- 50,
111
- 8,
112
- 104,
113
- 116,
114
- 116,
115
- 112,
116
- 47,
117
- 49,
118
- 46,
119
- 49,
120
- 0,
121
- 5,
122
- 0,
123
- 5,
124
- 1,
125
- 0,
126
- 0,
127
- 0,
128
- 0,
76
+ h.grease(2);
77
+ h.string([0, 0]);
78
+ h.permutation([
79
+ (w) => {
80
+ w.string([0, 0]);
81
+ w.beginScope();
82
+ w.beginScope();
83
+ w.string([0]);
84
+ w.beginScope();
85
+ w.domain();
86
+ w.endScope();
87
+ w.endScope();
88
+ w.endScope();
89
+ },
90
+ (w) => w.string([0, 5, 0, 5, 1, 0, 0, 0, 0]),
91
+ // status_request
92
+ (w) => {
93
+ w.string([0, 10, 0, 12, 0, 10]);
94
+ w.grease(4);
95
+ w.string([17, 236, 0, 29, 0, 23, 0, 24]);
96
+ },
97
+ (w) => w.string([0, 11, 0, 2, 1, 0]),
98
+ // ec_point_formats
99
+ (w) => w.string([
100
+ // signature_algorithms
129
101
  0,
130
102
  13,
131
103
  0,
@@ -147,27 +119,76 @@ function executeTlsOperations(h) {
147
119
  8,
148
120
  6,
149
121
  6,
150
- 1,
122
+ 1
123
+ ]),
124
+ (w) => w.string([
125
+ // application_layer_protocol_negotiation (ALPN)
151
126
  0,
152
- 18,
153
- 0,
154
- 0,
155
- 0,
156
- 51,
127
+ 16,
157
128
  0,
158
- 43,
129
+ 14,
159
130
  0,
160
- 41
161
- ]
162
- );
163
- h.grease(4);
164
- h.string([0, 1, 0, 0, 29, 0, 32]);
165
- h.key();
166
- h.string([0, 45, 0, 2, 1, 1, 0, 43, 0, 11, 10]);
167
- h.grease(6);
168
- h.string([3, 4, 3, 3, 3, 2, 3, 1, 0, 27, 0, 3, 2, 0, 2]);
131
+ 12,
132
+ 2,
133
+ 104,
134
+ 50,
135
+ 8,
136
+ 104,
137
+ 116,
138
+ 116,
139
+ 112,
140
+ 47,
141
+ 49,
142
+ 46,
143
+ 49
144
+ ]),
145
+ (w) => w.string([0, 18, 0, 0]),
146
+ // signed_certificate_timestamp
147
+ (w) => w.string([0, 23, 0, 0]),
148
+ // extended_master_secret
149
+ (w) => w.string([0, 27, 0, 3, 2, 0, 2]),
150
+ // compress_certificate
151
+ (w) => w.string([0, 35, 0, 0]),
152
+ // session_ticket
153
+ (w) => {
154
+ w.string([0, 43, 0, 7, 6]);
155
+ w.grease(6);
156
+ w.string([3, 4, 3, 3]);
157
+ },
158
+ (w) => w.string([0, 45, 0, 2, 1, 1]),
159
+ // psk_key_exchange_modes
160
+ (w) => {
161
+ w.string([0, 51, 4, 239, 4, 237]);
162
+ w.grease(4);
163
+ w.string([0, 1, 0, 17, 236, 4, 192]);
164
+ w.mlKem768Key();
165
+ w.key();
166
+ w.string([0, 29, 0, 32]);
167
+ w.key();
168
+ },
169
+ (w) => w.string([68, 205, 0, 5, 0, 3, 2, 104, 50]),
170
+ // application_settings (ALPS)
171
+ (w) => {
172
+ w.string([254, 13]);
173
+ w.beginScope();
174
+ w.string([0, 0, 1, 0, 1]);
175
+ w.random(1);
176
+ w.string([0, 32]);
177
+ w.random(32);
178
+ w.beginScope();
179
+ w.echPayload();
180
+ w.endScope();
181
+ w.endScope();
182
+ },
183
+ (w) => w.string([255, 1, 0, 1, 0])
184
+ // renegotiation_info
185
+ ]);
169
186
  h.grease(3);
170
- h.string([0, 1, 0, 0, 21]);
187
+ h.string([0, 1, 0]);
188
+ h.padding();
189
+ h.endScope();
190
+ h.endScope();
191
+ h.endScope();
171
192
  }
172
193
  function initGrease(crypto, size) {
173
194
  const buf = crypto.randomBytes(size);
@@ -182,12 +203,12 @@ function initGrease(crypto, size) {
182
203
  return buf;
183
204
  }
184
205
  class TlsHelloWriter {
185
- constructor(crypto, size, domain) {
206
+ constructor(crypto, domain, grease) {
186
207
  this.crypto = crypto;
187
208
  this._domain = domain;
188
- this.buf = u8.alloc(size);
209
+ this.buf = u8.alloc(MAX_TLS_HELLO_SIZE);
189
210
  this.dv = typed.toDataView(this.buf);
190
- this._grease = initGrease(this.crypto, 7);
211
+ this._grease = grease ?? initGrease(this.crypto, 7);
191
212
  }
192
213
  buf;
193
214
  dv;
@@ -228,6 +249,24 @@ class TlsHelloWriter {
228
249
  }
229
250
  }
230
251
  }
252
+ // fake X25519MLKEM768 hybrid keyshare's ml-kem-768 part: 384 coefficients
253
+ // (mod 3329) packed 3 bytes per 2 coefficients, followed by 32 random bytes
254
+ mlKem768Key() {
255
+ const rnd = this.crypto.randomBytes(384 * 8);
256
+ const dv = typed.toDataView(rnd);
257
+ for (let i = 0; i < 384; i++) {
258
+ const a = dv.getUint32(i * 8, true) % 3329;
259
+ const b = dv.getUint32(i * 8 + 4, true) % 3329;
260
+ this.buf[this.pos++] = a & 255;
261
+ this.buf[this.pos++] = (a >> 8) + ((b & 15) << 4);
262
+ this.buf[this.pos++] = b >> 4;
263
+ }
264
+ this.random(32);
265
+ }
266
+ // GREASE ECH payload: random bytes of length 144/176/208/240
267
+ echPayload() {
268
+ this.random(this._randomInt(4) * 32 + 144);
269
+ }
231
270
  beginScope() {
232
271
  this._scopes.push(this.pos);
233
272
  this.pos += 2;
@@ -237,29 +276,55 @@ class TlsHelloWriter {
237
276
  if (begin === void 0) {
238
277
  throw new Error("endScope called without beginScope");
239
278
  }
240
- const end = this.pos;
241
- const size = end - begin - 2;
242
- this.dv.setUint16(begin, size);
279
+ this.dv.setUint16(begin, this.pos - begin - 2);
243
280
  }
244
- async finish(secret) {
245
- const padSize = 515 - this.pos;
246
- const unixTime = ~~(Date.now() / 1e3);
281
+ // render each part into its own buffer, then emit them in random order —
282
+ // mimics chrome's per-connection tls extension shuffling
283
+ permutation(parts) {
284
+ const rendered = parts.map((fn) => {
285
+ const sub = new TlsHelloWriter(this.crypto, this._domain, this._grease);
286
+ fn(sub);
287
+ return sub.buf.subarray(0, sub.pos);
288
+ });
289
+ for (let i = rendered.length - 1; i > 0; i--) {
290
+ const j = this._randomInt(i + 1);
291
+ const tmp = rendered[i];
292
+ rendered[i] = rendered[j];
293
+ rendered[j] = tmp;
294
+ }
295
+ for (const part of rendered) {
296
+ this.string(part);
297
+ }
298
+ }
299
+ // tls padding extension, only emitted for hellos smaller than 513 bytes
300
+ padding() {
301
+ if (this.pos >= 513) return;
302
+ const size = 513 - this.pos;
303
+ this.string([0, 21]);
247
304
  this.beginScope();
248
- this.zero(padSize);
305
+ this.zero(size);
249
306
  this.endScope();
250
- const hash = await this.crypto.hmacSha256(this.buf, secret);
307
+ }
308
+ _randomInt(max) {
309
+ return typed.toDataView(this.crypto.randomBytes(4)).getUint32(0, true) % max;
310
+ }
311
+ async finish(secret) {
312
+ const data = this.buf.subarray(0, this.pos);
313
+ const unixTime = ~~(Date.now() / 1e3);
314
+ const hash = await this.crypto.hmacSha256(data, secret);
251
315
  const dv = typed.toDataView(hash);
252
316
  const old = dv.getInt32(28, true);
253
317
  dv.setInt32(28, old ^ unixTime, true);
254
- this.buf.set(hash, 11);
255
- return this.buf;
318
+ data.set(hash, 11);
319
+ return data;
256
320
  }
257
321
  }
258
322
  async function generateFakeTlsHeader(domain, secret, crypto) {
259
- const writer = new TlsHelloWriter(crypto, 517, domain);
323
+ const writer = new TlsHelloWriter(crypto, domain);
260
324
  executeTlsOperations(writer);
261
325
  return writer.finish(secret);
262
326
  }
327
+ const EMPTY_BYTES = Bytes.from(u8.empty);
263
328
  class FakeTlsPacketCodec {
264
329
  // protected _stream: Buffer = Buffer.alloc(0)
265
330
  constructor(_inner) {
@@ -294,23 +359,20 @@ class FakeTlsPacketCodec {
294
359
  }
295
360
  async decode(reader, eof) {
296
361
  if (eof) return null;
297
- if (reader.available < 5) return null;
298
- const header = reader.readSync(3);
299
- if (header[0] !== 23 || header[1] !== 3 || header[2] !== 3) {
300
- throw new Error("Invalid TLS header");
301
- }
302
- const length = read.uint16be(reader);
303
- if (length < reader.available - 5) {
304
- reader.rewind(5);
305
- return null;
306
- }
307
- const packet = reader.readSync(length);
308
- const inner = await this._inner.decode(Bytes.from(packet), eof);
309
- if (!inner) {
310
- reader.rewind(5 + length);
311
- return null;
362
+ while (reader.available >= 5) {
363
+ const header = reader.readSync(3);
364
+ if (header[0] !== 23 || header[1] !== 3 || header[2] !== 3) {
365
+ throw new Error("Invalid TLS header");
366
+ }
367
+ const length = read.uint16be(reader);
368
+ if (reader.available < length) {
369
+ reader.rewind(5);
370
+ break;
371
+ }
372
+ const inner = await this._inner.decode(Bytes.from(reader.readSync(length)), eof);
373
+ if (inner) return inner;
312
374
  }
313
- return inner;
375
+ return this._inner.decode(EMPTY_BYTES, eof);
314
376
  }
315
377
  reset() {
316
378
  this._isFirstTls = true;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -160,6 +160,13 @@ class MultiSessionConnection {
160
160
  if (this._connections[0].isConnected) return;
161
161
  this.connect();
162
162
  }
163
+ get isConnected() {
164
+ return this._connections.some((conn) => conn.isConnected);
165
+ }
166
+ destroyAuthKey() {
167
+ const conn = this._connections.find((c) => c.isConnected) ?? this._connections[0];
168
+ conn?.destroyAuthKey();
169
+ }
163
170
  _authKey = null;
164
171
  setAuthKey(authKey) {
165
172
  this._authKey = authKey;
@@ -29,6 +29,8 @@ export declare class MultiSessionConnection {
29
29
  sendRpc<T extends tl.RpcMethod>(request: T, timeout?: number, abortSignal?: AbortSignal, chainId?: string | number): Promise<tl.RpcCallReturn[T['_']] | mtp.RawMt_rpc_error>;
30
30
  connect(): void;
31
31
  ensureConnected(): void;
32
+ get isConnected(): boolean;
33
+ destroyAuthKey(): void;
32
34
  private _authKey;
33
35
  setAuthKey(authKey: Uint8Array | null): void;
34
36
  setTempAuthKey(authKey: Uint8Array | null, idx: number): void;
@@ -29,6 +29,8 @@ export declare class MultiSessionConnection {
29
29
  sendRpc<T extends tl.RpcMethod>(request: T, timeout?: number, abortSignal?: AbortSignal, chainId?: string | number): Promise<tl.RpcCallReturn[T['_']] | mtp.RawMt_rpc_error>;
30
30
  connect(): void;
31
31
  ensureConnected(): void;
32
+ get isConnected(): boolean;
33
+ destroyAuthKey(): void;
32
34
  private _authKey;
33
35
  setAuthKey(authKey: Uint8Array | null): void;
34
36
  setTempAuthKey(authKey: Uint8Array | null, idx: number): void;
@@ -153,6 +153,13 @@ class MultiSessionConnection {
153
153
  if (this._connections[0].isConnected) return;
154
154
  this.connect();
155
155
  }
156
+ get isConnected() {
157
+ return this._connections.some((conn) => conn.isConnected);
158
+ }
159
+ destroyAuthKey() {
160
+ const conn = this._connections.find((c) => c.isConnected) ?? this._connections[0];
161
+ conn?.destroyAuthKey();
162
+ }
156
163
  _authKey = null;
157
164
  setAuthKey(authKey) {
158
165
  this._authKey = authKey;
@@ -227,7 +227,7 @@ class NetworkManager {
227
227
  _: "initConnection",
228
228
  deviceModel,
229
229
  systemVersion: "1.0",
230
- appVersion: "0.30.0",
230
+ appVersion: "0.30.2",
231
231
  systemLangCode: "en",
232
232
  langPack: "",
233
233
  // "langPacks are for official apps only"
@@ -415,6 +415,12 @@ class NetworkManager {
415
415
  return user;
416
416
  }
417
417
  notifyLoggedOut() {
418
+ const primaryDcId = this._primaryDc?.dcId;
419
+ for (const dc of this._dcConnections.values()) {
420
+ if (dc.dcId === primaryDcId) continue;
421
+ const pool = [dc.main, dc.download, dc.upload, dc.downloadSmall].find((p) => p.isConnected);
422
+ pool?.destroyAuthKey();
423
+ }
418
424
  this._businessConnectionDcs.clear();
419
425
  this.setIsPremium(false);
420
426
  this.resetSessions();
@@ -220,7 +220,7 @@ class NetworkManager {
220
220
  _: "initConnection",
221
221
  deviceModel,
222
222
  systemVersion: "1.0",
223
- appVersion: "0.30.0",
223
+ appVersion: "0.30.2",
224
224
  systemLangCode: "en",
225
225
  langPack: "",
226
226
  // "langPacks are for official apps only"
@@ -408,6 +408,12 @@ class NetworkManager {
408
408
  return user;
409
409
  }
410
410
  notifyLoggedOut() {
411
+ const primaryDcId = this._primaryDc?.dcId;
412
+ for (const dc of this._dcConnections.values()) {
413
+ if (dc.dcId === primaryDcId) continue;
414
+ const pool = [dc.main, dc.download, dc.upload, dc.downloadSmall].find((p) => p.isConnected);
415
+ pool?.destroyAuthKey();
416
+ }
411
417
  this._businessConnectionDcs.clear();
412
418
  this.setIsPremium(false);
413
419
  this.resetSessions();
@@ -0,0 +1,60 @@
1
+ if (typeof globalThis !== "undefined" && !globalThis._MTCUTE_CJS_DEPRECATION_WARNED) {
2
+ globalThis._MTCUTE_CJS_DEPRECATION_WARNED = true;
3
+ console.warn("[@mtcute/core] CommonJS bundles are deprecated. They will be removed completely in one of the upcoming releases. No support is provided for CommonJS users. Please consider switching to ESM, it's " + (/* @__PURE__ */ new Date()).getFullYear() + " already.");
4
+ console.warn("[@mtcute/core] Learn more about switching to ESM: https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c");
5
+ }
6
+ "use strict";
7
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
8
+ const utils = require("@fuman/utils");
9
+ class ResourceLimiter {
10
+ constructor(max) {
11
+ this.max = max;
12
+ this._available = max;
13
+ }
14
+ _available;
15
+ _waiters = [];
16
+ setMax(max) {
17
+ this._available += max - this.max;
18
+ this.max = max;
19
+ this._pump();
20
+ }
21
+ tryAcquire(bytes) {
22
+ if (bytes > this.max) bytes = this.max;
23
+ if (!this._waiters.length && this._available >= bytes) {
24
+ this._available -= bytes;
25
+ return true;
26
+ }
27
+ return false;
28
+ }
29
+ acquire(bytes, signal) {
30
+ if (this.tryAcquire(bytes)) return Promise.resolve();
31
+ if (bytes > this.max) bytes = this.max;
32
+ const deferred = new utils.Deferred();
33
+ const waiter = { need: bytes, deferred };
34
+ this._waiters.push(waiter);
35
+ if (signal) {
36
+ const onAbort = () => {
37
+ const idx = this._waiters.indexOf(waiter);
38
+ if (idx >= 0) this._waiters.splice(idx, 1);
39
+ deferred.reject(signal.reason);
40
+ };
41
+ signal.addEventListener("abort", onAbort, { once: true });
42
+ const removeListener = signal.removeEventListener.bind(signal, "abort", onAbort);
43
+ deferred.promise.then(removeListener, removeListener);
44
+ }
45
+ return deferred.promise;
46
+ }
47
+ release(bytes) {
48
+ if (bytes > this.max) bytes = this.max;
49
+ this._available += bytes;
50
+ this._pump();
51
+ }
52
+ _pump() {
53
+ while (this._waiters.length && this._waiters[0].need <= this._available) {
54
+ const waiter = this._waiters.shift();
55
+ this._available -= waiter.need;
56
+ waiter.deferred.resolve();
57
+ }
58
+ }
59
+ }
60
+ exports.ResourceLimiter = ResourceLimiter;
@@ -0,0 +1,11 @@
1
+ export declare class ResourceLimiter {
2
+ max: number;
3
+ private _available;
4
+ private _waiters;
5
+ constructor(max: number);
6
+ setMax(max: number): void;
7
+ tryAcquire(bytes: number): boolean;
8
+ acquire(bytes: number, signal?: AbortSignal): Promise<void>;
9
+ release(bytes: number): void;
10
+ private _pump;
11
+ }
@@ -0,0 +1,11 @@
1
+ export declare class ResourceLimiter {
2
+ max: number;
3
+ private _available;
4
+ private _waiters;
5
+ constructor(max: number);
6
+ setMax(max: number): void;
7
+ tryAcquire(bytes: number): boolean;
8
+ acquire(bytes: number, signal?: AbortSignal): Promise<void>;
9
+ release(bytes: number): void;
10
+ private _pump;
11
+ }
@@ -0,0 +1,55 @@
1
+ import { Deferred } from "@fuman/utils";
2
+ class ResourceLimiter {
3
+ constructor(max) {
4
+ this.max = max;
5
+ this._available = max;
6
+ }
7
+ _available;
8
+ _waiters = [];
9
+ setMax(max) {
10
+ this._available += max - this.max;
11
+ this.max = max;
12
+ this._pump();
13
+ }
14
+ tryAcquire(bytes) {
15
+ if (bytes > this.max) bytes = this.max;
16
+ if (!this._waiters.length && this._available >= bytes) {
17
+ this._available -= bytes;
18
+ return true;
19
+ }
20
+ return false;
21
+ }
22
+ acquire(bytes, signal) {
23
+ if (this.tryAcquire(bytes)) return Promise.resolve();
24
+ if (bytes > this.max) bytes = this.max;
25
+ const deferred = new Deferred();
26
+ const waiter = { need: bytes, deferred };
27
+ this._waiters.push(waiter);
28
+ if (signal) {
29
+ const onAbort = () => {
30
+ const idx = this._waiters.indexOf(waiter);
31
+ if (idx >= 0) this._waiters.splice(idx, 1);
32
+ deferred.reject(signal.reason);
33
+ };
34
+ signal.addEventListener("abort", onAbort, { once: true });
35
+ const removeListener = signal.removeEventListener.bind(signal, "abort", onAbort);
36
+ deferred.promise.then(removeListener, removeListener);
37
+ }
38
+ return deferred.promise;
39
+ }
40
+ release(bytes) {
41
+ if (bytes > this.max) bytes = this.max;
42
+ this._available += bytes;
43
+ this._pump();
44
+ }
45
+ _pump() {
46
+ while (this._waiters.length && this._waiters[0].need <= this._available) {
47
+ const waiter = this._waiters.shift();
48
+ this._available -= waiter.need;
49
+ waiter.deferred.resolve();
50
+ }
51
+ }
52
+ }
53
+ export {
54
+ ResourceLimiter
55
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -11,12 +11,16 @@ class ServerSaltManager {
11
11
  _futureSalts = [];
12
12
  currentSalt = Long.ZERO;
13
13
  isFetching = false;
14
+ _getServerTime = () => Date.now() / 1e3;
15
+ setTimeSource(fn) {
16
+ this._getServerTime = fn;
17
+ }
14
18
  shouldFetchSalts() {
15
19
  return !this.isFetching && !this.currentSalt.isZero() && this._futureSalts.length < 2;
16
20
  }
17
21
  setFutureSalts(salts) {
18
22
  this._futureSalts = salts;
19
- const now = Date.now() / 1e3;
23
+ const now = this._getServerTime();
20
24
  while (salts.length > 0 && salts[0].validSince <= now) {
21
25
  this.currentSalt = salts[0].salt;
22
26
  this._futureSalts.shift();
@@ -30,11 +34,11 @@ class ServerSaltManager {
30
34
  this._timer = utils.timers.setTimeout(() => {
31
35
  this.currentSalt = salt.salt;
32
36
  this._replaceAndScheduleNext();
33
- }, salt.validSince * 1e3 - Date.now());
37
+ }, (salt.validSince - this._getServerTime()) * 1e3);
34
38
  }
35
39
  _replaceAndScheduleNext() {
36
40
  if (this._timer) utils.timers.clearTimeout(this._timer);
37
- const now = Date.now() / 1e3;
41
+ const now = this._getServerTime();
38
42
  while (this._futureSalts.length !== 0) {
39
43
  const salt = this._futureSalts[0];
40
44
  if (salt.validSince > now) break;
@@ -4,6 +4,8 @@ export declare class ServerSaltManager {
4
4
  private _futureSalts;
5
5
  currentSalt: Long;
6
6
  isFetching: boolean;
7
+ private _getServerTime;
8
+ setTimeSource(fn: () => number): void;
7
9
  shouldFetchSalts(): boolean;
8
10
  setFutureSalts(salts: mtp.RawMt_future_salt[]): void;
9
11
  private _timer?;
@@ -4,6 +4,8 @@ export declare class ServerSaltManager {
4
4
  private _futureSalts;
5
5
  currentSalt: Long;
6
6
  isFetching: boolean;
7
+ private _getServerTime;
8
+ setTimeSource(fn: () => number): void;
7
9
  shouldFetchSalts(): boolean;
8
10
  setFutureSalts(salts: mtp.RawMt_future_salt[]): void;
9
11
  private _timer?;
@@ -4,12 +4,16 @@ class ServerSaltManager {
4
4
  _futureSalts = [];
5
5
  currentSalt = Long.ZERO;
6
6
  isFetching = false;
7
+ _getServerTime = () => Date.now() / 1e3;
8
+ setTimeSource(fn) {
9
+ this._getServerTime = fn;
10
+ }
7
11
  shouldFetchSalts() {
8
12
  return !this.isFetching && !this.currentSalt.isZero() && this._futureSalts.length < 2;
9
13
  }
10
14
  setFutureSalts(salts) {
11
15
  this._futureSalts = salts;
12
- const now = Date.now() / 1e3;
16
+ const now = this._getServerTime();
13
17
  while (salts.length > 0 && salts[0].validSince <= now) {
14
18
  this.currentSalt = salts[0].salt;
15
19
  this._futureSalts.shift();
@@ -23,11 +27,11 @@ class ServerSaltManager {
23
27
  this._timer = timers.setTimeout(() => {
24
28
  this.currentSalt = salt.salt;
25
29
  this._replaceAndScheduleNext();
26
- }, salt.validSince * 1e3 - Date.now());
30
+ }, (salt.validSince - this._getServerTime()) * 1e3);
27
31
  }
28
32
  _replaceAndScheduleNext() {
29
33
  if (this._timer) timers.clearTimeout(this._timer);
30
- const now = Date.now() / 1e3;
34
+ const now = this._getServerTime();
31
35
  while (this._futureSalts.length !== 0) {
32
36
  const salt = this._futureSalts[0];
33
37
  if (salt.validSince > now) break;