@bruch/max-client 0.1.0

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 (174) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +168 -0
  3. package/UPSTREAM.md +10 -0
  4. package/dist/api/account.d.ts +24 -0
  5. package/dist/api/account.d.ts.map +1 -0
  6. package/dist/api/auth.d.ts +57 -0
  7. package/dist/api/auth.d.ts.map +1 -0
  8. package/dist/api/bots.d.ts +8 -0
  9. package/dist/api/bots.d.ts.map +1 -0
  10. package/dist/api/chats.d.ts +41 -0
  11. package/dist/api/chats.d.ts.map +1 -0
  12. package/dist/api/facade.d.ts +19 -0
  13. package/dist/api/facade.d.ts.map +1 -0
  14. package/dist/api/index.d.ts +10 -0
  15. package/dist/api/index.d.ts.map +1 -0
  16. package/dist/api/messages.d.ts +35 -0
  17. package/dist/api/messages.d.ts.map +1 -0
  18. package/dist/api/response.d.ts +7 -0
  19. package/dist/api/response.d.ts.map +1 -0
  20. package/dist/api/runtime.d.ts +19 -0
  21. package/dist/api/runtime.d.ts.map +1 -0
  22. package/dist/api/uploads.d.ts +23 -0
  23. package/dist/api/uploads.d.ts.map +1 -0
  24. package/dist/api/users.d.ts +25 -0
  25. package/dist/api/users.d.ts.map +1 -0
  26. package/dist/app.d.ts +55 -0
  27. package/dist/app.d.ts.map +1 -0
  28. package/dist/auth/flows.d.ts +27 -0
  29. package/dist/auth/flows.d.ts.map +1 -0
  30. package/dist/auth/index.d.ts +3 -0
  31. package/dist/auth/index.d.ts.map +1 -0
  32. package/dist/auth/index.js +109 -0
  33. package/dist/auth/index.js.map +11 -0
  34. package/dist/auth/providers.d.ts +11 -0
  35. package/dist/auth/providers.d.ts.map +1 -0
  36. package/dist/client.d.ts +139 -0
  37. package/dist/client.d.ts.map +1 -0
  38. package/dist/config.d.ts +80 -0
  39. package/dist/config.d.ts.map +1 -0
  40. package/dist/connection/connection.d.ts +25 -0
  41. package/dist/connection/connection.d.ts.map +1 -0
  42. package/dist/connection/index.d.ts +4 -0
  43. package/dist/connection/index.d.ts.map +1 -0
  44. package/dist/connection/pending.d.ts +9 -0
  45. package/dist/connection/pending.d.ts.map +1 -0
  46. package/dist/connection/readers.d.ts +17 -0
  47. package/dist/connection/readers.d.ts.map +1 -0
  48. package/dist/dispatch/dispatcher.d.ts +16 -0
  49. package/dist/dispatch/dispatcher.d.ts.map +1 -0
  50. package/dist/dispatch/index.d.ts +3 -0
  51. package/dist/dispatch/index.d.ts.map +1 -0
  52. package/dist/dispatch/router.d.ts +64 -0
  53. package/dist/dispatch/router.d.ts.map +1 -0
  54. package/dist/errors.d.ts +24 -0
  55. package/dist/errors.d.ts.map +1 -0
  56. package/dist/files/file.d.ts +29 -0
  57. package/dist/files/file.d.ts.map +1 -0
  58. package/dist/files/index.d.ts +2 -0
  59. package/dist/files/index.d.ts.map +1 -0
  60. package/dist/files/index.js +95 -0
  61. package/dist/files/index.js.map +10 -0
  62. package/dist/formatting/index.d.ts +2 -0
  63. package/dist/formatting/index.d.ts.map +1 -0
  64. package/dist/formatting/markdown.d.ts +13 -0
  65. package/dist/formatting/markdown.d.ts.map +1 -0
  66. package/dist/index.d.ts +15 -0
  67. package/dist/index.d.ts.map +1 -0
  68. package/dist/index.js +3967 -0
  69. package/dist/index.js.map +48 -0
  70. package/dist/logging.d.ts +10 -0
  71. package/dist/logging.d.ts.map +1 -0
  72. package/dist/protocol/compression.d.ts +8 -0
  73. package/dist/protocol/compression.d.ts.map +1 -0
  74. package/dist/protocol/enums.d.ts +175 -0
  75. package/dist/protocol/enums.d.ts.map +1 -0
  76. package/dist/protocol/index.d.ts +6 -0
  77. package/dist/protocol/index.d.ts.map +1 -0
  78. package/dist/protocol/index.js +438 -0
  79. package/dist/protocol/index.js.map +13 -0
  80. package/dist/protocol/tcp.d.ts +35 -0
  81. package/dist/protocol/tcp.d.ts.map +1 -0
  82. package/dist/protocol/types.d.ts +38 -0
  83. package/dist/protocol/types.d.ts.map +1 -0
  84. package/dist/protocol/websocket.d.ts +7 -0
  85. package/dist/protocol/websocket.d.ts.map +1 -0
  86. package/dist/session/index.d.ts +3 -0
  87. package/dist/session/index.d.ts.map +1 -0
  88. package/dist/session/index.js +179 -0
  89. package/dist/session/index.js.map +12 -0
  90. package/dist/session/store.d.ts +18 -0
  91. package/dist/session/store.d.ts.map +1 -0
  92. package/dist/session/types.d.ts +29 -0
  93. package/dist/session/types.d.ts.map +1 -0
  94. package/dist/telemetry/index.d.ts +4 -0
  95. package/dist/telemetry/index.d.ts.map +1 -0
  96. package/dist/telemetry/index.js +831 -0
  97. package/dist/telemetry/index.js.map +17 -0
  98. package/dist/telemetry/navigation.d.ts +41 -0
  99. package/dist/telemetry/navigation.d.ts.map +1 -0
  100. package/dist/telemetry/payloads.d.ts +30 -0
  101. package/dist/telemetry/payloads.d.ts.map +1 -0
  102. package/dist/telemetry/service.d.ts +53 -0
  103. package/dist/telemetry/service.d.ts.map +1 -0
  104. package/dist/transport/base.d.ts +18 -0
  105. package/dist/transport/base.d.ts.map +1 -0
  106. package/dist/transport/index.d.ts +4 -0
  107. package/dist/transport/index.d.ts.map +1 -0
  108. package/dist/transport/tcp.d.ts +28 -0
  109. package/dist/transport/tcp.d.ts.map +1 -0
  110. package/dist/transport/websocket.d.ts +14 -0
  111. package/dist/transport/websocket.d.ts.map +1 -0
  112. package/dist/types/attachments.d.ts +18 -0
  113. package/dist/types/attachments.d.ts.map +1 -0
  114. package/dist/types/index.d.ts +4 -0
  115. package/dist/types/index.d.ts.map +1 -0
  116. package/dist/types/index.js +376 -0
  117. package/dist/types/index.js.map +12 -0
  118. package/dist/types/models.d.ts +210 -0
  119. package/dist/types/models.d.ts.map +1 -0
  120. package/dist/types/utils.d.ts +10 -0
  121. package/dist/types/utils.d.ts.map +1 -0
  122. package/package.json +95 -0
  123. package/src/api/account.ts +93 -0
  124. package/src/api/auth.ts +312 -0
  125. package/src/api/bots.ts +21 -0
  126. package/src/api/chats.ts +234 -0
  127. package/src/api/facade.ts +28 -0
  128. package/src/api/index.ts +9 -0
  129. package/src/api/messages.ts +230 -0
  130. package/src/api/response.ts +24 -0
  131. package/src/api/runtime.ts +27 -0
  132. package/src/api/uploads.ts +91 -0
  133. package/src/api/users.ts +68 -0
  134. package/src/app.ts +271 -0
  135. package/src/auth/flows.ts +103 -0
  136. package/src/auth/index.ts +2 -0
  137. package/src/auth/providers.ts +30 -0
  138. package/src/client.ts +506 -0
  139. package/src/config.ts +161 -0
  140. package/src/connection/connection.ts +93 -0
  141. package/src/connection/index.ts +3 -0
  142. package/src/connection/pending.ts +49 -0
  143. package/src/connection/readers.ts +33 -0
  144. package/src/dispatch/dispatcher.ts +194 -0
  145. package/src/dispatch/index.ts +2 -0
  146. package/src/dispatch/router.ts +149 -0
  147. package/src/errors.ts +41 -0
  148. package/src/files/file.ts +92 -0
  149. package/src/files/index.ts +1 -0
  150. package/src/formatting/index.ts +1 -0
  151. package/src/formatting/markdown.ts +123 -0
  152. package/src/index.ts +15 -0
  153. package/src/logging.ts +67 -0
  154. package/src/protocol/compression.ts +69 -0
  155. package/src/protocol/enums.ts +175 -0
  156. package/src/protocol/index.ts +5 -0
  157. package/src/protocol/tcp.ts +139 -0
  158. package/src/protocol/types.ts +45 -0
  159. package/src/protocol/websocket.ts +47 -0
  160. package/src/session/index.ts +2 -0
  161. package/src/session/store.ts +154 -0
  162. package/src/session/types.ts +45 -0
  163. package/src/telemetry/index.ts +3 -0
  164. package/src/telemetry/navigation.ts +160 -0
  165. package/src/telemetry/payloads.ts +84 -0
  166. package/src/telemetry/service.ts +194 -0
  167. package/src/transport/base.ts +43 -0
  168. package/src/transport/index.ts +3 -0
  169. package/src/transport/tcp.ts +296 -0
  170. package/src/transport/websocket.ts +63 -0
  171. package/src/types/attachments.ts +24 -0
  172. package/src/types/index.ts +3 -0
  173. package/src/types/models.ts +461 -0
  174. package/src/types/utils.ts +45 -0
@@ -0,0 +1,831 @@
1
+ // @bun
2
+ // src/protocol/compression.ts
3
+ var DEFAULT_MAX_OUTPUT = 5 * 1024 * 1024;
4
+
5
+ class Lz4BlockCompression {
6
+ decompress(source, maxOutput = DEFAULT_MAX_OUTPUT) {
7
+ const output = [];
8
+ let position = 0;
9
+ while (position < source.length) {
10
+ const token = source[position++];
11
+ if (token === undefined)
12
+ break;
13
+ let literalLength = token >>> 4;
14
+ if (literalLength === 15) {
15
+ while (position < source.length) {
16
+ const byte = source[position++];
17
+ if (byte === undefined)
18
+ break;
19
+ literalLength += byte;
20
+ if (byte !== 255)
21
+ break;
22
+ }
23
+ }
24
+ if (position + literalLength > source.length) {
25
+ throw new RangeError("LZ4: literal length out of bounds");
26
+ }
27
+ for (let index = 0;index < literalLength; index += 1) {
28
+ output.push(source[position + index]);
29
+ }
30
+ position += literalLength;
31
+ this.ensureSize(output.length, maxOutput);
32
+ if (position >= source.length)
33
+ break;
34
+ if (position + 1 >= source.length)
35
+ throw new RangeError("LZ4: incomplete offset");
36
+ const offset = source[position] | source[position + 1] << 8;
37
+ position += 2;
38
+ if (offset === 0)
39
+ throw new RangeError("LZ4: zero offset");
40
+ let matchLength = (token & 15) + 4;
41
+ if ((token & 15) === 15) {
42
+ while (position < source.length) {
43
+ const byte = source[position++];
44
+ if (byte === undefined)
45
+ break;
46
+ matchLength += byte;
47
+ if (byte !== 255)
48
+ break;
49
+ }
50
+ }
51
+ const matchPosition = output.length - offset;
52
+ if (matchPosition < 0)
53
+ throw new RangeError("LZ4: match out of bounds");
54
+ for (let index = 0;index < matchLength; index += 1) {
55
+ output.push(output[matchPosition + index % offset]);
56
+ }
57
+ this.ensureSize(output.length, maxOutput);
58
+ }
59
+ return Uint8Array.from(output);
60
+ }
61
+ ensureSize(size, maximum) {
62
+ if (size > maximum)
63
+ throw new RangeError("LZ4: output too large");
64
+ }
65
+ }
66
+
67
+ class ZstdCompression {
68
+ decompress(source, maxOutput = DEFAULT_MAX_OUTPUT) {
69
+ const output = Bun.zstdDecompressSync(source);
70
+ if (output.byteLength > maxOutput)
71
+ throw new RangeError("Zstd: output too large");
72
+ return output;
73
+ }
74
+ }
75
+ // src/protocol/enums.ts
76
+ var Command = {
77
+ REQUEST: 0,
78
+ RESPONSE: 1,
79
+ EVENT: 2,
80
+ ERROR: 3
81
+ };
82
+ var Opcode = {
83
+ PING: 1,
84
+ DEBUG: 2,
85
+ RECONNECT: 3,
86
+ LOG: 5,
87
+ SESSION_INIT: 6,
88
+ PROFILE: 16,
89
+ AUTH_REQUEST: 17,
90
+ AUTH: 18,
91
+ LOGIN: 19,
92
+ LOGOUT: 20,
93
+ SYNC: 21,
94
+ CONFIG: 22,
95
+ AUTH_CONFIRM: 23,
96
+ PRESET_AVATARS: 25,
97
+ ASSETS_GET: 26,
98
+ ASSETS_UPDATE: 27,
99
+ ASSETS_GET_BY_IDS: 28,
100
+ ASSETS_ADD: 29,
101
+ SEARCH_FEEDBACK: 31,
102
+ CONTACT_INFO: 32,
103
+ CONTACT_ADD: 33,
104
+ CONTACT_UPDATE: 34,
105
+ CONTACT_PRESENCE: 35,
106
+ CONTACT_LIST: 36,
107
+ CONTACT_SEARCH: 37,
108
+ CONTACT_MUTUAL: 38,
109
+ CONTACT_PHOTOS: 39,
110
+ CONTACT_SORT: 40,
111
+ CONTACT_VERIFY: 42,
112
+ REMOVE_CONTACT_PHOTO: 43,
113
+ CONTACT_INFO_BY_PHONE: 46,
114
+ CHAT_INFO: 48,
115
+ CHAT_HISTORY: 49,
116
+ CHAT_MARK: 50,
117
+ CHAT_MEDIA: 51,
118
+ CHAT_DELETE: 52,
119
+ CHATS_LIST: 53,
120
+ CHAT_CLEAR: 54,
121
+ CHAT_UPDATE: 55,
122
+ CHAT_CHECK_LINK: 56,
123
+ CHAT_JOIN: 57,
124
+ CHAT_LEAVE: 58,
125
+ CHAT_MEMBERS: 59,
126
+ PUBLIC_SEARCH: 60,
127
+ CHAT_PERSONAL_CONFIG: 61,
128
+ CHAT_LIVESTREAM_INFO: 62,
129
+ CHAT_CREATE: 63,
130
+ MSG_SEND: 64,
131
+ MSG_TYPING: 65,
132
+ MSG_DELETE: 66,
133
+ MSG_EDIT: 67,
134
+ CHAT_SEARCH: 68,
135
+ MSG_SHARE_PREVIEW: 70,
136
+ MSG_GET: 71,
137
+ MSG_SEARCH_TOUCH: 72,
138
+ MSG_SEARCH: 73,
139
+ MSG_GET_STAT: 74,
140
+ CHAT_SUBSCRIBE: 75,
141
+ VIDEO_CHAT_START: 76,
142
+ CHAT_MEMBERS_UPDATE: 77,
143
+ VIDEO_CHAT_START_ACTIVE: 78,
144
+ VIDEO_CHAT_HISTORY: 79,
145
+ PHOTO_UPLOAD: 80,
146
+ STICKER_UPLOAD: 81,
147
+ VIDEO_UPLOAD: 82,
148
+ VIDEO_PLAY: 83,
149
+ VIDEO_CHAT_CREATE_JOIN_LINK: 84,
150
+ CHAT_PIN_SET_VISIBILITY: 86,
151
+ FILE_UPLOAD: 87,
152
+ FILE_DOWNLOAD: 88,
153
+ LINK_INFO: 89,
154
+ MSG_DELETE_RANGE: 92,
155
+ SESSIONS_INFO: 96,
156
+ SESSIONS_CLOSE: 97,
157
+ PHONE_BIND_REQUEST: 98,
158
+ PHONE_BIND_CONFIRM: 99,
159
+ AUTH_LOGIN_RESTORE_PASSWORD: 101,
160
+ GET_INBOUND_CALLS: 103,
161
+ AUTH_2FA_DETAILS: 104,
162
+ EXTERNAL_CALLBACK: 105,
163
+ AUTH_VALIDATE_PASSWORD: 107,
164
+ AUTH_VALIDATE_HINT: 108,
165
+ AUTH_VERIFY_EMAIL: 109,
166
+ AUTH_CHECK_EMAIL: 110,
167
+ AUTH_SET_2FA: 111,
168
+ AUTH_CREATE_TRACK: 112,
169
+ AUTH_CHECK_PASSWORD: 113,
170
+ AUTH_LOGIN_CHECK_PASSWORD: 115,
171
+ AUTH_LOGIN_PROFILE_DELETE: 116,
172
+ CHAT_COMPLAIN: 117,
173
+ MSG_SEND_CALLBACK: 118,
174
+ SUSPEND_BOT: 119,
175
+ LOCATION_STOP: 124,
176
+ LOCATION_SEND: 125,
177
+ LOCATION_REQUEST: 126,
178
+ GET_LAST_MENTIONS: 127,
179
+ NOTIF_MESSAGE: 128,
180
+ NOTIF_TYPING: 129,
181
+ NOTIF_MARK: 130,
182
+ NOTIF_CONTACT: 131,
183
+ NOTIF_PRESENCE: 132,
184
+ NOTIF_CONFIG: 134,
185
+ NOTIF_CHAT: 135,
186
+ NOTIF_ATTACH: 136,
187
+ NOTIF_CALL_START: 137,
188
+ NOTIF_CONTACT_SORT: 139,
189
+ NOTIF_MSG_DELETE_RANGE: 140,
190
+ NOTIF_MSG_DELETE: 142,
191
+ NOTIF_CALLBACK_ANSWER: 143,
192
+ CHAT_BOT_COMMANDS: 144,
193
+ BOT_INFO: 145,
194
+ NOTIF_LOCATION: 147,
195
+ NOTIF_LOCATION_REQUEST: 148,
196
+ NOTIF_ASSETS_UPDATE: 150,
197
+ NOTIF_DRAFT: 152,
198
+ NOTIF_DRAFT_DISCARD: 153,
199
+ NOTIF_MSG_DELAYED: 154,
200
+ NOTIF_MSG_REACTIONS_CHANGED: 155,
201
+ NOTIF_MSG_YOU_REACTED: 156,
202
+ CALLS_TOKEN: 158,
203
+ NOTIF_PROFILE: 159,
204
+ WEB_APP_INIT_DATA: 160,
205
+ COMPLAIN: 161,
206
+ COMPLAIN_REASONS_GET: 162,
207
+ VIDEO_CHAT_JOIN: 166,
208
+ DRAFT_SAVE: 176,
209
+ DRAFT_DISCARD: 177,
210
+ MSG_REACTION: 178,
211
+ MSG_CANCEL_REACTION: 179,
212
+ MSG_GET_REACTIONS: 180,
213
+ MSG_GET_DETAILED_REACTIONS: 181,
214
+ STICKER_CREATE: 193,
215
+ STICKER_SUGGEST: 194,
216
+ VIDEO_CHAT_MEMBERS: 195,
217
+ CHAT_HIDE: 196,
218
+ CHAT_SEARCH_COMMON_PARTICIPANTS: 198,
219
+ PROFILE_DELETE: 199,
220
+ PROFILE_DELETE_TIME: 200,
221
+ TRANSCRIBE_MEDIA: 202,
222
+ ORG_INFO: 256,
223
+ CHAT_REACTIONS_SETTINGS_SET: 257,
224
+ REACTIONS_SETTINGS_GET_BY_CHAT_ID: 258,
225
+ ASSETS_REMOVE: 259,
226
+ ASSETS_MOVE: 260,
227
+ ASSETS_LIST_MODIFY: 261,
228
+ FOLDERS_GET: 272,
229
+ FOLDERS_GET_BY_ID: 273,
230
+ FOLDERS_UPDATE: 274,
231
+ FOLDERS_REORDER: 275,
232
+ FOLDERS_DELETE: 276,
233
+ NOTIF_FOLDERS: 277,
234
+ GET_QR: 288,
235
+ GET_QR_STATUS: 289,
236
+ AUTH_QR_APPROVE: 290,
237
+ LOGIN_BY_QR: 291,
238
+ NOTIF_BANNERS: 292,
239
+ NOTIF_TRANSCRIPTION: 293,
240
+ CHAT_SUGGEST: 300,
241
+ AUDIO_PLAY: 301,
242
+ BANNERS_GET: 302,
243
+ MSG_DELIVERY: 303,
244
+ SEND_VOTE: 304,
245
+ VOTERS_LIST_BY_ANSWER: 305,
246
+ GET_POLL_UPDATES: 306
247
+ };
248
+ // src/protocol/tcp.ts
249
+ import { decode, encode } from "@msgpack/msgpack";
250
+ var TCP_HEADER_SIZE = 10;
251
+
252
+ class TcpPacketFramer {
253
+ pack(options) {
254
+ if (options.payloadBytes.byteLength > 16777215) {
255
+ throw new RangeError("TCP payload exceeds the 24-bit length field");
256
+ }
257
+ const result = new Uint8Array(TCP_HEADER_SIZE + options.payloadBytes.byteLength);
258
+ const view = new DataView(result.buffer);
259
+ view.setUint8(0, options.ver);
260
+ view.setUint8(1, options.cmd);
261
+ view.setUint16(2, options.seq, false);
262
+ view.setUint16(4, options.opcode, false);
263
+ const packedLength = (options.flags & 255) << 24 | options.payloadBytes.byteLength;
264
+ view.setUint32(6, packedLength >>> 0, false);
265
+ result.set(options.payloadBytes, TCP_HEADER_SIZE);
266
+ return result;
267
+ }
268
+ unpack(data) {
269
+ if (data.byteLength < TCP_HEADER_SIZE)
270
+ return null;
271
+ const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
272
+ const packedLength = view.getUint32(6, false);
273
+ const payloadLength = packedLength & 16777215;
274
+ if (data.byteLength < TCP_HEADER_SIZE + payloadLength)
275
+ return null;
276
+ return {
277
+ header: {
278
+ ver: view.getUint8(0),
279
+ cmd: view.getUint8(1),
280
+ seq: view.getUint16(2, false),
281
+ opcode: view.getUint16(4, false),
282
+ flags: packedLength >>> 24,
283
+ payloadLength
284
+ },
285
+ payloadBytes: data.slice(TCP_HEADER_SIZE, TCP_HEADER_SIZE + payloadLength)
286
+ };
287
+ }
288
+ unpackPayloadLength(data) {
289
+ if (data.byteLength < TCP_HEADER_SIZE)
290
+ return null;
291
+ return new DataView(data.buffer, data.byteOffset, data.byteLength).getUint32(6, false) & 16777215;
292
+ }
293
+ }
294
+
295
+ class MsgpackPayloadCodec {
296
+ encode(payload) {
297
+ if (payload === null || payload === undefined)
298
+ return new Uint8Array;
299
+ return encode(payload, { useBigInt64: true, ignoreUndefined: true });
300
+ }
301
+ decode(payload) {
302
+ if (payload.byteLength === 0)
303
+ return {};
304
+ return normalizeKeys(decode(payload, { useBigInt64: true }));
305
+ }
306
+ }
307
+
308
+ class TcpPayloadDecoder {
309
+ serializer;
310
+ lz4;
311
+ zstd;
312
+ constructor(serializer = new MsgpackPayloadCodec, lz4 = new Lz4BlockCompression, zstd = new ZstdCompression) {
313
+ this.serializer = serializer;
314
+ this.lz4 = lz4;
315
+ this.zstd = zstd;
316
+ }
317
+ decode(payload, flags = 0) {
318
+ if (payload.byteLength === 0)
319
+ return {};
320
+ let decoded = payload;
321
+ if (flags === 255)
322
+ decoded = this.zstd.decompress(payload);
323
+ else if (flags > 127)
324
+ throw new RangeError(`Invalid TCP compression factor: ${flags}`);
325
+ else if (flags > 0)
326
+ decoded = this.lz4.decompress(payload);
327
+ return this.serializer.decode(decoded);
328
+ }
329
+ }
330
+
331
+ class TcpProtocol {
332
+ version = 10;
333
+ framer = new TcpPacketFramer;
334
+ serializer = new MsgpackPayloadCodec;
335
+ payloadDecoder = new TcpPayloadDecoder(this.serializer);
336
+ encode(frame) {
337
+ const payloadBytes = this.serializer.encode(frame.payload);
338
+ return this.framer.pack({
339
+ ver: this.version,
340
+ cmd: frame.cmd ?? 0,
341
+ seq: frame.seq,
342
+ opcode: frame.opcode,
343
+ flags: 0,
344
+ payloadBytes
345
+ });
346
+ }
347
+ decode(raw) {
348
+ const packet = this.framer.unpack(raw);
349
+ if (!packet)
350
+ return { opcode: 0, cmd: 0, seq: null, payload: null, raw: null };
351
+ const payload = this.payloadDecoder.decode(packet.payloadBytes, packet.header.flags);
352
+ return {
353
+ opcode: packet.header.opcode,
354
+ cmd: packet.header.cmd,
355
+ seq: packet.header.seq,
356
+ payload,
357
+ raw: payload
358
+ };
359
+ }
360
+ }
361
+ function normalizeKeys(value) {
362
+ if (Array.isArray(value))
363
+ return value.map(normalizeKeys);
364
+ if (value instanceof Map) {
365
+ const result = Object.create(null);
366
+ for (const [key, item] of value)
367
+ result[normalizeKey(key)] = normalizeKeys(item);
368
+ return result;
369
+ }
370
+ if (value !== null && typeof value === "object" && !(value instanceof Uint8Array)) {
371
+ const result = Object.create(null);
372
+ for (const [key, item] of Object.entries(value))
373
+ result[normalizeKey(key)] = normalizeKeys(item);
374
+ return result;
375
+ }
376
+ return value;
377
+ }
378
+ function normalizeKey(value) {
379
+ if (value instanceof Uint8Array)
380
+ return new TextDecoder().decode(value);
381
+ return String(value);
382
+ }
383
+ // src/protocol/websocket.ts
384
+ import { isInteger, isSafeNumber, parse, stringify } from "lossless-json";
385
+
386
+ class WsProtocol {
387
+ version = 11;
388
+ encode(frame) {
389
+ return stringify({ ...frame, cmd: frame.cmd ?? 0, ver: this.version });
390
+ }
391
+ decode(raw) {
392
+ try {
393
+ const value = parse(raw, undefined, {
394
+ parseNumber: (text) => {
395
+ if (isInteger(text) && !isSafeNumber(text))
396
+ return BigInt(text);
397
+ return Number(text);
398
+ }
399
+ });
400
+ if (!isRecord(value))
401
+ return emptyFrame();
402
+ const opcode = safeHeaderNumber(value.opcode);
403
+ const cmd = safeHeaderNumber(value.cmd ?? 0);
404
+ const seq = value.seq === null || value.seq === undefined ? null : safeHeaderNumber(value.seq);
405
+ const payload = isRecord(value.payload) ? value.payload : null;
406
+ return { opcode, cmd, seq, payload, raw: payload };
407
+ } catch {
408
+ return emptyFrame();
409
+ }
410
+ }
411
+ }
412
+ function safeHeaderNumber(value) {
413
+ const result = typeof value === "bigint" ? Number(value) : value;
414
+ if (typeof result !== "number" || !Number.isSafeInteger(result)) {
415
+ throw new TypeError("Invalid WebSocket frame header");
416
+ }
417
+ return result;
418
+ }
419
+ function isRecord(value) {
420
+ return value !== null && typeof value === "object" && !Array.isArray(value);
421
+ }
422
+ function emptyFrame() {
423
+ return { opcode: 0, cmd: 0, seq: null, payload: null, raw: null };
424
+ }
425
+ // src/telemetry/navigation.ts
426
+ var Screen = {
427
+ BACKGROUND: 1,
428
+ CONTACTS: 100,
429
+ CHATS: 150,
430
+ SEARCH: 151,
431
+ CALLS: 300,
432
+ CHAT: 350,
433
+ SETTINGS: 450,
434
+ MINIAPP: 500
435
+ };
436
+ var mainTabParams = { source_type: 5, source_id: 1, tab_config: 2 };
437
+ var defaultProfiles = {
438
+ quick: {
439
+ steps: 2,
440
+ minPause: 35,
441
+ maxPause: 95,
442
+ longPauseChance: 0.05,
443
+ minLongPause: 180,
444
+ maxLongPause: 420,
445
+ backChance: 0.3
446
+ },
447
+ browse: {
448
+ steps: 4,
449
+ minPause: 70,
450
+ maxPause: 210,
451
+ longPauseChance: 0.12,
452
+ minLongPause: 240,
453
+ maxLongPause: 720,
454
+ backChance: 0.22
455
+ },
456
+ read: {
457
+ steps: 3,
458
+ minPause: 140,
459
+ maxPause: 360,
460
+ longPauseChance: 0.25,
461
+ minLongPause: 420,
462
+ maxLongPause: 1200,
463
+ backChance: 0.18
464
+ }
465
+ };
466
+ var graph = {
467
+ [Screen.BACKGROUND]: [
468
+ { screen: Screen.CHATS, weight: 10 },
469
+ { screen: Screen.SETTINGS, weight: 1 }
470
+ ],
471
+ [Screen.CHATS]: [
472
+ { screen: Screen.CHAT, weight: 7 },
473
+ { screen: Screen.CONTACTS, weight: 2 },
474
+ { screen: Screen.SEARCH, weight: 2 },
475
+ { screen: Screen.CALLS, weight: 1 },
476
+ { screen: Screen.SETTINGS, weight: 1 },
477
+ { screen: Screen.CHATS, weight: 2 }
478
+ ],
479
+ [Screen.CHAT]: [
480
+ { screen: Screen.CHATS, weight: 8 },
481
+ { screen: Screen.CHAT, weight: 2 },
482
+ { screen: Screen.SETTINGS, weight: 1 }
483
+ ],
484
+ [Screen.CONTACTS]: [
485
+ { screen: Screen.CHATS, weight: 6 },
486
+ { screen: Screen.CHAT, weight: 2 },
487
+ { screen: Screen.SEARCH, weight: 1 }
488
+ ],
489
+ [Screen.SEARCH]: [
490
+ { screen: Screen.CHATS, weight: 5 },
491
+ { screen: Screen.CHAT, weight: 3 },
492
+ { screen: Screen.CONTACTS, weight: 1 }
493
+ ],
494
+ [Screen.CALLS]: [
495
+ { screen: Screen.CHATS, weight: 5 },
496
+ { screen: Screen.CONTACTS, weight: 2 },
497
+ { screen: Screen.SETTINGS, weight: 2 }
498
+ ],
499
+ [Screen.SETTINGS]: [
500
+ { screen: Screen.CHATS, weight: 7 },
501
+ { screen: Screen.CONTACTS, weight: 2 },
502
+ { screen: Screen.CALLS, weight: 2 },
503
+ { screen: Screen.MINIAPP, weight: 1 }
504
+ ],
505
+ [Screen.MINIAPP]: [
506
+ { screen: Screen.SETTINGS, weight: 3 },
507
+ { screen: Screen.CHATS, weight: 6 }
508
+ ]
509
+ };
510
+
511
+ class NavigationPlanner {
512
+ random;
513
+ currentScreen = Screen.BACKGROUND;
514
+ history = [];
515
+ constructor(random = Math) {
516
+ this.random = random;
517
+ }
518
+ newProfile() {
519
+ const profiles = Object.values(defaultProfiles);
520
+ return profiles[Math.floor(this.random.random() * profiles.length)];
521
+ }
522
+ pause(profile) {
523
+ const long = this.random.random() < profile.longPauseChance;
524
+ return this.between(long ? profile.minLongPause : profile.minPause, long ? profile.maxLongPause : profile.maxPause);
525
+ }
526
+ nextScreen(profile) {
527
+ if (this.history.length > 0 && this.random.random() < profile.backChance) {
528
+ this.currentScreen = this.history.pop();
529
+ return this.currentScreen;
530
+ }
531
+ const transitions = graph[this.currentScreen];
532
+ const total = transitions.reduce((sum, item) => sum + item.weight, 0);
533
+ let point = Math.floor(this.random.random() * total) + 1;
534
+ let selected = transitions[transitions.length - 1];
535
+ for (const transition of transitions) {
536
+ point -= transition.weight;
537
+ if (point <= 0) {
538
+ selected = transition;
539
+ break;
540
+ }
541
+ }
542
+ if (selected.screen !== this.currentScreen) {
543
+ this.history.push(this.currentScreen);
544
+ if (this.history.length > 4)
545
+ this.history.shift();
546
+ }
547
+ this.currentScreen = selected.screen;
548
+ return selected.screen;
549
+ }
550
+ resetToBackground() {
551
+ this.currentScreen = Screen.BACKGROUND;
552
+ this.history.length = 0;
553
+ }
554
+ between(minimum, maximum) {
555
+ return minimum + this.random.random() * (maximum - minimum);
556
+ }
557
+ }
558
+ // src/telemetry/payloads.ts
559
+ class TelemetryPayloadBuilder {
560
+ random;
561
+ constructor(random = Math) {
562
+ this.random = random;
563
+ }
564
+ login(userId, sessionId) {
565
+ return this.event(userId, sessionId, "PERF", "login", {
566
+ properties: { connection_type: 2, vpn: 0, class: 2, background: 1, warm_start: 1 },
567
+ errorType: 100
568
+ });
569
+ }
570
+ navigation(options) {
571
+ return this.event(options.userId, options.sessionId, "NAV", "GO", {
572
+ prev_time: options.prevTime,
573
+ screen_to: options.screenTo,
574
+ action_id: options.actionId,
575
+ screen_from: options.screenFrom,
576
+ ...options.extraParams
577
+ });
578
+ }
579
+ openChat(userId, sessionId) {
580
+ const messages = this.integer(60, 240);
581
+ const render = this.integer(50, 260);
582
+ return this.event(userId, sessionId, "PERF", "open_chat_to_render", {
583
+ spans: [
584
+ { duration: messages + render, name: "open_chat_to_render" },
585
+ { duration: messages, name: "messages_list_created" },
586
+ { duration: render, name: "messages_render" }
587
+ ],
588
+ properties: { class: 2, warm: 1, flow: 1 }
589
+ });
590
+ }
591
+ openChats(userId, sessionId) {
592
+ const created = this.integer(50, 230);
593
+ const rendered = this.integer(180, 650);
594
+ return this.event(userId, sessionId, "PERF", "open_chats_to_render", {
595
+ spans: [
596
+ { duration: created + rendered, name: "open_chats_to_render" },
597
+ { duration: created, name: "chats_tab_created" },
598
+ { duration: rendered, name: "chat_list_render" }
599
+ ],
600
+ properties: { class: 2 }
601
+ });
602
+ }
603
+ toPayload(events) {
604
+ return { events };
605
+ }
606
+ event(userId, sessionId, type, event, params) {
607
+ return { time: Date.now(), userId, type, event, params, sessionId };
608
+ }
609
+ integer(minimum, maximum) {
610
+ return Math.floor(this.random.random() * (maximum - minimum + 1)) + minimum;
611
+ }
612
+ }
613
+ // src/logging.ts
614
+ var priorities = {
615
+ DEBUG: 10,
616
+ INFO: 20,
617
+ WARN: 30,
618
+ ERROR: 40,
619
+ SILENT: 100
620
+ };
621
+
622
+ class ConsoleLogger {
623
+ level;
624
+ constructor(level) {
625
+ this.level = level;
626
+ }
627
+ debug(message, context) {
628
+ this.write("DEBUG", message, context);
629
+ }
630
+ info(message, context) {
631
+ this.write("INFO", message, context);
632
+ }
633
+ warn(message, context) {
634
+ this.write("WARN", message, context);
635
+ }
636
+ error(message, context) {
637
+ this.write("ERROR", message, context);
638
+ }
639
+ write(level, message, context) {
640
+ if (priorities[level] < priorities[this.level])
641
+ return;
642
+ const suffix = context ? ` ${JSON.stringify(redact(context))}` : "";
643
+ const line = `[tsmax] ${level.toLowerCase()} ${message}${suffix}`;
644
+ if (level === "ERROR")
645
+ console.error(line);
646
+ else if (level === "WARN")
647
+ console.warn(line);
648
+ else
649
+ console.log(line);
650
+ }
651
+ }
652
+ var activeLogger = new ConsoleLogger("INFO");
653
+ function configureLogging(level = "INFO", logger) {
654
+ activeLogger = logger ?? new ConsoleLogger(level);
655
+ return activeLogger;
656
+ }
657
+ function getLogger() {
658
+ return activeLogger;
659
+ }
660
+ function redact(value) {
661
+ if (Array.isArray(value))
662
+ return value.map(redact);
663
+ if (value === null || typeof value !== "object")
664
+ return value;
665
+ const result = {};
666
+ for (const [key, item] of Object.entries(value)) {
667
+ result[key] = /token|password|phone|code/i.test(key) ? "[redacted]" : redact(item);
668
+ }
669
+ return result;
670
+ }
671
+
672
+ // src/telemetry/service.ts
673
+ var defaultTelemetryTiming = {
674
+ startupDelay: [15, 90],
675
+ sessionIdleDelay: [900, 2700],
676
+ renderDelay: [0.15, 1.2],
677
+ returnDelay: [12, 45],
678
+ returnToBackgroundChance: 0.4,
679
+ openChatsRenderChance: 0.2
680
+ };
681
+
682
+ class TelemetryService {
683
+ app;
684
+ random;
685
+ timing;
686
+ planner;
687
+ payloads;
688
+ controller = null;
689
+ task = null;
690
+ actionId = 0;
691
+ sessionId;
692
+ lastNavTime = Date.now();
693
+ constructor(app, random = Math, timing = defaultTelemetryTiming) {
694
+ this.app = app;
695
+ this.random = random;
696
+ this.timing = timing;
697
+ this.planner = new NavigationPlanner(random);
698
+ this.payloads = new TelemetryPayloadBuilder(random);
699
+ this.sessionId = app.config.device.clientSessionId;
700
+ }
701
+ get running() {
702
+ return this.task !== null;
703
+ }
704
+ get ready() {
705
+ return this.app.started && this.app.me !== null && this.app.connection.isOpen !== false;
706
+ }
707
+ start() {
708
+ if (this.running || !this.ready)
709
+ return;
710
+ const controller = new AbortController;
711
+ this.controller = controller;
712
+ this.task = this.run(controller.signal).finally(() => {
713
+ if (this.controller === controller) {
714
+ this.controller = null;
715
+ this.task = null;
716
+ }
717
+ });
718
+ }
719
+ async stop() {
720
+ const task = this.task;
721
+ this.controller?.abort();
722
+ this.controller = null;
723
+ if (task)
724
+ await task.catch(() => {
725
+ return;
726
+ });
727
+ this.task = null;
728
+ }
729
+ async sendEvents(events) {
730
+ if (events.length === 0 || !this.ready)
731
+ return;
732
+ await this.app.invoke(Opcode.LOG, this.payloads.toPayload(events), this.app.config.requestTimeout);
733
+ }
734
+ sourceParams(screen) {
735
+ if (screen === Screen.CHATS)
736
+ return { ...mainTabParams };
737
+ if (screen !== Screen.CHAT)
738
+ return {};
739
+ const chat = this.pickChat();
740
+ return chat ? { source_type: chat.type === "DIALOG" ? 1 : 2, source_id: chat.id } : { source_type: 1, source_id: this.userId };
741
+ }
742
+ async run(signal) {
743
+ try {
744
+ await sleep(this.between(this.timing.startupDelay) * 1000, signal);
745
+ await this.sendEvents([this.payloads.login(this.userId, this.sessionId)]);
746
+ while (!signal.aborted) {
747
+ this.sessionId += 1;
748
+ await this.sendEvents(await this.collectSessionEvents(this.planner.newProfile(), signal));
749
+ this.planner.resetToBackground();
750
+ await sleep(this.between(this.timing.sessionIdleDelay) * 1000, signal);
751
+ }
752
+ } catch (error) {
753
+ if (!signal.aborted)
754
+ getLogger().debug("telemetry loop stopped", { error: String(error) });
755
+ }
756
+ }
757
+ async collectSessionEvents(profile, signal) {
758
+ const events = [];
759
+ for (let step = 0;step < profile.steps; step += 1) {
760
+ await sleep(this.planner.pause(profile) * 1000, signal);
761
+ if (!this.ready)
762
+ return events;
763
+ const from = this.planner.currentScreen;
764
+ const to = this.planner.nextScreen(profile);
765
+ events.push(this.navigationEvent(from, to));
766
+ if (to === Screen.CHAT) {
767
+ await sleep(this.between(this.timing.renderDelay) * 1000, signal);
768
+ events.push(this.payloads.openChat(this.userId, this.sessionId));
769
+ } else if (to === Screen.CHATS && this.random.random() < this.timing.openChatsRenderChance) {
770
+ await sleep(this.between(this.timing.renderDelay) * 1000, signal);
771
+ events.push(this.payloads.openChats(this.userId, this.sessionId));
772
+ }
773
+ }
774
+ if (this.planner.currentScreen !== Screen.BACKGROUND && this.random.random() < this.timing.returnToBackgroundChance) {
775
+ await sleep(this.between(this.timing.returnDelay) * 1000, signal);
776
+ const from = this.planner.currentScreen;
777
+ this.planner.resetToBackground();
778
+ events.push(this.navigationEvent(from, Screen.BACKGROUND));
779
+ }
780
+ return events;
781
+ }
782
+ navigationEvent(from, to) {
783
+ this.actionId = this.actionId + 1 >>> 0;
784
+ const event = this.payloads.navigation({
785
+ userId: this.userId,
786
+ sessionId: this.sessionId,
787
+ screenFrom: from,
788
+ screenTo: to,
789
+ prevTime: this.lastNavTime,
790
+ actionId: this.actionId,
791
+ extraParams: this.sourceParams(to)
792
+ });
793
+ this.lastNavTime = event.time;
794
+ return event;
795
+ }
796
+ get userId() {
797
+ if (!this.app.me)
798
+ throw new Error("Telemetry requires an authenticated profile");
799
+ return this.app.me.contact.id;
800
+ }
801
+ pickChat() {
802
+ if (this.app.chats.length === 0)
803
+ return null;
804
+ return this.app.chats[Math.floor(this.random.random() * this.app.chats.length)] ?? null;
805
+ }
806
+ between(range) {
807
+ return range[0] + this.random.random() * (range[1] - range[0]);
808
+ }
809
+ }
810
+ async function sleep(milliseconds, signal) {
811
+ if (signal.aborted)
812
+ throw signal.reason;
813
+ await new Promise((resolve, reject) => {
814
+ const timer = setTimeout(resolve, milliseconds);
815
+ signal.addEventListener("abort", () => {
816
+ clearTimeout(timer);
817
+ reject(signal.reason);
818
+ }, { once: true });
819
+ });
820
+ }
821
+ export {
822
+ mainTabParams,
823
+ defaultTelemetryTiming,
824
+ defaultProfiles,
825
+ TelemetryService,
826
+ TelemetryPayloadBuilder,
827
+ Screen,
828
+ NavigationPlanner
829
+ };
830
+
831
+ //# debugId=3534F2E6FEFBAE9064756E2164756E21